Improve startup time for fresh or rollback'd session in index writing
[simantics/platform.git] / bundles / org.simantics / src / org / simantics / SimanticsPlatform.java
index 211b286a9401e290c0f5819bf9c5d76c035f9a5b..e529938e278a6f781f986dd618efd58285f46035 100644 (file)
@@ -72,6 +72,8 @@ import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.exception.ResourceNotFoundException;
 import org.simantics.db.indexing.DatabaseIndexing;
 import org.simantics.db.layer0.genericrelation.DependenciesRelation;
+import org.simantics.db.layer0.genericrelation.IndexException;
+import org.simantics.db.layer0.genericrelation.IndexedRelations;
 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
 import org.simantics.db.layer0.util.SimanticsKeys;
 import org.simantics.db.layer0.util.TGTransferableGraphSource;
@@ -101,6 +103,7 @@ import org.simantics.project.IProject;
 import org.simantics.project.ProjectFeatures;
 import org.simantics.project.ProjectKeys;
 import org.simantics.project.Projects;
+import org.simantics.project.SessionDescriptor;
 import org.simantics.project.exception.ProjectException;
 import org.simantics.project.features.registry.GroupReference;
 import org.simantics.project.management.DatabaseManagement;
@@ -229,7 +232,7 @@ public class SimanticsPlatform implements LifecycleListener {
         return application != null ? application : UUID.randomUUID().toString();
     }
 
