]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics/src/org/simantics/SimanticsPlatform.java
Speeding up platform startup time
[simantics/platform.git] / bundles / org.simantics / src / org / simantics / SimanticsPlatform.java
index 3638d3407df271caa1869b2e9d97cc266e3b535e..a4206e7da3e677a947a6b1db5e7033f547f32eaa 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2018 Association for Decentralized Information Management
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -41,6 +41,7 @@ import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.osgi.service.datalocation.Location;
 import org.eclipse.osgi.service.resolver.BundleDescription;
 import org.ini4j.Ini;
 import org.ini4j.InvalidFileFormatException;
@@ -59,16 +60,15 @@ import org.simantics.db.UndoContext;
 import org.simantics.db.VirtualGraph;
 import org.simantics.db.WriteGraph;
 import org.simantics.db.common.request.ObjectsWithType;
-import org.simantics.db.common.request.Queries;
 import org.simantics.db.common.request.WriteResultRequest;
 import org.simantics.db.common.utils.Transaction;
 import org.simantics.db.exception.ClusterSetExistException;
 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.request.PossibleResource;
 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
 import org.simantics.db.layer0.util.SimanticsKeys;
 import org.simantics.db.layer0.util.TGTransferableGraphSource;
@@ -91,6 +91,7 @@ import org.simantics.graph.db.TransferableGraphs;
 import org.simantics.graph.diff.Diff;
 import org.simantics.graph.diff.TransferableGraphDelta1;
 import org.simantics.internal.Activator;
+import org.simantics.internal.TimedSessionCache;
 import org.simantics.internal.startup.StartupExtensions;
 import org.simantics.layer0.Layer0;
 import org.simantics.operation.Layer0X;
@@ -109,10 +110,13 @@ import org.simantics.project.management.PlatformUtil;
 import org.simantics.project.management.ServerManager;
 import org.simantics.project.management.ServerManagerFactory;
 import org.simantics.project.management.WorkspaceUtil;
+import org.simantics.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.osgi.SCLOsgi;
 import org.simantics.utils.FileUtils;
 import org.simantics.utils.datastructures.Pair;
-import org.simantics.utils.logging.TimeLogger;
 import org.simantics.utils.strings.EString;
