]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.ui/src/org/simantics/ui/jobs/SessionGarbageCollectorJob.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / jobs / SessionGarbageCollectorJob.java
diff --git a/bundles/org.simantics.ui/src/org/simantics/ui/jobs/SessionGarbageCollectorJob.java b/bundles/org.simantics.ui/src/org/simantics/ui/jobs/SessionGarbageCollectorJob.java
new file mode 100644 (file)
index 0000000..c847ddf
--- /dev/null
@@ -0,0 +1,215 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.ui.jobs;\r
+\r
+import java.util.function.Consumer;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.jobs.Job;\r
+import org.simantics.DatabaseJob;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.util.SessionGarbageCollection;\r
+import org.simantics.db.service.LifecycleSupport;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class SessionGarbageCollectorJob extends Job {\r
+\r
+    private static SessionGarbageCollectorJob instance;\r
+\r
+    public synchronized static SessionGarbageCollectorJob getInstance() {\r
+        if (instance == null)\r
+            instance = new SessionGarbageCollectorJob();\r
+        return instance;\r
+    }\r
+\r
+    private static final boolean TRACE                  = false;\r
+\r
+    /**\r
+     * At least 60 seconds between executions.\r
+     */\r
+    private static final long    DEFAULT_QUIET_TIME     = 5000;\r
+\r
+    private long                 start;\r
+    private long                 quietTime;\r
+    private long                 userDefinedQuietTime;\r
+\r
+    private boolean              enabled                = true;\r
+\r
+    /**\r
+     * \r
+     */\r
+    public SessionGarbageCollectorJob() {\r
+        this(DEFAULT_QUIET_TIME);\r
+    }\r
+\r
+    /**\r
+     * @param delayBetweenExecutions\r
+     */\r
+    public SessionGarbageCollectorJob(long delayBetweenExecutions) {\r
+        super("Database Garbage Collector");\r
+        setPriority(Job.DECORATE);\r
+\r
+        // Hide job from users.\r
+        setSystem(true);\r
+\r
+        this.start = System.currentTimeMillis();\r
+        this.quietTime = delayBetweenExecutions;\r
+        this.userDefinedQuietTime = delayBetweenExecutions;\r
+    }\r
+\r
+    /**\r
+     * Cancels the currently scheduled execution of this job and reschedules\r
+     * another execution after the current quiet time. This can be used for\r
+     * easily pushing GC back a bit while performing an operation during which\r
+     * it is not efficient to GC.\r
+     *\r
+     * @see #setQuietTime(long)\r
+     */\r
+    public void rescheduleAfterQuietTime() {\r
+        cancel();\r
+        scheduleAfterQuietTime();\r
+    }\r
+\r
+    /**\r
+     * Cancels the currently scheduled execution of this job and reschedules\r
+     * another with no delay. This can be used for immediate forced execution of\r
+     * session GC.\r
+     */\r
+    public void rescheduleNow() {\r
+        cancel();\r
+        schedule();\r
+    }\r
+\r
+    /**\r
+     * @param enabled\r
+     * @return\r
+     */\r
+    public SessionGarbageCollectorJob setEnabled(boolean enabled) {\r
+        this.enabled = enabled;\r
+        return this;\r
+    }\r
+\r
+//    /**\r
+//     * @param quietTime quiet time between collections in\r
+//     *        milliseconds\r
+//     */\r
+//    public SessionGarbageCollectorJob setQuietTime(long quietTime) {\r
+//        this.quietTime = quietTime;\r
+//        return this;\r
+//    }\r
+\r
+    /**\r
+     * Schedules this job after the currently set quiet time.\r
+     * \r
+     * @see #setQuietTime(long)\r
+     */\r
+    public void scheduleAfterQuietTime() {\r
+        schedule(quietTime);\r
+    }\r
+\r
+    @Override\r
+    public boolean shouldSchedule() {\r
+        return enabled;\r
+    }\r
+\r
+    @Override\r
+    public boolean shouldRun() {\r
+        if (TRACE) {\r
+            if (!enabled) {\r
+                long t = System.currentTimeMillis();\r
+                System.out.println("GC disabled, not running @ " + ((double) (t - start) * 1e-3) + " seconds");\r
+            }\r
+        }\r
+        return enabled;\r
+    }\r
+\r
+    /**\r
+     * Only invoked with actual errors, not <code>null</code> values.\r
+     */\r
+    Consumer<DatabaseException> errorCallback = e -> ErrorLogger.defaultLogError(e);\r
+\r
+    @Override\r
+    protected IStatus run(IProgressMonitor monitor) {\r
+        long interval = quietTime;\r
+        try {\r
+            Session session = Simantics.peekSession();\r
+            if (session == null)\r
+                return Status.CANCEL_STATUS;\r
+            LifecycleSupport lfs = session.peekService(LifecycleSupport.class);\r
+            if (lfs == null || lfs.isClosed() || lfs.isClosing())\r
+                return Status.CANCEL_STATUS;\r
+\r
+            // Never run while a heavy database job is in progress.\r
+            if (DatabaseJob.inProgress()) {\r
+                // Schedule again in at most 10 seconds instead of\r
+                // waiting for the whole quiet time period again.\r
+                interval = Math.min(10, quietTime);\r
+                return Status.CANCEL_STATUS;\r
+            }\r
+\r
+//            // Don't run if there are currently write requests in progress\r
+//            TransactionSupport ts = session.getService(TransactionSupport.class);\r
+//            if (ts.getWriteCount() > 0) {\r
+//                if (TRACE) {\r
+//                    long t = System.currentTimeMillis();\r
+//                    System.out.println("Write in progress, no GC @ " + ((double) (t - start) * 1e-3) + " seconds");\r
+//                }\r
+//                return Status.CANCEL_STATUS;\r
+//            }\r
+\r
+            long begin = System.currentTimeMillis();\r
+            if (TRACE) {\r
+                System.out.println("running GC @ " + ((double) (begin - start) * 1e-3) + " seconds");\r
+            }\r
+\r
+            boolean busy = SessionGarbageCollection.gc(monitor, session, true, errorCallback);\r
+            if(busy) {\r
+               quietTime = Math.max((3*quietTime)/4, 100);\r
+            } else {\r
+               if(quietTime < userDefinedQuietTime)\r
+                       quietTime = Math.min(userDefinedQuietTime, (long)(1.2*quietTime));\r
+            }\r
+\r
+            if (TRACE)\r
+               if(busy)\r
+                       System.err.println("Session GC ended busy. New quiet time is " + quietTime);\r
+            \r
+            // This quiet time might have been adjusted in GC\r
+            interval = quietTime;\r
+\r
+            long intermediate = System.currentTimeMillis();\r
+\r
+            // Clean up heap of all garbage left behind by SessionGarbageCollection \r
+            //System.gc();\r
+\r
+            if (TRACE) {\r
+                //long end = System.currentTimeMillis();\r
+                //System.out.println("Session.GC " + (intermediate - begin) + "ms, System.GC " + (end-intermediate) + "ms, total " + (end - begin) + "ms");\r
+                System.out.println("Session.GC " + (intermediate - begin) + "ms");\r
+            }\r
+\r
+            // Reschedule after a quiet period.\r
+            return Status.OK_STATUS;\r
+        } finally {\r
+            schedule(interval);\r
+            monitor.done();\r
+        }\r
+    }\r
+\r
+}\r