diff options
17 files changed, 775 insertions, 382 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF index 98aad84a7c..55a6496d9a 100644 --- a/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.server;singleton:=true -Bundle-Version: 4.2.0.qualifier +Bundle-Version: 4.2.1.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -10,18 +10,18 @@ Bundle-Activator: org.eclipse.emf.cdo.internal.server.bundle.OM$Activator Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-ClassPath: . Require-Bundle: org.eclipse.emf.cdo;bundle-version="[4.0.0,5.0.0)";visibility:=reexport -Export-Package: org.eclipse.emf.cdo.internal.server;version="4.2.0"; +Export-Package: org.eclipse.emf.cdo.internal.server;version="4.2.1"; x-friends:="org.eclipse.emf.cdo.server.db, org.eclipse.emf.cdo.server.net4j, org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.workspace, org.eclipse.emf.cdo.server.hibernate", - org.eclipse.emf.cdo.internal.server.bundle;version="4.2.0";x-internal:=true, - org.eclipse.emf.cdo.internal.server.embedded;version="4.2.0";x-friends:="org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.internal.server.mem;version="4.2.0";x-friends:="org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.internal.server.messages;version="4.2.0";x-internal:=true, - org.eclipse.emf.cdo.internal.server.syncing;version="4.2.0";x-friends:="org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.server;version="4.2.0", - org.eclipse.emf.cdo.server.embedded;version="4.2.0", - org.eclipse.emf.cdo.server.mem;version="4.2.0", - org.eclipse.emf.cdo.spi.server;version="4.2.0" + org.eclipse.emf.cdo.internal.server.bundle;version="4.2.1";x-internal:=true, + org.eclipse.emf.cdo.internal.server.embedded;version="4.2.1";x-friends:="org.eclipse.emf.cdo.tests", + org.eclipse.emf.cdo.internal.server.mem;version="4.2.1";x-friends:="org.eclipse.emf.cdo.tests", + org.eclipse.emf.cdo.internal.server.messages;version="4.2.1";x-internal:=true, + org.eclipse.emf.cdo.internal.server.syncing;version="4.2.1";x-friends:="org.eclipse.emf.cdo.tests", + org.eclipse.emf.cdo.server;version="4.2.1", + org.eclipse.emf.cdo.server.embedded;version="4.2.1", + org.eclipse.emf.cdo.server.mem;version="4.2.1", + org.eclipse.emf.cdo.spi.server;version="4.2.1" diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java index 14f804b5cd..ab8f065d15 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java @@ -225,6 +225,7 @@ public class Session extends Container<IView> implements InternalSession this.lockNotificationMode = lockNotificationMode; } + @Deprecated public long getLastUpdateTime() { synchronized (lastUpdateTimeLock) diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TimeStampAuthority.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TimeStampAuthority.java index b31401ef8c..6d3c997efb 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TimeStampAuthority.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TimeStampAuthority.java @@ -33,17 +33,21 @@ class TimeStampAuthority private InternalRepository repository; /** - * Holds the timestamp that was issued in response to the last call to {@link #createTimestamp()} + * Holds the <i>begin</i> timestamp that was issued in response to the last call to {@link #startCommit(long, OMMonitor)}. + * <p> + * Synchronized on <code>TimeStampAuthority.this</code>. */ @ExcludeFromDump private transient long lastIssuedTimeStamp = CDOBranchPoint.UNSPECIFIED_DATE; /** - * Holds the timestamp that was last reported finished by a call to {@link #endCommit(long)} + * Holds the <i>begin</i> timestamp that was last reported finished by a call to {@link #endCommit(long)}. + * <p> + * Synchronized on <code>lastFinishedTimeStampLock</code>. */ private long lastFinishedTimeStamp; - private LastCommitTimeStampLock lastCommitTimeStampLock = new LastCommitTimeStampLock(); + private LastCommitTimeStampLock lastFinishedTimeStampLock = new LastCommitTimeStampLock(); private boolean strictOrdering; // TODO (CD) Should be a repo property @@ -76,11 +80,7 @@ class TimeStampAuthority synchronized long[] startCommit(long timeStampOverride, OMMonitor monitor) { monitor.begin(); - - if (strictOrdering) - { - strictOrderingLock.lock(); - } + lockIfNeeded(); try { @@ -100,10 +100,11 @@ class TimeStampAuthority now = timeStampOverride; } + long previousTimeStamp = lastIssuedTimeStamp; lastIssuedTimeStamp = now; - runningTransactions.add(lastIssuedTimeStamp); - return new long[] { lastIssuedTimeStamp, getLastFinishedTimeStamp() }; + runningTransactions.add(now); + return new long[] { now, previousTimeStamp }; } finally { @@ -124,41 +125,35 @@ class TimeStampAuthority // of the runningTransactions. Since both sets are sorted, we only need to compare the heads. long oldestRunning = runningTransactions.isEmpty() ? Long.MAX_VALUE : runningTransactions.get(0); long oldestFinished; - synchronized (lastCommitTimeStampLock) + synchronized (lastFinishedTimeStampLock) { long oldValue = lastFinishedTimeStamp; while (!finishedTransactions.isEmpty() && (oldestFinished = finishedTransactions.first()) < oldestRunning) { finishedTransactions.remove(oldestFinished); - internalSetLastFinished(oldestFinished); + setLastFinishedTimeStampUnsynced(oldestFinished); } // If we actually changed the lastFinishedTimeStamp, we need to notify waiting threads if (lastFinishedTimeStamp != oldValue) { - lastCommitTimeStampLock.notifyAll(); + lastFinishedTimeStampLock.notifyAll(); } } - if (strictOrdering) - { - strictOrderingLock.unlock(); - } + unlockIfNeeded(); } synchronized void failCommit(long timeStamp) { - if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE) // Exclude problems before TransactionCommitContext.setTimeStamp() + // Exclude problems before TransactionCommitContext.setTimeStamp() + if (timeStamp == CDOBranchPoint.UNSPECIFIED_DATE) { - if (!runningTransactions.remove(timeStamp)) - { - throw new IllegalArgumentException("Cannot fail transaction with unknown timestamp " + timeStamp); - } + unlockIfNeeded(); } - - if (strictOrdering) + else { - strictOrderingLock.unlock(); + endCommit(timeStamp); } } @@ -183,11 +178,11 @@ class TimeStampAuthority long waitForCommit(long timeout) { - synchronized (lastCommitTimeStampLock) + synchronized (lastFinishedTimeStampLock) { try { - lastCommitTimeStampLock.wait(timeout); + lastFinishedTimeStampLock.wait(timeout); } catch (Exception ignore) { @@ -199,22 +194,39 @@ class TimeStampAuthority void setLastFinishedTimeStamp(long lastCommitTimeStamp) { - synchronized (lastCommitTimeStampLock) + synchronized (lastFinishedTimeStampLock) { - if (lastFinishedTimeStamp < lastCommitTimeStamp) + if (lastCommitTimeStamp > lastFinishedTimeStamp) { - internalSetLastFinished(lastCommitTimeStamp); - lastCommitTimeStampLock.notifyAll(); + lastIssuedTimeStamp = lastCommitTimeStamp; + setLastFinishedTimeStampUnsynced(lastCommitTimeStamp); + lastFinishedTimeStampLock.notifyAll(); } } } - private void internalSetLastFinished(long lastCommitTimeStamp) + private void setLastFinishedTimeStampUnsynced(long lastCommitTimeStamp) { lastFinishedTimeStamp = lastCommitTimeStamp; repository.getStore().setLastCommitTime(lastFinishedTimeStamp); } + private void lockIfNeeded() + { + if (strictOrdering) + { + strictOrderingLock.lock(); + } + } + + private void unlockIfNeeded() + { + if (strictOrdering) + { + strictOrderingLock.unlock(); + } + } + /** * A separate class for better monitor debugging. * diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java index 6dbe4b310f..c7ac0db18c 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java @@ -78,6 +78,7 @@ import org.eclipse.net4j.util.io.ExtendedDataInputStream; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.monitor.Monitor; import org.eclipse.net4j.util.om.monitor.OMMonitor; +import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EPackage; @@ -101,6 +102,8 @@ import java.util.Set; */ public class TransactionCommitContext implements InternalCommitContext { + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_TRANSACTION, TransactionCommitContext.class); + private static final InternalCDORevision DETACHED = new StubCDORevision(null); private final InternalTransaction transaction; @@ -664,7 +667,11 @@ public class TransactionCommitContext implements InternalCommitContext { try { - OM.LOG.error(ex); + if (TRACER.isEnabled()) + { + TRACER.trace(ex); + } + String storeClass = repository.getStore().getClass().getSimpleName(); rollback("Rollback in " + storeClass + ": " + StringUtil.formatException(ex)); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -677,7 +684,10 @@ public class TransactionCommitContext implements InternalCommitContext try { - OM.LOG.error(ex1); + if (TRACER.isEnabled()) + { + TRACER.trace(ex1); + } } catch (Exception ignore) { @@ -741,10 +751,14 @@ public class TransactionCommitContext implements InternalCommitContext try { - InternalSession sender = transaction.getSession(); - CDOCommitInfo commitInfo = success ? createCommitInfo() : createFailureCommitInfo(); + // Send notifications (in particular FailureCommitInfos) only if timeStamp had been allocated + if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE) + { + InternalSession sender = transaction.getSession(); + CDOCommitInfo commitInfo = success ? createCommitInfo() : createFailureCommitInfo(); - repository.sendCommitNotification(sender, commitInfo, clearResourcePathCache); + repository.sendCommitNotification(sender, commitInfo, clearResourcePathCache); + } } catch (Exception ex) { @@ -1456,7 +1470,7 @@ public class TransactionCommitContext implements InternalCommitContext /** * @author Eike Stepper */ - private static final class RollbackException extends RuntimeException + protected static final class RollbackException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java index 9d5c13f363..4f3ffc4064 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/syncing/SynchronizableRepository.java @@ -366,6 +366,8 @@ public abstract class SynchronizableRepository extends Repository.Default implem { try { + long previousCommitTime = getLastCommitTimeStamp(); + int fromBranchID = lastReplicatedBranchID + 1; int toBranchID = in.readInt(); long fromCommitTime = lastReplicatedCommitTime + 1L; @@ -377,7 +379,7 @@ public abstract class SynchronizableRepository extends Repository.Default implem replicateRawReviseRevisions(); replicateRawReloadLocks(); - replicateRawNotifyClients(lastReplicatedCommitTime, toCommitTime); + replicateRawNotifyClients(lastReplicatedCommitTime, toCommitTime, previousCommitTime); setLastReplicatedBranchID(toBranchID); setLastReplicatedCommitTime(toCommitTime); @@ -422,7 +424,7 @@ public abstract class SynchronizableRepository extends Repository.Default implem getLockingManager().reloadLocks(); } - private void replicateRawNotifyClients(long fromCommitTime, long toCommitTime) + private void replicateRawNotifyClients(long fromCommitTime, long toCommitTime, long previousCommitTime) { InternalCDOCommitInfoManager manager = getCommitInfoManager(); InternalSessionManager sessionManager = getSessionManager(); @@ -447,7 +449,7 @@ public abstract class SynchronizableRepository extends Repository.Default implem CDOCommitData data = CDOCommitInfoUtil.createCommitData(newPackages, newObjects, changedObjects, detachedObjects); String comment = "<replicate raw commits>"; //$NON-NLS-1$ - CDOCommitInfo commitInfo = manager.createCommitInfo(branch, toCommitTime, fromCommitTime, SYSTEM_USER_ID, + CDOCommitInfo commitInfo = manager.createCommitInfo(branch, toCommitTime, previousCommitTime, SYSTEM_USER_ID, comment, data); sessionManager.sendCommitNotification(replicatorSession, commitInfo, true); } @@ -909,6 +911,8 @@ public abstract class SynchronizableRepository extends Repository.Default implem { private static final int ARTIFICIAL_VIEW_ID = 0; + private CommitTransactionResult result; + public WriteThroughCommitContext(InternalTransaction transaction) { super(transaction); @@ -1024,7 +1028,7 @@ public abstract class SynchronizableRepository extends Repository.Default implem // Delegate commit to the master CDOSessionProtocol sessionProtocol = getSynchronizer().getRemoteSession().getSessionProtocol(); - CommitTransactionResult result = sessionProtocol.commitDelegation(ctx, monitor); + result = sessionProtocol.commitDelegation(ctx, monitor); // Stop if commit to master failed String rollbackMessage = result.getRollbackMessage(); @@ -1034,8 +1038,7 @@ public abstract class SynchronizableRepository extends Repository.Default implem } // Prepare data needed for commit result and commit notifications - long timeStamp = result.getTimeStamp(); - setTimeStamp(timeStamp); + long timeStamp = result.getTimeStamp(); // result is set to null later! addIDMappings(result.getIDMappings()); applyIDMappings(new Monitor()); @@ -1064,10 +1067,14 @@ public abstract class SynchronizableRepository extends Repository.Default implem @Override protected long[] createTimeStamp(OMMonitor monitor) { - // Already set after commit to the master. - // Do not call getTimeStamp() of the enclosing Repo class!!! + long timeStamp = result.getTimeStamp(); + long previousTimeStamp = result.getPreviousTimeStamp(); + result = null; + InternalRepository repository = getTransaction().getSession().getManager().getRepository(); - return repository.forceCommitTimeStamp(WriteThroughCommitContext.this.getTimeStamp(), monitor); + repository.forceCommitTimeStamp(timeStamp, monitor); + + return new long[] { timeStamp, previousTimeStamp }; } @Override diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISession.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISession.java index c5c7931d69..38a511338d 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISession.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/ISession.java @@ -20,7 +20,7 @@ import org.eclipse.net4j.util.container.IContainer; /** * The server-side representation of a client {@link CDOSession session}. - * + * * @author Eike Stepper * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. @@ -43,7 +43,9 @@ public interface ISession extends CDOCommonSession, IContainer<IView> /** * @since 4.0 + * @deprecated The return value of this method can not be relied upon to be strictly ordered! */ + @Deprecated public long getLastUpdateTime(); /** diff --git a/plugins/org.eclipse.emf.cdo.tests.db/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests.db/META-INF/MANIFEST.MF index 24ee731456..10b0c034b1 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests.db/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.tests.db;singleton:=true -Bundle-Version: 4.0.200.qualifier +Bundle-Version: 4.0.201.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -24,10 +24,10 @@ Import-Package: com.mysql.jdbc.jdbc2.optional;version="[5.0.0,6.0.0)", org.hsqldb.jdbc;version="[2.0.0,3.0.0)", org.postgresql.ds;version="[9.0.0,10.0.0)", org.postgresql.ds.common;version="[9.0.0,10.0.0)" -Export-Package: org.eclipse.emf.cdo.tests.db;version="4.0.200";x-friends:="org.eclipse.emf.cdo.tests.all", - org.eclipse.emf.cdo.tests.db.bundle;version="4.0.200";x-internal:=true, - org.eclipse.emf.cdo.tests.db.capabilities;version="4.0.200";x-friends:="org.eclipse.emf.cdo.tests.all", - org.eclipse.emf.cdo.tests.db.offline;version="4.0.200";x-friends:="org.eclipse.emf.cdo.tests.all", - org.eclipse.emf.cdo.tests.db.performance;version="4.0.200";x-friends:="org.eclipse.emf.cdo.tests.all", - org.eclipse.emf.cdo.tests.db.revisioncache;version="4.0.200";x-friends:="org.eclipse.emf.cdo.tests.all", - org.eclipse.emf.cdo.tests.db.verifier;version="4.0.200";x-friends:="org.eclipse.emf.cdo.tests.all" +Export-Package: org.eclipse.emf.cdo.tests.db;version="4.0.201";x-friends:="org.eclipse.emf.cdo.tests.all", + org.eclipse.emf.cdo.tests.db.bundle;version="4.0.201";x-internal:=true, + org.eclipse.emf.cdo.tests.db.capabilities;version="4.0.201";x-friends:="org.eclipse.emf.cdo.tests.all", + org.eclipse.emf.cdo.tests.db.offline;version="4.0.201";x-friends:="org.eclipse.emf.cdo.tests.all", + org.eclipse.emf.cdo.tests.db.performance;version="4.0.201";x-friends:="org.eclipse.emf.cdo.tests.all", + org.eclipse.emf.cdo.tests.db.revisioncache;version="4.0.201";x-friends:="org.eclipse.emf.cdo.tests.all", + org.eclipse.emf.cdo.tests.db.verifier;version="4.0.201";x-friends:="org.eclipse.emf.cdo.tests.all" diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java index 46ed8313f2..cf30e97a63 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java @@ -65,13 +65,13 @@ public class H2Config extends DBConfig if (defaultDataSource == null) { defaultDataSource = new JdbcDataSource(); - defaultDataSource.setURL("jdbc:h2:" + reusableFolder.getAbsolutePath() + "/h2test"); + defaultDataSource.setURL("jdbc:h2:" + reusableFolder.getAbsolutePath() + "/h2test;LOCK_TIMEOUT=10000"); } H2Adapter.createSchema(defaultDataSource, repoName, !isRestarting()); JdbcDataSource dataSource = new JdbcDataSource(); - dataSource.setURL("jdbc:h2:" + reusableFolder.getAbsolutePath() + "/h2test;SCHEMA=" + repoName); + dataSource.setURL("jdbc:h2:" + reusableFolder.getAbsolutePath() + "/h2test;LOCK_TIMEOUT=10000;SCHEMA=" + repoName); return dataSource; } diff --git a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF index 6bf445139b..6be9e09234 100644 --- a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.tests;singleton:=true -Bundle-Version: 4.0.200.qualifier +Bundle-Version: 4.0.201.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -36,28 +36,28 @@ Require-Bundle: org.eclipse.net4j.tests;bundle-version="[4.0.0,5.0.0)";visibilit org.eclipse.emf.cdo.server.admin;bundle-version="[4.1.0,5.0.0)";visibility:=reexport, org.eclipse.gmf.runtime.notation;bundle-version="[1.5.0,2.0.0)";visibility:=reexport, org.eclipse.ocl.ecore;bundle-version="[3.0.0,4.0.0)" -Export-Package: base;version="4.0.200", - base.impl;version="4.0.200", - base.util;version="4.0.200", - derived;version="4.0.200", - derived.impl;version="4.0.200", - derived.util;version="4.0.200", - interface_;version="4.0.200", - interface_.impl;version="4.0.200", - interface_.util;version="4.0.200", - org.eclipse.emf.cdo.tests;version="4.0.200", - org.eclipse.emf.cdo.tests.bugzilla;version="4.0.200", - org.eclipse.emf.cdo.tests.bundle;version="4.0.200";x-internal:=true, - org.eclipse.emf.cdo.tests.config;version="4.0.200", - org.eclipse.emf.cdo.tests.config.impl;version="4.0.200", - org.eclipse.emf.cdo.tests.defs;version="4.0.200", - org.eclipse.emf.cdo.tests.offline;version="4.0.200", - org.eclipse.emf.cdo.tests.performance;version="4.0.200", - org.eclipse.emf.cdo.tests.performance.framework;version="4.0.200", - org.eclipse.emf.cdo.tests.revisioncache;version="4.0.200", - org.eclipse.emf.cdo.tests.util;version="4.0.200", - reference;version="4.0.200", - reference.impl;version="4.0.200"; +Export-Package: base;version="4.0.201", + base.impl;version="4.0.201", + base.util;version="4.0.201", + derived;version="4.0.201", + derived.impl;version="4.0.201", + derived.util;version="4.0.201", + interface_;version="4.0.201", + interface_.impl;version="4.0.201", + interface_.util;version="4.0.201", + org.eclipse.emf.cdo.tests;version="4.0.201", + org.eclipse.emf.cdo.tests.bugzilla;version="4.0.201", + org.eclipse.emf.cdo.tests.bundle;version="4.0.201";x-internal:=true, + org.eclipse.emf.cdo.tests.config;version="4.0.201", + org.eclipse.emf.cdo.tests.config.impl;version="4.0.201", + org.eclipse.emf.cdo.tests.defs;version="4.0.201", + org.eclipse.emf.cdo.tests.offline;version="4.0.201", + org.eclipse.emf.cdo.tests.performance;version="4.0.201", + org.eclipse.emf.cdo.tests.performance.framework;version="4.0.201", + org.eclipse.emf.cdo.tests.revisioncache;version="4.0.201", + org.eclipse.emf.cdo.tests.util;version="4.0.201", + reference;version="4.0.201", + reference.impl;version="4.0.201"; x-friends:="org.eclipse.emf.cdo.dawn.tests, org.eclipse.emf.cdo.tests.db, org.eclipse.emf.cdo.tests.db4o, @@ -66,5 +66,5 @@ Export-Package: base;version="4.0.200", org.eclipse.emf.cdo.tests.objectivity, org.eclipse.emf.cdo.tests.ui, org.eclipse.emf.cdo.tests.mongodb", - reference.util;version="4.0.200" + reference.util;version="4.0.201" Eclipse-BuddyPolicy: dependent diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_338779_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_338779_Test.java index 617404611f..f525ed643c 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_338779_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_338779_Test.java @@ -4,7 +4,7 @@ * 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: * Caspar De Groot - initial API and implementation */ @@ -31,10 +31,30 @@ import java.util.Date; */ public class Bugzilla_338779_Test extends AbstractCDOTest { - private void test(PassiveUpdateMode passiveUpdateMode) throws CommitException + public void test_refresh() throws CommitException + { + runTest(null); + } + + public void test_passiveUpdate_invalidations() throws CommitException + { + runTest(PassiveUpdateMode.INVALIDATIONS); + } + + public void test_passiveUpdate_changes() throws CommitException + { + runTest(PassiveUpdateMode.CHANGES); + } + + public void test_passiveUpdate_additions() throws CommitException + { + runTest(PassiveUpdateMode.ADDITIONS); + } + + private void runTest(PassiveUpdateMode passiveUpdateMode) throws CommitException { final CDOSession session = openSession(); - CDOTransaction tx = session.openTransaction(); + CDOTransaction transaction = session.openTransaction(); if (passiveUpdateMode != null) { session.options().setPassiveUpdateEnabled(true); @@ -44,15 +64,16 @@ public class Bugzilla_338779_Test extends AbstractCDOTest { session.options().setPassiveUpdateEnabled(false); } - CDOResource r1 = tx.createResource(getResourcePath("/r1")); //$NON-NLS-1$ - PurchaseOrder po1 = getModel1Factory().createPurchaseOrder(); - po1.setDate(new Date()); - r1.getContents().add(po1); + CDOResource resource1 = transaction.createResource(getResourcePath("/r1")); //$NON-NLS-1$ + + PurchaseOrder purchaseOrder1 = getModel1Factory().createPurchaseOrder(); + purchaseOrder1.setDate(new Date()); + resource1.getContents().add(purchaseOrder1); - tx.commit(); + transaction.commit(); - check(po1, session); + check(purchaseOrder1, session); long timestamp = doSecondSession(); if (passiveUpdateMode != null) @@ -62,7 +83,7 @@ public class Bugzilla_338779_Test extends AbstractCDOTest if (passiveUpdateMode == PassiveUpdateMode.INVALIDATIONS) { // Read something on the object to force load - po1.getDate(); + purchaseOrder1.getDate(); } } else @@ -70,32 +91,12 @@ public class Bugzilla_338779_Test extends AbstractCDOTest session.refresh(); } - check(po1, session); + check(purchaseOrder1, session); - tx.close(); + transaction.close(); session.close(); } - public void test_refresh() throws CommitException - { - test(null); - } - - public void test_passiveUpdate_invalidations() throws CommitException - { - test(PassiveUpdateMode.INVALIDATIONS); - } - - public void test_passiveUpdate_changes() throws CommitException - { - test(PassiveUpdateMode.CHANGES); - } - - public void test_passiveUpdate_additions() throws CommitException - { - test(PassiveUpdateMode.ADDITIONS); - } - private void check(EObject eObject, CDOSession session) { CDOObject obj = CDOUtil.getCDOObject(eObject); @@ -109,15 +110,15 @@ public class Bugzilla_338779_Test extends AbstractCDOTest private long doSecondSession() throws CommitException { CDOSession session = openSession(); - CDOTransaction tx = session.openTransaction(); - CDOResource r1 = tx.getResource(getResourcePath("/r1")); //$NON-NLS-1$ + CDOTransaction transaction = session.openTransaction(); + CDOResource resource1 = transaction.getResource(getResourcePath("/r1")); //$NON-NLS-1$ // Change the purchaseOrder - PurchaseOrder po1 = (PurchaseOrder)r1.getContents().get(0); - po1.setDate(new Date()); + PurchaseOrder purchaseOrder1 = (PurchaseOrder)resource1.getContents().get(0); + purchaseOrder1.setDate(new Date()); - CDOCommitInfo commitInfo = tx.commit(); - tx.close(); + CDOCommitInfo commitInfo = transaction.commit(); + transaction.close(); session.close(); return commitInfo.getTimeStamp(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java index 20412b07a4..950078044a 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_341995_Test.java @@ -4,7 +4,7 @@ * 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: * Caspar De Groot - initial API and implementation */ @@ -25,8 +25,8 @@ import org.eclipse.emf.cdo.util.CommitException; import java.util.concurrent.TimeUnit; /** - * See bug 341995. - * + * Bug 341995: + * * @author Caspar De Groot */ public class Bugzilla_341995_Test extends AbstractCDOTest @@ -34,16 +34,16 @@ public class Bugzilla_341995_Test extends AbstractCDOTest public void test() throws Exception { CDOSession session = openSession(); - CDOTransaction tx = session.openTransaction(); - CDOResource resource = tx.createResource(getResourcePath("test")); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("test")); Model1Factory factory = getModel1Factory(); - Category cat = factory.createCategory(); - resource.getContents().add(cat); - tx.commit(); + Category category = factory.createCategory(); + resource.getContents().add(category); + transaction.commit(); - CDOObject cdoCat = CDOUtil.getCDOObject(cat); - msg(cdoCat.cdoRevision().getVersion()); + CDOObject cdoCategory = CDOUtil.getCDOObject(category); + msg(cdoCategory.cdoRevision().getVersion()); long delay = 2000L; @@ -60,14 +60,14 @@ public class Bugzilla_341995_Test extends AbstractCDOTest // Attempt the lock; this must block for a while, because it needs to receive // the commitNotification from the commit in the other session, which we are // artificially delaying - cdoCat.cdoWriteLock().lock(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + cdoCategory.cdoWriteLock().lock(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); long timeTaken = System.currentTimeMillis() - time1; // We verify that there really was a delay - assertEquals("timeTaken == " + timeTaken, true, timeTaken >= delay); + assertEquals("timeTaken == " + timeTaken, true, timeTaken >= delay - 10); - tx.close(); + transaction.close(); session.close(); } finally @@ -83,17 +83,17 @@ public class Bugzilla_341995_Test extends AbstractCDOTest public void run() { CDOSession session = openSession(); - CDOTransaction tx = session.openTransaction(); - CDOResource resource = tx.getResource(getResourcePath("test")); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); - Category cat = (Category)resource.getContents().get(0); - cat.setName("dirty"); + Category category = (Category)resource.getContents().get(0); + category.setName("dirty"); CDOCommitInfo info; try { - info = tx.commit(); + info = transaction.commit(); } catch (CommitException ex) { @@ -102,7 +102,7 @@ public class Bugzilla_341995_Test extends AbstractCDOTest msg(info.getTimeStamp()); - tx.close(); + transaction.close(); session.close(); } }; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349804_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349804_Test.java index a0f8caed41..f929987779 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349804_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349804_Test.java @@ -4,7 +4,7 @@ * 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 */ @@ -17,6 +17,7 @@ import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext; import org.eclipse.emf.cdo.server.ITransaction; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.session.CDOSessionInvalidationEvent; +import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.emf.cdo.tests.AbstractCDOTest; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.transaction.CDOTransaction; @@ -31,39 +32,52 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** + * Bug 349804: Session is not invalidated after commit. + * * @author Egidijus Vaisnora */ public class Bugzilla_349804_Test extends AbstractCDOTest { public void testInvalidation() throws CommitException, InterruptedException { + disableConsole(); + long timeStamp; + { + InternalRepository repository = getRepository(); + CDOSession session = openSession(); - CDOTransaction transaction1 = session.openTransaction(); + CDOTransaction transaction = session.openTransaction(); - transaction1.createResource(getResourcePath("test")); - transaction1.commit(); + transaction.createResource(getResourcePath("test")); + timeStamp = transaction.commit().getTimeStamp(); Failure handler = new Failure(); - getRepository().addHandler(handler); - CDOTransaction failureTransaction = session.openTransaction(); - failureTransaction.createResource(getResourcePath("fail")); + repository.addHandler(handler); try { // Creating failure commit. It will change last update time on server TimeStampAuthority - failureTransaction.commit(); + transaction.createResource(getResourcePath("fail")); + transaction.commit(); fail("CommitException expected"); } catch (CommitException expected) { + // SUCCESS + } + finally + { + repository.removeHandler(handler); + session.close(); } - getRepository().removeHandler(handler); - session.close(); + assertNotSame(timeStamp, repository.getLastCommitTimeStamp()); } CDOSession session = openSession(); + assertEquals(getRepository().getLastCommitTimeStamp(), session.getLastUpdateTime()); + CDOTransaction transaction = session.openTransaction(); final CountDownLatch invalidationLatch = new CountDownLatch(1); @@ -85,7 +99,7 @@ public class Bugzilla_349804_Test extends AbstractCDOTest // Invalidation shall fail, because it will use lastUpdateTime from TimeStampAuthority for commit result transaction.commit(); - invalidationLatch.await(500, TimeUnit.MILLISECONDS); + invalidationLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); assertEquals("Invalidation was not delivered", 0, invalidationLatch.getCount()); } @@ -98,12 +112,12 @@ public class Bugzilla_349804_Test extends AbstractCDOTest transaction1.createResource(getResourcePath("test")); transaction1.commit(); - Failure handler = new Failure(); - getRepository().addHandler(handler); - CDOTransaction failureTransaction = session.openTransaction(); failureTransaction.createResource(getResourcePath("fail")); + Failure handler = new Failure(); + getRepository().addHandler(handler); + try { // Creating failure commit. It will change last update time on server TimeStampAuthority @@ -112,10 +126,13 @@ public class Bugzilla_349804_Test extends AbstractCDOTest } catch (CommitException expected) { + // SUCCESS + } + finally + { + getRepository().removeHandler(handler); + session.close(); } - - getRepository().removeHandler(handler); - session.close(); } CDOSession session = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_390185_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_390185_Test.java index cb06c5392f..b81aa684e9 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_390185_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_390185_Test.java @@ -15,7 +15,9 @@ import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.AbstractCDOTest; import org.eclipse.emf.cdo.tests.model1.Category; import org.eclipse.emf.cdo.transaction.CDOTransaction; -import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.cdo.util.CommitConflictException; + +import org.eclipse.net4j.util.concurrent.ConcurrencyUtil; import java.util.ArrayList; import java.util.List; @@ -24,17 +26,17 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** - * Bug 390185. + * Bug 390185: Deadlock on multiple concurrent transactions. * * @author Eike Stepper */ public class Bugzilla_390185_Test extends AbstractCDOTest { - private static final int THREADS = 5; + private static final int THREADS = 4; - private static final int TRANSACTIONS_PER_THREAD = 100; + private static final int TRANSACTIONS_PER_THREAD = 40; - public void testIvalidationDeadlock() throws Exception + public void testInvalidationDeadlock() throws Exception { CDOSession session = openSession(); @@ -48,7 +50,7 @@ public class Bugzilla_390185_Test extends AbstractCDOTest if (!latch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)) { - throw new TimeoutException(); + throw new TimeoutException("Not all actory finished in time"); } } @@ -80,6 +82,7 @@ public class Bugzilla_390185_Test extends AbstractCDOTest CDOTransaction transaction = session.openTransaction(); attemptCommit(transaction); transaction.close(); + ConcurrencyUtil.sleep(2); } latch.countDown(); @@ -102,7 +105,7 @@ public class Bugzilla_390185_Test extends AbstractCDOTest break; } } - catch (CommitException ex) + catch (CommitConflictException ex) { transaction.rollback(); } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_411927_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_411927_Test.java new file mode 100644 index 0000000000..92d1ae79aa --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_411927_Test.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2013 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.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.server.Repository; +import org.eclipse.emf.cdo.internal.server.TransactionCommitContext; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.spi.server.InternalCommitContext; +import org.eclipse.emf.cdo.spi.server.InternalRepository; +import org.eclipse.emf.cdo.spi.server.InternalTransaction; +import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig; +import org.eclipse.emf.cdo.tests.model1.Category; +import org.eclipse.emf.cdo.tests.model1.Company; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CDOUtil; +import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.cdo.util.ConcurrentAccessException; + +import java.util.Map; + +/** + * Bug 411927: CDOSessionImpl can "freeze" during invalidation reordering. + * + * @author Eike Stepper + */ +@CleanRepositoriesBefore +@CleanRepositoriesAfter +public class Bugzilla_411927_Test extends AbstractCDOTest +{ + private static final String RESOURCE_NAME = "res1"; + + private static final int CLIENTS = 20; + + private static final int COMMITS_PER_CLIENT = 3; + + private static final String BAD_COMMIT = "Bad Commit"; + + public void testWithoutFailure() throws Exception + { + executeTestWith(FailureTime.NEVER); + } + + public void testWithFailureBeforeTimeStamp() throws Exception + { + executeTestWith(FailureTime.BEFORE_TIMESTAMP); + } + + public void testWithFailureAfterTimeStamp() throws Exception + { + executeTestWith(FailureTime.AFTER_TIMESTAMP); + } + + private void initRepository(final FailureTime failureTime) + { + Repository repository = new Repository.Default() + { + @Override + public InternalCommitContext createCommitContext(InternalTransaction transaction) + { + return new TransactionCommitContext(transaction) + { + @Override + protected void lockObjects() throws InterruptedException + { + if (failureTime == FailureTime.BEFORE_TIMESTAMP) + { + simulateProblem(); + } + + super.lockObjects(); + } + + @Override + protected void adjustForCommit() + { + if (failureTime == FailureTime.AFTER_TIMESTAMP) + { + simulateProblem(); + } + + super.adjustForCommit(); + } + + private void simulateProblem() + { + if (BAD_COMMIT.equals(getCommitComment())) + { + RuntimeException cause = new RuntimeException("SIMULATED PROBLEM"); + throw new RollbackException(CDOProtocolConstants.ROLLBACK_REASON_OPTIMISTIC_LOCKING, cause); + } + } + }; + } + }; + + repository.setName(IRepositoryConfig.REPOSITORY_NAME); + + Map<String, String> props = getRepositoryProperties(); + ((InternalRepository)repository).setProperties(props); + + getTestProperties().put(RepositoryConfig.PROP_TEST_REPOSITORY, repository); + } + + private void executeTestWith(FailureTime failureTime) throws ConcurrentAccessException, CommitException, + InterruptedException + { + disableConsole(); + initRepository(failureTime); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_NAME)); + resource.getContents().add(getModel1Factory().createCompany()); + transaction.commit(); + + Thread[] clients = new Thread[CLIENTS]; + for (int id = 0; id < CLIENTS; id++) + { + if (failureTime == FailureTime.NEVER || id < CLIENTS - 1) + { + clients[id] = new GoodClient(id); + } + else + { + clients[id] = new BadClient(id); + } + } + + for (int id = 0; id < CLIENTS; id++) + { + clients[id].start(); + } + + for (int id = 0; id < CLIENTS; id++) + { + clients[id].join(); + } + + assertEquals("Invalidation queue is blocked", true, + session.waitForUpdate(getRepository().getLastCommitTimeStamp(), DEFAULT_TIMEOUT)); + } + + /** + * @author Eike Stepper + */ + private enum FailureTime + { + NEVER, BEFORE_TIMESTAMP, AFTER_TIMESTAMP + } + + /** + * @author Eike Stepper + */ + private final class GoodClient extends Thread + { + private final int id; + + private Category category; + + public GoodClient(int id) throws ConcurrentAccessException, CommitException + { + super("GoodClient-" + id); + this.id = id; + setDaemon(true); + + category = getModel1Factory().createCategory(); + category.setName(GoodClient.this.getName()); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath(RESOURCE_NAME)); + Company company = (Company)resource.getContents().get(0); + + company.getCategories().add(category); + transaction.commit(); + } + + @Override + public void run() + { + CDOTransaction transaction = (CDOTransaction)CDOUtil.getCDOObject(category).cdoView(); + int objectsPerCommit = 10 * (CLIENTS - id); + + for (int commit = 0; commit < COMMITS_PER_CLIENT; commit++) + { + for (int object = 0; object < objectsPerCommit; object++) + { + category.getProducts().add(getModel1Factory().createProduct1()); + } + + try + { + transaction.commit(); + } + catch (CommitException ex) + { + ex.printStackTrace(); + break; + } + } + } + } + + /** + * @author Eike Stepper + */ + private final class BadClient extends Thread + { + private Company company; + + public BadClient(int id) throws ConcurrentAccessException, CommitException + { + super("BadClient-" + id); + setDaemon(true); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath(RESOURCE_NAME)); + company = (Company)resource.getContents().get(0); + } + + @Override + public void run() + { + CDOTransaction transaction = (CDOTransaction)CDOUtil.getCDOObject(company).cdoView(); + for (int commit = 0; commit < 100 * COMMITS_PER_CLIENT; commit++) + { + company.setName("Company-" + commit); // Make the transaction dirty + + try + { + transaction.setCommitComment(BAD_COMMIT); + transaction.commit(); + } + catch (CommitException ex) + { + transaction.rollback(); + } + } + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java index 8dab040d42..dfb70f2e8f 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/offline/OfflineTest.java @@ -667,7 +667,7 @@ public class OfflineTest extends AbstractSyncingTest InternalRepository clone = getRepository(); waitForOnline(clone); - CDOSession session = openSession(); + CDOSession session = openSession(); // Session2 [repo1] session.options().setPassiveUpdateMode(PassiveUpdateMode.ADDITIONS); CDOTransaction transaction = session.openTransaction(); CDOResource resource = transaction.createResource(getResourcePath("/my/resource")); @@ -686,7 +686,7 @@ public class OfflineTest extends AbstractSyncingTest transaction.addListener(transactionListener); { - CDOSession masterSession = openSession("master"); + CDOSession masterSession = openSession("master"); // Session3 [master] CDOTransaction masterTransaction = masterSession.openTransaction(); CDOResource masterResource = masterTransaction.getResource(getResourcePath("/my/resource")); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java index b783e08b74..e20477f37b 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java @@ -47,6 +47,7 @@ import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta; import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta; +import org.eclipse.emf.cdo.common.util.CDOCommonUtil; import org.eclipse.emf.cdo.common.util.CDOException; import org.eclipse.emf.cdo.common.util.RepositoryStateChangedEvent; import org.eclipse.emf.cdo.common.util.RepositoryTypeChangedEvent; @@ -93,7 +94,7 @@ import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.concurrent.IRWLockManager; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.concurrent.IRWOLockManager; -import org.eclipse.net4j.util.concurrent.QueueRunner; +import org.eclipse.net4j.util.concurrent.QueueRunner2; import org.eclipse.net4j.util.concurrent.RWOLockManager; import org.eclipse.net4j.util.event.Event; import org.eclipse.net4j.util.event.EventUtil; @@ -105,6 +106,7 @@ import org.eclipse.net4j.util.lifecycle.ILifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.log.OMLogger; +import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.net4j.util.options.OptionsEvent; import org.eclipse.net4j.util.security.IPasswordCredentialsProvider; @@ -145,6 +147,8 @@ import java.util.Set; */ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl implements InternalCDOSession { + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_SESSION, CDOSessionImpl.class); + private ExceptionHandler exceptionHandler; private CDOIDGenerator idGenerator; @@ -180,9 +184,7 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme private CDOSession.Options options = createOptions(); - private OutOfSequenceInvalidations outOfSequenceInvalidations = new OutOfSequenceInvalidations(); - - private QueueRunner invalidationRunner; + private Invalidator invalidator = new Invalidator(); private CDORepositoryInfo repositoryInfo; @@ -1045,165 +1047,25 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme } } - @Deprecated - public void invalidate(CDOCommitInfo commitInfo, InternalCDOTransaction sender) + public Object startLocalCommit() { - invalidate(commitInfo, sender, true); + return invalidator.startLocalCommit(); } - public void invalidate(CDOCommitInfo commitInfo, InternalCDOTransaction sender, boolean clearResourcePathCache) + public void endLocalCommit(Object token) { - long previousTimeStamp = commitInfo.getPreviousTimeStamp(); - long lastUpdateTime = getLastUpdateTime(); - - if (previousTimeStamp < lastUpdateTime) - { - previousTimeStamp = lastUpdateTime; - } - - synchronized (outOfSequenceInvalidations) - { - outOfSequenceInvalidations.put(previousTimeStamp, new OutOfSequenceInvalidation(commitInfo, sender, - clearResourcePathCache)); - } - - long nextPreviousTimeStamp = lastUpdateTime; - for (;;) - { - Runnable invalidationRunnable = null; - synchronized (outOfSequenceInvalidations) - { - OutOfSequenceInvalidation currentInvalidation = outOfSequenceInvalidations.remove(nextPreviousTimeStamp); - if (currentInvalidation == null) - { - // If we don't have the invalidation that follows the last one we processed, - // then there is nothing we can do right now - break; - } - - final CDOCommitInfo currentCommitInfo = currentInvalidation.getCommitInfo(); - final InternalCDOTransaction currentSender = currentInvalidation.getSender(); - final boolean currentClearResourcePathCache = currentInvalidation.isClearResourcePathCache(); - nextPreviousTimeStamp = currentCommitInfo.getTimeStamp(); - - invalidationRunnable = new Runnable() - { - public void run() - { - invalidateOrdered(currentCommitInfo, currentSender, currentClearResourcePathCache); - } - }; - - if (sender == null) - { - QueueRunner invalidationRunner = getInvalidationRunner(); - invalidationRunner.addWork(invalidationRunnable); - invalidationRunnable = null; - } - } - - if (invalidationRunnable != null) - { - invalidationRunnable.run(); - } - } - } - - /** - * This method is synchronized on outOfSequenceInvalidations by the caller! - */ - private QueueRunner getInvalidationRunner() - { - if (invalidationRunner == null) - { - invalidationRunner = new QueueRunner() - { - @Override - protected void noWork(WorkContext context) - { - if (isClosed()) - { - context.terminate(); - } - } - - @Override - protected String getThreadName() - { - return "CDOSessionInvalidationRunner-" + CDOSessionImpl.this; - } - }; - - invalidationRunner.activate(); - } - - return invalidationRunner; - } - - private void invalidateOrdered(CDOCommitInfo commitInfo, InternalCDOTransaction sender, boolean clearResourcePathCache) - { - Map<CDOID, InternalCDORevision> oldRevisions = null; - boolean success = commitInfo.getBranch() != null; - if (success) - { - oldRevisions = reviseRevisions(commitInfo); - } - - if (options.isPassiveUpdateEnabled()) - { - setLastUpdateTime(commitInfo.getTimeStamp()); - } - - if (success) - { - fireInvalidationEvent(sender, commitInfo); - commitInfoManager.notifyCommitInfoHandlers(commitInfo); - } - - for (InternalCDOView view : getViews()) - { - if (view != sender) - { - invalidateView(commitInfo, view, oldRevisions, clearResourcePathCache); - } - else - { - view.setLastUpdateTime(commitInfo.getTimeStamp()); - } - } + invalidator.endLocalCommit(token); } - private void invalidateView(CDOCommitInfo commitInfo, InternalCDOView view, - Map<CDOID, InternalCDORevision> oldRevisions, boolean clearResourcePathCache) + @Deprecated + public void invalidate(CDOCommitInfo commitInfo, InternalCDOTransaction sender) { - try - { - CDOBranch branch = commitInfo.getBranch(); - long lastUpdateTime = commitInfo.getTimeStamp(); - List<CDORevisionKey> allChangedObjects = commitInfo.getChangedObjects(); - List<CDOIDAndVersion> allDetachedObjects = commitInfo.getDetachedObjects(); - view.invalidate(branch, lastUpdateTime, allChangedObjects, allDetachedObjects, oldRevisions, true, - clearResourcePathCache); - } - catch (RuntimeException ex) - { - if (view.isActive()) - { - OM.LOG.error(ex); - } - else - { - OM.LOG.info(Messages.getString("CDOSessionImpl.1")); //$NON-NLS-1$ - } - } + invalidate(commitInfo, sender, true); } - /** - * @since 2.0 - */ - public void fireInvalidationEvent(InternalCDOTransaction sender, CDOCommitInfo commitInfo) + public void invalidate(CDOCommitInfo commitInfo, InternalCDOTransaction sender, boolean clearResourcePathCache) { - fireEvent(new InvalidationEvent(sender, commitInfo)); + invalidator.reorderInvalidations(commitInfo, sender, clearResourcePathCache); } public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) @@ -1393,6 +1255,7 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme protected void doActivate() throws Exception { super.doActivate(); + LifecycleUtil.activate(invalidator); InternalCDORemoteSessionManager remoteSessionManager = new CDORemoteSessionManagerImpl(); remoteSessionManager.setLocalSession(this); @@ -1406,11 +1269,9 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme @Override protected void doDeactivate() throws Exception { + LifecycleUtil.deactivate(invalidator); super.doDeactivate(); - LifecycleUtil.deactivate(invalidationRunner); - outOfSequenceInvalidations.clear(); - unhookSessionProtocol(); CDORemoteSessionManager remoteSessionManager = getRemoteSessionManager(); @@ -1455,49 +1316,6 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme /** * @author Eike Stepper - */ - private static final class OutOfSequenceInvalidation - { - private CDOCommitInfo commitInfo; - - private InternalCDOTransaction sender; - - private boolean clearResourcePathCache; - - public OutOfSequenceInvalidation(CDOCommitInfo commitInfo, InternalCDOTransaction sender, - boolean clearResourcePathCache) - { - this.commitInfo = commitInfo; - this.sender = sender; - this.clearResourcePathCache = clearResourcePathCache; - } - - public CDOCommitInfo getCommitInfo() - { - return commitInfo; - } - - public InternalCDOTransaction getSender() - { - return sender; - } - - public boolean isClearResourcePathCache() - { - return clearResourcePathCache; - } - } - - /** - * @author Eike Stepper - */ - private static final class OutOfSequenceInvalidations extends HashMap<Long, OutOfSequenceInvalidation> - { - private static final long serialVersionUID = 1L; - } - - /** - * @author Eike Stepper * @since 2.0 */ protected class OptionsImpl extends Notifier implements Options @@ -1829,6 +1647,240 @@ public abstract class CDOSessionImpl extends CDOTransactionContainerImpl impleme /** * @author Eike Stepper */ + private class Invalidator extends QueueRunner2<Invalidation> + { + private static final boolean DEBUG = false; + + private final Set<Object> unfinishedLocalCommits = new HashSet<Object>(); + + private final List<Invalidation> reorderQueue = new ArrayList<Invalidation>(); + + public Invalidator() + { + } + + public synchronized Object startLocalCommit() + { + if (!isActive()) + { + return null; + } + + final String threadName = Thread.currentThread().getName(); + Object token = new Object() + { + @Override + public String toString() + { + return threadName; + } + }; + + unfinishedLocalCommits.add(token); + return token; + } + + public synchronized void endLocalCommit(Object token) + { + unfinishedLocalCommits.remove(token); + } + + public synchronized void reorderInvalidations(CDOCommitInfo commitInfo, InternalCDOTransaction sender, + boolean clearResourcePathCache) + { + if (!isActive()) + { + return; + } + + Invalidation invalidation = new Invalidation(commitInfo, sender, clearResourcePathCache); + reorderQueue.add(invalidation); + Collections.sort(reorderQueue); + + if (DEBUG) + { + IOUtil.OUT().println( + CDOSessionImpl.this + " [" + getLastUpdateTime() % 10000 + "] " + commitInfo.getPreviousTimeStamp() % 10000 + + " --> " + commitInfo.getTimeStamp() % 10000 + " reorderQueue=" + reorderQueue + + " unfinishedLocalCommits=" + unfinishedLocalCommits); + } + + scheduleInvalidations(); + } + + public synchronized void scheduleInvalidations() + { + while (!reorderQueue.isEmpty() && canProcess(reorderQueue.get(0))) + { + Invalidation invalidation0 = reorderQueue.remove(0); + addWork(invalidation0); + } + } + + protected boolean canProcess(Invalidation invalidation) + { + if (options().isPassiveUpdateEnabled()) + { + long previousTimeStamp = invalidation.getPreviousTimeStamp(); + long lastUpdateTime = getLastUpdateTime(); + return previousTimeStamp <= lastUpdateTime; // Can be smaller in replication scenarios + } + + return unfinishedLocalCommits.size() == 1; // Ourselves + } + + @Override + protected void noWork(WorkContext context) + { + if (isClosed()) + { + context.terminate(); + } + } + + @Override + protected String getThreadName() + { + return "CDOSessionInvalidator-" + CDOSessionImpl.this; + } + } + + /** + * @author Eike Stepper + */ + private final class Invalidation implements Comparable<Invalidation>, Runnable + { + private final CDOCommitInfo commitInfo; + + private final InternalCDOTransaction sender; + + private final boolean clearResourcePathCache; + + public Invalidation(CDOCommitInfo commitInfo, InternalCDOTransaction sender, boolean clearResourcePathCache) + { + this.commitInfo = commitInfo; + this.sender = sender; + this.clearResourcePathCache = clearResourcePathCache; + } + + public long getTimeStamp() + { + return commitInfo.getTimeStamp(); + } + + public long getPreviousTimeStamp() + { + return commitInfo.getPreviousTimeStamp(); + } + + public int compareTo(Invalidation o) + { + return CDOCommonUtil.compareTimeStamps(getTimeStamp(), o.getTimeStamp()); + } + + @Override + public String toString() + { + return Long.toString(commitInfo.getTimeStamp() % 10000); + } + + public void run() + { + long timeStamp = commitInfo.getTimeStamp(); + + if (Invalidator.DEBUG) + { + IOUtil.OUT().println( + CDOSessionImpl.this + " [" + getLastUpdateTime() % 10000 + "] " + timeStamp % 10000 + " INVALIDATE"); + } + + try + { + Map<CDOID, InternalCDORevision> oldRevisions = null; + boolean success = commitInfo.getBranch() != null; + if (success) + { + oldRevisions = reviseRevisions(commitInfo); + } + + if (options.isPassiveUpdateEnabled()/* || sender != null */) + { + setLastUpdateTime(timeStamp); + } + + if (success) + { + CDOSessionImpl.this.fireEvent(new InvalidationEvent(sender, commitInfo)); + commitInfoManager.notifyCommitInfoHandlers(commitInfo); + } + + for (InternalCDOView view : getViews()) + { + invalidateView(commitInfo, view, sender, oldRevisions, clearResourcePathCache); + } + } + catch (RuntimeException ex) + { + if (isActive()) + { + throw ex; + } + + if (TRACER.isEnabled()) + { + TRACER.trace(Messages.getString("CDOSessionImpl.2")); //$NON-NLS-1$ + } + } + finally + { + // setLastUpdateTimeStamp() is not synchronized with the Invalidator. + // Give the Invalidator another chance to schedule Invalidations. + invalidator.scheduleInvalidations(); + } + } + + private void invalidateView(CDOCommitInfo commitInfo, InternalCDOView view, InternalCDOTransaction sender, + Map<CDOID, InternalCDORevision> oldRevisions, boolean clearResourcePathCache) + { + try + { + long lastUpdateTime = commitInfo.getTimeStamp(); + if (view == sender) + { + // The committing view (sender) is already valid, just the timestamp must be set "in sequence". + // Setting the sender's timestamp synchronously can lead to deadlock + view.invalidate(null, lastUpdateTime, null, null, null, true, false); + } + else + { + CDOBranch branch = commitInfo.getBranch(); + List<CDORevisionKey> allChangedObjects = commitInfo.getChangedObjects(); + List<CDOIDAndVersion> allDetachedObjects = commitInfo.getDetachedObjects(); + + view.invalidate(branch, lastUpdateTime, allChangedObjects, allDetachedObjects, oldRevisions, true, + clearResourcePathCache); + } + } + catch (RuntimeException ex) + { + if (view.isActive()) + { + OM.LOG.error(ex); + } + else + { + if (TRACER.isEnabled()) + { + TRACER.trace(Messages.getString("CDOSessionImpl.1")); //$NON-NLS-1$ + } + } + } + } + } + + /** + * @author Eike Stepper + */ private final class InvalidationEvent extends Event implements CDOSessionInvalidationEvent { private static final long serialVersionUID = 1L; diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java index 21d9f1a5f2..385ab88557 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java @@ -112,6 +112,7 @@ import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder; import org.eclipse.emf.internal.cdo.object.CDOObjectMerger; import org.eclipse.emf.internal.cdo.object.CDOObjectWrapper; import org.eclipse.emf.internal.cdo.query.CDOQueryImpl; +import org.eclipse.emf.internal.cdo.session.CDOSessionImpl; import org.eclipse.emf.internal.cdo.util.CommitIntegrityCheck; import org.eclipse.emf.internal.cdo.util.CompletePackageClosure; import org.eclipse.emf.internal.cdo.util.IPackageClosure; @@ -1169,11 +1170,32 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa return new CDOCommitContextImpl(this); } + public/* synchronized */CDOCommitInfo commit() throws CommitException + { + return commit(null); + } + /** * @since 2.0 */ - public synchronized CDOCommitInfo commit(IProgressMonitor progressMonitor) throws CommitException + public/* synchronized */CDOCommitInfo commit(IProgressMonitor progressMonitor) throws CommitException + { + CDOCommitInfo info = commitSynced(progressMonitor); + if (info != null) + { + long timeStamp = info.getTimeStamp(); + waitForUpdate(timeStamp, 10000); + } + + return info; + } + + private synchronized CDOCommitInfo commitSynced(IProgressMonitor progressMonitor) throws DanglingIntegrityException, + CommitException { + InternalCDOSession session = getSession(); + Object token = null; + try { checkActive(); @@ -1182,6 +1204,11 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa throw new LocalCommitConflictException(Messages.getString("CDOTransactionImpl.2")); //$NON-NLS-1$ } + if (session instanceof CDOSessionImpl) + { + token = ((CDOSessionImpl)session).startLocalCommit(); + } + if (progressMonitor == null) { progressMonitor = new NullProgressMonitor(); @@ -1210,15 +1237,15 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa } finally { + if (session instanceof CDOSessionImpl) + { + ((CDOSessionImpl)session).endLocalCommit(token); + } + clearResourcePathCacheIfNecessary(null); } } - public synchronized CDOCommitInfo commit() throws CommitException - { - return commit(null); - } - /** * @since 2.0 */ @@ -3013,7 +3040,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa getAdapterManager().committedTransaction(transaction, this); cleanUp(this); - Map<CDOID, CDOID> idMappings = result.getIDMappings(); + IListener[] listeners = getListeners(); if (listeners != null) { @@ -3022,6 +3049,7 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa fireViewTargetChangedEvent(oldBranch.getHead(), listeners); } + Map<CDOID, CDOID> idMappings = result.getIDMappings(); fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.COMMITTED, idMappings), listeners); } |