]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.ui.jobs;\r
13 \r
14 import java.util.function.Consumer;\r
15 \r
16 import org.eclipse.core.runtime.IProgressMonitor;\r
17 import org.eclipse.core.runtime.IStatus;\r
18 import org.eclipse.core.runtime.Status;\r
19 import org.eclipse.core.runtime.jobs.Job;\r
20 import org.simantics.DatabaseJob;\r
21 import org.simantics.Simantics;\r
22 import org.simantics.db.Session;\r
23 import org.simantics.db.exception.DatabaseException;\r
24 import org.simantics.db.layer0.util.SessionGarbageCollection;\r
25 import org.simantics.db.service.LifecycleSupport;\r
26 import org.simantics.utils.ui.ErrorLogger;\r
27 \r
28 /**\r
29  * @author Tuukka Lehtonen\r
30  */\r
31 public class SessionGarbageCollectorJob extends Job {\r
32 \r
33     private static SessionGarbageCollectorJob instance;\r
34 \r
35     public synchronized static SessionGarbageCollectorJob getInstance() {\r
36         if (instance == null)\r
37             instance = new SessionGarbageCollectorJob();\r
38         return instance;\r
39     }\r
40 \r
41     private static final boolean TRACE                  = false;\r
42 \r
43     /**\r
44      * At least 60 seconds between executions.\r
45      */\r
46     private static final long    DEFAULT_QUIET_TIME     = 5000;\r
47 \r
48     private long                 start;\r
49     private long                 quietTime;\r
50     private long                 userDefinedQuietTime;\r
51 \r
52     private boolean              enabled                = true;\r
53 \r
54     /**\r
55      * \r
56      */\r
57     public SessionGarbageCollectorJob() {\r
58         this(DEFAULT_QUIET_TIME);\r
59     }\r
60 \r
61     /**\r
62      * @param delayBetweenExecutions\r
63      */\r
64     public SessionGarbageCollectorJob(long delayBetweenExecutions) {\r
65         super("Database Garbage Collector");\r
66         setPriority(Job.DECORATE);\r
67 \r
68         // Hide job from users.\r
69         setSystem(true);\r
70 \r
71         this.start = System.currentTimeMillis();\r
72         this.quietTime = delayBetweenExecutions;\r
73         this.userDefinedQuietTime = delayBetweenExecutions;\r
74     }\r
75 \r
76     /**\r
77      * Cancels the currently scheduled execution of this job and reschedules\r
78      * another execution after the current quiet time. This can be used for\r
79      * easily pushing GC back a bit while performing an operation during which\r
80      * it is not efficient to GC.\r
81      *\r
82      * @see #setQuietTime(long)\r
83      */\r
84     public void rescheduleAfterQuietTime() {\r
85         cancel();\r
86         scheduleAfterQuietTime();\r
87     }\r
88 \r
89     /**\r
90      * Cancels the currently scheduled execution of this job and reschedules\r
91      * another with no delay. This can be used for immediate forced execution of\r
92      * session GC.\r
93      */\r
94     public void rescheduleNow() {\r
95         cancel();\r
96         schedule();\r
97     }\r
98 \r
99     /**\r
100      * @param enabled\r
101      * @return\r
102      */\r
103     public SessionGarbageCollectorJob setEnabled(boolean enabled) {\r
104         this.enabled = enabled;\r
105         return this;\r
106     }\r
107 \r
108 //    /**\r
109 //     * @param quietTime quiet time between collections in\r
110 //     *        milliseconds\r
111 //     */\r
112 //    public SessionGarbageCollectorJob setQuietTime(long quietTime) {\r
113 //        this.quietTime = quietTime;\r
114 //        return this;\r
115 //    }\r
116 \r
117     /**\r
118      * Schedules this job after the currently set quiet time.\r
119      * \r
120      * @see #setQuietTime(long)\r
121      */\r
122     public void scheduleAfterQuietTime() {\r
123         schedule(quietTime);\r
124     }\r
125 \r
126     @Override\r
127     public boolean shouldSchedule() {\r
128         return enabled;\r
129     }\r
130 \r
131     @Override\r
132     public boolean shouldRun() {\r
133         if (TRACE) {\r
134             if (!enabled) {\r
135                 long t = System.currentTimeMillis();\r
136                 System.out.println("GC disabled, not running @ " + ((double) (t - start) * 1e-3) + " seconds");\r
137             }\r
138         }\r
139         return enabled;\r
140     }\r
141 \r
142     /**\r
143      * Only invoked with actual errors, not <code>null</code> values.\r
144      */\r
145     Consumer<DatabaseException> errorCallback = e -> ErrorLogger.defaultLogError(e);\r
146 \r
147     @Override\r
148     protected IStatus run(IProgressMonitor monitor) {\r
149         long interval = quietTime;\r
150         try {\r
151             Session session = Simantics.peekSession();\r
152             if (session == null)\r
153                 return Status.CANCEL_STATUS;\r
154             LifecycleSupport lfs = session.peekService(LifecycleSupport.class);\r
155             if (lfs == null || lfs.isClosed() || lfs.isClosing())\r
156                 return Status.CANCEL_STATUS;\r
157 \r
158             // Never run while a heavy database job is in progress.\r
159             if (DatabaseJob.inProgress()) {\r
160                 // Schedule again in at most 10 seconds instead of\r
161                 // waiting for the whole quiet time period again.\r
162                 interval = Math.min(10, quietTime);\r
163                 return Status.CANCEL_STATUS;\r
164             }\r
165 \r
166 //            // Don't run if there are currently write requests in progress\r
167 //            TransactionSupport ts = session.getService(TransactionSupport.class);\r
168 //            if (ts.getWriteCount() > 0) {\r
169 //                if (TRACE) {\r
170 //                    long t = System.currentTimeMillis();\r
171 //                    System.out.println("Write in progress, no GC @ " + ((double) (t - start) * 1e-3) + " seconds");\r
172 //                }\r
173 //                return Status.CANCEL_STATUS;\r
174 //            }\r
175 \r
176             long begin = System.currentTimeMillis();\r
177             if (TRACE) {\r
178                 System.out.println("running GC @ " + ((double) (begin - start) * 1e-3) + " seconds");\r
179             }\r
180 \r
181             boolean busy = SessionGarbageCollection.gc(monitor, session, true, errorCallback);\r
182             if(busy) {\r
183                 quietTime = Math.max((3*quietTime)/4, 100);\r
184             } else {\r
185                 if(quietTime < userDefinedQuietTime)\r
186                         quietTime = Math.min(userDefinedQuietTime, (long)(1.2*quietTime));\r
187             }\r
188 \r
189             if (TRACE)\r
190                 if(busy)\r
191                         System.err.println("Session GC ended busy. New quiet time is " + quietTime);\r
192             \r
193             // This quiet time might have been adjusted in GC\r
194             interval = quietTime;\r
195 \r
196             long intermediate = System.currentTimeMillis();\r
197 \r
198             // Clean up heap of all garbage left behind by SessionGarbageCollection \r
199             //System.gc();\r
200 \r
201             if (TRACE) {\r
202                 //long end = System.currentTimeMillis();\r
203                 //System.out.println("Session.GC " + (intermediate - begin) + "ms, System.GC " + (end-intermediate) + "ms, total " + (end - begin) + "ms");\r
204                 System.out.println("Session.GC " + (intermediate - begin) + "ms");\r
205             }\r
206 \r
207             // Reschedule after a quiet period.\r
208             return Status.OK_STATUS;\r
209         } finally {\r
210             schedule(interval);\r
211             monitor.done();\r
212         }\r
213     }\r
214 \r
215 }\r