Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2013-05-29 03:22:20 -0400
committerEike Stepper2013-05-29 03:52:11 -0400
commit5ce7219182441088fbcdda476c58d3efd04aec03 (patch)
tree3c0ab3d872521474343f70294c53d653f7b062dc
parent1c67bb211f590b914809556206b1622a0e7ff5f2 (diff)
downloadcdo-5ce7219182441088fbcdda476c58d3efd04aec03.tar.gz
cdo-5ce7219182441088fbcdda476c58d3efd04aec03.tar.xz
cdo-5ce7219182441088fbcdda476c58d3efd04aec03.zip
[396743] [DB] List size column mismatching the row entries
https://bugs.eclipse.org/bugs/show_bug.cgi?id=396743
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java7
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java50
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_396743_Test.java179
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfig.java13
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java1
5 files changed, 230 insertions, 20 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java
index a4ad92e6d3..d41443ab6d 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/RevisionInfo.java
@@ -24,6 +24,7 @@ import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import java.io.IOException;
+import java.text.MessageFormat;
import java.util.List;
/**
@@ -104,6 +105,12 @@ public abstract class RevisionInfo
out.writeCDOID(getID());
}
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("RevisionInfo.{0}[{1}, {2}]", getClass().getSimpleName(), id, requestedBranchPoint); //$NON-NLS-1$
+ }
+
public static RevisionInfo read(CDODataInput in, CDOBranchPoint requestedBranchPoint) throws IOException
{
byte ordinal = in.readByte();
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
index 7dddc0aa6c..b3a4b34e9f 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
@@ -36,6 +36,7 @@ import org.eclipse.emf.ecore.EStructuralFeature;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.text.MessageFormat;
/**
* This is a default implementation for the {@link ITypeMapping} interface which provides default behavor for all common
@@ -58,10 +59,10 @@ public abstract class AbstractTypeMapping implements ITypeMapping
private EStructuralFeature feature;
- private IDBField field;
-
private DBType dbType;
+ private IDBField field;
+
/**
* Create a new type mapping
*/
@@ -69,14 +70,19 @@ public abstract class AbstractTypeMapping implements ITypeMapping
{
}
+ public final IMappingStrategy getMappingStrategy()
+ {
+ return mappingStrategy;
+ }
+
public final void setMappingStrategy(IMappingStrategy mappingStrategy)
{
this.mappingStrategy = mappingStrategy;
}
- public final IMappingStrategy getMappingStrategy()
+ public final EStructuralFeature getFeature()
{
- return mappingStrategy;
+ return feature;
}
public final void setFeature(EStructuralFeature feature)
@@ -84,9 +90,14 @@ public abstract class AbstractTypeMapping implements ITypeMapping
this.feature = feature;
}
- public final EStructuralFeature getFeature()
+ public final void setDBType(DBType dbType)
{
- return feature;
+ this.dbType = dbType;
+ }
+
+ public DBType getDBType()
+ {
+ return dbType;
}
public final void setValueFromRevision(PreparedStatement stmt, int index, InternalCDORevision revision)
@@ -151,14 +162,14 @@ public abstract class AbstractTypeMapping implements ITypeMapping
field = table.addField(fieldName, fieldType, fieldLength);
}
- public final void setDBField(IDBTable table, String fieldName)
+ public final IDBField getField()
{
- field = table.getFieldSafe(fieldName);
+ return field;
}
- public final IDBField getField()
+ public final void setDBField(IDBTable table, String fieldName)
{
- return field;
+ field = table.getFieldSafe(fieldName);
}
public final void readValueToRevision(ResultSet resultSet, InternalCDORevision revision) throws SQLException
@@ -208,6 +219,15 @@ public abstract class AbstractTypeMapping implements ITypeMapping
return value;
}
+ @Override
+ public String toString()
+ {
+ Object mappedElement = field != null ? field : dbType;
+ return MessageFormat
+ .format(
+ "{0}[{1}.{2} --> {3}]", getClass().getSimpleName(), feature.getEContainingClass().getName(), feature.getName(), mappedElement); //$NON-NLS-1$
+ }
+
protected Object getDefaultValue()
{
return feature.getDefaultValue();
@@ -245,16 +265,6 @@ public abstract class AbstractTypeMapping implements ITypeMapping
return getDBType().getCode();
}
- public final void setDBType(DBType dbType)
- {
- this.dbType = dbType;
- }
-
- public DBType getDBType()
- {
- return dbType;
- }
-
protected int getDBLength(DBType type)
{
String value = DBAnnotation.COLUMN_LENGTH.getValue(feature);
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_396743_Test.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_396743_Test.java
new file mode 100644
index 0000000000..49c116fa82
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_396743_Test.java
@@ -0,0 +1,179 @@
+/*
+ * 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.db;
+
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.server.StoreThreadLocal;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalNonAuditMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.NonAuditListTableMapping;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips;
+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.net4j.db.IDBPreparedStatement;
+import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Bug 396743: [DB] List size column mismatching the row entries.
+ * <p>
+ * The problem only occurs in non-auditing.
+ *
+ * @author Eike Stepper
+ */
+@Skips(IRepositoryConfig.CAPABILITY_AUDITING)
+public class Bugzilla_396743_Test extends AbstractCDOTest
+{
+ private CountDownLatch readValueLatch;
+
+ private CountDownLatch commitLatch;
+
+ private void awaitReadValues()
+ {
+ if (readValueLatch == null)
+ {
+ return;
+ }
+
+ if (StoreThreadLocal.getCommitContext() != null)
+ {
+ // Don't block reads that are triggered from commit processing
+ return;
+ }
+
+ try
+ {
+ if (!readValueLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS))
+ {
+ throw new TimeoutRuntimeException();
+ }
+ }
+ catch (InterruptedException ex)
+ {
+ throw WrappedException.wrap(ex);
+ }
+ }
+
+ public void testWrongListSizeAdditions() throws Exception
+ {
+ getTestProperties().put(DBConfig.PROP_TEST_MAPPING_STRATEGY, new HorizontalNonAuditMappingStrategy()
+ {
+ @Override
+ public IListMapping doCreateListMapping(EClass containingClass, EStructuralFeature feature)
+ {
+ if (feature == getModel1Package().getCompany_Categories())
+ {
+ msg("Instrumenting " + feature);
+ return new NonAuditListTableMapping(this, containingClass, feature)
+ {
+ @Override
+ protected void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException
+ {
+ if (((IDBPreparedStatement)stmt).getSQL().toUpperCase().startsWith("SELECT")
+ && revision.getEClass() == getModel1Package().getCompany())
+ {
+ commitLatch.countDown(); // Let main thread execute a commit
+ awaitReadValues(); // Wait for commit to finish
+ }
+
+ super.setKeyFields(stmt, revision);
+ }
+ };
+ }
+
+ return super.doCreateListMapping(containingClass, feature);
+ }
+ });
+
+ Company company1 = getModel1Factory().createCompany();
+ company1.getCategories().add(getModel1Factory().createCategory());
+
+ CDOSession session1 = openSession();
+ CDOTransaction transaction1 = session1.openTransaction();
+ CDOResource resource1 = transaction1.createResource(getResourcePath("res"));
+ resource1.getContents().add(company1);
+ transaction1.commit();
+
+ // Remove the company revision from the server cache to trigger DBAccessor.readRevision()
+ CDORevision revision = CDOUtil.getCDOObject(company1).cdoRevision();
+ getRepository().getRevisionManager().getCache().removeRevision(revision.getID(), revision);
+
+ readValueLatch = new CountDownLatch(1);
+ commitLatch = new CountDownLatch(1);
+
+ final boolean[] exceptionOccured = { false };
+ Thread readerClient = new Thread("Test Reader Client")
+ {
+ @Override
+ public void run()
+ {
+ CDOSession session2 = openSession();
+ CDOTransaction transaction2 = session2.openTransaction();
+ CDOResource resource2 = transaction2.getResource(getResourcePath("res"));
+
+ try
+ {
+ resource2.getContents().get(0); // Will trigger readValues() in the DBStore
+ }
+ catch (Exception ex)
+ {
+ exceptionOccured[0] = ex.getMessage().contains("IndexOutOfBoundsException");
+ }
+
+ session2.close();
+ }
+ };
+
+ readerClient.start();
+ commitLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+
+ company1.getCategories().add(getModel1Factory().createCategory());
+
+ try
+ {
+ transaction1.commit();
+ }
+ catch (Exception ex)
+ {
+ if (ex.getMessage().contains("TimeoutRuntimeException"))
+ {
+ // The test logic to produce the timing problem causes a deadlock in TransactionCommitContext.lockObjects() if
+ // the problem is fixed. This is the success case, i.e., no IndexOutOfBoundsException in
+ // AbstractListTableMapping.readValues().
+ return;
+ }
+
+ throw ex;
+ }
+ finally
+ {
+ readValueLatch.countDown();
+ readerClient.join(DEFAULT_TIMEOUT);
+ }
+
+ // Check that no IndexOutOfBoundsException has been thrown in the reader
+ assertEquals("In the reader thread an IndexOutOfBoundsException occured", false, exceptionOccured[0]);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfig.java
index 28315c0dba..d12df32e2c 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfig.java
@@ -38,6 +38,8 @@ public abstract class DBConfig extends RepositoryConfig
public static final String CAPABILITY_COPY_ON_BRANCH = "DB.copy.on.branch";
+ public static final String PROP_TEST_MAPPING_STRATEGY = "test.repository.MappingStrategy";
+
private static final long serialVersionUID = 1L;
private boolean withRanges;
@@ -127,9 +129,20 @@ public abstract class DBConfig extends RepositoryConfig
protected IMappingStrategy createMappingStrategy()
{
+ IMappingStrategy mappingStrategy = getTestMappingStrategy();
+ if (mappingStrategy != null)
+ {
+ return mappingStrategy;
+ }
+
return CDODBUtil.createHorizontalMappingStrategy(isSupportingAudits(), isSupportingBranches(), withRanges);
}
+ protected IMappingStrategy getTestMappingStrategy()
+ {
+ return (IMappingStrategy)getTestProperty(PROP_TEST_MAPPING_STRATEGY);
+ }
+
@Override
protected String getMappingStrategySpecialization()
{
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
index 8f812ff137..8b99aeb619 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DBConfigs.java
@@ -40,6 +40,7 @@ public abstract class DBConfigs extends AllConfigs
testClasses.add(CustomTypeMappingTest.class);
testClasses.add(SQLQueryTest.class);
testClasses.add(Bugzilla_351068_Test.class);
+ testClasses.add(Bugzilla_396743_Test.class);
super.initTestClasses(testClasses, scenario);
testClasses.remove(MEMStoreQueryTest.class);

Back to the top