diff options
6 files changed, 160 insertions, 16 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java index 5320675c9e..0fef9e2e66 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java @@ -75,6 +75,7 @@ import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.collection.CloseableIterator; import org.eclipse.net4j.util.collection.Pair; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.concurrent.TrackableTimerTask; import org.eclipse.net4j.util.io.IOUtil; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.monitor.OMMonitor; @@ -105,7 +106,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TimerTask; /** * @author Eike Stepper @@ -1372,7 +1372,7 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, /** * @author Stefan Winkler */ - private static final class ConnectionKeepAliveTask extends TimerTask + private static final class ConnectionKeepAliveTask extends TrackableTimerTask { public static final long EXECUTION_PERIOD = 1000 * 60 * 60 * 4; // 4 hours diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java index 06ca4b1b4d..4c1e469114 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java @@ -528,15 +528,16 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp finally { schemaTransaction.close(); - if (async != null) - { - async.stop(); - } } } } finally { + if (async != null) + { + async.stop(); + } + if (packageRegistryCommitLock != null) { systemPackageMappingInfo.ecoreMapped |= ecoreNew; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java index e5ddeb5b2d..2226749082 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java @@ -176,8 +176,8 @@ public class Bugzilla_329254_Test extends AbstractCDOTest thread11.start(); thread21.start(); - thread11.join(); - thread21.join(); + thread11.join(DEFAULT_TIMEOUT); + thread21.join(DEFAULT_TIMEOUT); transaction22.waitForUpdate(transaction11async.getLastCommitTime(), DEFAULT_TIMEOUT); transaction22.waitForUpdate(transaction21async.getLastCommitTime(), DEFAULT_TIMEOUT); @@ -282,8 +282,8 @@ public class Bugzilla_329254_Test extends AbstractCDOTest commitThread1.start(); commitThread2.start(); - commitThread1.join(); - commitThread2.join(); + commitThread1.join(DEFAULT_TIMEOUT); + commitThread2.join(DEFAULT_TIMEOUT); transaction1.waitForUpdate(transaction3.getLastCommitTime(), DEFAULT_TIMEOUT); transaction1.waitForUpdate(transaction2.getLastCommitTime(), DEFAULT_TIMEOUT); @@ -381,8 +381,8 @@ public class Bugzilla_329254_Test extends AbstractCDOTest commitThread1.start(); commitThread2.start(); - commitThread1.join(); - commitThread2.join(); + commitThread1.join(DEFAULT_TIMEOUT); + commitThread2.join(DEFAULT_TIMEOUT); transaction1.waitForUpdate(transaction3.getLastCommitTime(), DEFAULT_TIMEOUT); transaction1.waitForUpdate(transaction2.getLastCommitTime(), DEFAULT_TIMEOUT); diff --git a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java index bd8427a724..5ae8866c0d 100644 --- a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java +++ b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java @@ -14,6 +14,7 @@ import org.eclipse.net4j.internal.util.test.TestExecuter; import org.eclipse.net4j.tests.bundle.OM; import org.eclipse.net4j.util.ReflectUtil; import org.eclipse.net4j.util.concurrent.ConcurrencyUtil; +import org.eclipse.net4j.util.concurrent.TrackableTimerTask; import org.eclipse.net4j.util.event.EventUtil; import org.eclipse.net4j.util.event.IListener; import org.eclipse.net4j.util.io.IORuntimeException; @@ -203,6 +204,15 @@ public abstract class AbstractOMTest extends TestCase try { + TrackableTimerTask.logConstructionStackTraces(2 * DEFAULT_TIMEOUT); + } + catch (Exception ex) + { + IOUtil.print(ex); + } + + try + { clearReferences(getClass()); } catch (Exception ex) diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/TrackableTimerTask.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/TrackableTimerTask.java new file mode 100644 index 0000000000..14fb116af3 --- /dev/null +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/concurrent/TrackableTimerTask.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.net4j.util.concurrent; + +import org.eclipse.net4j.internal.util.bundle.OM; +import org.eclipse.net4j.util.om.OMPlatform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.TimerTask; +import java.util.WeakHashMap; + +/** + * @author Eike Stepper + * @since 3.3 + */ +public abstract class TrackableTimerTask extends TimerTask +{ + /** + * The boolean value of the system property <code>org.eclipse.net4j.util.concurrent.TrackTimerTasks</code>. + */ + public static final boolean TRACK_TIMER_TASKS = Boolean.parseBoolean(OMPlatform.INSTANCE.getProperty( + "org.eclipse.net4j.util.concurrent.TrackTimerTasks", "false")); + + private static final Map<TrackableTimerTask, ConstructionInfo> CONSTRUCTION_INFOS = TRACK_TIMER_TASKS ? new WeakHashMap<TrackableTimerTask, ConstructionInfo>() + : null; + + protected TrackableTimerTask() + { + if (TRACK_TIMER_TASKS) + { + synchronized (CONSTRUCTION_INFOS) + { + CONSTRUCTION_INFOS.put(this, new ConstructionInfo()); + } + } + } + + @Override + public boolean cancel() + { + if (TRACK_TIMER_TASKS) + { + synchronized (CONSTRUCTION_INFOS) + { + CONSTRUCTION_INFOS.remove(this); + } + } + + return super.cancel(); + } + + public static Collection<Exception> getConstructionStackTraces(long minLifeTimeMillis) + { + if (!TRACK_TIMER_TASKS) + { + return Collections.emptyList(); + } + + long maxTimeStamp = System.currentTimeMillis() - minLifeTimeMillis; + Collection<Exception> result = new ArrayList<Exception>(); + + synchronized (CONSTRUCTION_INFOS) + { + for (ConstructionInfo constructionInfo : CONSTRUCTION_INFOS.values()) + { + if (constructionInfo.timeStamp < maxTimeStamp) + { + result.add(constructionInfo.stackTrace); + } + } + } + + return result; + } + + public static void logConstructionStackTraces(long minLifeTimeMillis) + { + if (TRACK_TIMER_TASKS) + { + Collection<Exception> constructionStackTraces = getConstructionStackTraces(minLifeTimeMillis); + if (!constructionStackTraces.isEmpty()) + { + for (Exception exception : constructionStackTraces) + { + OM.LOG.info(exception); + } + } + } + } + + /** + * @author Eike Stepper + */ + private final class ConstructionInfo + { + public final long timeStamp = System.currentTimeMillis(); + + public final Exception stackTrace = getStackTrace(); + + private Exception getStackTrace() + { + try + { + throw new Exception("The timer task " + TrackableTimerTask.this + " has been constructed here:"); + } + catch (Exception ex) + { + return ex; + } + } + } +} diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/monitor/AbstractMonitor.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/monitor/AbstractMonitor.java index 579e4b54ac..84fbdc893d 100644 --- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/monitor/AbstractMonitor.java +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/om/monitor/AbstractMonitor.java @@ -11,6 +11,8 @@ package org.eclipse.net4j.util.om.monitor; import org.eclipse.net4j.internal.util.bundle.OM; +import org.eclipse.net4j.util.concurrent.TrackableTimerTask; +import org.eclipse.net4j.util.om.OMPlatform; import java.util.Timer; import java.util.TimerTask; @@ -21,6 +23,9 @@ import java.util.TimerTask; */ public abstract class AbstractMonitor implements OMMonitor { + private static final boolean CHECK_BEGIN = Boolean.parseBoolean(OMPlatform.INSTANCE.getProperty( + "org.eclipse.net4j.util.om.monitor.CheckBegin", "false")); + private static final long NOT_BEGUN = -1; private double totalWork = NOT_BEGUN; @@ -138,7 +143,7 @@ public abstract class AbstractMonitor implements OMMonitor private void checkBegun() throws MonitorCanceledException { - if (!hasBegun()) + if (CHECK_BEGIN && !hasBegun()) { throw new IllegalStateException("begin() has not been called"); //$NON-NLS-1$ } @@ -155,7 +160,7 @@ public abstract class AbstractMonitor implements OMMonitor /** * @author Eike Stepper */ - public static class AsyncTimerTask extends TimerTask implements Async + public static class AsyncTimerTask extends TrackableTimerTask implements Async { private OMMonitor monitor; @@ -172,7 +177,7 @@ public abstract class AbstractMonitor implements OMMonitor { try { - if (!canceled) + if (!canceled && monitor != null) { double work = 1 - monitor.getWork(); monitor.worked(work / TEN); @@ -188,7 +193,11 @@ public abstract class AbstractMonitor implements OMMonitor { try { - monitor.done(); + if (monitor != null) + { + monitor.done(); + } + cancel(); } catch (Exception ex) @@ -201,6 +210,7 @@ public abstract class AbstractMonitor implements OMMonitor public boolean cancel() { canceled = true; + monitor = null; return super.cancel(); } } |