1 /*******************************************************************************
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.ui.jobs;
14 import java.util.function.Consumer;
16 import org.eclipse.core.runtime.IProgressMonitor;
17 import org.eclipse.core.runtime.IStatus;
18 import org.eclipse.core.runtime.Status;
19 import org.eclipse.core.runtime.jobs.Job;
20 import org.simantics.DatabaseJob;
21 import org.simantics.Simantics;
22 import org.simantics.db.Session;
23 import org.simantics.db.exception.DatabaseException;
24 import org.simantics.db.layer0.util.SessionGarbageCollection;
25 import org.simantics.db.service.LifecycleSupport;
26 import org.simantics.utils.ui.ErrorLogger;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * @author Tuukka Lehtonen
33 public class SessionGarbageCollectorJob extends Job {
35 private static final Logger LOGGER = LoggerFactory.getLogger(SessionGarbageCollectorJob.class);
36 private static SessionGarbageCollectorJob instance;
38 public synchronized static SessionGarbageCollectorJob getInstance() {
40 instance = new SessionGarbageCollectorJob();
44 private static final boolean TRACE = false;
47 * At least 60 seconds between executions.
49 private static final long DEFAULT_QUIET_TIME = 5000;
52 private long quietTime;
53 private long userDefinedQuietTime;
55 private boolean enabled = true;
60 public SessionGarbageCollectorJob() {
61 this(DEFAULT_QUIET_TIME);
65 * @param delayBetweenExecutions
67 public SessionGarbageCollectorJob(long delayBetweenExecutions) {
68 super("Database Garbage Collector");
69 setPriority(Job.DECORATE);
71 // Hide job from users.
74 this.start = System.currentTimeMillis();
75 this.quietTime = delayBetweenExecutions;
76 this.userDefinedQuietTime = delayBetweenExecutions;
80 * Cancels the currently scheduled execution of this job and reschedules
81 * another execution after the current quiet time. This can be used for
82 * easily pushing GC back a bit while performing an operation during which
83 * it is not efficient to GC.
85 * @see #setQuietTime(long)
87 public void rescheduleAfterQuietTime() {
89 scheduleAfterQuietTime();
93 * Cancels the currently scheduled execution of this job and reschedules
94 * another with no delay. This can be used for immediate forced execution of
97 public void rescheduleNow() {
106 public SessionGarbageCollectorJob setEnabled(boolean enabled) {
107 this.enabled = enabled;
112 // * @param quietTime quiet time between collections in
115 // public SessionGarbageCollectorJob setQuietTime(long quietTime) {
116 // this.quietTime = quietTime;
121 * Schedules this job after the currently set quiet time.
123 * @see #setQuietTime(long)
125 public void scheduleAfterQuietTime() {
130 public boolean shouldSchedule() {
135 public boolean shouldRun() {
138 long t = System.currentTimeMillis();
139 LOGGER.info("GC disabled, not running @ " + ((double) (t - start) * 1e-3) + " seconds");
146 * Only invoked with actual errors, not <code>null</code> values.
148 Consumer<DatabaseException> errorCallback = e -> ErrorLogger.defaultLogError(e);
151 protected IStatus run(IProgressMonitor monitor) {
152 long interval = quietTime;
154 Session session = Simantics.peekSession();
156 return Status.CANCEL_STATUS;
157 LifecycleSupport lfs = session.peekService(LifecycleSupport.class);
158 if (lfs == null || lfs.isClosed() || lfs.isClosing())
159 return Status.CANCEL_STATUS;
161 // Never run while a heavy database job is in progress.
162 if (DatabaseJob.inProgress()) {
163 // Schedule again in at most 10 seconds instead of
164 // waiting for the whole quiet time period again.
165 interval = Math.min(10, quietTime);
166 return Status.CANCEL_STATUS;
169 // // Don't run if there are currently write requests in progress
170 // TransactionSupport ts = session.getService(TransactionSupport.class);
171 // if (ts.getWriteCount() > 0) {
173 // long t = System.currentTimeMillis();
174 // System.out.println("Write in progress, no GC @ " + ((double) (t - start) * 1e-3) + " seconds");
176 // return Status.CANCEL_STATUS;
179 long begin = System.currentTimeMillis();
181 LOGGER.info("running GC @ " + ((double) (begin - start) * 1e-3) + " seconds");
184 boolean busy = SessionGarbageCollection.gc(monitor, session, true, errorCallback);
186 quietTime = Math.max((3*quietTime)/4, 100);
188 if(quietTime < userDefinedQuietTime)
189 quietTime = Math.min(userDefinedQuietTime, (long)(1.2*quietTime));
194 LOGGER.info("Session GC ended busy. New quiet time is " + quietTime);
196 // This quiet time might have been adjusted in GC
197 interval = quietTime;
199 long intermediate = System.currentTimeMillis();
201 // Clean up heap of all garbage left behind by SessionGarbageCollection
205 //long end = System.currentTimeMillis();
206 //System.out.println("Session.GC " + (intermediate - begin) + "ms, System.GC " + (end-intermediate) + "ms, total " + (end - begin) + "ms");
207 LOGGER.info("Session.GC " + (intermediate - begin) + "ms");
210 // Reschedule after a quiet period.
211 return Status.OK_STATUS;