]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics/src/org/simantics/DatabaseBaselines.java
Platform startup performance improvements
[simantics/platform.git] / bundles / org.simantics / src / org / simantics / DatabaseBaselines.java
diff --git a/bundles/org.simantics/src/org/simantics/DatabaseBaselines.java b/bundles/org.simantics/src/org/simantics/DatabaseBaselines.java
new file mode 100644 (file)
index 0000000..96db5ed
--- /dev/null
@@ -0,0 +1,130 @@
+package org.simantics;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+import org.simantics.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.34.0
+ */
+public class DatabaseBaselines {
+
+       private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseBaselines.class);
+
+       private static final boolean REQUIRE_INDEX_IN_BASELINE = false;
+       
+       private static final String DB_DIRECTORY = "db"; //$NON-NLS-1$
+       private static final String INDEX_DIRECTORY = ".metadata/.plugins/org.simantics.db.indexing"; //$NON-NLS-1$
+
+       private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("d. MMM yyyy HH:mm:ss");
+
+       public static Path packageBaseline(Path fromWorkspace, Path packageFile) throws IOException {
+               return compressZip(fromWorkspace, collectBaselinePaths(fromWorkspace), packageFile);
+       }
+
+       private static List<Path> collectBaselinePaths(Path workspace) throws IOException {
+               Path dbPath = workspace.resolve(DB_DIRECTORY);
+               Path indexPath = workspace.resolve(INDEX_DIRECTORY);
+
+               if (!Files.isDirectory(dbPath))
+                       throw new IllegalArgumentException("workspace database directory " + dbPath + " does not exist");
+
+               List<Path> paths = Files.walk(dbPath).collect(Collectors.toList());
+               if (Files.isDirectory(indexPath)) {
+                       List<Path> indexPaths = Files.walk(indexPath).collect(Collectors.toList());
+                       paths.addAll(indexPaths);
+               } else {
+                       if (REQUIRE_INDEX_IN_BASELINE)
+                               throw new IllegalArgumentException("workspace database index directory " + indexPath + " does not exist");
+               }
+               return paths;
+       }
+
+       private static Path compressZip(Path relativeRoot, List<Path> paths, Path zipFile) throws IOException {
+               if (LOGGER.isDebugEnabled())
+                       LOGGER.debug("Compressing " + paths.size() + " path entries into ZIP file " + zipFile);
+               try (ZipOutputStream zout = new ZipOutputStream(Files.newOutputStream(zipFile))) {
+                       compressZip(relativeRoot, zout, paths);
+                       return zipFile;
+               } finally {
+                       if (LOGGER.isDebugEnabled())
+                               LOGGER.debug("Compressed " + paths.size() + " entries into " + zipFile);
+               }
+       }
+
+       private static void compressZip(Path relativeRoot, ZipOutputStream zout, List<Path> paths) throws IOException {
+               for (Path p : paths) {
+                       Path rp = relativeRoot.relativize(p);
+                       String name = rp.toString();
+                       if (Files.isDirectory(p)) {
+                               name = name.endsWith("/") ? name : name + "/";
+                               zout.putNextEntry(new ZipEntry(name));
+                       } else {
+                               zout.putNextEntry(new ZipEntry(name));
+                               FileUtils.copy(p.toFile(), zout);
+                               zout.closeEntry();
+                       }
+               }
+       }
+
+       public static byte[] baselineIndicatorContents(Path path) throws IOException {
+               return String.format("%s%n%s%n",
+                               path.toString(),
+                               Instant.now().atZone(ZoneId.systemDefault()).format(TIMESTAMP_FORMAT))
+                               .getBytes("UTF-8");
+       }
+
+       public static void validateWorkspaceForBaselineInitialization(Path workspaceLocation) throws PlatformException {
+               try {
+                       Path db = workspaceLocation.resolve(DB_DIRECTORY);
+                       if (Files.exists(db))
+                               throw new PlatformException("Database location " + db + " already exists. Cannot re-initialize workspace from baseline.");
+                       if (REQUIRE_INDEX_IN_BASELINE) {
+                               Path index = workspaceLocation.resolve(INDEX_DIRECTORY);
+                               if (!Files.exists(index) || !isEmptyDirectory(index))
+                                       throw new PlatformException("Index location " + index + " already exists. Cannot re-initialize workspace from baseline.");
+                       }
+               } catch (IOException e) {
+                       throw new PlatformException("Failed to validate workspace for baseline initialization", e);
+               }
+       }
+
+       private static boolean isEmptyDirectory(Path dir) throws IOException {
+               return Files.walk(dir).count() == 1;
+       }
+
+       public static void validateBaselineFile(Path baseline) throws PlatformException {
+               try (ZipFile zip = new ZipFile(baseline.toFile())) {
+                       ZipEntry db = zip.getEntry(DB_DIRECTORY);
+                       if (db == null)
+                               throw new PlatformException("Baseline archive does not contain database directory '" + DB_DIRECTORY + "'");
+
+                       if (REQUIRE_INDEX_IN_BASELINE) {
+                               ZipEntry index = zip.getEntry(INDEX_DIRECTORY);
+                               if (index == null)
+                                       throw new PlatformException("Baseline archive does not contain database index directory '" + INDEX_DIRECTORY + "'");
+                       }
+               } catch (IOException e) {
+                       throw new PlatformException("Failed to validate baseline archive " + baseline, e);
+               }
+       }
+
+       public static void main(String[] args) throws IOException {
+               packageBaseline(Paths.get("D:/temp/desktop/workspace"), Paths.get("d:/temp/desktop/workspace/baseline.zip"));
+       }
+
+}