diff options
77 files changed, 1653 insertions, 1073 deletions
diff --git a/features/org.eclipse.emf.cdo.server.db-feature/feature.xml b/features/org.eclipse.emf.cdo.server.db-feature/feature.xml index 54b7add447..b093772ecc 100644 --- a/features/org.eclipse.emf.cdo.server.db-feature/feature.xml +++ b/features/org.eclipse.emf.cdo.server.db-feature/feature.xml @@ -12,7 +12,7 @@ <feature id="org.eclipse.emf.cdo.server.db" label="%featureName" - version="4.4.100.qualifier" + version="4.5.0.qualifier" provider-name="%providerName" license-feature="org.eclipse.emf.cdo.license" license-feature-version="0.0.0"> diff --git a/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF index 080b953d5a..a80fee0aae 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.server.db;singleton:=true -Bundle-Version: 4.4.100.qualifier +Bundle-Version: 4.5.0.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -12,10 +12,10 @@ Bundle-ClassPath: . Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", org.eclipse.net4j.db;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, org.eclipse.emf.cdo.server;bundle-version="[4.0.0,5.0.0)";visibility:=reexport -Export-Package: org.eclipse.emf.cdo.server.db;version="4.4.100", - org.eclipse.emf.cdo.server.db.mapping;version="4.4.100", - org.eclipse.emf.cdo.server.internal.db;version="4.4.100";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db,org.eclipse.emf.cdo.explorer.ui", - org.eclipse.emf.cdo.server.internal.db.bundle;version="4.4.100";x-internal:=true, - org.eclipse.emf.cdo.server.internal.db.mapping;version="4.4.100";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", - org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;version="4.4.100";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", - org.eclipse.emf.cdo.server.internal.db.messages;version="4.4.100";x-internal:=true +Export-Package: org.eclipse.emf.cdo.server.db;version="4.5.0", + org.eclipse.emf.cdo.server.db.mapping;version="4.5.0", + org.eclipse.emf.cdo.server.internal.db;version="4.5.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db,org.eclipse.emf.cdo.explorer.ui", + org.eclipse.emf.cdo.server.internal.db.bundle;version="4.5.0";x-internal:=true, + org.eclipse.emf.cdo.server.internal.db.mapping;version="4.5.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", + org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;version="4.5.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", + org.eclipse.emf.cdo.server.internal.db.messages;version="4.5.0";x-internal:=true diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java index 19fb5be943..3f158fccab 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java @@ -10,11 +10,14 @@ */ package org.eclipse.emf.cdo.server.db; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.IStoreAccessor.UnitSupport; import org.eclipse.net4j.db.IDBConnection; +import org.eclipse.emf.ecore.EClass; + import java.sql.Connection; /** @@ -36,6 +39,11 @@ public interface IDBStoreAccessor extends IStoreAccessor.Raw2, UnitSupport public Connection getConnection(); /** + * @since 4.5 + */ + public EClass getObjectType(CDOID id); + + /** * @since 2.0 * @deprecated As of 4.2 use {@link IDBConnection#prepareStatement(String, org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability)}. */ diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy2.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy2.java new file mode 100644 index 0000000000..cbf383ba98 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy2.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 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.server.db.mapping; + +import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; + +import org.eclipse.net4j.util.om.monitor.OMMonitor; + +/** + * Interface to complement {@link IMappingStrategy}. + * + * @author Eike Stepper + * @since 4.5 + */ +public interface IMappingStrategy2 extends IMappingStrategy +{ + public boolean needsRevisionPostProcessing(); + + public void postProcessRevisions(IDBStoreAccessor accessor, CommitContext context, OMMonitor monitor); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java index 154bf1243d..ff53f34073 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBAnnotation.java @@ -28,7 +28,8 @@ public enum DBAnnotation COLUMN_NAME("columnName"), // COLUMN_TYPE("columnType"), // COLUMN_LENGTH("columnLength"), // - TYPE_MAPPING("typeMapping"); + TYPE_MAPPING("typeMapping"), // + INVERSE_LIST("inverseList"); public static final String SOURCE_URI = "http://www.eclipse.org/CDO/DBStore"; diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java index c658103dbc..39a8c36597 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java @@ -39,6 +39,7 @@ import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2; import org.eclipse.emf.cdo.server.ITransaction; import org.eclipse.emf.cdo.server.IView; +import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; @@ -47,6 +48,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; import org.eclipse.emf.cdo.server.db.mapping.IClassMappingAuditSupport; import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy2; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalClassMapping; import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.UnitMappingTable; @@ -209,7 +211,7 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, return mappingStrategy.readObjectType(this, id); } - protected EClass getObjectType(CDOID id) + public EClass getObjectType(CDOID id) { IRepository repository = getStore().getRepository(); if (id.equals(repository.getRootResourceID())) @@ -223,6 +225,16 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, return result; } + CommitContext commitContext = StoreThreadLocal.getCommitContext(); + if (commitContext != null) + { + InternalCDORevision revision = commitContext.getNewRevisions().get(id); + if (revision != null) + { + return revision.getEClass(); + } + } + CDOClassifierRef type = readObjectType(id); if (type != null) { @@ -603,6 +615,28 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, mapping.writeRevision(this, revision, mapType, revise, monitor); } + @Override + protected boolean needsRevisionPostProcessing() + { + IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); + if (mappingStrategy instanceof IMappingStrategy2) + { + return ((IMappingStrategy2)mappingStrategy).needsRevisionPostProcessing(); + } + + return super.needsRevisionPostProcessing(); + } + + @Override + protected void postProcessRevisions(InternalCommitContext context, OMMonitor monitor) + { + IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); + if (mappingStrategy instanceof IMappingStrategy2) + { + ((IMappingStrategy2)mappingStrategy).postProcessRevisions(this, context, monitor); + } + } + /* * XXX Eike: change API from CDOID[] to CDOIDAndVersion[] */ diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java index fa26cae563..1de3e75ff8 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java @@ -508,7 +508,7 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp { async = monitor.forkAsync(); - boolean isInitialCommit = passedPackageUnits && contains(packageUnits, EresourcePackage.eINSTANCE.getNsURI()); + boolean isInitialCommit = passedPackageUnits && containsPackageUnit(packageUnits, EresourcePackage.eINSTANCE.getNsURI()); if (isInitialCommit) { systemPackageMappingInfo = new SystemPackageMappingInfo(); @@ -629,42 +629,33 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp return store.getDBSchema().getTable(tableName) != null; } - private boolean contains(InternalCDOPackageUnit[] packageUnits, String packageUnitID) + protected Set<IClassMapping> mapPackageUnits(InternalCDOPackageUnit[] packageUnits, Connection connection, boolean unmap) { - for (InternalCDOPackageUnit packageUnit : packageUnits) - { - if (packageUnit.getID().equals(packageUnitID)) - { - return true; - } - } + Set<IClassMapping> classMappings = new HashSet<IClassMapping>(); - return false; - } - - private void mapPackageUnits(InternalCDOPackageUnit[] packageUnits, Connection connection, boolean unmap) - { if (packageUnits != null && packageUnits.length != 0) { for (InternalCDOPackageUnit packageUnit : packageUnits) { InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos(); - mapPackageInfos(packageInfos, connection, unmap); + mapPackageInfos(packageInfos, connection, unmap, classMappings); } } + + return classMappings; } - private void mapPackageInfos(InternalCDOPackageInfo[] packageInfos, Connection connection, boolean unmap) + private void mapPackageInfos(InternalCDOPackageInfo[] packageInfos, Connection connection, boolean unmap, Set<IClassMapping> classMappings) { for (InternalCDOPackageInfo packageInfo : packageInfos) { EPackage ePackage = packageInfo.getEPackage(); EClass[] persistentClasses = EMFUtil.getPersistentClasses(ePackage); - mapClasses(connection, unmap, persistentClasses); + mapClasses(connection, unmap, persistentClasses, classMappings); } } - private void mapClasses(Connection connection, boolean unmap, EClass... eClasses) + private void mapClasses(Connection connection, boolean unmap, EClass[] eClasses, Set<IClassMapping> classMappings) { for (EClass eClass : eClasses) { @@ -678,13 +669,10 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp continue; } - if (unmap) - { - removeClassMapping(eClass); - } - else + IClassMapping classMapping = unmap ? removeClassMapping(eClass) : createClassMapping(eClass); + if (classMapping != null) { - createClassMapping(eClass); + classMappings.add(classMapping); } } } @@ -692,29 +680,30 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp private IClassMapping createClassMapping(EClass eClass) { - IClassMapping mapping = doCreateClassMapping(eClass); - if (mapping != null) + IClassMapping classMapping = doCreateClassMapping(eClass); + if (classMapping != null) { - classMappings.put(eClass, mapping); + classMappings.put(eClass, classMapping); } - return mapping; + return classMapping; } private IClassMapping removeClassMapping(EClass eClass) { - IClassMapping mapping = classMappings.get(eClass); - if (mapping != null) + IClassMapping classMapping = classMappings.get(eClass); + if (classMapping != null) { IDBSchema schema = getStore().getDBSchema(); - for (IDBTable table : mapping.getDBTables()) + for (IDBTable table : classMapping.getDBTables()) { schema.removeTable(table.getName()); } classMappings.remove(eClass); } - return mapping; + + return classMapping; } protected abstract IClassMapping doCreateClassMapping(EClass eClass); @@ -781,17 +770,14 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp InternalCDOPackageRegistry packageRegistry = repository.getPackageRegistry(false); for (InternalCDOPackageInfo packageInfo : packageRegistry.getPackageInfos()) { - if (!packageInfo.isSystemPackage()) + for (EClassifier eClassifier : packageInfo.getEPackage().getEClassifiers()) { - for (EClassifier eClassifier : packageInfo.getEPackage().getEClassifiers()) + if (eClassifier instanceof EClass) { - if (eClassifier instanceof EClass) + EClass eClass = (EClass)eClassifier; + if (isMapped(eClass)) { - EClass eClass = (EClass)eClassifier; - if (isMapped(eClass)) - { - getClassMapping(eClass); // Get or create it - } + getClassMapping(eClass); // Get or create it } } } @@ -842,6 +828,19 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp } } + private static boolean containsPackageUnit(InternalCDOPackageUnit[] packageUnits, String packageUnitID) + { + for (InternalCDOPackageUnit packageUnit : packageUnits) + { + if (packageUnit.getID().equals(packageUnitID)) + { + return true; + } + } + + return false; + } + private static Set<CDOFeatureType> doGetForceIndexes(IMappingStrategy mappingStrategy) { return CDOFeatureType.readCombination(mappingStrategy.getProperties().get(Props.FORCE_INDEXES)); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java index d872901630..266089cada 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java @@ -12,14 +12,40 @@ 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.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.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IIDHandler; import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; import org.eclipse.emf.cdo.server.db.mapping.IListMapping3; 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.bundle.OM; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EStructuralFeature; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + /** * @author Stefan Winkler */ @@ -75,4 +101,875 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM } public abstract void rawDeleted(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, int version); + + /** + * @author Eike Stepper + */ + public static abstract class AbstractListDeltaWriter implements CDOFeatureDeltaVisitor + { + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractListDeltaWriter.class); + + private static final int UNBOUNDED_SHIFT = -1; + + private static final int NO_INDEX = Integer.MIN_VALUE; + + private static final int NONE = 0; + + private static final int SET = 1 << 1; + + private static final int MOVE = 1 << 2; + + private static final int INSERT = 1 << 3; + + private static final int DELETE = 1 << 4; + + protected final IDBStoreAccessor accessor; + + protected final CDOID id; + + private final List<CDOFeatureDelta> listChanges; + + private final List<Manipulation> manipulations; + + private boolean clearFirst; + + private int offsetBefore; + + /** + * Start of a range [tempIndex, tempIndex-1, ...] which lies outside of the normal list indexes and which serve as + * temporary space to move items temporarily to get them out of the way of other operations. + */ + private int tmpIndex = -1; + + private int newListSize; + + public AbstractListDeltaWriter(IDBStoreAccessor accessor, CDOID id, List<CDOFeatureDelta> listChanges, int oldListSize) + { + this.accessor = accessor; + this.id = id; + this.listChanges = listChanges; + + manipulations = createManipulations(id, listChanges, oldListSize); + newListSize = oldListSize; + } + + public void writeListDeltas() + { + if (TRACER.isEnabled()) + { + TRACER.trace("Processing list deltas..."); //$NON-NLS-1$ + } + + for (CDOFeatureDelta listDelta : listChanges) + { + listDelta.accept(this); + } + + boolean zeroBasedIndex = ((HorizontalNonAuditMappingStrategy)accessor.getStore().getMappingStrategy()).shallForceZeroBasedIndex(); + if (!zeroBasedIndex) + { + if (TRACER.isEnabled()) + { + TRACER.trace("Optimizing list indexes..."); //$NON-NLS-1$ + } + + optimizeListIndexes(); + } + + if (TRACER.isEnabled()) + { + TRACER.trace("Result to be written to DB:"); + for (Manipulation manipulation : manipulations) + { + TRACER.trace(manipulation.toString()); + } + } + + try + { + writeResultToDatabase(); + } + catch (SQLException e) + { + throw new DBException(e); + } + + throw new NewListSizeResult(newListSize); + } + + public void visit(CDOAddFeatureDelta delta) + { + if (TRACER.isEnabled()) + { + TRACER.format(" - insert at {0} value {1}", delta.getIndex(), delta.getValue()); //$NON-NLS-1$ + } + + // Make room for the new item + shiftIndexes(delta.getIndex(), UNBOUNDED_SHIFT, +1); + + // Create the item + manipulations.add(Manipulation.createInsertedElement(delta.getIndex(), delta.getValue())); + ++newListSize; + } + + public void visit(CDORemoveFeatureDelta delta) + { + if (TRACER.isEnabled()) + { + TRACER.format(" - remove at {0}", delta.getIndex()); //$NON-NLS-1$ + } + + Manipulation e = findManipulation(delta.getIndex()); + deleteItem(e); + + // Fill the gap by shifting all subsequent items down + shiftIndexes(delta.getIndex() + 1, UNBOUNDED_SHIFT, -1); + --newListSize; + } + + public void visit(CDOSetFeatureDelta delta) + { + if (TRACER.isEnabled()) + { + TRACER.format(" - set at {0} value {1}", delta.getIndex(), delta.getValue()); //$NON-NLS-1$ + } + + Manipulation manipulation = findManipulation(delta.getIndex()); + + // Set the new value + manipulation.value = delta.getValue(); + + // If the item is freshly inserted we do not set the SET-mark. + // Setting the value of a new item results in inserting with the new value at once. + if (!manipulation.is(INSERT)) + { + // Else mark the existing item to be set to a new value + manipulation.addType(SET); + } + } + + public void visit(CDOUnsetFeatureDelta delta) + { + // TODO Shouldn't that be "!unsettable"?! + if (delta.getFeature().isUnsettable()) + { + throw new IllegalArgumentException("Feature is unsettable: " + delta); + } + + if (TRACER.isEnabled()) + { + TRACER.format(" - unset list"); //$NON-NLS-1$ + } + + // Set the clear-flag + clearFirst = true; + + // And also clear all manipulation items + manipulations.clear(); + newListSize = 0; + } + + public void visit(CDOClearFeatureDelta delta) + { + if (TRACER.isEnabled()) + { + TRACER.format(" - clear list"); //$NON-NLS-1$ + } + + // Set the clear-flag + clearFirst = true; + + // And also clear all manipulation items + manipulations.clear(); + newListSize = 0; + } + + public void visit(CDOMoveFeatureDelta delta) + { + int fromIdx = delta.getOldPosition(); + int toIdx = delta.getNewPosition(); + + if (TRACER.isEnabled()) + { + TRACER.format(" - move {0} -> {1}", fromIdx, toIdx); //$NON-NLS-1$ + } + + // Ignore the trivial case + if (fromIdx == toIdx) + { + return; + } + + Manipulation manipulation = findManipulation(fromIdx); + + // Adjust indexes and shift either up or down + if (fromIdx < toIdx) + { + shiftIndexes(fromIdx + 1, toIdx, -1); + } + else + { + // fromIdx > toIdx here + shiftIndexes(toIdx, fromIdx - 1, +1); + } + + // Set the new index + manipulation.dstIndex = toIdx; + + // If it is a new element, no MOVE mark needed, because we insert it at the new position + if (!manipulation.is(INSERT)) + { + // Else we need to handle the move of an existing item + manipulation.addType(MOVE); + } + } + + @Deprecated + public void visit(CDOListFeatureDelta delta) + { + throw new UnsupportedOperationException("Should never be called"); + } + + @Deprecated + public void visit(CDOContainerFeatureDelta delta) + { + throw new UnsupportedOperationException("Should never be called"); + } + + protected List<Manipulation> createManipulations(CDOID id, List<CDOFeatureDelta> listChanges, int oldListSize) + { + List<Manipulation> manipulations = new ArrayList<Manipulation>(oldListSize); + + // Create list and initialize with original indexes + for (int i = 0; i < oldListSize; i++) + { + manipulations.add(Manipulation.createOriginalElement(i)); + } + + return manipulations; + } + + /** + * Helper method: shift all (destination) indexes in the interval [from,to] (inclusive at both ends) by offset + * (positive or negative). + */ + private void shiftIndexes(int from, int to, int offset) + { + for (Manipulation manipulation : manipulations) + { + if (manipulation.dstIndex >= from && (to == UNBOUNDED_SHIFT || manipulation.dstIndex <= to)) + { + manipulation.dstIndex += offset; + } + } + } + + /** + * Find a manipulation item by destination index). + */ + private Manipulation findManipulation(int index) + { + for (Manipulation manipulation : manipulations) + { + if (manipulation.dstIndex == index) + { + return manipulation; + } + } + + throw new IllegalStateException("Should never be reached"); + } + + /** + * Delete an element (used in remove and clear) + */ + private void deleteItem(Manipulation manipulation) + { + if (manipulation.is(INSERT)) + { + // Newly inserted items are simply removed, as removing inserted items is equal to no change at all. + manipulations.remove(manipulation); + } + else + { + // Mark the existing item as to be deleted. + // Previous MOVE and SET conditions are overridden by setting the exclusive DELETE type. + manipulation.types = DELETE; + manipulation.dstIndex = NO_INDEX; + } + } + + /** + * Called after all deltas are applied and before the results are written to the database. This method post-processes + * the manipulation elements in order to minimize database access. + */ + private void optimizeListIndexes() + { + /* + * This is an optimization which reduces the amount of modifications on the database to maintain list indexes. For + * the optimization, we let go of the assumption that indexes are zero-based. Instead, we work with an offset at + * the database level which can change with every change to the list (e.g. if the second element is removed from a + * list with 1000 elements, instead of shifting down indexes 2 to 1000 by 1, we shift up index 0 by 1 and have now + * a list with indexes starting at 1 instead of 0. This optimization is applied by modifying the list of + * Manipulations, which can be seen as the database modification plan. + */ + + // First, get the current offset. + offsetBefore = getCurrentIndexOffset(); + if (TRACER.isEnabled()) + { + TRACER.trace("Offset optimization."); //$NON-NLS-1$ + TRACER.trace("Current offset = " + offsetBefore); //$NON-NLS-1$ + } + + applyOffsetToSourceIndexes(offsetBefore); + + int offsetAfter; + + if ((long)Math.abs(offsetBefore) + (long)manipulations.size() > Integer.MAX_VALUE) + { + // Safety belt for really huge collections or for collections that have been manipulated lots of times + // -> Do not optimize after this border is crossed. Instead, reset offset for the whole list to a zero-based + // index. + offsetAfter = 0; + } + else + { + offsetAfter = calculateOptimalOffset(); + } + + if (TRACER.isEnabled()) + { + TRACER.trace("New offset = " + offsetAfter); //$NON-NLS-1$ + } + + applyOffsetToDestinationIndexes(offsetAfter); + + // Make sure temporary indexes do not get in the way of the other operations. + tmpIndex = Math.min(offsetBefore, offsetAfter) - 1; + } + + /** + * Calculate the optimal offset w.r.t. the manipulations planned. The optimal offset is the offset which occurs the + * most in the manipulations (because letting this offset be neutral leads to the least manipulations. Note: the + * zero offset is also regarded as an offset as any other, because selecting an offset != 0 would also lead to + * elements with original offset 0 to be moved. + */ + private int calculateOptimalOffset() + { + HashMap<Integer, Integer> occurrences = new HashMap<Integer, Integer>(); + int bestOffset = 0; + int bestOffsetOccurrence = 0; + + for (Manipulation manipulation : manipulations) + { + int srcIndex = manipulation.srcIndex; + int dstIndex = manipulation.dstIndex; + + if (srcIndex != NO_INDEX && dstIndex != NO_INDEX) + { + int offset = dstIndex - srcIndex; + Integer oldOccurrence = occurrences.get(offset); + + int newOccurrence; + if (oldOccurrence == null) + { + newOccurrence = 1; + } + else + { + newOccurrence = oldOccurrence + 1; + } + + occurrences.put(offset, newOccurrence); + + // Remember maximum along the way + if (newOccurrence > bestOffsetOccurrence) + { + bestOffsetOccurrence = newOccurrence; + bestOffset = offset; + } + } + } + + // The offset which has occurred the most has to be applied negatively to normalize the list + // therefore return the negative offset as the new offset to be applied + return -bestOffset; + } + + private void applyOffsetToSourceIndexes(int offsetBefore) + { + if (offsetBefore != 0) + { + for (Manipulation manipulation : manipulations) + { + if (manipulation.srcIndex != NO_INDEX) + { + manipulation.srcIndex += offsetBefore; + } + } + } + } + + private void applyOffsetToDestinationIndexes(int offsetAfter) + { + if (offsetAfter != 0) + { + for (Manipulation manipulation : manipulations) + { + if (manipulation.dstIndex != NO_INDEX) + { + // Apply the offset to all indices to make them relative to the new offset + manipulation.dstIndex += offsetAfter; + } + } + } + } + + protected final int getOffsetBefore() + { + return offsetBefore; + } + + protected final int getNextTmpIndex() + { + return --tmpIndex; + } + + /** + * Write calculated changes to the database + */ + protected void writeResultToDatabase() throws SQLException + { + IIDHandler idHandler = accessor.getStore().getIDHandler(); + if (TRACER.isEnabled()) + { + TRACER.trace("Writing to database:"); //$NON-NLS-1$ + } + + if (clearFirst) + { + if (TRACER.isEnabled()) + { + TRACER.trace(" - clear list"); //$NON-NLS-1$ + } + + clearList(); + } + + for (Manipulation manipulation : manipulations) + { + if (manipulation.is(DELETE)) + { + /* + * Step 1: DELETE all elements e which have e.is(DELETE) by e.srcIndex + */ + dbDelete(idHandler, manipulation.srcIndex); + + if (TRACER.isEnabled()) + { + TRACER.format(" - delete at {0} ", manipulation.srcIndex); //$NON-NLS-1$ + } + } + + if (manipulation.is(MOVE)) + { + /* + * Step 2: MOVE all elements e (by e.srcIndex) which have e.is(MOVE) to tmpIndex (-1, -2, -3, -4, ...) and + * store tmpIndex in e.tempIndex + */ + manipulation.tmpIndex = getNextTmpIndex(); + dbMove(idHandler, manipulation.srcIndex, manipulation.tmpIndex, manipulation.srcIndex); + + if (TRACER.isEnabled()) + { + TRACER.format(" - move {0} -> {1} ", manipulation.srcIndex, manipulation.tmpIndex); //$NON-NLS-1$ + } + } + } + + writeShifts(idHandler); + + ITypeMapping typeMapping = getTypeMapping(); + for (Manipulation manipulation : manipulations) + { + if (manipulation.is(MOVE)) + { + /* + * Step 4: MOVE all elements e have e.is(MOVE) from e.tempIdx to e.dstIndex (because we have moved them + * before, moveStmt is always initialized + */ + dbMove(idHandler, manipulation.tmpIndex, manipulation.dstIndex, manipulation.srcIndex); + + if (TRACER.isEnabled()) + { + TRACER.format(" - move {0} -> {1} ", manipulation.tmpIndex, manipulation.dstIndex); //$NON-NLS-1$ + } + } + + if (manipulation.is(SET)) + { + /* + * Step 5: SET all elements which have e.type == SET by index == e.dstIndex + */ + dbSet(idHandler, typeMapping, manipulation.dstIndex, manipulation.value, manipulation.srcIndex); + + if (TRACER.isEnabled()) + { + TRACER.format(" - set value at {0} to {1} ", manipulation.dstIndex, manipulation.value); //$NON-NLS-1$ + } + } + + if (manipulation.is(INSERT)) + { + /* + * Step 6: INSERT all elements which have e.type == INSERT. + */ + dbInsert(idHandler, typeMapping, manipulation.dstIndex, manipulation.value); + + if (TRACER.isEnabled()) + { + TRACER.format(" - insert value at {0} : value {1} ", manipulation.dstIndex, manipulation.value); //$NON-NLS-1$ + } + } + } + } + + /** + * Perform the shift operations to adjust indexes resulting from remove, insert, and move operations. + * + * @see #writeResultToDatabase(IDBStoreAccessor, CDOID) + * @throws SQLException + */ + protected void writeShifts(IIDHandler idHandler) throws SQLException + { + /* + * Step 3: shift all elements which have to be shifted up or down because of add, remove or move of other elements + * to their proper position. This has to be done in two phases to avoid collisions, as the index has to be unique + * and shift up operations have to be executed in top to bottom order. + */ + LinkedList<Shift> shiftOperations = new LinkedList<Shift>(); + + /* + * If a necessary shift is detected (source and destination indices differ), firstIndex is set to the current + * index and currentOffset is set to the offset of the shift operation. When a new offset is detected or the range + * is interrupted, we record the range and start a new one if needed. + */ + int rangeStartIndex = NO_INDEX; + int rangeOffset = 0; + int lastElementIndex = NO_INDEX; + + // Iterate through the manipulationElements and collect the necessary operations + for (Manipulation manipulation : manipulations) + { + /* + * Shift applies only to elements which are not moved, inserted or deleted (i.e. only plain SET and NONE are + * affected) + */ + if (manipulation.types == NONE || manipulation.types == SET) + { + int elementOffset = manipulation.dstIndex - manipulation.srcIndex; + + /* + * First make sure if we have to close a previous range. This is the case, if the current element's offset + * differs from the rangeOffset and a range is open. + */ + if (elementOffset != rangeOffset && rangeStartIndex != NO_INDEX) + { + // There is an open range but the rangeOffset differs. We have to close the open range + shiftOperations.add(new Shift(rangeStartIndex, lastElementIndex, rangeOffset)); + + // And reset the state + rangeStartIndex = NO_INDEX; + rangeOffset = 0; + } + + /* + * At this point, either a range is open, which means that the current element also fits in the range (i.e. + * the offsets match) or no range is open. In the latter case, we have to open one if the current element's + * offset is not 0. + */ + if (elementOffset != 0 && rangeStartIndex == NO_INDEX) + { + rangeStartIndex = manipulation.srcIndex; + rangeOffset = elementOffset; + } + } + else + { + // Shift does not apply to this element because of its type + if (rangeStartIndex != NO_INDEX) + { + // If there is an open range, we have to close and remember it + shiftOperations.add(new Shift(rangeStartIndex, lastElementIndex, rangeOffset)); + + // And reset the state + rangeStartIndex = NO_INDEX; + rangeOffset = 0; + } + } + + lastElementIndex = manipulation.srcIndex; + } + + // After the iteration, we have to make sure that we remember the last open range, if it is there + if (rangeStartIndex != NO_INDEX) + { + shiftOperations.add(new Shift(rangeStartIndex, lastElementIndex, rangeOffset)); + } + + /* + * Now process the operations. Move down operations can be performed directly, move up operations need to be + * performed later in the reverse direction + */ + ListIterator<Shift> operationIt = shiftOperations.listIterator(); + writeShiftsDown(idHandler, operationIt); + writeShiftsUp(idHandler, operationIt); + } + + protected void writeShiftsDown(IIDHandler idHandler, ListIterator<Shift> operationIt) throws SQLException + { + while (operationIt.hasNext()) + { + Shift operation = operationIt.next(); + if (operation.offset < 0) + { + dbShiftDown(idHandler, operation.offset, operation.startIndex, operation.endIndex); + + if (TRACER.isEnabled()) + { + TRACER.format(" - shift down {0} ", operation); //$NON-NLS-1$ + } + + operationIt.remove(); + } + } + } + + protected void writeShiftsUp(IIDHandler idHandler, ListIterator<Shift> operationIt) throws SQLException + { + while (operationIt.hasPrevious()) + { + Shift operation = operationIt.previous(); + dbShiftUp(idHandler, operation.offset, operation.startIndex, operation.endIndex); + + if (TRACER.isEnabled()) + { + TRACER.format(" - shift up {0} ", operation); //$NON-NLS-1$ + } + } + } + + protected abstract void dbDelete(IIDHandler idHandler, int index) throws SQLException; + + protected abstract void dbMove(IIDHandler idHandler, int fromIndex, int toIndex, int srcIndex) throws SQLException; + + protected abstract void dbSet(IIDHandler idHandler, ITypeMapping typeMapping, int index, Object value, int srcIndex) throws SQLException; + + protected abstract void dbInsert(IIDHandler idHandler, ITypeMapping typeMapping, int index, Object value) throws SQLException; + + protected abstract void dbShiftDown(IIDHandler idHandler, int offset, int startIndex, int endIndex) throws SQLException; + + protected abstract void dbShiftUp(IIDHandler idHandler, int offset, int startIndex, int endIndex) throws SQLException; + + protected static void close(PreparedStatement... stmts) + { + Throwable t = null; + + for (PreparedStatement stmt : stmts) + { + try + { + if (stmt != null) + { + try + { + stmt.clearBatch(); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + DBUtil.close(stmt); + } + } + } + catch (Throwable th) + { + if (t == null) + { + // Remember first exception + t = th; + } + + // More exceptions go to the log + OM.LOG.error(t); + } + } + + if (t != null) + { + throw new DBException(t); + } + } + + protected abstract ITypeMapping getTypeMapping(); + + protected abstract int getCurrentIndexOffset(); + + protected abstract void clearList(); + + /** + * @author Eike Stepper + */ + public static final class NewListSizeResult extends RuntimeException + { + private static final long serialVersionUID = 1L; + + private final int newListSize; + + public NewListSizeResult(int newListSize) + { + this.newListSize = newListSize; + } + + public int getNewListSize() + { + return newListSize; + } + } + + /** + * @author Eike Stepper + */ + public static final class Manipulation + { + private static final Object NIL = new Object() + { + @Override + public String toString() + { + return "NIL"; + } + }; + + public int types; + + public int srcIndex; + + public int tmpIndex; + + public int dstIndex; + + public Object value; + + public Manipulation(int types, int srcIndex, int dstIndex, Object value) + { + this.types = types; + this.srcIndex = srcIndex; + tmpIndex = NO_INDEX; + this.dstIndex = dstIndex; + this.value = value; + } + + public boolean is(int type) + { + return type == NONE ? types == NONE : (types & type) != 0; + } + + public void addType(int type) + { + types |= type; + } + + @Override + public String toString() + { + return MessageFormat.format("Manipulation[types={0}, srcIndex={1}, tmpIndex={2}, dstIndex={3}, value={4}]", formatTypes(types), formatIndex(srcIndex), + formatIndex(tmpIndex), formatIndex(dstIndex), String.valueOf(value)); + } + + /** + * Create a Manipulation which represents an element which already is in the list. + */ + public static Manipulation createOriginalElement(int index) + { + return new Manipulation(NONE, index, index, NIL); + } + + /** + * Create a Manipulation which represents an element which is inserted in the list. + */ + public static Manipulation createInsertedElement(int index, Object value) + { + return new Manipulation(INSERT, NO_INDEX, index, value); + } + + private static String formatTypes(int types) + { + StringBuilder builder = new StringBuilder(); + formatType(types, DELETE, "DELETE", builder); + formatType(types, INSERT, "INSERT", builder); + formatType(types, MOVE, "MOVE", builder); + formatType(types, SET, "SET", builder); + + if (builder.length() != 0) + { + return builder.toString(); + } + + return "NONE"; + } + + private static void formatType(int types, int type, String label, StringBuilder builder) + { + if ((types & type) != 0) + { + if (builder.length() != 0) + { + builder.append("|"); + } + + builder.append(label); + } + } + + private static String formatIndex(int index) + { + if (index == NO_INDEX) + { + return "NONE"; + } + + return Integer.toString(index); + } + } + + /** + * @author Eike Stepper + */ + public static final class Shift + { + public final int startIndex; + + public final int endIndex; + + public final int offset; + + public Shift(int startIndex, int endIndex, int offset) + { + this.startIndex = startIndex; + this.endIndex = endIndex; + this.offset = offset; + } + + @Override + public String toString() + { + return "Shift[" + startIndex + ".." + endIndex + ", offset=" + offset + "]"; + } + } + } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java index 4cd9795010..88281b8424 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java @@ -53,7 +53,6 @@ import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.net4j.spi.db.ddl.InternalDBIndex; import org.eclipse.net4j.util.lifecycle.IDeactivateable; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; @@ -137,7 +136,7 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I table.addField(ATTRIBUTES_CREATED, DBType.BIGINT, true); table.addField(ATTRIBUTES_REVISED, DBType.BIGINT, true); table.addField(ATTRIBUTES_RESOURCE, idType, idLength, true); - table.addField(ATTRIBUTES_CONTAINER, idType, idLength, true); + addContainerField(table, idType, idLength); table.addField(ATTRIBUTES_FEATURE, DBType.INTEGER, true); IDBIndex primaryKey = table.addIndex(IDBIndex.Type.PRIMARY_KEY, ATTRIBUTES_ID, ATTRIBUTES_VERSION); @@ -179,6 +178,11 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I mapping = mappingStrategy.createListMapping(eClass, feature); } + if (mapping == null) + { + continue; + } + if (mapping instanceof IListMapping3) { ((IListMapping3)mapping).setClassMapping(this); @@ -225,8 +229,8 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I if (!table.hasIndexFor(field)) { - InternalDBIndex index = (InternalDBIndex)table.addIndex(IDBIndex.Type.NON_UNIQUE, field); - index.setOptional(true); // Creation might fail for unsupported column type! + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! } } @@ -281,8 +285,8 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I if (!table.hasIndexFor(fields)) { - InternalDBIndex index = (InternalDBIndex)table.addIndex(IDBIndex.Type.NON_UNIQUE, fields); - index.setOptional(true); // Creation might fail for unsupported column type! + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, fields); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! } } else @@ -301,8 +305,8 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I if (!table.hasIndexFor(field)) { - InternalDBIndex index = (InternalDBIndex)table.addIndex(IDBIndex.Type.NON_UNIQUE, field); - index.setOptional(true); // Creation might fail for unsupported column type! + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! } } } @@ -313,8 +317,8 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I if (!table.hasIndexFor(field)) { - InternalDBIndex index = (InternalDBIndex)table.addIndex(IDBIndex.Type.NON_UNIQUE, field); - index.setOptional(true); // Creation might fail for unsupported column type! + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! } } } @@ -341,6 +345,11 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I sqlSelectForChangeSet = builder.toString(); } + protected IDBField addContainerField(IDBTable table, DBType idType, int idLength) + { + return table.addField(ATTRIBUTES_CONTAINER, idType, idLength, true); + } + protected IDBField addBranchField(IDBTable table) { return null; diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java index 877a96cd03..880122d66f 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java @@ -423,7 +423,7 @@ public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingS } /** - * This is an intermediate implementation. It should be changed after classmappings support a general way to implement + * This is an intermediate implementation. It should be changed after class mappings support a general way to implement * queries ... * * @param accessor 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 ba6d836dbf..901c0cdfee 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 @@ -39,7 +39,6 @@ import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.db.ddl.IDBIndex.Type; import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.net4j.spi.db.ddl.InternalDBIndex; import org.eclipse.net4j.util.collection.MoveableList; import org.eclipse.net4j.util.om.trace.ContextTracer; @@ -132,8 +131,8 @@ public abstract class AbstractListTableMapping extends AbstractBasicListTableMap if (!table.hasIndexFor(field)) { - InternalDBIndex index = (InternalDBIndex)table.addIndex(IDBIndex.Type.NON_UNIQUE, field); - index.setOptional(true); // Creation might fail for unsupported column type! + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! } } } @@ -272,7 +271,7 @@ public abstract class AbstractListTableMapping extends AbstractBasicListTableMap { if (stmt.getMaxRows() != 0) { - stmt.setMaxRows(0); + stmt.setMaxRows(0); // No limit. } } @@ -472,12 +471,12 @@ public abstract class AbstractListTableMapping extends AbstractBasicListTableMap CDOID targetId = idHandler.getCDOID(resultSet, 2); int idx = resultSet.getInt(3); - boolean more = context.addXRef(targetId, srcId, (EReference)getFeature(), idx); if (TRACER.isEnabled()) { TRACER.format(" add XRef to context: src={0}, tgt={1}, idx={2}", srcId, targetId, idx); } + boolean more = context.addXRef(targetId, srcId, (EReference)getFeature(), idx); if (!more) { if (TRACER.isEnabled()) diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java index 73ff927688..2879544040 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java @@ -38,7 +38,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.DBStore; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; -import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.NonAuditListTableMapping.NewListSizeResult; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractBasicListTableMapping.AbstractListDeltaWriter.NewListSizeResult; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; @@ -447,6 +447,28 @@ public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMappi } @Override + protected void reviseOldRevision(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, long timeStamp) + { + // do nothing + } + + @Override + protected String getListXRefsWhere(QueryXRefsContext context) + { + if (CDORevision.UNSPECIFIED_DATE != context.getTimeStamp()) + { + throw new IllegalArgumentException("Non-audit mode does not support timestamp specification"); + } + + if (!context.getBranch().isMainBranch()) + { + throw new IllegalArgumentException("Non-audit mode does not support branch specification"); + } + + return ATTRIBUTES_REVISED + "=0"; + } + + @Override protected void detachAttributes(IDBStoreAccessor accessor, CDOID id, int version, CDOBranch branch, long timeStamp, OMMonitor monitor) { rawDelete(accessor, id, version, branch, monitor); @@ -570,6 +592,7 @@ public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMappi } } + @Deprecated public void visit(CDOMoveFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ @@ -621,16 +644,19 @@ public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMappi } } + @Deprecated public void visit(CDOClearFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ } + @Deprecated public void visit(CDOAddFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ } + @Deprecated public void visit(CDORemoveFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ @@ -755,26 +781,4 @@ public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMappi return col; } } - - @Override - protected void reviseOldRevision(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, long timeStamp) - { - // do nothing - } - - @Override - protected String getListXRefsWhere(QueryXRefsContext context) - { - if (CDORevision.UNSPECIFIED_DATE != context.getTimeStamp()) - { - throw new IllegalArgumentException("Non-audit mode does not support timestamp specification"); - } - - if (!context.getBranch().isMainBranch()) - { - throw new IllegalArgumentException("Non-audit mode does not support branch specification"); - } - - return ATTRIBUTES_REVISED + "=0"; - } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditListTableMapping.java index 14db7837e1..15216499a6 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditListTableMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditListTableMapping.java @@ -15,20 +15,13 @@ 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.revision.CDORevision; -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.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; 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.bundle.OM; import org.eclipse.net4j.db.DBException; @@ -41,15 +34,9 @@ import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.core.runtime.Assert; - import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.ListIterator; @@ -63,8 +50,6 @@ public class NonAuditListTableMapping extends AbstractListTableMapping implement { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, NonAuditListTableMapping.class); - private static final int UNBOUNDED_SHIFT = -1; - private String sqlClear; private String sqlUpdateValue; @@ -197,7 +182,7 @@ public class NonAuditListTableMapping extends AbstractListTableMapping implement @Override protected void addKeyFields(List<FieldInfo> list) { - // Do nothing + // Do nothing. } @Override @@ -212,6 +197,27 @@ public class NonAuditListTableMapping extends AbstractListTableMapping implement clearList(accessor, id); } + @Override + public void rawDeleted(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, int version) + { + clearList(accessor, id); + } + + public void processDelta(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion, long created, CDOListFeatureDelta delta) + { + List<CDOFeatureDelta> listChanges = delta.getListChanges(); + int oldListSize = delta.getOriginSize(); + + if (TRACER.isEnabled()) + { + TRACER.format("ListTableMapping.processDelta for object {0} - original list size: {1}", id, //$NON-NLS-1$ + oldListSize); + } + + ListDeltaWriter writer = new ListDeltaWriter(accessor, id, listChanges, oldListSize); + writer.writeListDeltas(); + } + /** * Clear a list of a given revision. * @@ -220,7 +226,7 @@ public class NonAuditListTableMapping extends AbstractListTableMapping implement * @param id * the id of the revision from which to remove all items */ - public void clearList(IDBStoreAccessor accessor, CDOID id) + private void clearList(IDBStoreAccessor accessor, CDOID id) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlClear, ReuseProbability.HIGH); @@ -240,13 +246,7 @@ public class NonAuditListTableMapping extends AbstractListTableMapping implement } } - @Override - public void rawDeleted(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, int version) - { - clearList(accessor, id); - } - - public int getCurrentIndexOffset(IDBStoreAccessor accessor, CDOID id) + private int getCurrentIndexOffset(IDBStoreAccessor accessor, CDOID id) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlReadCurrentIndexOffset, ReuseProbability.HIGH); @@ -258,11 +258,11 @@ public class NonAuditListTableMapping extends AbstractListTableMapping implement rset = stmt.executeQuery(); if (!rset.next()) { - // list is empty. Return the default offset of 0. + // List is empty. Return the default offset of 0. return 0; } - // return the minimum index which is equal to the current offset. + // Return the minimum index which is equal to the current offset. return rset.getInt(1); } catch (SQLException e) @@ -272,991 +272,257 @@ public class NonAuditListTableMapping extends AbstractListTableMapping implement finally { DBUtil.close(rset); - close(stmt); - } - } - - public void processDelta(final IDBStoreAccessor accessor, final CDOID id, int branchId, int oldVersion, final int newVersion, long created, - CDOListFeatureDelta delta) - { - int oldListSize = delta.getOriginSize(); - - if (TRACER.isEnabled()) - { - TRACER.format("ListTableMapping.processDelta for object {0} - original list size: {1}", id, //$NON-NLS-1$ - oldListSize); - } - - // let the visitor collect the changes - ListDeltaVisitor visitor = new ListDeltaVisitor(oldListSize); - - if (TRACER.isEnabled()) - { - TRACER.trace("Processing deltas..."); //$NON-NLS-1$ - } - - for (CDOFeatureDelta listDelta : delta.getListChanges()) - { - listDelta.accept(visitor); - } - - visitor.postProcess(accessor, id); - - if (TRACER.isEnabled()) - { - TRACER.trace("Result to be written to DB:"); - for (ManipulationElement e : visitor.manipulations) - { - TRACER.trace(e.toString()); - } - } - - // finally, write results to the database - visitor.writeResultToDatabase(accessor, id); - - throw new NewListSizeResult(visitor.getNewListSize()); - } - - private void close(PreparedStatement... stmts) - { - Throwable t = null; - - for (PreparedStatement stmt : stmts) - { - try - { - if (stmt != null) - { - try - { - stmt.clearBatch(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - DBUtil.close(stmt); - } - } - } - catch (Throwable th) - { - if (t == null) - { - // Remember first exception - t = th; - } - - // More exceptions go to the log - OM.LOG.error(t); - } - } - - if (t != null) - { - throw new DBException(t); + DBUtil.close(stmt); } } /** * @author Eike Stepper */ - static final class NewListSizeResult extends RuntimeException + private final class ListDeltaWriter extends AbstractListDeltaWriter { - private static final long serialVersionUID = 1L; + private IDBPreparedStatement stmtDelete; - private final int newListSize; + private IDBPreparedStatement stmtMove; - public NewListSizeResult(int newListSize) - { - this.newListSize = newListSize; - } + private IDBPreparedStatement stmtSet; - public int getNewListSize() - { - return newListSize; - } - } + private IDBPreparedStatement stmtInsert; - /** - * @author Eike Stepper - */ - private final class ListDeltaVisitor implements CDOFeatureDeltaVisitor - { - private boolean clearFirst; + private IDBPreparedStatement stmtShiftDown; - private ArrayList<ManipulationElement> manipulations; + private IDBPreparedStatement stmtShiftUp; - /** - * Start of a range [tempIndex, tempIndex-1, ...] which lies outside of the normal list indexes and which serve as - * temporary space to move items temporarily to get them out of the way of other operations. - */ - private int tempIndex = -1; + private int countDelete; - private int newListSize; + private int countMove; - public ListDeltaVisitor(int oldListSize) - { - // Reset the clear-flag - clearFirst = false; - manipulations = new ArrayList<ManipulationElement>(oldListSize); + private int countSet; - // Create list and initialize with original indexes - for (int i = 0; i < oldListSize; i++) - { - manipulations.add(ManipulationElement.createOriginalElement(i)); - } + private int countInsert; - newListSize = oldListSize; - } + private int countShiftDown; - public int getNewListSize() - { - return newListSize; - } + private int countShiftUp; - public void visit(CDOAddFeatureDelta delta) + public ListDeltaWriter(IDBStoreAccessor accessor, CDOID id, List<CDOFeatureDelta> listChanges, int oldListSize) { - if (TRACER.isEnabled()) - { - TRACER.format(" - insert at {0} value {1}", delta.getIndex(), delta.getValue()); //$NON-NLS-1$ - } - - // Make room for the new item - shiftIndexes(delta.getIndex(), UNBOUNDED_SHIFT, +1); - - // Create the item - manipulations.add(ManipulationElement.createInsertedElement(delta.getIndex(), delta.getValue())); - ++newListSize; - } - - public void visit(CDORemoveFeatureDelta delta) - { - if (TRACER.isEnabled()) - { - TRACER.format(" - remove at {0}", delta.getIndex()); //$NON-NLS-1$ - } - - ManipulationElement e = findElement(delta.getIndex()); - deleteItem(e); - - // Fill the gap by shifting all subsequent items down - shiftIndexes(delta.getIndex() + 1, UNBOUNDED_SHIFT, -1); - --newListSize; - } - - public void visit(CDOSetFeatureDelta delta) - { - if (TRACER.isEnabled()) - { - TRACER.format(" - set at {0} value {1}", delta.getIndex(), delta.getValue()); //$NON-NLS-1$ - } - - ManipulationElement e = findElement(delta.getIndex()); - - // Set the new value - e.value = delta.getValue(); - - // If the item is freshly inserted we do not set the SET-mark. - // Setting the value of a new item results in inserting with the new value at once. - if (!e.is(ManipulationConstants.INSERT)) - { - // Else mark the existing item to be set to a new value - e.addType(ManipulationConstants.SET_VALUE); - } - } - - public void visit(CDOUnsetFeatureDelta delta) - { - if (delta.getFeature().isUnsettable()) - { - Assert.isTrue(false); - } - - if (TRACER.isEnabled()) - { - TRACER.format(" - unset list"); //$NON-NLS-1$ - } - - // Set the clear-flag - clearFirst = true; - - // And also clear all manipulation items - manipulations.clear(); - newListSize = 0; - } - - public void visit(CDOClearFeatureDelta delta) - { - if (TRACER.isEnabled()) - { - TRACER.format(" - clear list"); //$NON-NLS-1$ - } - - // Set the clear-flag - clearFirst = true; - - // And also clear all manipulation items - manipulations.clear(); - newListSize = 0; - } - - public void visit(CDOMoveFeatureDelta delta) - { - int fromIdx = delta.getOldPosition(); - int toIdx = delta.getNewPosition(); - - if (TRACER.isEnabled()) - { - TRACER.format(" - move {0} -> {1}", fromIdx, toIdx); //$NON-NLS-1$ - } - - // Ignore the trivial case - if (fromIdx == toIdx) - { - return; - } - - ManipulationElement e = findElement(fromIdx); - - // Adjust indexes and shift either up or down - if (fromIdx < toIdx) - { - shiftIndexes(fromIdx + 1, toIdx, -1); - } - else - { - // fromIdx > toIdx here - shiftIndexes(toIdx, fromIdx - 1, +1); - } - - // Set the new index - e.destinationIndex = toIdx; - - // If it is a new element, no MOVE mark needed, because we insert it at the new position - if (!e.is(ManipulationConstants.INSERT)) - { - // Else we need to handle the move of an existing item - e.addType(ManipulationConstants.MOVE); - } - } - - public void visit(CDOListFeatureDelta delta) - { - // Never called - Assert.isTrue(false); - } - - public void visit(CDOContainerFeatureDelta delta) - { - // Never called - Assert.isTrue(false); - } - - /** - * Helper method: shift all (destination) indexes in the interval [from,to] (inclusive at both ends) by offset - * (positive or negative). - */ - private void shiftIndexes(int from, int to, int offset) - { - for (ManipulationElement e : manipulations) - { - if (e.destinationIndex >= from && (to == UNBOUNDED_SHIFT || e.destinationIndex <= to)) - { - e.destinationIndex += offset; - } - } - } - - /** - * Find a manipulation item by destination index). - */ - private ManipulationElement findElement(int index) - { - for (ManipulationElement e : manipulations) - { - if (e.destinationIndex == index) - { - return e; - } - } - - // never reached - Assert.isTrue(false); - return null; - } - - /** - * Delete an element (used in remove and clear) - */ - private void deleteItem(ManipulationElement e) - { - if (e.is(ManipulationConstants.INSERT)) - { - // Newly inserted items are simply removed, as removing inserted items is equal to no change at all. - manipulations.remove(e); - } - else - { - // Mark the existing item as to be deleted. - // Previous MOVE and SET conditions are overridden by setting the exclusive DELETE type. - e.type = ManipulationConstants.DELETE; - e.destinationIndex = ManipulationConstants.NO_INDEX; - } - } - - /** - * Called after all deltas are applied an before the results are written to the database. This method post-processes - * the manipulation elements in order to minimize database access. - */ - public void postProcess(IDBStoreAccessor accessor, CDOID id) - { - if (!((HorizontalNonAuditMappingStrategy)getMappingStrategy()).shallForceZeroBasedIndex()) - { - /* - * This is an optimization which reduces the amount of modifications on the database to maintain list indexes. - * For the optimization, we let go of the assumption that indexes are zero-based. Instead, we work with an - * offset at the database level which can change with every change to the list (e.g. if the second element is - * removed from a list with 1000 elements, instead of shifting down indexes 2 to 1000 by 1, we shift up index 0 - * by 1 and have now a list with indexes starting at 1 instead of 0. This optimization is applied by modifying - * the list of ManipulationElements, which can be seen as the database modification plan. - */ - - // First, get the current offset - int offsetBefore = getCurrentIndexOffset(accessor, id); - if (TRACER.isEnabled()) - { - TRACER.trace("Offset optimization."); //$NON-NLS-1$ - TRACER.trace("Current offset = " + offsetBefore); //$NON-NLS-1$ - } - - applyOffsetToSourceIndexes(offsetBefore); - - int offsetAfter; - - if ((long)Math.abs(offsetBefore) + (long)manipulations.size() > Integer.MAX_VALUE) - { - // Security belt for really huge collections or for collections that have been manipulated lots of times - // -> Do not optimize after this border is crossed. Instead, reset offset for the whole list to a zero-based - // index. - offsetAfter = 0; - } - else - { - offsetAfter = calculateOptimalOffset(); - } - - if (TRACER.isEnabled()) - { - TRACER.trace("New offset = " + offsetAfter); //$NON-NLS-1$ - } - - applyOffsetToDestinationIndexes(offsetAfter); - - // Make sure temporary indexes do not get in the way of the other operations - tempIndex = Math.min(offsetBefore, offsetAfter) - 1; - } + super(accessor, id, listChanges, oldListSize); } - /** - * Calculate the optimal offset wrt the manipulations planned. The optimal offset is the offset which occurs the - * most in the manipulations (because letting this offset be neutral leads to the least manipulations. Note: the - * zero offset is also regarded as an offset as any other, because selecting an offset != 0 would also lead to - * elements with original offset 0 to be moved. - */ - private int calculateOptimalOffset() + @Override + protected ITypeMapping getTypeMapping() { - HashMap<Integer, Integer> occurrences = new HashMap<Integer, Integer>(); - int bestOffset = 0; - int bestOffsetOccurrence = 0; - - for (ManipulationElement element : manipulations) - { - int srcIdx = element.sourceIndex; - int destIdx = element.destinationIndex; - if (srcIdx != ManipulationConstants.NO_INDEX && destIdx != ManipulationConstants.NO_INDEX) - { - int offset = destIdx - srcIdx; - Integer oldOccurrence = occurrences.get(offset); - int newOccurrence; - if (oldOccurrence == null) - { - newOccurrence = 1; - } - else - { - newOccurrence = oldOccurrence + 1; - } - occurrences.put(offset, newOccurrence); - - // Remember maximum along the way - if (newOccurrence > bestOffsetOccurrence) - { - bestOffsetOccurrence = newOccurrence; - bestOffset = offset; - } - } - } - - // The offset which has occurred the most has to be applied negatively to normalize the list - // therefore return the negative offset as the new offset to be applied - return -bestOffset; + return NonAuditListTableMapping.this.getTypeMapping(); } - private void applyOffsetToSourceIndexes(int offsetBefore) + @Override + protected int getCurrentIndexOffset() { - if (offsetBefore != 0) - { - for (ManipulationElement element : manipulations) - { - if (element.sourceIndex != ManipulationConstants.NO_INDEX) - { - element.sourceIndex += offsetBefore; - } - } - } + return NonAuditListTableMapping.this.getCurrentIndexOffset(accessor, id); } - private void applyOffsetToDestinationIndexes(int offsetAfter) + @Override + protected void clearList() { - if (offsetAfter != 0) - { - for (ManipulationElement element : manipulations) - { - if (element.destinationIndex != ManipulationConstants.NO_INDEX) - { - // Apply the offset to all indices to make them relative to the new offset - element.destinationIndex += offsetAfter; - } - } - } + NonAuditListTableMapping.this.clearList(accessor, id); } - /** - * Write calculated changes to the database - */ - private void writeResultToDatabase(IDBStoreAccessor accessor, CDOID id) + @Override + protected void writeResultToDatabase() throws SQLException { - IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); - IDBPreparedStatement deleteStmt = null; - IDBPreparedStatement moveStmt = null; - IDBPreparedStatement setValueStmt = null; - IDBPreparedStatement insertStmt = null; - - int deleteCounter = 0; - int moveCounter = 0; - int setValueCounter = 0; - int insertCounter = 0; - - if (TRACER.isEnabled()) - { - TRACER.trace("Writing to database:"); //$NON-NLS-1$ - } - - if (clearFirst) - { - if (TRACER.isEnabled()) - { - TRACER.trace(" - clear list"); //$NON-NLS-1$ - } - - clearList(accessor, id); - } - try { - for (ManipulationElement element : manipulations) - { - if (element.is(ManipulationConstants.DELETE)) - { - /* - * Step 1: DELETE all elements e which have e.is(DELETE) by e.sourceIdx - */ - - if (deleteStmt == null) - { - deleteStmt = accessor.getDBConnection().prepareStatement(sqlDeleteItem, ReuseProbability.HIGH); - idHandler.setCDOID(deleteStmt, 1, id); - } - - deleteStmt.setInt(2, element.sourceIndex); - deleteStmt.addBatch(); - deleteCounter++; - - if (TRACER.isEnabled()) - { - TRACER.format(" - delete at {0} ", element.sourceIndex); //$NON-NLS-1$ - } - } - - if (element.is(ManipulationConstants.MOVE)) - { - /* - * Step 2: MOVE all elements e (by e.sourceIdx) which have e.is(MOVE) to temporary idx (-1, -2, -3, -4, ...) - * and store temporary idx in e.tempIndex - */ - if (moveStmt == null) - { - moveStmt = accessor.getDBConnection().prepareStatement(sqlUpdateIndex, ReuseProbability.HIGH); - idHandler.setCDOID(moveStmt, 2, id); - } - - moveStmt.setInt(3, element.sourceIndex); // from index - moveStmt.setInt(1, --tempIndex); // to index - element.tempIndex = tempIndex; - moveStmt.addBatch(); - moveCounter++; - - if (TRACER.isEnabled()) - { - TRACER.format(" - move {0} -> {1} ", element.sourceIndex, element.tempIndex); //$NON-NLS-1$ - } - } - } - - /* Now perform deletes and moves ... */ - if (deleteCounter > 0) - { - if (TRACER.isEnabled()) - { - TRACER.format("Performing {0} delete operations", deleteCounter); //$NON-NLS-1$ - } - - DBUtil.executeBatch(deleteStmt, deleteCounter); - } - - if (moveCounter > 0) - { - if (TRACER.isEnabled()) - { - TRACER.format("Performing {0} move operations", moveCounter); //$NON-NLS-1$ - } - - DBUtil.executeBatch(moveStmt, moveCounter); - moveStmt.clearBatch(); - moveCounter = 0; - } - - writeShiftOperations(accessor, id); + super.writeResultToDatabase(); - for (ManipulationElement element : manipulations) - { - if (element.is(ManipulationConstants.MOVE)) - { - /* - * Step 4: MOVE all elements e have e.is(MOVE) from e.tempIdx to e.destinationIdx (because we have moved - * them before, moveStmt is always initialized - */ - moveStmt.setInt(3, element.tempIndex); // from index - moveStmt.setInt(1, element.destinationIndex); // to index - moveStmt.addBatch(); - moveCounter++; - - if (TRACER.isEnabled()) - { - TRACER.format(" - move {0} -> {1} ", element.tempIndex, element.destinationIndex); //$NON-NLS-1$ - } - } - - if (element.is(ManipulationConstants.SET_VALUE)) - { - /* - * Step 5: SET all elements which have e.type == SET_VALUE by index == e.destinationIdx - */ - if (setValueStmt == null) - { - setValueStmt = accessor.getDBConnection().prepareStatement(sqlUpdateValue, ReuseProbability.HIGH); - idHandler.setCDOID(setValueStmt, 2, id); - } - - setValueStmt.setInt(3, element.destinationIndex); - getTypeMapping().setValue(setValueStmt, 1, element.value); - setValueStmt.addBatch(); - setValueCounter++; - - if (TRACER.isEnabled()) - { - TRACER.format(" - set value at {0} to {1} ", element.destinationIndex, element.value); //$NON-NLS-1$ - } - } - - if (element.is(ManipulationConstants.INSERT)) - { - /* - * Step 6: INSERT all elements which have e.type == INSERT. - */ - if (insertStmt == null) - { - insertStmt = accessor.getDBConnection().prepareStatement(sqlInsertValue, ReuseProbability.HIGH); - idHandler.setCDOID(insertStmt, 1, id); - } - - insertStmt.setInt(2, element.destinationIndex); - getTypeMapping().setValue(insertStmt, 3, element.value); - insertStmt.addBatch(); - insertCounter++; - - if (TRACER.isEnabled()) - { - TRACER.format(" - insert value at {0} : value {1} ", element.destinationIndex, element.value); //$NON-NLS-1$ - } - } - } - - if (moveCounter > 0) + if (countMove > 0) { if (TRACER.isEnabled()) { - TRACER.format("Performing {0} move operations", moveCounter); //$NON-NLS-1$ + TRACER.format("Performing {0} move operations", countMove); //$NON-NLS-1$ } - DBUtil.executeBatch(moveStmt, moveCounter); + DBUtil.executeBatch(stmtMove, countMove); } - if (insertCounter > 0) + if (countInsert > 0) { if (TRACER.isEnabled()) { - TRACER.format("Performing {0} insert operations", insertCounter); //$NON-NLS-1$ + TRACER.format("Performing {0} insert operations", countInsert); //$NON-NLS-1$ } - DBUtil.executeBatch(insertStmt, insertCounter); + DBUtil.executeBatch(stmtInsert, countInsert); } - if (setValueCounter > 0) + if (countSet > 0) { if (TRACER.isEnabled()) { - TRACER.format("Performing {0} set operations", setValueCounter); //$NON-NLS-1$ + TRACER.format("Performing {0} set operations", countSet); //$NON-NLS-1$ } - DBUtil.executeBatch(setValueStmt, setValueCounter); + DBUtil.executeBatch(stmtSet, countSet); } } - catch (SQLException e) - { - throw new DBException(e); - } finally { - close(deleteStmt, moveStmt, insertStmt, setValueStmt); + close(stmtDelete, stmtMove, stmtInsert, stmtSet); } } - /** - * Perform the shift operations to adjust indexes resulting from remove, insert, and move operations. - * - * @see #writeResultToDatabase(IDBStoreAccessor, CDOID) - * @throws SQLException - */ - private void writeShiftOperations(IDBStoreAccessor accessor, CDOID id) throws SQLException + @Override + protected void writeShifts(IIDHandler idHandler) throws SQLException { - /* - * Step 3: shift all elements which have to be shifted up or down because of add, remove or move of other elements - * to their proper position. This has to be done in two phases to avoid collisions, as the index has to be unique - * and shift up operations have to be executed in top to bottom order. - */ - IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); - LinkedList<ShiftOperation> shiftOperations = new LinkedList<ShiftOperation>(); - - /* - * If a necessary shift is detected (source and destination indices differ), firstIndex is set to the current - * index and currentOffset is set to the offset of the shift operation. When a new offset is detected or the range - * is interrupted, we record the range and start a new one if needed. - */ - int rangeStartIndex = ManipulationConstants.NO_INDEX; - int rangeOffset = 0; - int lastElementIndex = ManipulationConstants.NO_INDEX; - - // Iterate through the manipulationElements and collect the necessary operations - for (ManipulationElement element : manipulations) + if (countDelete > 0) { - /* - * Shift applies only to elements which are not moved, inserted or deleted (i.e. only plain SET_VALUE and NONE - * are affected) - */ - if (element.type == ManipulationConstants.NONE || element.type == ManipulationConstants.SET_VALUE) - { - int elementOffset = element.destinationIndex - element.sourceIndex; - - /* - * First make sure if we have to close a previous range. This is the case, if the current element's offset - * differs from the rangeOffset and a range is open. - */ - if (elementOffset != rangeOffset && rangeStartIndex != ManipulationConstants.NO_INDEX) - { - // There is an open range but the rangeOffset differs. We have to close the open range - shiftOperations.add(new ShiftOperation(rangeStartIndex, lastElementIndex, rangeOffset)); - - // And reset the state - rangeStartIndex = ManipulationConstants.NO_INDEX; - rangeOffset = 0; - } - - /* - * At this point, either a range is open, which means that the current element also fits in the range (i.e. - * the offsets match) or no range is open. In the latter case, we have to open one if the current element's - * offset is not 0. - */ - if (elementOffset != 0 && rangeStartIndex == ManipulationConstants.NO_INDEX) - { - rangeStartIndex = element.sourceIndex; - rangeOffset = elementOffset; - } - } - else + if (TRACER.isEnabled()) { - // Shift does not apply to this element because of its type - if (rangeStartIndex != ManipulationConstants.NO_INDEX) - { - // If there is an open range, we have to close and remember it - shiftOperations.add(new ShiftOperation(rangeStartIndex, lastElementIndex, rangeOffset)); - - // And reset the state - rangeStartIndex = ManipulationConstants.NO_INDEX; - rangeOffset = 0; - } + TRACER.format("Performing {0} delete operations", countDelete); //$NON-NLS-1$ } - lastElementIndex = element.sourceIndex; + DBUtil.executeBatch(stmtDelete, countDelete); } - // After the iteration, we have to make sure that we remember the last open range, if it is there - if (rangeStartIndex != ManipulationConstants.NO_INDEX) + if (countMove > 0) { - shiftOperations.add(new ShiftOperation(rangeStartIndex, lastElementIndex, rangeOffset)); - } + if (TRACER.isEnabled()) + { + TRACER.format("Performing {0} move operations", countMove); //$NON-NLS-1$ + } - /* - * Now process the operations. Move down operations can be performed directly, move up operations need to be - * performed later in the reverse direction - */ - ListIterator<ShiftOperation> operationIt = shiftOperations.listIterator(); + DBUtil.executeBatch(stmtMove, countMove); + countMove = 0; + } - IDBPreparedStatement shiftDownStmt = null; - int operationCounter = 0; + super.writeShifts(idHandler); + } + @Override + protected void writeShiftsDown(IIDHandler idHandler, ListIterator<Shift> operationIt) throws SQLException + { try { - while (operationIt.hasNext()) - { - ShiftOperation operation = operationIt.next(); - if (operation.offset < 0) - { - if (shiftDownStmt == null) - { - shiftDownStmt = accessor.getDBConnection().prepareStatement(sqlShiftDownIndex, ReuseProbability.HIGH); - idHandler.setCDOID(shiftDownStmt, 2, id); - } - - if (TRACER.isEnabled()) - { - TRACER.format(" - shift down {0} ", operation); //$NON-NLS-1$ - } - - shiftDownStmt.setInt(1, operation.offset); - shiftDownStmt.setInt(3, operation.startIndex); - shiftDownStmt.setInt(4, operation.endIndex); - shiftDownStmt.addBatch(); - operationCounter++; - - operationIt.remove(); - } - } + super.writeShiftsDown(idHandler, operationIt); - if (operationCounter > 0) + if (countShiftDown > 0) { - DBUtil.executeBatch(shiftDownStmt, operationCounter, false); + DBUtil.executeBatch(stmtShiftDown, countShiftDown, false); } } finally { - close(shiftDownStmt); + close(stmtShiftDown); } + } - IDBPreparedStatement shiftUpStmt = null; - operationCounter = 0; - + @Override + protected void writeShiftsUp(IIDHandler idHandler, ListIterator<Shift> operationIt) throws SQLException + { try { - while (operationIt.hasPrevious()) - { - ShiftOperation operation = operationIt.previous(); - if (shiftUpStmt == null) - { - shiftUpStmt = accessor.getDBConnection().prepareStatement(sqlShiftUpIndex, ReuseProbability.HIGH); - idHandler.setCDOID(shiftUpStmt, 2, id); - } - - if (TRACER.isEnabled()) - { - TRACER.format(" - shift up {0} ", operation); //$NON-NLS-1$ - } + super.writeShiftsUp(idHandler, operationIt); - shiftUpStmt.setInt(1, operation.offset); - shiftUpStmt.setInt(3, operation.startIndex); - shiftUpStmt.setInt(4, operation.endIndex); - shiftUpStmt.addBatch(); - operationCounter++; - } - - if (operationCounter > 0) + if (countShiftUp > 0) { - DBUtil.executeBatch(shiftUpStmt, operationCounter, false); + DBUtil.executeBatch(stmtShiftUp, countShiftUp, false); } } finally { - close(shiftUpStmt); + close(stmtShiftUp); } } - } - - /** - * @author Eike Stepper - */ - private static interface ManipulationConstants - { - public static final int NO_INDEX = Integer.MIN_VALUE; - - public static final Object NIL = new Object(); - - public static final int NONE = 0; - - public static final int SET_VALUE = 1 << 1; - - public static final int MOVE = 1 << 2; - - public static final int INSERT = 1 << 3; - - public static final int DELETE = 1 << 4; - } - - /** - * @author Eike Stepper - */ - private static final class ManipulationElement implements ManipulationConstants - { - public int type; - - public int sourceIndex; - - public int tempIndex; - - public int destinationIndex; - - public Object value; - - public ManipulationElement(int t, int srcIdx, int dstIdx, Object val) - { - sourceIndex = srcIdx; - tempIndex = NO_INDEX; - destinationIndex = dstIdx; - value = val; - type = t; - } - /** - * Create a ManipulationElement which represents an element which already is in the list. - */ - public static ManipulationElement createOriginalElement(int index) + @Override + protected void dbDelete(IIDHandler idHandler, int index) throws SQLException { - return new ManipulationElement(NONE, index, index, NIL); - } + if (stmtDelete == null) + { + stmtDelete = accessor.getDBConnection().prepareStatement(sqlDeleteItem, ReuseProbability.HIGH); + idHandler.setCDOID(stmtDelete, 1, id); + } - /** - * Create a ManipulationElement which represents an element which is inserted in the list. - */ - public static ManipulationElement createInsertedElement(int index, Object value) - { - return new ManipulationElement(ManipulationConstants.INSERT, NO_INDEX, index, value); + stmtDelete.setInt(2, index); + stmtDelete.addBatch(); + ++countDelete; } - public boolean is(int t) + @Override + protected void dbMove(IIDHandler idHandler, int fromIndex, int toIndex, int srcIndex) throws SQLException { - return (type & t) > 0; - } + if (stmtMove == null) + { + stmtMove = accessor.getDBConnection().prepareStatement(sqlUpdateIndex, ReuseProbability.HIGH); + idHandler.setCDOID(stmtMove, 2, id); + } - public void addType(int t) - { - type |= t; + stmtMove.setInt(3, fromIndex); + stmtMove.setInt(1, toIndex); + stmtMove.addBatch(); + ++countMove; } @Override - public String toString() + protected void dbSet(IIDHandler idHandler, ITypeMapping typeMapping, int index, Object value, int srcIndex) throws SQLException { - return MessageFormat.format("Manipulation[type={0}, sourceIndex={1}, tempIndex={2}, destinationIndex={3}, value={4}]", formatType(type), - formatIndex(sourceIndex), formatIndex(tempIndex), formatIndex(destinationIndex), formatValue(value)); - } - - private static String formatType(int type) - { - switch (type) + if (stmtSet == null) { - case NONE: - return "none"; - - case DELETE: - return "DELETE"; - - case INSERT: - return "INSERT"; - - case MOVE: - return "MOVE"; - - case SET_VALUE: - return "SET_VALUE"; + stmtSet = accessor.getDBConnection().prepareStatement(sqlUpdateValue, ReuseProbability.HIGH); + idHandler.setCDOID(stmtSet, 2, id); } - return "<invalid>"; + stmtSet.setInt(3, index); + typeMapping.setValue(stmtSet, 1, value); + stmtSet.addBatch(); + ++countSet; } - private static String formatIndex(int index) + @Override + protected void dbInsert(IIDHandler idHandler, ITypeMapping typeMapping, int index, Object value) throws SQLException { - if (index == NO_INDEX) + if (stmtInsert == null) { - return "NONE"; + stmtInsert = accessor.getDBConnection().prepareStatement(sqlInsertValue, ReuseProbability.HIGH); + idHandler.setCDOID(stmtInsert, 1, id); } - return Integer.toString(index); + stmtInsert.setInt(2, index); + typeMapping.setValue(stmtInsert, 3, value); + stmtInsert.addBatch(); + ++countInsert; } - private static String formatValue(Object val) + @Override + protected void dbShiftDown(IIDHandler idHandler, int offset, int startIndex, int endIndex) throws SQLException { - if (val == NIL) + if (stmtShiftDown == null) { - return "NIL"; + stmtShiftDown = accessor.getDBConnection().prepareStatement(sqlShiftDownIndex, ReuseProbability.HIGH); + idHandler.setCDOID(stmtShiftDown, 2, id); } - return String.valueOf(val); - } - } - - /** - * @author Eike Stepper - */ - private static class ShiftOperation - { - final int startIndex; - - final int endIndex; - - final int offset; - - ShiftOperation(int startIndex, int endIndex, int offset) - { - this.startIndex = startIndex; - this.endIndex = endIndex; - this.offset = offset; + stmtShiftDown.setInt(1, offset); + stmtShiftDown.setInt(3, startIndex); + stmtShiftDown.setInt(4, endIndex); + stmtShiftDown.addBatch(); + ++countShiftDown; } @Override - public String toString() + protected void dbShiftUp(IIDHandler idHandler, int offset, int startIndex, int endIndex) throws SQLException { - return "range [" + startIndex + ".." + endIndex + "] offset " + offset; + if (stmtShiftUp == null) + { + stmtShiftUp = accessor.getDBConnection().prepareStatement(sqlShiftUpIndex, ReuseProbability.HIGH); + idHandler.setCDOID(stmtShiftUp, 2, id); + } + + stmtShiftUp.setInt(1, offset); + stmtShiftUp.setInt(3, startIndex); + stmtShiftUp.setInt(4, endIndex); + stmtShiftUp.addBatch(); + ++countShiftUp; } } } diff --git a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java index ab8a2bfcbd..3089107c43 100644 --- a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java +++ b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java @@ -217,6 +217,16 @@ public class HibernateRawCommitContext implements InternalCommitContext return new CDOBranchVersion[0]; } + public Map<CDOID, InternalCDORevision> getOldRevisions() + { + return null; + } + + public Map<CDOID, InternalCDORevision> getNewRevisions() + { + return null; + } + public ExtendedDataInputStream getLobs() { return null; @@ -292,6 +302,11 @@ public class HibernateRawCommitContext implements InternalCommitContext return new InternalCDORevision[0]; } + public InternalCDORevision[] getDetachedRevisions(boolean check) + { + return getDetachedRevisions(); + } + public void setClearResourcePathCache(boolean clearResourcePathCache) { } diff --git a/plugins/org.eclipse.emf.cdo.server.mongodb/src/org/eclipse/emf/cdo/server/internal/mongodb/MongoDBStore.java b/plugins/org.eclipse.emf.cdo.server.mongodb/src/org/eclipse/emf/cdo/server/internal/mongodb/MongoDBStore.java index dab5a722f3..eb8e6f3176 100644 --- a/plugins/org.eclipse.emf.cdo.server.mongodb/src/org/eclipse/emf/cdo/server/internal/mongodb/MongoDBStore.java +++ b/plugins/org.eclipse.emf.cdo.server.mongodb/src/org/eclipse/emf/cdo/server/internal/mongodb/MongoDBStore.java @@ -21,7 +21,6 @@ import org.eclipse.emf.cdo.server.internal.mongodb.bundle.OM; import org.eclipse.emf.cdo.server.mongodb.IMongoDBStore; import org.eclipse.emf.cdo.server.mongodb.IMongoDBStoreAccessor; import org.eclipse.emf.cdo.spi.server.InternalRepository; -import org.eclipse.emf.cdo.spi.server.InternalStore.NoExternalReferences; import org.eclipse.emf.cdo.spi.server.InternalStore.NoFeatureMaps; import org.eclipse.emf.cdo.spi.server.InternalStore.NoHandleRevisions; import org.eclipse.emf.cdo.spi.server.InternalStore.NoLargeObjects; @@ -66,7 +65,7 @@ import java.util.Set; * @author Eike Stepper */ public class MongoDBStore extends Store implements IMongoDBStore, // - NoExternalReferences, NoQueryXRefs, NoLargeObjects, NoFeatureMaps, NoHandleRevisions, NoRawAccess + NoQueryXRefs, NoLargeObjects, NoFeatureMaps, NoHandleRevisions, NoRawAccess { public static final String TYPE = "mongodb"; //$NON-NLS-1$ 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 e2f88189ed..35cd1dab7f 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 @@ -2112,7 +2112,7 @@ public class Repository extends Container<Object> implements InternalRepository, initSystemPackages(true); } - public void initSystemPackages(boolean firstStart) + public void initSystemPackages(final boolean firstStart) { IStoreAccessor writer = store.getWriter(null); StoreThreadLocal.setAccessor(writer); @@ -2149,6 +2149,19 @@ public class Repository extends Container<Object> implements InternalRepository, { StoreThreadLocal.release(); } + + fireEvent(new PackagesInitializedEvent() + { + public InternalRepository getSource() + { + return Repository.this; + } + + public boolean isFirstStart() + { + return firstStart; + } + }); } protected InternalCDOPackageUnit initPackage(EPackage ePackage) @@ -2420,6 +2433,7 @@ public class Repository extends Container<Object> implements InternalRepository, { readPackageUnits(); initSystemPackages(false); + readRootResource(); } } 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 327737b0e2..50b6110799 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 @@ -165,6 +165,10 @@ public class TransactionCommitContext implements InternalCommitContext private Map<CDOID, InternalCDORevision> cachedRevisions; + private Map<CDOID, InternalCDORevision> oldRevisions = CDOIDUtil.createMap(); + + private Map<CDOID, InternalCDORevision> newRevisions; + private Set<Object> lockedObjects = new HashSet<Object>(); private List<CDOID> lockedTargets; @@ -325,12 +329,20 @@ public class TransactionCommitContext implements InternalCommitContext public InternalCDORevision[] getDetachedRevisions() { - // This array can contain null values as they only come from the cache! - for (InternalCDORevision cachedDetachedRevision : cachedDetachedRevisions) + return getDetachedRevisions(true); + } + + public InternalCDORevision[] getDetachedRevisions(boolean check) + { + if (check) { - if (cachedDetachedRevision == null) + // This array can contain null values as they only come from the cache! + for (InternalCDORevision cachedDetachedRevision : cachedDetachedRevisions) { - throw new AssertionError("Detached revisions are incomplete"); + if (cachedDetachedRevision == null) + { + throw new AssertionError("Detached revisions are incomplete"); + } } } @@ -342,6 +354,27 @@ public class TransactionCommitContext implements InternalCommitContext return dirtyObjectDeltas; } + public Map<CDOID, InternalCDORevision> getOldRevisions() + { + return oldRevisions; + } + + public Map<CDOID, InternalCDORevision> getNewRevisions() + { + if (newRevisions == null) + { + newRevisions = CDOIDUtil.createMap(); + + for (int i = 0; i < newObjects.length; i++) + { + InternalCDORevision revision = newObjects[i]; + newRevisions.put(revision.getID(), revision); + } + } + + return newRevisions; + } + public InternalCDORevision getRevision(CDOID id) { if (cachedRevisions == null) @@ -1204,6 +1237,8 @@ public class TransactionCommitContext implements InternalCommitContext // Make sure all chunks are loaded repository.ensureChunks(oldRevision, CDORevision.UNCHUNKED); + oldRevisions.put(id, oldRevision); + InternalCDORevision newRevision = oldRevision.copy(); newRevision.adjustForCommit(branch, timeStamp); diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java index f8d408a2e0..b21141d0e6 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java @@ -385,6 +385,16 @@ public interface IStoreAccessor extends IQueryHandlerProvider, BranchLoader, Com public CDOBranchVersion[] getDetachedObjectVersions(); /** + * @since 4.6 + */ + public Map<CDOID, InternalCDORevision> getOldRevisions(); + + /** + * @since 4.6 + */ + public Map<CDOID, InternalCDORevision> getNewRevisions(); + + /** * Returns a stream that all {@link CDOLob lobs} can be read from. The format of the data delivered through the * stream is: * <p> diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java index f9238d24a2..dbb9078daa 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java @@ -103,6 +103,11 @@ public interface InternalCommitContext extends IStoreAccessor.CommitContext, CDO public InternalCDORevision[] getDetachedRevisions(); /** + * @since 4.6 + */ + public InternalCDORevision[] getDetachedRevisions(boolean check); + + /** * @since 4.2 */ public void setClearResourcePathCache(boolean clearResourcePathCache); 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 3c389f839d..406201d695 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 @@ -43,6 +43,7 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager.Revisi import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.container.IManagedContainer; +import org.eclipse.net4j.util.event.IEvent; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.emf.ecore.EClass; @@ -321,4 +322,15 @@ public interface InternalRepository extends IRepository, PackageProcessor, Packa * @since 4.3 */ public void setOptimisticLockingTimeout(long optimisticLockingTimeout); + + /** + * @author Eike Stepper + * @since 4.6 + */ + public interface PackagesInitializedEvent extends IEvent + { + public InternalRepository getSource(); + + public boolean isFirstStart(); + } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalStore.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalStore.java index 0391fa05f2..89e0611fe6 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalStore.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalStore.java @@ -70,7 +70,9 @@ public interface InternalStore extends IStore, ILifecycle * * @author Eike Stepper * @since 4.0 + * @deprecated As of 4.6 use IRepositoryConfig.CAPABILITY_EXTERNAL_REFS. */ + @Deprecated public interface NoExternalReferences { } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java index 02f519b839..eff729a0b2 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java @@ -73,11 +73,13 @@ public abstract class StoreAccessor extends StoreAccessorBase CDOID[] detachedObjects = context.getDetachedObjects(); InternalCDORevisionDelta[] dirtyObjectDeltas = context.getDirtyObjectDeltas(); InternalCDORevision[] dirtyObjects = context.getDirtyObjects(); + int dirtyCount = deltas ? dirtyObjectDeltas.length : dirtyObjects.length; + int postProcessCount = needsRevisionPostProcessing() ? newObjects.length + detachedObjects.length + dirtyCount : 0; try { - monitor.begin(1 + newPackageUnits.length + 2 + newObjects.length + detachedObjects.length + dirtyCount + 1); + monitor.begin(1 + newPackageUnits.length + 2 + newObjects.length + detachedObjects.length + dirtyCount + postProcessCount + 1); writeCommitInfo(branch, timeStamp, previousTimeStamp, userID, commitComment, mergeSource, monitor.fork()); writePackageUnits(newPackageUnits, monitor.fork(newPackageUnits.length)); @@ -112,6 +114,11 @@ public abstract class StoreAccessor extends StoreAccessorBase } } + if (needsRevisionPostProcessing()) + { + postProcessRevisions(context, monitor.fork(postProcessCount)); + } + ExtendedDataInputStream in = context.getLobs(); if (in != null) { @@ -154,6 +161,15 @@ public abstract class StoreAccessor extends StoreAccessorBase } } + protected boolean needsRevisionPostProcessing() + { + return false; + } + + protected void postProcessRevisions(InternalCommitContext context, OMMonitor monitor) + { + } + /** * @since 3.0 */ diff --git a/plugins/org.eclipse.emf.cdo.tests.all/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests.all/META-INF/MANIFEST.MF index afff98aa00..9d43c7cedd 100644 --- a/plugins/org.eclipse.emf.cdo.tests.all/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests.all/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.tests.all;singleton:=true -Bundle-Version: 4.1.300.qualifier +Bundle-Version: 4.1.400.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -12,5 +12,5 @@ Bundle-ClassPath: . Require-Bundle: org.eclipse.net4j.tests;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, org.eclipse.emf.cdo.tests;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, org.eclipse.emf.cdo.tests.db;bundle-version="[4.0.0,5.0.0)";visibility:=reexport -Export-Package: org.eclipse.emf.cdo.tests.all;version="4.1.300";x-internal:=true, - org.eclipse.emf.cdo.tests.all.bundle;version="4.1.300";x-internal:=true +Export-Package: org.eclipse.emf.cdo.tests.all;version="4.1.400";x-internal:=true, + org.eclipse.emf.cdo.tests.all.bundle;version="4.1.400";x-internal:=true diff --git a/plugins/org.eclipse.emf.cdo.tests.all/src/org/eclipse/emf/cdo/tests/all/GerritTests.java b/plugins/org.eclipse.emf.cdo.tests.all/src/org/eclipse/emf/cdo/tests/all/GerritTests.java index b44cf7b985..139c8f9cbd 100644 --- a/plugins/org.eclipse.emf.cdo.tests.all/src/org/eclipse/emf/cdo/tests/all/GerritTests.java +++ b/plugins/org.eclipse.emf.cdo.tests.all/src/org/eclipse/emf/cdo/tests/all/GerritTests.java @@ -31,7 +31,7 @@ public class GerritTests extends DBConfigs @Override protected void initConfigSuites(TestSuite parent) { - addScenario(parent, new H2Config(false, false, true, false, IDGenerationLocation.STORE), JVM, NATIVE); - addScenario(parent, new H2Config(true, true, true, false, IDGenerationLocation.STORE), JVM, NATIVE); + addScenario(parent, new H2Config(false, false, true, false, false, IDGenerationLocation.STORE), JVM, NATIVE); + addScenario(parent, new H2Config(true, true, true, false, false, IDGenerationLocation.STORE), JVM, NATIVE); } } diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AbstractSetupDBConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AbstractSetupDBConfig.java index 7948b5cd89..18192d8c60 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AbstractSetupDBConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AbstractSetupDBConfig.java @@ -31,9 +31,9 @@ public abstract class AbstractSetupDBConfig extends DBConfig private transient DataSource setupDataSource; public AbstractSetupDBConfig(String name, boolean supportingAudits, boolean supportingBranches, boolean withRanges, boolean copyOnBranch, - IDGenerationLocation idGenerationLocation) + boolean inverseLists, IDGenerationLocation idGenerationLocation) { - super(name, supportingAudits, supportingBranches, withRanges, copyOnBranch, idGenerationLocation); + super(name, supportingAudits, supportingBranches, withRanges, copyOnBranch, inverseLists, idGenerationLocation); } protected String getDBName(String repoName) diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Audit.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Audit.java index ce92cf494b..d0105fdb7f 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Audit.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Audit.java @@ -30,10 +30,10 @@ public class AllTestsDBH2Audit extends DBConfigs public static void initConfigSuites(ConfigTestSuite suite, TestSuite parent, IDGenerationLocation idGenerationLocation) { // Without ranges - suite.addScenario(parent, new H2Config(true, false, false, false, idGenerationLocation), JVM, NATIVE); + suite.addScenario(parent, new H2Config(true, false, false, false, false, idGenerationLocation), JVM, NATIVE); // With ranges - suite.addScenario(parent, new H2Config(true, false, true, false, idGenerationLocation), JVM, NATIVE); + suite.addScenario(parent, new H2Config(true, false, true, false, false, idGenerationLocation), JVM, NATIVE); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Branching.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Branching.java index 8b27926dc4..26e658e3e7 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Branching.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2Branching.java @@ -29,10 +29,10 @@ public class AllTestsDBH2Branching extends DBConfigs public static void initConfigSuites(ConfigTestSuite suite, TestSuite parent, IDGenerationLocation idGenerationLocation) { // Without ranges - suite.addScenario(parent, new H2Config(true, true, false, false, idGenerationLocation), JVM, NATIVE); + suite.addScenario(parent, new H2Config(true, true, false, false, false, idGenerationLocation), JVM, NATIVE); // With ranges - suite.addScenario(parent, new H2Config(true, true, true, false, idGenerationLocation), JVM, NATIVE); + suite.addScenario(parent, new H2Config(true, true, true, false, false, idGenerationLocation), JVM, NATIVE); // With ranges and copy-on-branch // suite.addScenario(parent, new H2Config(true, true, true, true, idGenerationLocation), JVM, NATIVE); diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2BranchingUUIDs.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2BranchingUUIDs.java index 2c46aa7c37..a587a52153 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2BranchingUUIDs.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2BranchingUUIDs.java @@ -28,6 +28,6 @@ public class AllTestsDBH2BranchingUUIDs extends DBConfigs @Override protected void initConfigSuites(TestSuite parent) { - addScenario(parent, new H2Config(true, true, false, false, IDGenerationLocation.CLIENT), JVM, NATIVE); + addScenario(parent, new H2Config(true, true, false, false, false, IDGenerationLocation.CLIENT), JVM, NATIVE); } } diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2NonAudit.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2NonAudit.java index d188a04b3a..f1a0f668a2 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2NonAudit.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBH2NonAudit.java @@ -28,7 +28,7 @@ public class AllTestsDBH2NonAudit extends DBConfigs public static void initConfigSuites(ConfigTestSuite suite, TestSuite parent, IDGenerationLocation idGenerationLocation) { - suite.addScenario(parent, new H2Config(false, false, false, false, idGenerationLocation), JVM, NATIVE); + suite.addScenario(parent, new H2Config(false, false, false, false, false, idGenerationLocation), JVM, NATIVE); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBMysql.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBMysql.java index ec4500aa7a..6d1386cfd6 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBMysql.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AllTestsDBMysql.java @@ -36,7 +36,7 @@ public class AllTestsDBMysql extends DBConfigs @Override protected void initConfigSuites(TestSuite parent) { - addScenario(parent, new MysqlConfig(false, false, IDGenerationLocation.STORE), JVM, NATIVE); + addScenario(parent, new MysqlConfig(false, false, false, IDGenerationLocation.STORE), JVM, NATIVE); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AnyTestManyTimesDB.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AnyTestManyTimesDB.java index 0406ec07c9..5b017c0079 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AnyTestManyTimesDB.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/AnyTestManyTimesDB.java @@ -36,9 +36,11 @@ public class AnyTestManyTimesDB extends TestSuite implements IConstants private static final boolean COPY_ON_BRANCH = false; + private static final boolean INVERSE_LISTS = false; + private static final IDGenerationLocation ID_GENERATION_LOCATION = IDGenerationLocation.STORE; - private static final RepositoryConfig REPOSITORY_CONFIG = new H2Config(SUPPORTING_AUDITS, SUPPORTING_BRANCHES, WITH_RANGES, COPY_ON_BRANCH, + private static final RepositoryConfig REPOSITORY_CONFIG = new H2Config(SUPPORTING_AUDITS, SUPPORTING_BRANCHES, WITH_RANGES, COPY_ON_BRANCH, INVERSE_LISTS, ID_GENERATION_LOCATION); private static final SessionConfig SESSION_CONFIG = JVM; diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_351068_Test.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_351068_Test.java index e9455bfa7d..46353cc411 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_351068_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/Bugzilla_351068_Test.java @@ -40,7 +40,7 @@ import java.sql.Statement; * * @author Eike Stepper */ -@Skips(IRepositoryConfig.CAPABILITY_AUDITING) +@Skips({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.inverse.lists" }) public class Bugzilla_351068_Test extends AbstractCDOTest { @CleanRepositoriesBefore(reason = "Row counting") 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 cf4b5696d6..8a34e65832 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 @@ -39,6 +39,8 @@ public abstract class DBConfig extends RepositoryConfig public static final String CAPABILITY_COPY_ON_BRANCH = "DB.copy.on.branch"; + public static final String CAPABILITY_INVERSE_LISTS = "DB.inverse.lists"; + public static final String PROP_TEST_MAPPING_STRATEGY = "test.repository.MappingStrategy"; private static final long serialVersionUID = 1L; @@ -47,14 +49,17 @@ public abstract class DBConfig extends RepositoryConfig private boolean copyOnBranch; + private boolean inverseLists; + private transient IDBAdapter dbAdapter; - public DBConfig(String name, boolean supportingAudits, boolean supportingBranches, boolean withRanges, boolean copyOnBranch, + public DBConfig(String name, boolean supportingAudits, boolean supportingBranches, boolean withRanges, boolean copyOnBranch, boolean inverseLists, IDGenerationLocation idGenerationLocation) { super(name, supportingAudits, supportingBranches, idGenerationLocation); this.withRanges = withRanges; this.copyOnBranch = copyOnBranch; + this.inverseLists = inverseLists; } @Override @@ -73,6 +78,11 @@ public abstract class DBConfig extends RepositoryConfig { capabilities.add(CAPABILITY_COPY_ON_BRANCH); } + + if (isInverseLists()) + { + capabilities.add(CAPABILITY_INVERSE_LISTS); + } } protected IDBAdapter getDBAdapter() @@ -103,6 +113,11 @@ public abstract class DBConfig extends RepositoryConfig return copyOnBranch; } + public boolean isInverseLists() + { + return inverseLists; + } + @Override public void setUp() throws Exception { @@ -161,7 +176,7 @@ public abstract class DBConfig extends RepositoryConfig @Override protected String getMappingStrategySpecialization() { - return (withRanges ? "-ranges" : "") + (copyOnBranch ? "-copy" : ""); + return (withRanges ? "-ranges" : "") + (copyOnBranch ? "-copy" : "") + (inverseLists ? "-inverse" : ""); } protected abstract IDBAdapter createDBAdapter(); diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DerbyConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DerbyConfig.java index 3d3839c952..a9e591d4bc 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DerbyConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/DerbyConfig.java @@ -43,7 +43,7 @@ public class DerbyConfig extends DBConfig public DerbyConfig(boolean supportingAudits, boolean supportingBranches, IDGenerationLocation idGenerationLocation) { - super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, idGenerationLocation); + super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, false, idGenerationLocation); } @Override 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 d2f28227fb..027808fcd7 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 @@ -36,9 +36,10 @@ public class H2Config extends DBConfig private static JdbcDataSource defaultDataSource; - public H2Config(boolean supportingAudits, boolean supportingBranches, boolean withRanges, boolean copyOnBranch, IDGenerationLocation idGenerationLocation) + public H2Config(boolean supportingAudits, boolean supportingBranches, boolean withRanges, boolean copyOnBranch, boolean inverseLists, + IDGenerationLocation idGenerationLocation) { - super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, withRanges, copyOnBranch, idGenerationLocation); + super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, withRanges, copyOnBranch, inverseLists, idGenerationLocation); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/HsqldbConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/HsqldbConfig.java index 88d050547c..42951cdbe9 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/HsqldbConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/HsqldbConfig.java @@ -47,7 +47,7 @@ public class HsqldbConfig extends DBConfig public HsqldbConfig(boolean supportingAudits, boolean supportingBranches, IDGenerationLocation idGenerationLocation) { - super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, idGenerationLocation); + super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, false, idGenerationLocation); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java index 5e3c33fc85..72e7252120 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java @@ -35,7 +35,7 @@ public class MysqlConfig extends AbstractSetupDBConfig */ public static final String HOST = "localhost"; - public static final String SCHEMA = "test"; + public static final String SCHEMA = "big"; public static final String USER = "test"; @@ -43,9 +43,9 @@ public class MysqlConfig extends AbstractSetupDBConfig private static final long serialVersionUID = 1L; - public MysqlConfig(boolean supportingAudits, boolean supportingBranches, IDGenerationLocation idGenerationLocation) + public MysqlConfig(boolean supportingAudits, boolean supportingBranches, boolean inverseLists, IDGenerationLocation idGenerationLocation) { - super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, idGenerationLocation); + super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, inverseLists, idGenerationLocation); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/OracleConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/OracleConfig.java index 3e0afc8529..03240bb814 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/OracleConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/OracleConfig.java @@ -51,7 +51,7 @@ public abstract class OracleConfig extends AbstractSetupDBConfig public OracleConfig(boolean supportingAudits, boolean supportingBranches, IDGenerationLocation idGenerationLocation) { - super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, idGenerationLocation); + super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, false, idGenerationLocation); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java index 52ce550bfd..541be6617a 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/PostgresqlConfig.java @@ -40,7 +40,7 @@ public class PostgresqlConfig extends AbstractSetupDBConfig public PostgresqlConfig(boolean supportingAudits, boolean supportingBranches, IDGenerationLocation idGenerationLocation) { - super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, idGenerationLocation); + super(DB_ADAPTER_NAME, supportingAudits, supportingBranches, false, false, false, idGenerationLocation); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/performance/AllPerformanceTestsH2NonAudit.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/performance/AllPerformanceTestsH2NonAudit.java index 46714c0fe3..24335f3645 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/performance/AllPerformanceTestsH2NonAudit.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/performance/AllPerformanceTestsH2NonAudit.java @@ -30,6 +30,6 @@ public class AllPerformanceTestsH2NonAudit extends AllPerformanceTests @Override protected void initConfigSuites(TestSuite parent) { - addScenario(parent, new H2Config(false, false, false, false, IDGenerationLocation.STORE), JVM, NATIVE); + addScenario(parent, new H2Config(false, false, false, false, false, IDGenerationLocation.STORE), JVM, NATIVE); } } diff --git a/plugins/org.eclipse.emf.cdo.tests.hibernate/src/org/eclipse/emf/cdo/tests/hibernate/AllTestsHibernate.java b/plugins/org.eclipse.emf.cdo.tests.hibernate/src/org/eclipse/emf/cdo/tests/hibernate/AllTestsHibernate.java index d7468e54cb..12f74d9789 100644 --- a/plugins/org.eclipse.emf.cdo.tests.hibernate/src/org/eclipse/emf/cdo/tests/hibernate/AllTestsHibernate.java +++ b/plugins/org.eclipse.emf.cdo.tests.hibernate/src/org/eclipse/emf/cdo/tests/hibernate/AllTestsHibernate.java @@ -19,7 +19,6 @@ import org.eclipse.emf.cdo.tests.CrossReferenceTest; import org.eclipse.emf.cdo.tests.DynamicXSDTest; import org.eclipse.emf.cdo.tests.EMFCompareTest; import org.eclipse.emf.cdo.tests.ExternalReferenceTest; -import org.eclipse.emf.cdo.tests.FeatureMapTest; import org.eclipse.emf.cdo.tests.LockingManagerRestartRepositoryTest; import org.eclipse.emf.cdo.tests.LockingManagerRestartSessionTest; import org.eclipse.emf.cdo.tests.LockingManagerRestartTransactionTest; @@ -187,7 +186,7 @@ public class AllTestsHibernate extends AllConfigs testClasses.add(Hibernate_Bugzilla_303466_Test.class); // feature maps are not handled correctly in CDO with auditing - testClasses.remove(FeatureMapTest.class); + // testClasses.remove(FeatureMapTest.class); } else { diff --git a/plugins/org.eclipse.emf.cdo.tests.lissome/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests.lissome/META-INF/MANIFEST.MF index 4d35ec6bdc..08547277db 100644 --- a/plugins/org.eclipse.emf.cdo.tests.lissome/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests.lissome/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.tests.lissome;singleton:=true -Bundle-Version: 4.2.100.qualifier +Bundle-Version: 4.2.200.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -12,6 +12,6 @@ Bundle-ClassPath: . Require-Bundle: org.eclipse.emf.cdo.tests;bundle-version="[4.0.0,5.0.0)", org.eclipse.emf.cdo.server.lissome;bundle-version="[4.2.0,5.0.0)", org.eclipse.net4j.db.h2;bundle-version="[4.0.0,5.0.0)" -Export-Package: org.eclipse.emf.cdo.tests.lissome;version="4.2.100", - org.eclipse.emf.cdo.tests.lissome.bundle;version="4.2.100";x-internal:=true +Export-Package: org.eclipse.emf.cdo.tests.lissome;version="4.2.200", + org.eclipse.emf.cdo.tests.lissome.bundle;version="4.2.200";x-internal:=true Import-Package: org.h2.jdbcx;version="[1.0.0,2.0.0)" diff --git a/plugins/org.eclipse.emf.cdo.tests.lissome/src/org/eclipse/emf/cdo/tests/lissome/LissomeConfig.java b/plugins/org.eclipse.emf.cdo.tests.lissome/src/org/eclipse/emf/cdo/tests/lissome/LissomeConfig.java index e11d78e62c..8678857c2a 100644 --- a/plugins/org.eclipse.emf.cdo.tests.lissome/src/org/eclipse/emf/cdo/tests/lissome/LissomeConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.lissome/src/org/eclipse/emf/cdo/tests/lissome/LissomeConfig.java @@ -63,6 +63,12 @@ public class LissomeConfig extends RepositoryConfig return true; } + @Override + public boolean isSupportingExtRefs() + { + return false; + } + public IStore createStore(String repoName) { if (reusableFolder == null) diff --git a/plugins/org.eclipse.emf.cdo.tests.mongodb/src/org/eclipse/emf/cdo/tests/mongodb/MongoDBConfig.java b/plugins/org.eclipse.emf.cdo.tests.mongodb/src/org/eclipse/emf/cdo/tests/mongodb/MongoDBConfig.java index fafacdfa0e..932cfc0033 100644 --- a/plugins/org.eclipse.emf.cdo.tests.mongodb/src/org/eclipse/emf/cdo/tests/mongodb/MongoDBConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests.mongodb/src/org/eclipse/emf/cdo/tests/mongodb/MongoDBConfig.java @@ -85,4 +85,10 @@ public class MongoDBConfig extends RepositoryConfig } } } + + @Override + public boolean isSupportingExtRefs() + { + return false; + } } 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 23738fe630..2cfe30a034 100644 --- a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF @@ -37,7 +37,8 @@ Require-Bundle: org.eclipse.net4j.tests;bundle-version="[4.0.0,5.0.0)";visibilit 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)", org.apache.log4j;bundle-version="[1.2.0,2.0.0)", - com.google.guava;bundle-version="[10.0.0,20.0.0)" + com.google.guava;bundle-version="[10.0.0,20.0.0)", + org.eclipse.emf.cdo.server.db;bundle-version="[4.0.0,5.0.0)" Export-Package: base;version="4.0.200", base.impl;version="4.0.200", base.util;version="4.0.200", diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java index bdcb9fdcb5..cae164936a 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java @@ -99,7 +99,7 @@ public class AllConfigs extends ConfigTestSuite testClasses.add(LockingSequenceTest.class); testClasses.add(MultiValuedOfAttributeTest.class); testClasses.add(MapTest.class); - testClasses.add(FeatureMapTest.class); + // testClasses.add(FeatureMapTest.class); testClasses.add(AdapterManagerTest.class); testClasses.add(ConflictResolverTest.class); testClasses.add(ConflictResolverExtendedTest.class); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOIDTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOIDTest.java index 02bc88869a..bdb0bfba18 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOIDTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOIDTest.java @@ -57,12 +57,14 @@ public class CDOIDTest extends AbstractCDOTest assertIllegalArgument(id); } + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testGetLong_ExtTempId() { CDOIDTempObjectExternalImpl id = CDOIDTempObjectExternalImpl.create("cdo://repo123/resource456"); assertIllegalArgument(id); } + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testGetLong_ExtId() { CDOIDExternal id = CDOIDUtil.createExternal("cdo://repo123/resource456"); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingClearCachedRevisionTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingClearCachedRevisionTest.java index e04ecd7d89..04265d01fa 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingClearCachedRevisionTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingClearCachedRevisionTest.java @@ -15,6 +15,7 @@ import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.model1.Customer; import org.eclipse.emf.cdo.tests.model1.SalesOrder; import org.eclipse.emf.cdo.transaction.CDOTransaction; @@ -31,6 +32,7 @@ import java.util.Iterator; */ public class ChunkingClearCachedRevisionTest extends AbstractCDOTest { + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testReadNative() throws Exception { CDORevision revisionToRemove = null; @@ -78,6 +80,7 @@ public class ChunkingClearCachedRevisionTest extends AbstractCDOTest } } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testWriteNative() throws Exception { CDORevision revisionToRemove = null; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java index a3e433fa3c..399fcaa0db 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java @@ -12,6 +12,8 @@ package org.eclipse.emf.cdo.tests; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; import org.eclipse.emf.cdo.tests.model1.Category; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.tests.model1.Customer; @@ -36,6 +38,7 @@ import java.util.List; /** * @author Eike Stepper */ +@Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public class ChunkingTest extends AbstractCDOTest { private static final String RESOURCE_PATH = "/test"; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CrossReferenceTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CrossReferenceTest.java index 00ef7cd404..5cd0fe5401 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CrossReferenceTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CrossReferenceTest.java @@ -15,6 +15,7 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.revision.CDORevisionData; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.tests.model1.Customer; import org.eclipse.emf.cdo.tests.model1.SalesOrder; @@ -326,9 +327,9 @@ public class CrossReferenceTest extends AbstractCDOTest } @Skips("Hibernate") + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testDetachXRefExternal() throws Exception { - skipStoreWithoutExternalReferences(); Customer customer = getModel1Factory().createCustomer(); customer.setName("customer"); @@ -393,9 +394,9 @@ public class CrossReferenceTest extends AbstractCDOTest } @Skips("Hibernate") + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testNewMakeExternal() throws Exception { - skipStoreWithoutExternalReferences(); Customer customer = getModel1Factory().createCustomer(); customer.setName("customer"); @@ -423,6 +424,7 @@ public class CrossReferenceTest extends AbstractCDOTest assertEquals(true, id.isExternal()); } + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testExternalMakeNew() throws Exception { Customer customer = getModel1Factory().createCustomer(); @@ -456,10 +458,9 @@ public class CrossReferenceTest extends AbstractCDOTest } @Skips("Hibernate") + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testExternalMakeDangling() throws Exception { - skipStoreWithoutExternalReferences(); - Customer customer = getModel1Factory().createCustomer(); customer.setName("customer"); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ExternalReferenceTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ExternalReferenceTest.java index f01fbb088f..2e7a8cbee8 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ExternalReferenceTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ExternalReferenceTest.java @@ -20,6 +20,8 @@ import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.internal.net4j.protocol.LoadRevisionsRequest; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.config.IModelConfig; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; import org.eclipse.emf.cdo.tests.model1.Supplier; @@ -59,14 +61,13 @@ import java.util.Map; /** * @author Simon McDuff */ +@Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public class ExternalReferenceTest extends AbstractCDOTest { private static final String REPOSITORY_B_NAME = "repo2"; public void testExternalWithDynamicEObject() throws Exception { - skipStoreWithoutExternalReferences(); - ResourceSet resourceSet = new ResourceSetImpl(); resourceSet.getResourceFactoryRegistry().getProtocolToFactoryMap().put("test", new XMIResourceFactoryImpl()); @@ -94,8 +95,6 @@ public class ExternalReferenceTest extends AbstractCDOTest public void testExternalWithEClass() throws Exception { - skipStoreWithoutExternalReferences(); - { ResourceSet resourceSet = new ResourceSetImpl(); @@ -129,8 +128,6 @@ public class ExternalReferenceTest extends AbstractCDOTest public void testExternalWithEPackage() throws Exception { - skipStoreWithoutExternalReferences(); - { CDOSession sessionA = openSession(); @@ -168,8 +165,6 @@ public class ExternalReferenceTest extends AbstractCDOTest @Skips("Postgresql") public void testOneXMIResourceManyViewsOnOneResourceSet() throws Exception { - skipStoreWithoutExternalReferences(); - byte[] dataOfresD = null; getRepository(REPOSITORY_B_NAME); @@ -279,8 +274,6 @@ public class ExternalReferenceTest extends AbstractCDOTest @Skips({ IModelConfig.CAPABILITY_LEGACY, "Postgresql" }) public void testManyViewsOnOneResourceSet() throws Exception { - skipStoreWithoutExternalReferences(); - getRepository(REPOSITORY_B_NAME); { @@ -390,8 +383,6 @@ public class ExternalReferenceTest extends AbstractCDOTest public void testWithXML() throws Exception { - skipStoreWithoutExternalReferences(); - ResourceSet resourceSet = new ResourceSetImpl(); Map<String, Object> map = resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap(); map.put("xml", new XMLResourceFactoryImpl()); @@ -417,7 +408,6 @@ public class ExternalReferenceTest extends AbstractCDOTest public void testWithXMLAndPrefetching() throws Exception { - skipStoreWithoutExternalReferences(); { ResourceSet resourceSet = new ResourceSetImpl(); @@ -491,8 +481,6 @@ public class ExternalReferenceTest extends AbstractCDOTest @CleanRepositoriesBefore(reason = "Ref counting") public void testXRefExternalObject() throws Exception { - skipStoreWithoutExternalReferences(); - ResourceSet resourceSet = new ResourceSetImpl(); Map<String, Object> map = resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap(); map.put("xml", new XMLResourceFactoryImpl()); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/FeatureMapTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/FeatureMapTest.java index 7bae3be135..1d1f5863f6 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/FeatureMapTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/FeatureMapTest.java @@ -36,6 +36,7 @@ import java.util.List; /** * @author Simon McDuff */ +@Deprecated public class FeatureMapTest extends AbstractCDOTest { private EPackage pkg; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/InitialTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/InitialTest.java index bc74a6b92a..a91a77b1f0 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/InitialTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/InitialTest.java @@ -183,6 +183,33 @@ public class InitialTest extends AbstractCDOTest assertCreatedTime(supplier, commit.getTimeStamp()); } + public void testCommitNewInverseList() throws Exception + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("/test1")); + + Category category = getModel1Factory().createCategory(); + category.setName("Category"); + resource.getContents().add(category); + + Product1 product = getModel1Factory().createProduct1(); + product.setName("Product1"); + category.getProducts().add(product); + + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + orderDetail.setPrice(47.11f); + orderDetail.setProduct(product); + resource.getContents().add(orderDetail); + + CDOCommitInfo commit = transaction.commit(); + assertEquals(CDOState.CLEAN, resource.cdoState()); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(orderDetail).cdoState()); + assertEquals(1, CDOUtil.getCDOObject(orderDetail).cdoRevision().getVersion()); + assertCreatedTime(resource, commit.getTimeStamp()); + assertCreatedTime(orderDetail, commit.getTimeStamp()); + } + public void testReadResourceClean() throws Exception { CDOSession session = openSession(); @@ -262,6 +289,41 @@ public class InitialTest extends AbstractCDOTest assertCreatedTime(supplier, commitTime2); } + public void testCommitDirtyInverseList() throws Exception + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("/test1")); + + Category category = getModel1Factory().createCategory(); + category.setName("Category"); + resource.getContents().add(category); + + Product1 product = getModel1Factory().createProduct1(); + product.setName("Product1"); + category.getProducts().add(product); + + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + orderDetail.setPrice(47.11f); + orderDetail.setProduct(product); + resource.getContents().add(orderDetail); + + CDOCommitInfo commit = transaction.commit(); + long commitTime1 = commit.getTimeStamp(); + assertCreatedTime(product, commitTime1); + + OrderDetail orderDetail2 = getModel1Factory().createOrderDetail(); + orderDetail2.setPrice(0.815f); + orderDetail2.setProduct(product); + resource.getContents().add(orderDetail2); + + long commitTime2 = transaction.commit().getTimeStamp(); + assertEquals(true, commitTime1 < commitTime2); + assertEquals(CDOState.CLEAN, resource.cdoState()); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(product).cdoState()); + assertCreatedTime(product, commitTime2); + } + public void testGetResource() throws Exception { CDOSession session = openSession(); @@ -456,6 +518,52 @@ public class InitialTest extends AbstractCDOTest assertEquals("Stepper", s.getName()); } + public void testLoadObjectInverseList() throws Exception + { + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("/test1")); + + Category category = getModel1Factory().createCategory(); + category.setName("Category"); + resource.getContents().add(category); + + Product1 product = getModel1Factory().createProduct1(); + product.setName("Product1"); + category.getProducts().add(product); + + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + orderDetail.setPrice(47.11f); + orderDetail.setProduct(product); + resource.getContents().add(orderDetail); + + transaction.commit(); + session.close(); + clearCache(getRepository().getRevisionManager()); + } + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("/test1")); + EList<EObject> contents = resource.getContents(); + + Category category = (Category)contents.get(0); + assertNotNull(category); + assertEquals("Category", category.getName()); + assertEquals(1, category.getProducts().size()); + + Product1 product = category.getProducts().get(0); + assertNotNull(product); + assertEquals("Product1", product.getName()); + assertEquals(1, product.getOrderDetails().size()); + + OrderDetail orderDetail = product.getOrderDetails().get(0); + assertNotNull(orderDetail); + assertEquals(47.11f, orderDetail.getPrice()); + assertEquals(product, orderDetail.getProduct()); + } + /** * bug 226317 */ diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java index dfda28180d..1d33264d91 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.tests; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.model3.MetaRef; import org.eclipse.emf.cdo.transaction.CDOTransaction; @@ -22,10 +23,9 @@ import org.eclipse.emf.ecore.EReference; */ public class MetaTest extends AbstractCDOTest { + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testMetaReference() throws Exception { - skipStoreWithoutExternalReferences(); - { CDOSession session = openSession(); CDOTransaction transaction = session.openTransaction(); @@ -46,10 +46,9 @@ public class MetaTest extends AbstractCDOTest assertEquals(getModel3Package(), metaRef.getEPackageRef()); } + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testMetaReferenceAttachFirst() throws Exception { - skipStoreWithoutExternalReferences(); - { CDOSession session = openSession(); CDOTransaction transaction = session.openTransaction(); @@ -70,10 +69,9 @@ public class MetaTest extends AbstractCDOTest assertEquals(getModel3Package(), metaRef.getEPackageRef()); } + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testMetaReference2() throws Exception { - skipStoreWithoutExternalReferences(); - EReference targetRef = getModel3SubpackagePackage().getClass2_Class1(); { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MultiValuedOfAttributeTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MultiValuedOfAttributeTest.java index f43cf3b917..f65eee1771 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MultiValuedOfAttributeTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MultiValuedOfAttributeTest.java @@ -13,6 +13,8 @@ package org.eclipse.emf.cdo.tests; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.cdo.util.CommitException; @@ -31,6 +33,7 @@ import java.util.List; /** * @author Simon McDuff */ +@Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public class MultiValuedOfAttributeTest extends AbstractCDOTest { public void testListOfString() throws Exception diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ViewTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ViewTest.java index 1db4442fdc..bdd29e4263 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ViewTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ViewTest.java @@ -15,6 +15,7 @@ import org.eclipse.emf.cdo.common.revision.CDORevisionData; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOUtil; @@ -98,6 +99,7 @@ public class ViewTest extends AbstractCDOTest session.close(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testUniqueResourceContents() throws Exception { { @@ -137,6 +139,7 @@ public class ViewTest extends AbstractCDOTest session.close(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testNonUniqueResourceContents() throws Exception { { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/XATransactionTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/XATransactionTest.java index 88d048c12c..9b169596a7 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/XATransactionTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/XATransactionTest.java @@ -80,9 +80,9 @@ public class XATransactionTest extends AbstractCDOTest xaTransaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testRollback_AfterSetpoint() throws Exception { - skipStoreWithoutExternalReferences(); getRepository(REPOSITORY2_NAME); CDOSession sessionA = openSession(); @@ -143,9 +143,9 @@ public class XATransactionTest extends AbstractCDOTest // XXX disabled because of Bug 290097 @Skips("Postgresql") + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testCommitFromTransactionDisabled() throws Exception { - skipStoreWithoutExternalReferences(); getRepository(REPOSITORY2_NAME); { @@ -191,9 +191,9 @@ public class XATransactionTest extends AbstractCDOTest // Skip this test until the problems with XATransactions are solved. @Skips({ IModelConfig.CAPABILITY_LEGACY, IRepositoryConfig.CAPABILITY_UUIDS, "DB" }) + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testNotUsingXATransaction_Exception() throws Exception { - skipStoreWithoutExternalReferences(); getRepository(REPOSITORY2_NAME); { @@ -236,9 +236,9 @@ public class XATransactionTest extends AbstractCDOTest // XXX disabled because of Bug 290097 @Skips("Postgresql") + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void test_ExceptionInReadingStream() throws Exception { - skipStoreWithoutExternalReferences(); getRepository(REPOSITORY2_NAME); CDOSession sessionA = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_306998_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_306998_Test.java index 4cc3b0e3e8..3bb065a980 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_306998_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_306998_Test.java @@ -15,7 +15,6 @@ import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.AbstractCDOTest; import org.eclipse.emf.cdo.tests.model1.VAT; -import org.eclipse.emf.cdo.tests.model1.legacy.Model1Package; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.cdo.util.CommitException; @@ -36,7 +35,7 @@ public class Bugzilla_306998_Test extends AbstractCDOTest { EPackage pkg = createUniquePackage(); EClass cls = EMFUtil.createEClass(pkg, "cls", false, false); - EAttribute att = EMFUtil.createEAttribute(cls, "att", Model1Package.eINSTANCE.getVAT()); + EAttribute att = EMFUtil.createEAttribute(cls, "att", getModel1Package().getVAT()); att.setDefaultValueLiteral("vat7"); CDOUtil.prepareDynamicEPackage(pkg); @@ -75,9 +74,9 @@ public class Bugzilla_306998_Test extends AbstractCDOTest { EPackage pkg = createUniquePackage(); EClass cls = EMFUtil.createEClass(pkg, "cls", false, false); - EAttribute att = EMFUtil.createEAttribute(cls, "att", Model1Package.eINSTANCE.getVAT()); + EAttribute att = EMFUtil.createEAttribute(cls, "att", getModel1Package().getVAT()); att.setDefaultValueLiteral("vat8"); - att.setDefaultValue(Model1Package.eINSTANCE.getVAT().getEEnumLiteral("vat8")); + att.setDefaultValue(getModel1Package().getVAT().getEEnumLiteral("vat8")); CDOUtil.prepareDynamicEPackage(pkg); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_322218_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_322218_Test.java index bfb8cf4252..148d678a7e 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_322218_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_322218_Test.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo.tests.bugzilla; import org.eclipse.emf.cdo.eresource.CDOResource; 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.model6.MyEnum; import org.eclipse.emf.cdo.tests.model6.MyEnumList; import org.eclipse.emf.cdo.tests.model6.MyEnumListUnsettable; @@ -73,6 +74,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumListPCL() throws Exception { MyEnumList myEnumList = getModel6Factory().createMyEnumList(); @@ -91,6 +93,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumList2PCL() throws Exception { CDOSession session = openSession(); @@ -109,6 +112,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumList3PCL() throws Exception { CDOSession session = openSession(); @@ -128,6 +132,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumList3PCL_Reload() throws Exception { { @@ -207,6 +212,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumListUnsettablePCL() throws Exception { MyEnumListUnsettable myEnumList = getModel6Factory().createMyEnumListUnsettable(); @@ -225,6 +231,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumListUnsettable2PCL() throws Exception { CDOSession session = openSession(); @@ -243,6 +250,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumListUnsettable3PCL() throws Exception { CDOSession session = openSession(); @@ -262,6 +270,7 @@ public class Bugzilla_322218_Test extends AbstractCDOTest transaction.commit(); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testMyEnumListUnsettable3PCL_Reload() throws Exception { { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_323930_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_323930_Test.java index 66d19bf54d..236c636881 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_323930_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_323930_Test.java @@ -36,7 +36,6 @@ public class Bugzilla_323930_Test extends AbstractCDOTest protected void doSetUp() throws Exception { super.doSetUp(); - skipStoreWithoutQueryXRefs(); } public void testChangeIndexesInTargetList() throws Exception diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_335675_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_335675_Test.java index 10d4791771..daebd19d17 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_335675_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_335675_Test.java @@ -15,6 +15,8 @@ import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.spi.common.revision.BaseCDORevision; import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IModelConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; import org.eclipse.emf.cdo.tests.model1.Model1Factory; import org.eclipse.emf.cdo.tests.model1.Model1Package; import org.eclipse.emf.cdo.tests.model1.OrderDetail; @@ -37,6 +39,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil; /** * @author Caspar De Groot */ +@Requires(IModelConfig.CAPABILITY_LEGACY) public class Bugzilla_335675_Test extends AbstractCDOTest { public void test0() throws Exception diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337054_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337054_Test.java index adc5782cca..6f931a7b31 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337054_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337054_Test.java @@ -30,7 +30,7 @@ public class Bugzilla_337054_Test extends AbstractCDOTest private static final int LIST_SIZE = 3; - @Requires({ IRepositoryConfig.CAPABILITY_BRANCHING, IRepositoryConfig.CAPABILITY_RESTARTABLE }) + @Requires({ IRepositoryConfig.CAPABILITY_BRANCHING, IRepositoryConfig.CAPABILITY_CHUNKING, IRepositoryConfig.CAPABILITY_RESTARTABLE }) public void testCDOElementProxies() throws Exception { CDOSession session = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337587_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337587_Test.java index 69ab6970da..4dcefcdbf7 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337587_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_337587_Test.java @@ -15,6 +15,7 @@ import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.model1.Customer; import org.eclipse.emf.cdo.tests.model1.SalesOrder; import org.eclipse.emf.cdo.transaction.CDOTransaction; @@ -29,6 +30,7 @@ import org.eclipse.emf.spi.cdo.InternalCDOTransaction; */ public class Bugzilla_337587_Test extends AbstractCDOTest { + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testRevisionCompare() throws CommitException { { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_347964_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_347964_Test.java index 9037ba2aab..f2ecf67141 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_347964_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_347964_Test.java @@ -28,7 +28,7 @@ public class Bugzilla_347964_Test extends AbstractCDOTest { private static final String RESOURCE_NAME = "res347964"; - @Requires(IRepositoryConfig.CAPABILITY_RESTARTABLE) + @Requires({ IRepositoryConfig.CAPABILITY_RESTARTABLE, IRepositoryConfig.CAPABILITY_CHUNKING }) public void testIndexDeletion() throws Exception { CDOSession session = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_351393_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_351393_Test.java index de1be03a69..d75d99d79d 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_351393_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_351393_Test.java @@ -33,10 +33,9 @@ public class Bugzilla_351393_Test extends AbstractCDOTest { // Ext-Refs with client-side UUIDs are stored "in sito", where the tests use even less chars. @Skips(IRepositoryConfig.CAPABILITY_UUIDS) + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testExtRef() throws Exception { - skipStoreWithoutExternalReferences(); - ResourceSet resourceSet = new ResourceSetImpl(); resourceSet.getResourceFactoryRegistry().getProtocolToFactoryMap().put("test", new XMIResourceFactoryImpl()); URI uri = URI.createURI("test:///tmp/file.xmi?" + "12345678901234567890" + // 41 diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270_Test.java index 2c9777e920..5512cdeae4 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270_Test.java @@ -15,6 +15,8 @@ import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.eresource.CDOResource; 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.Requires; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; import org.eclipse.emf.cdo.tests.model1.Supplier; @@ -52,6 +54,7 @@ import java.util.Map; * * @author Esteban Dugueperoux */ +@Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public class Bugzilla_362270_Test extends AbstractCDOTest { private final EReference SUPPLIERS = getModel1Package().getCompany_Suppliers(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270c_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270c_Test.java index cf9ffb77d9..474a9a413b 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270c_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_362270c_Test.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo.tests.bugzilla; import org.eclipse.emf.cdo.eresource.CDOResource; 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.model1.Company; import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; import org.eclipse.emf.cdo.tests.model1.Supplier; @@ -53,6 +54,7 @@ public class Bugzilla_362270c_Test extends AbstractCDOTest { private static final String RESOURCE_PATH = "/test1"; + @Requires(IRepositoryConfig.CAPABILITY_EXTERNAL_REFS) public void testNotifierNotACDOLegacyAdapter() throws Exception { TransactionalEditingDomain domain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_369646_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_369646_Test.java index 7f3d024ec3..6f96be741e 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_369646_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_369646_Test.java @@ -64,6 +64,7 @@ public class Bugzilla_369646_Test extends AbstractCDOTest transaction.setBranch(sub1); } + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testSetBranchWithPCL() throws Exception { { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_405606_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_405606_Test.java index 14bbb71813..8f578d9f1d 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_405606_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_405606_Test.java @@ -14,6 +14,7 @@ import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.model1.Category; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOUtil; @@ -26,6 +27,7 @@ import org.eclipse.net4j.util.io.IOUtil; */ public class Bugzilla_405606_Test extends AbstractCDOTest { + @Requires(IRepositoryConfig.CAPABILITY_CHUNKING) public void testUnchunkedRevisionWithPCL() throws Exception { { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_436246_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_436246_Test.java index 079cb4876d..7654764a51 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_436246_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_436246_Test.java @@ -250,9 +250,11 @@ public class Bugzilla_436246_Test extends AbstractCDOTest protocol.removeListener(signalCounter); } + /** + * @author Eike Stepper + */ private class CustomCDOFetchRuleManager implements CDOFetchRuleManager { - private CDOID companyCDOID; public CustomCDOFetchRuleManager(CDOID companyCDOID) diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485394_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485394_Test.java index 626410cc73..247179de8d 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485394_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485394_Test.java @@ -36,6 +36,8 @@ public class Bugzilla_485394_Test extends AbstractCDOTest return map; } + // With inverse list mappings there is no referential integrity violation in this case. + @Skips("DB.inverse.lists") public void testReferentialIntegrityWithContainmentProxy() throws Exception { skipStoreWithoutQueryXRefs(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IRepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IRepositoryConfig.java index 4cac391e45..e9344a7042 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IRepositoryConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IRepositoryConfig.java @@ -35,6 +35,10 @@ public interface IRepositoryConfig extends IConfig, IRepositoryProvider public static final String CAPABILITY_BRANCHING = "repository.branching"; + public static final String CAPABILITY_CHUNKING = "repository.chunking"; + + public static final String CAPABILITY_EXTERNAL_REFS = "repository.external.refs"; + public static final String CAPABILITY_UUIDS = "repository.uuids"; public static final String CAPABILITY_OFFLINE = "repository.offline"; @@ -49,6 +53,10 @@ public interface IRepositoryConfig extends IConfig, IRepositoryProvider public boolean isSupportingBranches(); + public boolean isSupportingChunks(); + + public boolean isSupportingExtRefs(); + public IDGenerationLocation getIDGenerationLocation(); public Map<String, String> getRepositoryProperties(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTest.java index 40601e442b..aeffedfeb2 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTest.java @@ -20,7 +20,6 @@ import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.emf.cdo.spi.server.InternalStore.NoChangeSets; import org.eclipse.emf.cdo.spi.server.InternalStore.NoCommitInfos; import org.eclipse.emf.cdo.spi.server.InternalStore.NoDurableLocking; -import org.eclipse.emf.cdo.spi.server.InternalStore.NoExternalReferences; import org.eclipse.emf.cdo.spi.server.InternalStore.NoFeatureMaps; import org.eclipse.emf.cdo.spi.server.InternalStore.NoHandleRevisions; import org.eclipse.emf.cdo.spi.server.InternalStore.NoLargeObjects; @@ -726,11 +725,6 @@ public abstract class ConfigTest extends AbstractOMTest implements IConstants || ObjectUtil.equals(getModelConfig(), config); } - protected void skipStoreWithoutExternalReferences() - { - skipTest(getRepository().getStore() instanceof NoExternalReferences); - } - protected void skipStoreWithoutQueryXRefs() { skipTest(getRepository().getStore() instanceof NoQueryXRefs); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java index ad9f618b85..2dec90aa22 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java @@ -179,6 +179,16 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf } } + if (isSupportingChunks()) + { + capabilities.add(CAPABILITY_CHUNKING); + } + + if (isSupportingExtRefs()) + { + capabilities.add(CAPABILITY_EXTERNAL_REFS); + } + if (getIDGenerationLocation() == IDGenerationLocation.CLIENT) { capabilities.add(CAPABILITY_UUIDS); @@ -209,6 +219,16 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf return supportingBranches; } + public boolean isSupportingChunks() + { + return true; + } + + public boolean isSupportingExtRefs() + { + return true; + } + public IDGenerationLocation getIDGenerationLocation() { return idGenerationLocation; diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java index b9c5e53481..c3b0736f6c 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java @@ -10,6 +10,7 @@ */ package org.eclipse.net4j.db; +import org.eclipse.net4j.db.ddl.IDBElement; import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.db.ddl.IDBNamedElement; import org.eclipse.net4j.db.ddl.IDBSchema; @@ -22,6 +23,7 @@ import org.eclipse.net4j.internal.db.bundle.OM; import org.eclipse.net4j.internal.db.ddl.DBIndex; import org.eclipse.net4j.internal.db.ddl.DBNamedElement; import org.eclipse.net4j.spi.db.DBAdapter; +import org.eclipse.net4j.spi.db.ddl.InternalDBIndex; import org.eclipse.net4j.util.ReflectUtil; import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.io.ExtendedDataInput; @@ -469,6 +471,35 @@ public final class DBUtil } /** + * @since 4.6 + */ + public static boolean isOptional(IDBElement element) + { + if (element instanceof InternalDBIndex) + { + InternalDBIndex index = (InternalDBIndex)element; + return index.isOptional(); + } + + return false; + } + + /** + * @since 4.6 + */ + public static boolean setOptional(IDBElement element, boolean optional) + { + if (element instanceof InternalDBIndex) + { + InternalDBIndex index = (InternalDBIndex)element; + index.setOptional(optional); + return true; + } + + return false; + } + + /** * @since 4.2 */ public static boolean setAutoCommit(Connection connection, boolean autoCommit) @@ -876,6 +907,17 @@ public final class DBUtil { throw new DBException(ex); } + finally + { + try + { + stmt.clearBatch(); + } + catch (SQLException ex) + { + OM.LOG.warn(ex); + } + } } public static int update(Connection connection, String sql) diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBSchema.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBSchema.java index c48e835fed..19dfe0e24a 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBSchema.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBSchema.java @@ -25,7 +25,6 @@ import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.db.ddl.SchemaElementNotFoundException; import org.eclipse.net4j.db.ddl.delta.IDBSchemaDelta; import org.eclipse.net4j.internal.db.ddl.delta.DBSchemaDelta; -import org.eclipse.net4j.spi.db.ddl.InternalDBIndex; import org.eclipse.net4j.spi.db.ddl.InternalDBSchema; import javax.sql.DataSource; @@ -75,7 +74,7 @@ public class DBSchema extends DBSchemaElement implements InternalDBSchema for (IDBIndex sourceIndex : sourceTable.getIndices()) { IDBIndex index = table.addIndexEmpty(sourceIndex.getName(), sourceIndex.getType()); - ((InternalDBIndex)index).setOptional(((InternalDBIndex)sourceIndex).isOptional()); + DBUtil.setOptional(index, DBUtil.isOptional(sourceIndex)); for (IDBField sourceField : sourceIndex.getFields()) { diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java index 74e4143d00..7695755cb0 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java @@ -11,6 +11,7 @@ package org.eclipse.net4j.internal.db.ddl.delta; 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.IDBIndex; import org.eclipse.net4j.db.ddl.IDBIndexField; @@ -23,7 +24,6 @@ import org.eclipse.net4j.db.ddl.delta.IDBIndexDelta; import org.eclipse.net4j.db.ddl.delta.IDBIndexFieldDelta; import org.eclipse.net4j.db.ddl.delta.IDBSchemaDelta; import org.eclipse.net4j.db.ddl.delta.IDBTableDelta; -import org.eclipse.net4j.spi.db.ddl.InternalDBIndex; import org.eclipse.net4j.spi.db.ddl.InternalDBSchema; import java.text.MessageFormat; @@ -204,8 +204,8 @@ public final class DBSchemaDelta extends DBDelta implements IDBSchemaDelta Boolean optional = delta.getPropertyValue(IDBIndexDelta.OPTIONAL_PROPERTY); IDBTable table = delta.getParent().getSchemaElement(schema); - InternalDBIndex index = (InternalDBIndex)table.addIndexEmpty(name, type); - index.setOptional(optional == Boolean.TRUE); + IDBIndex index = table.addIndexEmpty(name, type); + DBUtil.setOptional(index, optional == Boolean.TRUE); } @Override |