From 3d0ab17c22fc6d48becf04bc0406b785b769d8ad Mon Sep 17 00:00:00 2001
From: Stefan Winkler
Date: Mon, 18 Jan 2010 15:06:26 +0000
Subject: [270716] Provide support for branching
https://bugs.eclipse.org/bugs/show_bug.cgi?id=270716
---
plugins/org.eclipse.emf.cdo.server.db/plugin.xml | 4 +
.../emf/cdo/server/internal/db/CDODBSchema.java | 8 +
.../internal/db/SmartPreparedStatementCache.java | 4 +
.../horizontal/AbstractFeatureMapTableMapping.java | 117 +-
.../horizontal/AbstractListTableMapping.java | 79 +-
.../AuditFeatureMapTableMappingWithRanges.java | 1265 ++++++++++++++++++++
.../AuditListTableMappingWithRanges.java | 1067 +++++++++++++++++
.../horizontal/BasicAbstractListTableMapping.java | 52 +
.../horizontal/HorizontalAuditClassMapping.java | 135 ++-
.../HorizontalAuditMappingStrategyWithRanges.java | 64 +
.../server/TransactionCommitContextImpl.java | 10 +-
.../org/eclipse/emf/cdo/tests/db/AllTestsDBH2.java | 37 +-
.../eclipse/emf/cdo/tests/AllTestsAllConfigs.java | 2 +
.../cdo/tests/bugzilla/Bugzilla_298561_Test.java | 233 ++++
.../cdo/transaction/CDOTransactionImpl.java | 42 +
15 files changed, 2969 insertions(+), 150 deletions(-)
create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java
create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BasicAbstractListTableMapping.java
create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategyWithRanges.java
create mode 100644 plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_298561_Test.java
diff --git a/plugins/org.eclipse.emf.cdo.server.db/plugin.xml b/plugins/org.eclipse.emf.cdo.server.db/plugin.xml
index c91c8f3d32..780a98b78d 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/plugin.xml
+++ b/plugins/org.eclipse.emf.cdo.server.db/plugin.xml
@@ -37,5 +37,9 @@
class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalBranchingMappingStrategy"
type="horizontalBranching">
+
+
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
index eadf834faf..fb3e5af950 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
@@ -182,6 +182,10 @@ public class CDODBSchema extends DBSchema
public static final String LIST_REVISION_VERSION = "cdo_version"; //$NON-NLS-1$
+ public static final String LIST_REVISION_VERSION_ADDED = "cdo_version_added"; //$NON-NLS-1$
+
+ public static final String LIST_REVISION_VERSION_REMOVED = "cdo_version_removed"; //$NON-NLS-1$
+
public static final String LIST_REVISION_BRANCH = "cdo_branch"; //$NON-NLS-1$
public static final String LIST_IDX = "cdo_idx"; //$NON-NLS-1$
@@ -195,6 +199,10 @@ public class CDODBSchema extends DBSchema
public static final String FEATUREMAP_VERSION = "cdo_version"; //$NON-NLS-1$
+ public static final String FEATUREMAP_VERSION_ADDED = "cdo_version_added"; //$NON-NLS-1$
+
+ public static final String FEATUREMAP_VERSION_REMOVED = "cdo_version_removed"; //$NON-NLS-1$
+
public static final String FEATUREMAP_BRANCH = "cdo_branch"; //$NON-NLS-1$
public static final String FEATUREMAP_IDX = "cdo_idx"; //$NON-NLS-1$
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java
index e6fedad034..41d5c42d95 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java
@@ -49,6 +49,10 @@ public class SmartPreparedStatementCache extends AbstractPreparedStatementCache
return result;
}
+ /**
+ * @param ps
+ * the prepared statement to be released to the cache, or null
.
+ */
public void releasePreparedStatement(PreparedStatement ps)
{
if (ps != null) // Bug 276926: Silently accept ps == null and do nothing.
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
index 08cf34dcee..4ff583abf9 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java
@@ -20,8 +20,8 @@ import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
import org.eclipse.emf.cdo.server.db.CDODBUtil;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
-import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
@@ -57,19 +57,14 @@ import java.util.Map;
/**
* This abstract base class provides basic behavior needed for mapping many-valued attributes to tables.
- *
+ *
* @author Eike Stepper
* @since 3.0
*/
-public abstract class AbstractFeatureMapTableMapping implements IListMapping
+public abstract class AbstractFeatureMapTableMapping extends BasicAbstractListTableMapping
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractFeatureMapTableMapping.class);
- /**
- * The feature for this mapping.
- */
- private EStructuralFeature feature;
-
/**
* The table of this mapping.
*/
@@ -90,11 +85,6 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
*/
private Map typeMappings;
- /**
- * The associated mapping strategy.
- */
- private IMappingStrategy mappingStrategy;
-
// --------- SQL strings - see initSqlStrings() -----------------
private String sqlSelectChunksPrefix;
@@ -102,18 +92,13 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
protected String sqlInsert;
- private EClass containingClass;
-
private String sqlGetListLastIndex;
private List dbTypes;
public AbstractFeatureMapTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
{
- this.mappingStrategy = mappingStrategy;
- this.feature = feature;
- containingClass = eClass;
-
+ super(mappingStrategy, eClass, feature);
initDBTypes();
initTable();
initSqlStrings();
@@ -122,14 +107,13 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
private void initDBTypes()
{
// TODO add annotation processing here ...
-
dbTypes = new ArrayList(TypeMappingFactory.getDefaultFeatureMapDBTypes());
}
private void initTable()
{
- String tableName = mappingStrategy.getTableName(containingClass, feature);
- table = mappingStrategy.getStore().getDBSchema().addTable(tableName);
+ String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
+ table = getMappingStrategy().getStore().getDBSchema().addTable(tableName);
// add fields for keys (cdo_id, version, feature_id)
FieldInfo[] fields = getKeyFields();
@@ -274,21 +258,11 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
sqlInsert = builder.toString();
}
- public final EStructuralFeature getFeature()
- {
- return feature;
- }
-
protected List getDBTypes()
{
return dbTypes;
}
- public final EClass getContainingClass()
- {
- return containingClass;
- }
-
protected final IDBTable getTable()
{
return table;
@@ -331,33 +305,26 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
if (TRACER.isEnabled())
{
- TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature.getName(),
- revision.getID(), revision.getVersion());
+ TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), getFeature()
+ .getName(), revision.getID(), revision.getVersion());
}
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try
{
String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
-
- pstmt = accessor.getStatementCache().getPreparedStatement(sql, ReuseProbability.HIGH);
-
+ pstmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
setKeyFields(pstmt, revision);
- // if (TRACER.isEnabled())
- // {
- // TRACER.trace(pstmt.toString());
- // }
-
if (listChunk != CDORevision.UNCHUNKED)
{
pstmt.setMaxRows(listChunk); // optimization - don't read unneeded rows.
}
resultSet = pstmt.executeQuery();
-
while ((listChunk == CDORevision.UNCHUNKED || --listChunk >= 0) && resultSet.next())
{
Long tag = resultSet.getLong(1);
@@ -388,13 +355,13 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
finally
{
DBUtil.close(resultSet);
- accessor.getStatementCache().releasePreparedStatement(pstmt);
+ statementCache.releasePreparedStatement(pstmt);
}
if (TRACER.isEnabled())
{
- TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature //$NON-NLS-1$
- .getName(), revision.getID(), revision.getVersion());
+ TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(),
+ getFeature().getName(), revision.getID(), revision.getVersion());
}
}
@@ -402,7 +369,7 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
{
EStructuralFeature modelFeature = getFeatureByTag(tag);
- TypeMapping typeMapping = (TypeMapping)mappingStrategy.createValueMapping(modelFeature);
+ TypeMapping typeMapping = (TypeMapping)getMappingStrategy().createValueMapping(modelFeature);
String column = CDODBSchema.FEATUREMAP_VALUE + "_" + typeMapping.getDBType();
tagMap.put(tag, column);
@@ -412,7 +379,7 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
/**
* Return the last (maximum) list index. (euals to size-1)
- *
+ *
* @param accessor
* the accessor to use
* @param revision
@@ -421,22 +388,16 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
*/
private int getListLastIndex(IDBStoreAccessor accessor, InternalCDORevision revision)
{
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try
{
- pstmt = accessor.getStatementCache().getPreparedStatement(sqlGetListLastIndex, ReuseProbability.HIGH);
-
+ pstmt = statementCache.getPreparedStatement(sqlGetListLastIndex, ReuseProbability.HIGH);
setKeyFields(pstmt, revision);
- // if (TRACER.isEnabled())
- // {
- // TRACER.trace(pstmt.toString());
- // }
-
resultSet = pstmt.executeQuery();
-
if (!resultSet.next())
{
if (TRACER.isEnabled())
@@ -464,7 +425,7 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
finally
{
DBUtil.close(resultSet);
- accessor.getStatementCache().releasePreparedStatement(pstmt);
+ statementCache.releasePreparedStatement(pstmt);
}
}
@@ -472,10 +433,11 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
{
if (TRACER.isEnabled())
{
- TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature //$NON-NLS-1$
- .getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+ TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(),
+ getFeature().getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
}
+ IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
PreparedStatement pstmt = null;
ResultSet resultSet = null;
@@ -491,7 +453,7 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
builder.append(sqlOrderByIndex);
String sql = builder.toString();
- pstmt = chunkReader.getAccessor().getStatementCache().getPreparedStatement(sql, ReuseProbability.LOW);
+ pstmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
setKeyFields(pstmt, chunkReader.getRevision());
resultSet = pstmt.executeQuery();
@@ -538,8 +500,8 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
if (TRACER.isEnabled())
{
- TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}v{3}", containingClass.getName(),
- getTagByFeature(feature), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+ TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(),
+ getTagByFeature(getFeature()), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
}
}
catch (SQLException ex)
@@ -549,7 +511,7 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
finally
{
DBUtil.close(resultSet);
- chunkReader.getAccessor().getStatementCache().releasePreparedStatement(pstmt);
+ statementCache.releasePreparedStatement(pstmt);
}
}
@@ -566,13 +528,14 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value)
{
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
PreparedStatement stmt = null;
if (TRACER.isEnabled())
{
TRACER
.format(
- "Writing value for feature {0}.{1} index {2} of {3}v{4} : {5}", containingClass.getName(), getTagByFeature(feature), idx, revision.getID(), revision.getVersion(), value); //$NON-NLS-1$
+ "Writing value for feature {0}.{1} index {2} of {3}v{4} : {5}", getContainingClass().getName(), getTagByFeature(getFeature()), idx, revision.getID(), revision.getVersion(), value); //$NON-NLS-1$
}
try
@@ -583,9 +546,7 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
String column = getColumnName(tag);
String sql = sqlInsert;
-
- stmt = accessor.getStatementCache().getPreparedStatement(sql, ReuseProbability.HIGH);
-
+ stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
setKeyFields(stmt, revision);
int stmtIndex = getKeyFields().length + 1;
@@ -603,7 +564,6 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
stmt.setInt(stmtIndex++, idx);
stmt.setLong(stmtIndex++, tag);
-
CDODBUtil.sqlUpdate(stmt, true);
}
catch (SQLException e)
@@ -612,18 +572,17 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
}
finally
{
- accessor.getStatementCache().releasePreparedStatement(stmt);
+ statementCache.releasePreparedStatement(stmt);
}
}
/**
* Get column name (lazy)
- *
+ *
* @param tag
* The feature's MetaID in CDO
* @return the column name where the values are stored
*/
-
protected String getColumnName(Long tag)
{
String column = tagMap.get(tag);
@@ -638,12 +597,11 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
/**
* Get type mapping (lazy)
- *
+ *
* @param tag
* The feature's MetaID in CDO
* @return the corresponding type mapping
*/
-
protected ITypeMapping getTypeMapping(Long tag)
{
ITypeMapping typeMapping = typeMappings.get(tag);
@@ -660,10 +618,9 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
* @param metaID
* @return the column name where the values are stored
*/
-
private EStructuralFeature getFeatureByTag(Long tag)
{
- return (EStructuralFeature)mappingStrategy.getStore().getMetaDataManager().getMetaInstance(tag);
+ return (EStructuralFeature)getMappingStrategy().getStore().getMetaDataManager().getMetaInstance(tag);
}
/**
@@ -671,21 +628,15 @@ public abstract class AbstractFeatureMapTableMapping implements IListMapping
* The EStructuralFeature
* @return The feature's MetaID in CDO
*/
-
protected Long getTagByFeature(EStructuralFeature feature)
{
- return mappingStrategy.getStore().getMetaDataManager().getMetaID(feature);
+ return getMappingStrategy().getStore().getMetaDataManager().getMetaID(feature);
}
- /**
- * @param metaID
- * The feature's MetaID in CDO
- * @return the column name where the values are stored
- */
/**
* Used by subclasses to indicate which fields should be in the table. I.e. just a pair of name and DBType ...
- *
+ *
* @author Stefan Winkler
*/
protected static class FieldInfo
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java
index 0f8d7c8e89..1afc16dfaf 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java
@@ -18,8 +18,8 @@ import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
import org.eclipse.emf.cdo.server.db.CDODBUtil;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
-import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
@@ -52,15 +52,10 @@ import java.util.List;
* @author Eike Stepper
* @since 2.0
*/
-public abstract class AbstractListTableMapping implements IListMapping
+public abstract class AbstractListTableMapping extends BasicAbstractListTableMapping
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractListTableMapping.class);
- /**
- * The feature for this mapping.
- */
- private EStructuralFeature feature;
-
/**
* The table of this mapping.
*/
@@ -71,11 +66,6 @@ public abstract class AbstractListTableMapping implements IListMapping
*/
private ITypeMapping typeMapping;
- /**
- * The associated mapping strategy.
- */
- private IMappingStrategy mappingStrategy;
-
// --------- SQL strings - see initSqlStrings() -----------------
private String sqlSelectChunksPrefix;
@@ -83,23 +73,19 @@ public abstract class AbstractListTableMapping implements IListMapping
private String sqlInsertEntry;
- private EClass containingClass;
-
private String sqlGetListLastIndex;
public AbstractListTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
{
- this.mappingStrategy = mappingStrategy;
- this.feature = feature;
- containingClass = eClass;
-
+ super(mappingStrategy, eClass, feature);
initTable();
initSqlStrings();
}
private void initTable()
{
- String tableName = mappingStrategy.getTableName(containingClass, feature);
+ IMappingStrategy mappingStrategy = getMappingStrategy();
+ String tableName = mappingStrategy.getTableName(getContainingClass(), getFeature());
table = mappingStrategy.getStore().getDBSchema().addTable(tableName);
// add fields for keys (cdo_id, version, feature_id)
@@ -115,7 +101,7 @@ public abstract class AbstractListTableMapping implements IListMapping
dbFields[dbFields.length - 1] = table.addField(CDODBSchema.LIST_IDX, DBType.INTEGER);
// add field for value
- typeMapping = mappingStrategy.createValueMapping(feature);
+ typeMapping = mappingStrategy.createValueMapping(getFeature());
typeMapping.createDBField(table, CDODBSchema.LIST_VALUE);
// add table indexes
@@ -212,16 +198,6 @@ public abstract class AbstractListTableMapping implements IListMapping
sqlInsertEntry = builder.toString();
}
- public final EStructuralFeature getFeature()
- {
- return feature;
- }
-
- public final EClass getContainingClass()
- {
- return containingClass;
- }
-
protected final IDBTable getTable()
{
return table;
@@ -254,19 +230,18 @@ public abstract class AbstractListTableMapping implements IListMapping
if (TRACER.isEnabled())
{
- TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature.getName(), //$NON-NLS-1$
- revision.getID(), revision.getVersion());
+ TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), revision.getID(), revision.getVersion());
}
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try
{
String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
-
- pstmt = accessor.getStatementCache().getPreparedStatement(sql, ReuseProbability.HIGH);
-
+ pstmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
setKeyFields(pstmt, revision);
if (TRACER.isEnabled())
@@ -309,13 +284,13 @@ public abstract class AbstractListTableMapping implements IListMapping
finally
{
DBUtil.close(resultSet);
- accessor.getStatementCache().releasePreparedStatement(pstmt);
+ statementCache.releasePreparedStatement(pstmt);
}
if (TRACER.isEnabled())
{
- TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature //$NON-NLS-1$
- .getName(), revision.getID(), revision.getVersion());
+ TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), revision.getID(), revision.getVersion());
}
}
@@ -330,13 +305,13 @@ public abstract class AbstractListTableMapping implements IListMapping
*/
private int getListLastIndex(IDBStoreAccessor accessor, InternalCDORevision revision)
{
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try
{
- pstmt = accessor.getStatementCache().getPreparedStatement(sqlGetListLastIndex, ReuseProbability.HIGH);
-
+ pstmt = statementCache.getPreparedStatement(sqlGetListLastIndex, ReuseProbability.HIGH);
setKeyFields(pstmt, revision);
if (TRACER.isEnabled())
@@ -373,7 +348,7 @@ public abstract class AbstractListTableMapping implements IListMapping
finally
{
DBUtil.close(resultSet);
- accessor.getStatementCache().releasePreparedStatement(pstmt);
+ statementCache.releasePreparedStatement(pstmt);
}
}
@@ -381,10 +356,11 @@ public abstract class AbstractListTableMapping implements IListMapping
{
if (TRACER.isEnabled())
{
- TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature //$NON-NLS-1$
- .getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+ TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
}
+ IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
PreparedStatement pstmt = null;
ResultSet resultSet = null;
@@ -400,7 +376,7 @@ public abstract class AbstractListTableMapping implements IListMapping
builder.append(sqlOrderByIndex);
String sql = builder.toString();
- pstmt = chunkReader.getAccessor().getStatementCache().getPreparedStatement(sql, ReuseProbability.LOW);
+ pstmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
setKeyFields(pstmt, chunkReader.getRevision());
resultSet = pstmt.executeQuery();
@@ -446,8 +422,8 @@ public abstract class AbstractListTableMapping implements IListMapping
if (TRACER.isEnabled())
{
- TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}v{3}", containingClass.getName(), //$NON-NLS-1$
- feature.getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
+ TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}v{3}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion());
}
}
catch (SQLException ex)
@@ -457,7 +433,7 @@ public abstract class AbstractListTableMapping implements IListMapping
finally
{
DBUtil.close(resultSet);
- chunkReader.getAccessor().getStatementCache().releasePreparedStatement(pstmt);
+ statementCache.releasePreparedStatement(pstmt);
}
}
@@ -474,17 +450,18 @@ public abstract class AbstractListTableMapping implements IListMapping
protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value)
{
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
PreparedStatement stmt = null;
if (TRACER.isEnabled())
{
- TRACER.format("Writing value for feature {0}.{1} index {2} of {3}v{4} : {5}", containingClass.getName(), feature //$NON-NLS-1$
- .getName(), idx, revision.getID(), revision.getVersion(), value);
+ TRACER.format("Writing value for feature {0}.{1} index {2} of {3}v{4} : {5}", getContainingClass().getName(),
+ getFeature().getName(), idx, revision.getID(), revision.getVersion(), value);
}
try
{
- stmt = accessor.getStatementCache().getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH);
+ stmt = statementCache.getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH);
setKeyFields(stmt, revision);
int stmtIndex = getKeyFields().length + 1;
@@ -499,7 +476,7 @@ public abstract class AbstractListTableMapping implements IListMapping
}
finally
{
- accessor.getStatementCache().releasePreparedStatement(stmt);
+ statementCache.releasePreparedStatement(stmt);
}
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
new file mode 100644
index 0000000000..fcfb591140
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java
@@ -0,0 +1,1265 @@
+/**
+ * Copyright (c) 2004 - 2009 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
+ * Stefan Winkler - Bug 271444: [DB] Multiple refactorings bug 271444
+ * Christopher Albert - Bug 254455: [DB] Support FeatureMaps bug 254455
+ * Victor Roldan Betancort - Bug 283998: [DB] Chunk reading for multiple chunks fails
+ * Lothar Werzinger - Bug 296440: [DB] Change RDB schema to improve scalability of to-many references in audit mode
+ * Stefan Winkler - cleanup, merge and maintenance *
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
+import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
+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.CDOSetFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
+import org.eclipse.emf.cdo.server.IRepository;
+import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
+import org.eclipse.emf.cdo.server.db.CDODBUtil;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.mapping.TypeMappingFactory;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.db.ddl.IDBIndex.Type;
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.collection.MoveableList;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMap;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This is a featuremap-table mapping for audit mode. It is optimized for frequent insert operations at the list's end,
+ * which causes just 1 DB row to be changed. This is achieved by introducing a version range (columns
+ * {@link CDODBSchema#LIST_REVISION_VERSION_ADDED cdo_version_added} and
+ * {@link CDODBSchema#LIST_REVISION_VERSION_REMOVED cdo_version_removed}) which records for which revisions a particular
+ * entry existed. Also, this mapping is mainly optimized for potentially very large lists: the need for having the
+ * complete list stored in memory to do in-the-middle-moved and inserts is traded in for a few more DB access
+ * operations.
+ *
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @author Lothar Werzinger
+ * @since 3.0
+ */
+public class AuditFeatureMapTableMappingWithRanges extends BasicAbstractListTableMapping implements
+ IListMappingDeltaSupport
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AuditFeatureMapTableMappingWithRanges.class);
+
+ /**
+ * Used to clean up lists for detached objects.
+ */
+ private static final int FINAL_VERSION = Integer.MAX_VALUE;
+
+ /**
+ * The table of this mapping.
+ */
+ private IDBTable table;
+
+ /**
+ * The tags mapped to column names
+ */
+ private HashMap tagMap;
+
+ /**
+ * Column name Set
+ */
+ private List columnNames;
+
+ /**
+ * The type mappings for the value fields.
+ */
+ private Map typeMappings;
+
+ // --------- SQL strings - see initSqlStrings() -----------------
+ private String sqlSelectChunksPrefix;
+
+ private String sqlOrderByIndex;
+
+ protected String sqlInsert;
+
+ private String sqlGetListLastIndex;
+
+ private List dbTypes;
+
+ private String sqlRemoveEntry;
+
+ private String sqlDeleteEntry;
+
+ private String sqlUpdateIndex;
+
+ private String sqlGetValue;
+
+ private String sqlClearList;
+
+ private String sqlDeleteList;
+
+ public AuditFeatureMapTableMappingWithRanges(IMappingStrategy mappingStrategy, EClass eClass,
+ EStructuralFeature feature)
+ {
+ super(mappingStrategy, eClass, feature);
+ initDBTypes();
+ initTable();
+ initSqlStrings();
+ }
+
+ private void initDBTypes()
+ {
+ // TODO add annotation processing here ...
+ dbTypes = new ArrayList(TypeMappingFactory.getDefaultFeatureMapDBTypes());
+ }
+
+ private void initTable()
+ {
+ String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
+ table = getMappingStrategy().getStore().getDBSchema().addTable(tableName);
+
+ // add fields for CDOID
+ IDBField idField = table.addField(CDODBSchema.FEATUREMAP_REVISION_ID, DBType.INTEGER);
+
+ // add fields for version range
+ IDBField versionAddedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_ADDED, DBType.INTEGER);
+ IDBField versionRemovedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_REMOVED, DBType.INTEGER);
+
+ // add field for list index
+ IDBField idxField = table.addField(CDODBSchema.FEATUREMAP_IDX, DBType.INTEGER);
+
+ // add field for FeatureMap tag (MetaID for Feature in CDO registry)
+ IDBField tagField = table.addField(CDODBSchema.FEATUREMAP_TAG, DBType.INTEGER);
+
+ tagMap = new HashMap();
+ typeMappings = new HashMap();
+ columnNames = new ArrayList();
+
+ // create columns for all DBTypes
+ for (DBType type : getDBTypes())
+ {
+ String column = CDODBSchema.FEATUREMAP_VALUE + "_" + type.name();
+ table.addField(column, type);
+ columnNames.add(column);
+ }
+
+ // TODO think about indices
+ table.addIndex(Type.NON_UNIQUE, idField);
+ table.addIndex(Type.NON_UNIQUE, versionAddedField);
+ table.addIndex(Type.NON_UNIQUE, versionRemovedField);
+ table.addIndex(Type.NON_UNIQUE, idxField);
+ table.addIndex(Type.NON_UNIQUE, tagField);
+ }
+
+ public Collection getDBTables()
+ {
+ return Arrays.asList(table);
+ }
+
+ private void initSqlStrings()
+ {
+ String tableName = getTable().getName();
+
+ // ---------------- SELECT to read chunks ----------------------------
+ StringBuilder builder = new StringBuilder();
+ builder.append("SELECT ");
+
+ builder.append(CDODBSchema.FEATUREMAP_TAG);
+ builder.append(", ");
+
+ Iterator iter = columnNames.iterator();
+ while (iter.hasNext())
+ {
+ builder.append(iter.next());
+ if (iter.hasNext())
+ {
+ builder.append(", ");
+ }
+ }
+
+ builder.append(" FROM ");
+ builder.append(tableName);
+ builder.append(" WHERE ");
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append(" <= ? AND ( "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL OR "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" > ? )"); //$NON-NLS-1$
+ sqlSelectChunksPrefix = builder.toString();
+
+ sqlOrderByIndex = " ORDER BY " + CDODBSchema.FEATUREMAP_IDX; //$NON-NLS-1$
+
+ // ----------------- count list size --------------------------
+
+ builder = new StringBuilder("SELECT count(1) FROM ");
+ builder.append(tableName);
+ builder.append(" WHERE ");
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append(" <= ? AND ( "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL OR "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" > ? )"); //$NON-NLS-1$
+ sqlGetListLastIndex = builder.toString();
+
+ // ----------------- INSERT - prefix -----------------
+ builder = new StringBuilder("INSERT INTO ");
+ builder.append(tableName);
+ builder.append("(");
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append(",");
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
+ builder.append(",");
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append(",");
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append(",");
+ builder.append(CDODBSchema.LIST_VALUE);
+
+ for (int i = 0; i < columnNames.size(); i++)
+ {
+ builder.append(columnNames.get(i));
+ builder.append(", "); //$NON-NLS-1$
+ }
+
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_TAG);
+ builder.append(") VALUES (?, ?, ?, ?, ?, "); //$NON-NLS-1$
+ for (int i = 0; i < columnNames.size(); i++)
+ {
+ builder.append("?, ");
+ }
+
+ builder.append("?, ?)");
+ sqlInsert = builder.toString();
+
+ // ----------------- remove current entry -----------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" = ? "); //$NON-NLS-1$
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlRemoveEntry = builder.toString();
+
+ // ----------------- delete temporary entry -----------------
+ builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append(" = ?"); //$NON-NLS-1$
+ sqlDeleteEntry = builder.toString();
+
+ // ----------------- update index -----------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(" = ? WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(" = ?"); //$NON-NLS-1$
+ sqlUpdateIndex = builder.toString();
+
+ // ----------------- get current value -----------------
+ builder = new StringBuilder("SELECT "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_TAG);
+ builder.append(", ");
+
+ iter = columnNames.iterator();
+ while (iter.hasNext())
+ {
+ builder.append(iter.next());
+ if (iter.hasNext())
+ {
+ builder.append(", ");
+ }
+ }
+
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlGetValue = builder.toString();
+
+ // ----------- clear list items -------------------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" = ? "); //$NON-NLS-1$
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlClearList = builder.toString();
+
+ // ----------- delete temporary list items -------------------------
+ builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append(" = ? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlDeleteList = builder.toString();
+ }
+
+ protected List getDBTypes()
+ {
+ return dbTypes;
+ }
+
+ protected final IDBTable getTable()
+ {
+ return table;
+ }
+
+ protected final List getColumnNames()
+ {
+ return columnNames;
+ }
+
+ protected final Map getTypeMappings()
+ {
+ return typeMappings;
+ }
+
+ protected final Map getTagMap()
+ {
+ return tagMap;
+ }
+
+ public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
+ {
+ MoveableList