+import org.simantics.utils.threads.ExecutorWorker;
+import org.simantics.utils.threads.ThreadUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -186,7 +190,6 @@ public class SimanticsPlatform implements LifecycleListener {
 
     /** Session specific bindings */
     public SimanticsBindings simanticsBindings;
-    public SimanticsBindings simanticsBindings2;
 
     public Thread mainThread;
 
@@ -395,8 +398,7 @@ public class SimanticsPlatform implements LifecycleListener {
                             sb.append("Conflict with "+problem.first+" and "+problem.second+".\n");
                         }
                         throw new PlatformException(sb.toString());
-                    }
-                    else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {
+                    } else if(!session.syncRequest( analyzer.queryExternalDependenciesSatisfied )) {
                         Collection<IdentityNode> unsatisfiedDependencies = analyzer.getUnsatisfiedDependencies();
                         StringBuilder sb = new StringBuilder();
                         for (IdentityNode dep: unsatisfiedDependencies) {
@@ -408,6 +410,10 @@ public class SimanticsPlatform implements LifecycleListener {
                         throw new PlatformException(sb.toString());
                     }
 
+                    message = "Analyzed graph bundles";
+                    monitor.subTask(message);
+                    LOGGER.info(message);
+
                     List<GraphBundle> sortedBundles = analyzer.getSortedGraphs();
                     if(!sortedBundles.isEmpty()) {
 
@@ -486,6 +492,9 @@ public class SimanticsPlatform implements LifecycleListener {
                 }
                 session.getService(XSupport.class).setServiceMode(false, false);
             }
+            message = "Ontologies synchronized";
+            monitor.subTask(message);
+            LOGGER.info(message);
             monitor.worked(100);
         } catch (IOException e) {
             throw new PlatformException(e);
@@ -537,30 +546,31 @@ public class SimanticsPlatform implements LifecycleListener {
 
         monitor.setTaskName("Asserting project resource exists in the database");
         try {
-            projectResource = session.syncRequest( Queries.resource( projectURI ) );
-        } catch (ResourceNotFoundException nfe) {
-            // Project was not found
-            if (workspacePolicy == RecoveryPolicy.ThrowError)
-                throw new PlatformException("Project Resource "+projectURI+" is not found in the database.");
-            // Create empty project with no features
-            try {
-                Transaction.startTransaction(session, true);
+            projectResource = session.syncRequest(new PossibleResource(projectURI));
+            if (projectResource == null) {
+                // Project was not found
+                if (workspacePolicy == RecoveryPolicy.ThrowError)
+                    throw new PlatformException("Project Resource "+projectURI+" is not found in the database.");
+                // Create empty project with no features
                 try {
-                    // The project needs to be created mutable.
-                    session.getService(XSupport.class).setServiceMode(true, false);
+                    Transaction.startTransaction(session, true);
+                    try {
+                        // The project needs to be created mutable.
+                        session.getService(XSupport.class).setServiceMode(true, false);
 
-                    ArrayList<String> empty = new ArrayList<String>();
-                    projectResource = mgmt.createProject(projectName, empty);
-                    installProject |= true;
+                        ArrayList<String> empty = new ArrayList<String>();
+                        projectResource = mgmt.createProject(projectName, empty);
+                        installProject |= true;
 
-                    session.getService(XSupport.class).setServiceMode(false, false);
-                    Transaction.commit();
-                } finally {
-                    Transaction.endTransaction();
+                        session.getService(XSupport.class).setServiceMode(false, false);
+                        Transaction.commit();
+                    } finally {
+                        Transaction.endTransaction();
+                    }
+                    //session.getService( LifecycleSupport.class ).save();
+                } catch (DatabaseException e) {
+                    throw new PlatformException("Failed to create "+projectURI, e);
                 }
-                //session.getService( LifecycleSupport.class ).save();
-            } catch (DatabaseException e) {
-                throw new PlatformException("Failed to create "+projectURI, e);
             }
         } catch (DatabaseException e) {
             throw new PlatformException("Failed to create "+projectURI, e);
@@ -696,7 +706,42 @@ public class SimanticsPlatform implements LifecycleListener {
         resetDatabase(monitor);
     }
 
-    public boolean handleBaselineDatabase() throws PlatformException {
+    private static Path tryGetInstallLocation() {
+        Location l = Platform.getInstallLocation();
+        return l == null ? null : new File(l.getURL().getPath()).toPath();
+    }
+
+    private Path resolveBaselineFile() throws PlatformException {
+        String dbBaselineArchive = System.getProperty("org.simantics.db.baseline", null);
+        if (dbBaselineArchive == null)
+            return null;
+
+        Path baseline = Paths.get(dbBaselineArchive);
+        if (baseline.isAbsolute()) {
+            if (!Files.isRegularFile(baseline))
+                throw new PlatformException("Specified database baseline archive " + baseline
+                        + " does not exist. Cannot initialize workspace database from baseline.");
+            return baseline;
+        }
+
+        // Relative path resolution order:
+        // 1. from the platform "install location"
+        // 2. from working directory
+        Path installLocation = tryGetInstallLocation();
+        if (installLocation != null) {
+            Path installedBaseline = installLocation.resolve(dbBaselineArchive);
+            if (Files.isRegularFile(installedBaseline))
+                return installedBaseline;
+        }
+        if (!Files.isRegularFile(baseline))
+            throw new PlatformException("Specified database baseline archive " + baseline
+                    + " does not exist in either the install location (" + installLocation
+                    + ") or the working directory (" + Paths.get(".").toAbsolutePath()
+                    + "). Cannot initialize workspace database.");
+        return null;
+    }
+
+    private boolean handleBaselineDatabase() throws PlatformException {
         Path workspaceLocation = Platform.getLocation().toFile().toPath();
         Path baselineIndicatorFile = workspaceLocation.resolve(".baselined");
         if (Files.isRegularFile(baselineIndicatorFile)) {
@@ -705,14 +750,10 @@ public class SimanticsPlatform implements LifecycleListener {
             return true;
         }
 
-        String dbBaselineArchive = System.getProperty("org.simantics.db.baseline", null);
-        if (dbBaselineArchive == null)
+        Path baseline = resolveBaselineFile();
+        if (baseline == null)
             return false;
 
-        Path baseline = Paths.get(dbBaselineArchive);
-        if (!Files.isRegularFile(baseline))
-            throw new PlatformException("Specified database baseline archive " + baseline + " does not exist. Cannot initialize workspace database.");
-
         DatabaseBaselines.validateBaselineFile(baseline);
         DatabaseBaselines.validateWorkspaceForBaselineInitialization(workspaceLocation);
         DatabaseBaselines.initializeWorkspaceWithBaseline(baseline, workspaceLocation, baselineIndicatorFile);
@@ -750,8 +791,6 @@ public class SimanticsPlatform implements LifecycleListener {
     {
 
         assert(!running);
-        TimeLogger.log("Beginning of SimanticsPlatform.startUp");
-
         LOGGER.info("Beginning of SimanticsPlatform.startUp");
 
         SubMonitor monitor = SubMonitor.convert(progressMonitor, 1000);
@@ -763,15 +802,19 @@ public class SimanticsPlatform implements LifecycleListener {
 
         // 0. Consult all startup extensions before doing anything with the workspace.
         StartupExtensions.consultStartupExtensions();
-        TimeLogger.log("Consulted platform pre-startup extensions");
+        LOGGER.info("Consulted platform pre-startup extensions");
 
         // 0.1. Clear all temporary files
         Simantics.clearTemporaryDirectory();
-        TimeLogger.log("Cleared temporary directory");
+        LOGGER.info("Cleared temporary directory");
 
         // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb
         VariableRepository.clear();
 
+        // 0.2.1 Activate org.simantics.scl.osgi to prime the SCL compiler early.
+        @SuppressWarnings("unused")
+        ModuleRepository modRepo = SCLOsgi.MODULE_REPOSITORY;
+
         // 0.3 Handle baseline database before opening db
         @SuppressWarnings("unused")
         boolean usingBaseline = handleBaselineDatabase();
@@ -779,8 +822,8 @@ public class SimanticsPlatform implements LifecycleListener {
         // 1. Assert there is a database at <workspace>/db
         SessionDescriptor sessionDescriptor = setupDatabase(databaseDriverId, monitor.newChild(200, SubMonitor.SUPPRESS_NONE), workspacePolicy, userAgent);
         session = sessionDescriptor.getSession();
-        TimeLogger.log("Database setup complete");
-        
+        LOGGER.info("Database setup complete");
+
         // 2. 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);
@@ -794,7 +837,6 @@ public class SimanticsPlatform implements LifecycleListener {
 
         // 3. Assert all graphs, and correct versions, are installed to the database
         synchronizeOntologies(monitor.newChild(400, SubMonitor.SUPPRESS_NONE), ontologyPolicy, requireSynchronize);
-        TimeLogger.log("Synchronized ontologies");
 
         // 4. Assert simantics.cfg exists
         boolean installProject = assertConfiguration(monitor.newChild(25, SubMonitor.SUPPRESS_NONE),workspacePolicy);
@@ -804,7 +846,7 @@ public class SimanticsPlatform implements LifecycleListener {
 
         // 6. Install all features into project, if in debug mode
         updateInstalledGroups(monitor.newChild(25), true); //installProject);
-        TimeLogger.log("Installed all features into project");
+        LOGGER.info("Installed all features into project");
 
         // 7. Assert L0.Session in database for this session
         assertSessionModel(monitor.newChild(25, SubMonitor.SUPPRESS_NONE));
@@ -812,19 +854,21 @@ public class SimanticsPlatform implements LifecycleListener {
         session.getService(XSupport.class).setServiceMode(false, false);
 
         try {
-            monitor.setTaskName("Flush query cache");
+            String message = "Flush query cache";
+            monitor.setTaskName(message);
+            LOGGER.info(message);
             session.syncRequest((Write) graph -> {
                 QueryControl qc = graph.getService(QueryControl.class);
                 qc.flush(graph);
             });
-            TimeLogger.log("Flushed queries");
         } catch (DatabaseException e) {
             LOGGER.error("Flushing queries failed.", e);
         }
         boolean loadProject = true;
         try {
-
-            monitor.setTaskName("Open database session");
+            String message = "Open database session";
+            monitor.setTaskName(message);
+            LOGGER.info(message);
                sessionContext = SimanticsPlatform.INSTANCE.createSessionContext(true);
                // This must be before setSessionContext since some listeners might query this
             sessionContext.setHint(SimanticsKeys.KEY_PROJECT, SimanticsPlatform.INSTANCE.projectResource);
@@ -832,24 +876,24 @@ public class SimanticsPlatform implements LifecycleListener {
             Simantics.setSessionContext(sessionContext);
 
             // 1. Put ResourceBinding that throws an exception to General Bindings
-            simanticsBindings = new SimanticsBindings( null );
+            message = "Put ResourceBinding that throws an exception to General Bindings";
+            LOGGER.info(message);
+            simanticsBindings = new SimanticsBindings();
             Bindings.classBindingFactory.addFactory( simanticsBindings );
 
-
-            // 2. Create session-specific second Binding context (Databoard) and
-            //    put that to Session as a service
             Session session = sessionContext.getSession();
-            Databoard sessionDataboard = new Databoard();
-            session.registerService(Databoard.class, sessionDataboard);
-            simanticsBindings2 = new SimanticsBindings( session );
-            sessionDataboard.classBindingFactory.addFactory( simanticsBindings2 );
+            session.registerService(Databoard.class, Bindings.databoard);
 
             // Register datatype bindings
+            message = "Register datatype bindings";
+            LOGGER.info(message);
             Bindings.defaultBindingFactory.getRepository().put(RGB.Integer.BINDING.type(), RGB.Integer.BINDING);
             Bindings.defaultBindingFactory.getRepository().put(Font.BINDING.type(), Font.BINDING);
 
             if (support.rolledback() || sessionDescriptor.isFreshDatabase()) {
-                monitor.setTaskName("Rebuilding all indexes");
+                message = "Rebuilding all indexes";
+                LOGGER.info(message);
+                monitor.setTaskName(message);
                 try {
                     session.getService(IndexedRelations.class).fullRebuild(monitor.newChild(100), session);
                 } catch (IndexException e) {
@@ -860,17 +904,21 @@ public class SimanticsPlatform implements LifecycleListener {
             }
 
             if(loadProject) {
-                TimeLogger.log("Load project");
-                monitor.setTaskName("Load project");
+                message = "Load project";
+                monitor.setTaskName(message);
+                LOGGER.info(message);
                 project = Projects.loadProject(sessionContext.getSession(), SimanticsPlatform.INSTANCE.projectResource);
                 sessionContext.setHint(ProjectKeys.KEY_PROJECT, project);
                 monitor.worked(100);
-                TimeLogger.log("Loading projects complete");
+                message = "Loading projects complete";
+                LOGGER.info(message);
 
-                monitor.setTaskName("Activate project");
+                message = "Activate project";
+                monitor.setTaskName(message);
+                LOGGER.info(message);
                 project.activate();
                 monitor.worked(100);
-                TimeLogger.log("Project activated");
+                LOGGER.info("Project activated");
             }
 
         } catch (DatabaseException e) {
@@ -892,7 +940,7 @@ public class SimanticsPlatform implements LifecycleListener {
         // the user from undoing any initialization operations performed
         // by the platform startup.
         SimanticsPlatform.INSTANCE.discardSessionUndoHistory();
-        TimeLogger.log("Discarded session undo history");
+        LOGGER.info("Discarded session undo history");
 
         return sessionContext;
 
@@ -902,10 +950,12 @@ public class SimanticsPlatform implements LifecycleListener {
         try {
             // Construct and initialize SessionContext from Session.
             SessionContext sessionContext = SessionContext.create(session, init);
-            TimeLogger.log("Session context created");
+            String message = "Session context created";
+            LOGGER.info(message);
             if (init) {
                 sessionContext.registerServices();
-                TimeLogger.log("Session services registered");
+                message = "Session services registered";
+                LOGGER.info(message);
             }
             return sessionContext;
         } catch (DatabaseException e) {
@@ -948,14 +998,19 @@ public class SimanticsPlatform implements LifecycleListener {
             }
             progress.worked(10);
 
+            // NOP at the moment
+            TimedSessionCache.close();
+
+            progress.subTask("Thread pools");
+            ThreadUtils.shutdown();
+            ExecutorWorker.shutdown();
+            progress.worked(5);
+
             running = false;
             progress.subTask("Close Database Session");
-            Databoard databoard = null;
             if (sessionContext != null) {
                 Session s = sessionContext.peekSession();
                 if (s != null) {
-                    databoard = s.peekService(Databoard.class);
-
                     progress.subTask("Flushing Index Caches");
                     try {
                         Simantics.flushIndexCaches(progress.newChild(20), s);
@@ -973,18 +1028,11 @@ public class SimanticsPlatform implements LifecycleListener {
                 Bindings.classBindingFactory.removeFactory( simanticsBindings );
                 simanticsBindings = null;
             }
-            if (databoard != null) {
-               if (simanticsBindings2 != null) {
-                       databoard.classBindingFactory.removeFactory( simanticsBindings2 );
-                       simanticsBindings2 = null;
-               }
-               databoard.clear();
-            }
 
             // Make sure Simantics clipboard doesn't store unwanted session data references.
             Simantics.setClipboard(new SimanticsClipboardImpl());
 
-            progress.worked(30);
+            progress.worked(50);
 
             session = null;
             projectResource = null;
@@ -1006,6 +1054,15 @@ public class SimanticsPlatform implements LifecycleListener {
         }
         progress.worked(10);
 
+        progress.subTask("Clear index status");
+        try {
+            // Everything ok, clear index dirty state.
+            DatabaseIndexing.clearAllDirty();
+        } catch (IOException e) {
+            LOGGER.error("Problems encountered while refreshing database index states, see exception for details.", e);
+        }
+        progress.worked(5);
+
         if (clearTemporaryFiles) {
             progress.subTask("Clearing Workspace Temporary Directory");
             try {