Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2011-08-04 01:57:01 -0400
committerEike Stepper2011-08-04 01:57:01 -0400
commit73585ecb2cd91a1d05a7f8aaad571f0cc1d12aa1 (patch)
treebb0267feca103a72a5aef0bcb335d2192f8e5cc0
parent39fd1f6f14231b77ec03187a236900422b090196 (diff)
downloadcdo-73585ecb2cd91a1d05a7f8aaad571f0cc1d12aa1.tar.gz
cdo-73585ecb2cd91a1d05a7f8aaad571f0cc1d12aa1.tar.xz
cdo-73585ecb2cd91a1d05a7f8aaad571f0cc1d12aa1.zip
[353246] [DB] Duplicate entry / Violation of unique index in 'cdo_package_units_idx0'
https://bugs.eclipse.org/bugs/show_bug.cgi?id=353246
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java23
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageInfo.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageRegistry.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageUnit.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java11
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java50
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/PackageRegistryTest.java27
8 files changed, 107 insertions, 16 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java
index 5bd33df87d..72b865d98d 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java
@@ -119,6 +119,8 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
this.packageLoader = packageLoader;
}
+ static int lockCount;
+
@Override
public Object get(Object key)
{
@@ -126,8 +128,9 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
return super.get(key);
}
- public Set<String> getAllKeys()
+ public synchronized Set<String> getAllKeys()
{
+ LifecycleUtil.checkActive(this);
Set<String> result = new HashSet<String>();
result.addAll(keySet());
if (delegateRegistry != null)
@@ -145,8 +148,9 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
return result;
}
- public Object getWithDelegation(String nsURI, boolean resolve)
+ public synchronized Object getWithDelegation(String nsURI, boolean resolve)
{
+ LifecycleUtil.checkActive(this);
Object result = getFrom(this, nsURI, resolve);
if (result == null && delegateRegistry != null)
{
@@ -166,7 +170,7 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
return registry.get(nsURI);
}
- public Object basicPut(String nsURI, Object value)
+ public synchronized Object basicPut(String nsURI, Object value)
{
LifecycleUtil.checkActive(this);
if (TRACER.isEnabled())
@@ -237,6 +241,7 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
public synchronized Object putEPackage(EPackage ePackage)
{
+ LifecycleUtil.checkActive(this);
return put(ePackage.getNsURI(), ePackage);
}
@@ -263,6 +268,7 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
public synchronized void putPackageUnits(InternalCDOPackageUnit[] packageUnits, State state)
{
+ LifecycleUtil.checkActive(this);
for (InternalCDOPackageUnit packageUnit : packageUnits)
{
if (state != null)
@@ -339,8 +345,9 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
return packageInfos;
}
- public InternalCDOPackageUnit getPackageUnit(EPackage ePackage)
+ public synchronized InternalCDOPackageUnit getPackageUnit(EPackage ePackage)
{
+ LifecycleUtil.checkActive(this);
CDOPackageInfo packageInfo = getPackageInfo(ePackage);
if (packageInfo == null)
{
@@ -383,7 +390,7 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
return null;
}
- public InternalCDOPackageUnit[] getPackageUnits(long startTime, long endTime)
+ public synchronized InternalCDOPackageUnit[] getPackageUnits(long startTime, long endTime)
{
LifecycleUtil.checkActive(this);
if (endTime == CDOBranchPoint.UNSPECIFIED_DATE)
@@ -421,7 +428,7 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
return result.toArray(new InternalCDOPackageUnit[result.size()]);
}
- public InternalCDOPackageUnit[] getPackageUnits(boolean withSystemPackages)
+ public synchronized InternalCDOPackageUnit[] getPackageUnits(boolean withSystemPackages)
{
LifecycleUtil.checkActive(this);
return collectPackageUnits(withSystemPackages);
@@ -490,8 +497,9 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
return result.toArray(new EPackage[result.size()]);
}
- public EEnumLiteral getEnumLiteralFor(Enumerator value)
+ public synchronized EEnumLiteral getEnumLiteralFor(Enumerator value)
{
+ LifecycleUtil.checkActive(this);
EEnumLiteral result = enumLiterals.get(value);
if (result != null)
{
@@ -541,6 +549,7 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte
public synchronized Map<EClass, List<EClass>> getSubTypes()
{
+ LifecycleUtil.checkActive(this);
if (subTypes == null)
{
subTypes = CDOModelUtil.getSubTypes(this);
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageInfo.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageInfo.java
index b6e3bc1b48..c1ff2302f9 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageInfo.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageInfo.java
@@ -21,6 +21,8 @@ import java.io.IOException;
/**
* @author Eike Stepper
* @since 2.0
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
*/
public interface InternalCDOPackageInfo extends CDOPackageInfo, Adapter.Internal
{
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageRegistry.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageRegistry.java
index 3a73cf3400..a891faf885 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageRegistry.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageRegistry.java
@@ -23,6 +23,8 @@ import java.util.Set;
/**
* @author Eike Stepper
* @since 2.0
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
*/
public interface InternalCDOPackageRegistry extends CDOPackageRegistry, ILifecycle
{
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageUnit.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageUnit.java
index 2ac4ea8719..9ea712595f 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageUnit.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/model/InternalCDOPackageUnit.java
@@ -23,6 +23,8 @@ import java.io.IOException;
/**
* @author Eike Stepper
* @since 2.0
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
*/
public interface InternalCDOPackageUnit extends CDOPackageUnit
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
index 95e3d3ad47..f207568e10 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
@@ -111,6 +111,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.Semaphore;
/**
* @author Eike Stepper
@@ -140,6 +141,11 @@ public class Repository extends Container<Object> implements InternalRepository
private IDGenerationLocation idGenerationLocation;
+ /**
+ * Must not be thread-bound to support XA commits.
+ */
+ private Semaphore packageRegistryCommitLock = new Semaphore(1);
+
private InternalCDOPackageRegistry packageRegistry;
private InternalCDOBranchManager branchManager;
@@ -657,6 +663,11 @@ public class Repository extends Container<Object> implements InternalRepository
return packageRegistry;
}
+ public Semaphore getPackageRegistryCommitLock()
+ {
+ return packageRegistryCommitLock;
+ }
+
public InternalCDOPackageRegistry getPackageRegistry()
{
return getPackageRegistry(true);
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 ed52b2753a..376ef17ef8 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
@@ -67,6 +67,7 @@ import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.collection.IndexedList;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
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;
@@ -96,7 +97,7 @@ public class TransactionCommitContext implements InternalCommitContext
{
private static final InternalCDORevision DETACHED = new StubCDORevision(null);
- private InternalTransaction transaction;
+ private final InternalTransaction transaction;
private InternalRepository repository;
@@ -104,6 +105,10 @@ public class TransactionCommitContext implements InternalCommitContext
private InternalLockManager lockManager;
+ private InternalCDOPackageRegistry repositoryPackageRegistry;
+
+ private boolean packageRegistryLocked;
+
private TransactionPackageRegistry packageRegistry;
private IStoreAccessor accessor;
@@ -157,7 +162,8 @@ public class TransactionCommitContext implements InternalCommitContext
lockManager = repository.getLockManager();
ensuringReferentialIntegrity = repository.isEnsuringReferentialIntegrity();
- packageRegistry = new TransactionPackageRegistry(repository.getPackageRegistry(false));
+ repositoryPackageRegistry = repository.getPackageRegistry(false);
+ packageRegistry = new TransactionPackageRegistry(repositoryPackageRegistry);
packageRegistry.activate();
}
@@ -408,6 +414,28 @@ public class TransactionCommitContext implements InternalCommitContext
monitor.begin(107);
dirtyObjects = new InternalCDORevision[dirtyObjectDeltas.length];
+ if (newPackageUnits.length != 0)
+ {
+ repository.getPackageRegistryCommitLock().acquire();
+ packageRegistryLocked = true;
+
+ List<InternalCDOPackageUnit> noDuplicates = new ArrayList<InternalCDOPackageUnit>();
+ for (InternalCDOPackageUnit newPackageUnit : newPackageUnits)
+ {
+ String id = newPackageUnit.getID();
+ if (!repositoryPackageRegistry.containsKey(id))
+ {
+ noDuplicates.add(newPackageUnit);
+ }
+ }
+
+ int newSize = noDuplicates.size();
+ if (newPackageUnits.length != newSize)
+ {
+ newPackageUnits = noDuplicates.toArray(new InternalCDOPackageUnit[newSize]);
+ }
+ }
+
lockObjects(); // Can take long and must come before setTimeStamp()
monitor.worked();
@@ -420,14 +448,13 @@ public class TransactionCommitContext implements InternalCommitContext
checkXRefs();
monitor.worked();
- if (rollbackMessage != null)
+
+ if (rollbackMessage == null)
{
- return;
+ detachObjects(monitor.fork());
+ repository.notifyWriteAccessHandlers(transaction, this, true, monitor.fork());
+ accessor.write(this, monitor.fork(100));
}
-
- detachObjects(monitor.fork());
- repository.notifyWriteAccessHandlers(transaction, this, true, monitor.fork());
- accessor.write(this, monitor.fork(100));
}
catch (Throwable t)
{
@@ -534,6 +561,11 @@ public class TransactionCommitContext implements InternalCommitContext
public void postCommit(boolean success)
{
+ if (packageRegistryLocked)
+ {
+ repository.getPackageRegistryCommitLock().release();
+ }
+
try
{
InternalSession sender = transaction.getSession();
@@ -648,7 +680,6 @@ public class TransactionCommitContext implements InternalCommitContext
try
{
-
final boolean supportingBranches = repository.isSupportingBranches();
CDOFeatureDeltaVisitor deltaTargetLocker = null;
@@ -1140,6 +1171,7 @@ public class TransactionCommitContext implements InternalCommitContext
@Override
public synchronized void putPackageUnit(InternalCDOPackageUnit packageUnit)
{
+ LifecycleUtil.checkActive(this);
packageUnit.setPackageRegistry(this);
for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos())
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
index 340e7d375a..3e7306d3b6 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
@@ -47,6 +47,7 @@ import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Semaphore;
/**
* @author Eike Stepper
@@ -74,6 +75,11 @@ public interface InternalRepository extends IRepository, PackageProcessor, Packa
public void setBranchManager(InternalCDOBranchManager branchManager);
/**
+ * @since 4.1
+ */
+ public Semaphore getPackageRegistryCommitLock();
+
+ /**
* Same as calling {@link #getPackageRegistry(boolean) getPackageRegistry(true)}.
*/
public InternalCDOPackageRegistry getPackageRegistry();
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/PackageRegistryTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/PackageRegistryTest.java
index bce801d264..01cbf72704 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/PackageRegistryTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/PackageRegistryTest.java
@@ -585,6 +585,33 @@ public class PackageRegistryTest extends AbstractCDOTest
}
}
+ /**
+ * Bug 353246.
+ * <p>
+ * Cannot reproduce the problem with MEMStore because MEMStoreAccessor.writePackageUnits() is empty.
+ */
+ @CleanRepositoriesBefore
+ public void testConcurrentPackageRegistration2() throws Exception
+ {
+ CDOSession session1 = openSession();
+ CDOTransaction transaction1 = session1.openTransaction();
+ CDOResource resource1 = transaction1.createResource(getResourcePath("/res1"));
+ transaction1.commit();
+
+ CDOSession session2 = openSession();
+ CDOTransaction transaction2 = session2.openTransaction();
+ CDOResource resource2 = transaction2.createResource(getResourcePath("/res2"));
+ transaction2.commit();
+
+ session2.options().setPassiveUpdateEnabled(false);
+
+ resource1.getContents().add(getModel1Factory().createCompany());
+ transaction1.commit();
+
+ resource2.getContents().add(getModel1Factory().createCompany());
+ transaction2.commit();
+ }
+
@CleanRepositoriesBefore
public void testPopulator() throws Exception
{

Back to the top