X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.acorn%2Fsrc%2Forg%2Fsimantics%2Facorn%2FMainState.java;fp=bundles%2Forg.simantics.acorn%2Fsrc%2Forg%2Fsimantics%2Facorn%2FMainState.java;h=ec8451cca78adfef37ea4377cd1fad26e2eff89f;hp=77335289d73b446b6f10b20a0f1a03ce930ce4f0;hb=d9a9d77c7024260e3e3b3a8558ddc84b2a8b99b3;hpb=0144ba232323a0e4f7ec8fe0681a150faafd7caf diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java index 77335289d..ec8451cca 100644 --- a/bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java +++ b/bundles/org.simantics.acorn/src/org/simantics/acorn/MainState.java @@ -1,69 +1,96 @@ package org.simantics.acorn; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; +import java.io.OutputStream; import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.simantics.acorn.exception.InvalidHeadStateException; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.binding.mutable.MutableVariant; import org.simantics.databoard.file.RuntimeIOException; +import org.simantics.databoard.serialization.Serializer; +import org.simantics.databoard.util.binary.BinaryMemory; import org.simantics.utils.FileUtils; public class MainState implements Serializable { private static final long serialVersionUID = 6237383147637270225L; + public static final String MAIN_STATE = "main.state"; + public int headDir = 0; public MainState() { } - - public MainState(int headDir) { + + private MainState(int headDir) { this.headDir = headDir; } - public static MainState load(Path directory) throws IOException { + public static MainState load(Path directory, Consumer callback) throws IOException { Files.createDirectories(directory); - Path f = directory.resolve("main.state"); + Path mainState = directory.resolve(MAIN_STATE); try { + byte[] bytes = Files.readAllBytes(mainState); MainState state = null; - try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(f)))) { - state = (MainState) in.readObject(); + try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { + state = (MainState) org.simantics.databoard.Files.readFile(bais, Bindings.getBindingUnchecked(MainState.class)); } + while (true) { - Path last = directory.resolve(Integer.toString(state.headDir - 1)); + Path latest = directory.resolve(Integer.toString(state.headDir - 1)); try { - Path headState = last.resolve("head.state"); + Path headState = latest.resolve(HeadState.HEAD_STATE); HeadState.validateHeadStateIntegrity(headState); break; } catch (InvalidHeadStateException e) { e.printStackTrace(); state.headDir--; - uncheckedDeleteAll(last); + callback.accept(e); + } finally { + cleanBaseDirectory(directory, latest, callback); } } return state; - } catch(IOException i) { - return new MainState( findNewHeadState(directory) ); - } catch(ClassNotFoundException c) { - throw new Error("MainState class not found", c); + } catch(Exception i) { + callback.accept(i); + int largest = -1; + Path latest = findNewHeadStateDir(directory, callback); + if (latest != null) + largest = safeParseInt(-1, latest.getFileName().toString()); + // +1 because we want to return the next head version to use, + // not the latest existing version. + largest++; + MainState state = new MainState( largest ); + cleanBaseDirectory(directory, latest, callback); + return state; } finally { - if (Files.exists(f)) { - Files.delete(f); + if (Files.exists(mainState)) { + Files.delete(mainState); } } } public void save(Path directory) throws IOException { - Path f = directory.resolve("main.state"); - try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(f)))) { - out.writeObject(this); + Path f = directory.resolve(MAIN_STATE); + BinaryMemory rf = new BinaryMemory(4096); + try { + MutableVariant v = new MutableVariant(Bindings.getBindingUnchecked(MainState.class), this); + Serializer s = Bindings.getSerializerUnchecked( Bindings.VARIANT ); + s.serialize(rf, v); + } finally { + rf.close(); + } + byte[] bytes = rf.toByteBuffer().array(); + try (OutputStream out = Files.newOutputStream(f)) { + out.write(bytes); } FileIO.syncPath(f); } @@ -78,13 +105,13 @@ public class MainState implements Serializable { } /** - * TODO> shouldn't do two things in the same function, this does both head.state search and directory cleanup * * @param directory + * @param callback * @return * @throws IOException */ - private static int findNewHeadState(Path directory) throws IOException { + private static Path findNewHeadStateDir(Path directory, Consumer callback) throws IOException { try (Stream s = Files.walk(directory, 1)) { List reverseSortedPaths = s .filter(p -> !p.equals(directory) && isInteger(p) && Files.isDirectory(p)) @@ -94,25 +121,19 @@ public class MainState implements Serializable { return Integer.compare(p2Name, p1Name); }).collect(Collectors.toList()); - int largest = -1; + Path latest = null; for (Path last : reverseSortedPaths) { - Path headState = last.resolve("head.state"); - if (Files.exists(headState)) { - try { - HeadState.validateHeadStateIntegrity(headState); - largest = safeParseInt(-1, last.getFileName().toString()); - break; - } catch (IOException | InvalidHeadStateException e) { - e.printStackTrace(); - uncheckedDeleteAll(last); - } - } else { - uncheckedDeleteAll(last); + Path headState = last.resolve(HeadState.HEAD_STATE); + try { + HeadState.validateHeadStateIntegrity(headState); + latest = last; + break; + } catch (IOException | InvalidHeadStateException e) { + // Cleanup is done in {@link cleanBaseDirectory} method + callback.accept(e); } } - // +1 because we want to return the next head version to use, - // not the latest existing version. - return largest + 1; + return latest; } } @@ -124,6 +145,30 @@ public class MainState implements Serializable { } } + private static void cleanBaseDirectory(Path directory, Path latest, Consumer callback) throws IOException { + try (Stream s = Files.walk(directory, 1)) { + List reverseSortedPaths = s + .filter(p -> !p.equals(directory) && isInteger(p) && Files.isDirectory(p)) + .sorted((p1, p2) -> { + int p1Name = Integer.parseInt(p1.getFileName().toString()); + int p2Name = Integer.parseInt(p2.getFileName().toString()); + return Integer.compare(p2Name, p1Name); + }).collect(Collectors.toList()); + + for (Path p : reverseSortedPaths) { + if (!p.equals(latest)) { + // this indicates that there is a possibility that index and vg's are out of sync + // if we are able to find folders with higher number than the current head.state + callback.accept(null); + uncheckedDeleteAll(p); + } else { + break; + } + } + + } + } + private static void uncheckedDeleteAll(Path path) { try { FileUtils.deleteAll(path.toFile());