-    private Session setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException {
+    private SessionDescriptor setupDatabase(String databaseDriverId, IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, PlatformUserAgent userAgent) throws PlatformException {
         if (progressMonitor == null)
             progressMonitor = new NullProgressMonitor();
         Path workspaceLocation = Platform.getLocation().toFile().toPath();
@@ -274,12 +277,16 @@ public class SimanticsPlatform implements LifecycleListener {
 
         PlatformUtil.compileAllDynamicOntologies();
 
-        progressMonitor.setTaskName("Asserting all ontologies are installed");
+        String message = "Asserting all ontologies are installed";
+        LOGGER.info(message);
+        progressMonitor.setTaskName(message);
         final Map<GraphBundleRef, GraphBundleEx> platformTGs = new HashMap<GraphBundleRef, GraphBundleEx>();
         try {
 
             // Get a list of bundles installed into the database
-            progressMonitor.subTask("find installed bundles from database");
+            message = "find installed bundles from database";
+            progressMonitor.subTask(message);
+            LOGGER.info(message);
             Map<GraphBundleRef, GraphBundleEx> installedTGs = new HashMap<GraphBundleRef, GraphBundleEx>();
             for (GraphBundle b : session.syncRequest( mgmt.GraphBundleQuery )) {
                 installedTGs.put(GraphBundleRef.of(b), GraphBundleEx.extend(b));
@@ -289,10 +296,13 @@ public class SimanticsPlatform implements LifecycleListener {
 //            if(installedTGs.size() > 1) return;
 
             // Get a list of all bundles in the platform (Bundle Context)
-            List<GraphBundle> tgs = new ArrayList<GraphBundle>();
-            progressMonitor.subTask("load all transferable graphs from platform");
-            PlatformUtil.getAllGraphs(tgs);
-            progressMonitor.subTask("extend bundles to compile versions");
+            message = "load all transferable graphs from platform";
+            progressMonitor.subTask(message);
+            LOGGER.info(message);
+            Collection<GraphBundle> tgs = PlatformUtil.getAllGraphs();
+            message = "extend bundles to compile versions";
+            progressMonitor.subTask(message);
+            LOGGER.info(message);
             for (GraphBundle b : tgs) {
                 GraphBundleEx gbe = GraphBundleEx.extend(b);
                 gbe.build();
@@ -300,7 +310,9 @@ public class SimanticsPlatform implements LifecycleListener {
             }
 
             // Compile a list of TGs that need to be installed or reinstalled in the database
-            progressMonitor.subTask("check bundle reinstallation demand");
+            message = "check bundle reinstallation demand";
+            progressMonitor.subTask(message);
+            LOGGER.info(message);
             List<GraphBundleEx> installTGs = new ArrayList<GraphBundleEx>();
             // Create list of TGs to update, <newTg, oldTg>
             Map<GraphBundleEx,GraphBundleEx> reinstallTGs = new TreeMap<GraphBundleEx,GraphBundleEx>();
@@ -373,7 +385,9 @@ public class SimanticsPlatform implements LifecycleListener {
                 }
 
                 if (ontologyPolicy == OntologyRecoveryPolicy.Merge) {
-                    progressMonitor.subTask("Merging ontology changes");
+                    message = "Merging ontology changes";
+                    progressMonitor.subTask(message);
+                    LOGGER.info(message);
                     // Sort missing TGs into install order
                     GraphDependencyAnalyzer<GraphBundle> analyzer = new GraphDependencyAnalyzer<GraphBundle>();
                     for(GraphBundle tg : installTGs) analyzer.addGraph(tg, tg.getGraph());
@@ -526,11 +540,11 @@ public class SimanticsPlatform implements LifecycleListener {
 
     public boolean assertProject(IProgressMonitor progressMonitor, RecoveryPolicy workspacePolicy, boolean installProject) throws PlatformException {
 
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
+        SubMonitor monitor = SubMonitor.convert(progressMonitor, 10);
 
         final DatabaseManagement mgmt = new DatabaseManagement();
 
-        progressMonitor.setTaskName("Asserting project resource exists in the database");
+        monitor.setTaskName("Asserting project resource exists in the database");
         try {
             projectResource = session.syncRequest( Queries.resource( projectURI ) );
         } catch (ResourceNotFoundException nfe) {
@@ -560,7 +574,7 @@ public class SimanticsPlatform implements LifecycleListener {
         } catch (DatabaseException e) {
             throw new PlatformException("Failed to create "+projectURI, e);
         }
-        progressMonitor.worked(10);
+        monitor.worked(10);
 
         return installProject;
 
@@ -794,8 +808,8 @@ public class SimanticsPlatform implements LifecycleListener {
         TimeLogger.log("Beginning of SimanticsPlatform.startUp");
 
         LOGGER.info("Beginning of SimanticsPlatform.startUp");
-        
-        if (progressMonitor == null) progressMonitor = new NullProgressMonitor();
+
+        SubMonitor monitor = SubMonitor.convert(progressMonitor, 1000);
 
         // For debugging on what kind of platform automatic tests are running in
         // case there are problems.
@@ -817,10 +831,12 @@ public class SimanticsPlatform implements LifecycleListener {
         boolean usingBaseline = handleBaselineDatabase();
         
         // 1. Assert there is a database at <workspace>/db
-        session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent);
+        SessionDescriptor sessionDescriptor = setupDatabase(databaseDriverId, monitor.newChild(200, SubMonitor.SUPPRESS_NONE), workspacePolicy, userAgent);
+        session = sessionDescriptor.getSession();
         TimeLogger.log("Database setup complete");
         
-        // 1.1 
+        // 1.1 Delete all indexes if we cannot be certain they are up-to-date
+        //     A full index rebuild will be done later, before project activation.
         XSupport support = session.getService(XSupport.class);
         if (support.rolledback()) {
             try {
@@ -832,26 +848,27 @@ public class SimanticsPlatform implements LifecycleListener {
         
         // 2. Assert all graphs, and correct versions, are installed to the database
         if(!usingBaseline) {
-            synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize);
+            synchronizeOntologies(monitor.newChild(400, SubMonitor.SUPPRESS_NONE), ontologyPolicy, requireSynchronize);
             TimeLogger.log("Synchronized ontologies");
         }
 
         // 4. Assert simantics.cfg exists
-        boolean installProject = assertConfiguration(progressMonitor,workspacePolicy);
+        boolean installProject = assertConfiguration(monitor.newChild(25, SubMonitor.SUPPRESS_NONE),workspacePolicy);
 
         // 5. Assert Project Resource is installed in the database
-        installProject = assertProject(progressMonitor, workspacePolicy, installProject);
+        installProject = assertProject(monitor.newChild(25, SubMonitor.SUPPRESS_NONE), workspacePolicy, installProject);
 
         // 6. Install all features into project, if in debug mode
-        updateInstalledGroups(progressMonitor, true); //installProject);
+        updateInstalledGroups(monitor.newChild(25), true); //installProject);
         TimeLogger.log("Installed all features into project");
 
         // 7. Assert L0.Session in database for this session
-        assertSessionModel(progressMonitor);
+        assertSessionModel(monitor.newChild(25, SubMonitor.SUPPRESS_NONE));
 
         session.getService(XSupport.class).setServiceMode(false, false);
 
         try {
+            monitor.setTaskName("Flush query cache");
             session.syncRequest((Write) graph -> {
                 QueryControl qc = graph.getService(QueryControl.class);
                 qc.flush(graph);
@@ -863,6 +880,7 @@ public class SimanticsPlatform implements LifecycleListener {
         boolean loadProject = true;
         try {
 
+            monitor.setTaskName("Open database session");
                sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true);
                // This must be before setSessionContext since some listeners might query this
             sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource);
@@ -886,16 +904,28 @@ public class SimanticsPlatform implements LifecycleListener {
             Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING);
             Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING);
 
-            if(loadProject) {
+            if (support.rolledback() || sessionDescriptor.isFreshDatabase()) {
+                monitor.setTaskName("Rebuilding all indexes");
+                try {
+                    session.getService(IndexedRelations.class).fullRebuild(monitor.newChild(100), session);
+                } catch (IndexException e) {
+                    LOGGER.error("Failed to re-build all indexes", e);
+                }
+            } else {
+                monitor.worked(100);
+            }
 
+            if(loadProject) {
                 TimeLogger.log("Load projects");
                 project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource);
+                monitor.worked(100);
 
                 sessionContext.setHint(ProjectKeys.KEY_PROJECT, project);
                 TimeLogger.log("Loading projects complete");
 
                 project.activate();
                 TimeLogger.log("Project activated");
+                monitor.worked(100);
             }
 
         } catch (DatabaseException e) {