diff options
Diffstat (limited to 'plugins/org.eclipse.emf.cdo.server.db')
17 files changed, 1287 insertions, 369 deletions
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 4b80d68f95..78b9747bcd 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 @@ -11,6 +11,7 @@ package org.eclipse.emf.cdo.server.db; import org.eclipse.emf.cdo.server.IStoreAccessor; +import org.eclipse.emf.cdo.server.IStoreAccessor.UnitSupport; import org.eclipse.net4j.db.IDBConnection; @@ -23,7 +24,7 @@ import java.sql.Connection; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBStoreAccessor extends IStoreAccessor.Raw +public interface IDBStoreAccessor extends IStoreAccessor.Raw, UnitSupport { public IDBStore getStore(); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingUnitSupport.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingUnitSupport.java new file mode 100644 index 0000000000..65e8e77d33 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingUnitSupport.java @@ -0,0 +1,30 @@ +/* + * 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.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; + +import java.sql.SQLException; + +/** + * An extension interface for {@link IClassMapping class mappings} that support <i>units</i>. + * + * @author Eike Stepper + * @since 4.4 + */ +public interface IClassMappingUnitSupport extends IClassMapping +{ + public void readUnitRevisions(IDBStoreAccessor accessor, CDOBranchPoint branchPoint, CDOID rootID, + CDORevisionHandler revisionHandler) throws SQLException; +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping3.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping3.java new file mode 100644 index 0000000000..8fc37c5a4e --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping3.java @@ -0,0 +1,22 @@ +/* + * 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; + +/** + * Extension interface to {@link IListMapping2}. + * + * @author Eike Stepper + * @since 4.4 + */ +public interface IListMapping3 extends IListMapping2 +{ + public void setClassMapping(IClassMapping classMapping); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingUnitSupport.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingUnitSupport.java new file mode 100644 index 0000000000..c97e0f363b --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingUnitSupport.java @@ -0,0 +1,34 @@ +/* + * 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.common.id.CDOID; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IIDHandler; + +import org.eclipse.net4j.util.collection.MoveableList; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Interface to complement {@link IListMapping} in order to provide unit support. + * + * @author Eike Stepper + * @since 4.4 + */ +public interface IListMappingUnitSupport extends IListMapping +{ + public ResultSet queryUnitEntries(IDBStoreAccessor accessor, IIDHandler idHandler, CDOID rootID) throws SQLException; + + public void readUnitEntries(ResultSet resultSet, IIDHandler idHandler, CDOID id, MoveableList<Object> list) + throws SQLException; +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java index 6b42da68b6..efc86e0dc7 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java @@ -35,13 +35,13 @@ public class CDODBSchema public static final IDBTable PROPERTIES = INSTANCE.addTable("cdo_properties"); //$NON-NLS-1$ public static final IDBField PROPERTIES_NAME = // - PROPERTIES.addField("name", DBType.VARCHAR, 255, true); //$NON-NLS-1$ + PROPERTIES.addField("name", DBType.VARCHAR, 255, true); //$NON-NLS-1$ public static final IDBField PROPERTIES_VALUE = // - PROPERTIES.addField("value", DBType.LONGVARCHAR); //$NON-NLS-1$ + PROPERTIES.addField("value", DBType.LONGVARCHAR); //$NON-NLS-1$ public static final IDBIndex INDEX_PROPERTIES_PK = // - PROPERTIES.addIndex(IDBIndex.Type.PRIMARY_KEY, PROPERTIES_NAME); + PROPERTIES.addIndex(IDBIndex.Type.PRIMARY_KEY, PROPERTIES_NAME); public static final String SQL_DELETE_PROPERTIES = "DELETE FROM " + PROPERTIES + " WHERE " + PROPERTIES_NAME + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -60,19 +60,19 @@ public class CDODBSchema public static final IDBTable PACKAGE_UNITS = INSTANCE.addTable("cdo_package_units"); //$NON-NLS-1$ public static final IDBField PACKAGE_UNITS_ID = // - PACKAGE_UNITS.addField("id", DBType.VARCHAR, 255, true); //$NON-NLS-1$ + PACKAGE_UNITS.addField("id", DBType.VARCHAR, 255, true); //$NON-NLS-1$ public static final IDBField PACKAGE_UNITS_ORIGINAL_TYPE = // - PACKAGE_UNITS.addField("original_type", DBType.INTEGER); //$NON-NLS-1$ + PACKAGE_UNITS.addField("original_type", DBType.INTEGER); //$NON-NLS-1$ public static final IDBField PACKAGE_UNITS_TIME_STAMP = // - PACKAGE_UNITS.addField("time_stamp", DBType.BIGINT); //$NON-NLS-1$ + PACKAGE_UNITS.addField("time_stamp", DBType.BIGINT); //$NON-NLS-1$ public static final IDBField PACKAGE_UNITS_PACKAGE_DATA = // - PACKAGE_UNITS.addField("package_data", DBType.BLOB); //$NON-NLS-1$ + PACKAGE_UNITS.addField("package_data", DBType.BLOB); //$NON-NLS-1$ public static final IDBIndex INDEX_PACKAGE_UNITS_PK = // - PACKAGE_UNITS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_UNITS_ID); + PACKAGE_UNITS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_UNITS_ID); /** * DBTable cdo_packages @@ -80,22 +80,22 @@ public class CDODBSchema public static final IDBTable PACKAGE_INFOS = INSTANCE.addTable("cdo_package_infos"); //$NON-NLS-1$ public static final IDBField PACKAGE_INFOS_URI = // - PACKAGE_INFOS.addField("uri", DBType.VARCHAR, 255, true); //$NON-NLS-1$ + PACKAGE_INFOS.addField("uri", DBType.VARCHAR, 255, true); //$NON-NLS-1$ public static final IDBField PACKAGE_INFOS_PARENT = // - PACKAGE_INFOS.addField("parent", DBType.VARCHAR, 255); //$NON-NLS-1$ + PACKAGE_INFOS.addField("parent", DBType.VARCHAR, 255); //$NON-NLS-1$ public static final IDBField PACKAGE_INFOS_UNIT = // - PACKAGE_INFOS.addField("unit", DBType.VARCHAR, 255); //$NON-NLS-1$ + PACKAGE_INFOS.addField("unit", DBType.VARCHAR, 255); //$NON-NLS-1$ public static final IDBIndex INDEX_PACKAGE_INFOS_PK = // - PACKAGE_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_INFOS_URI); + PACKAGE_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_INFOS_URI); public static final IDBIndex INDEX_PACKAGE_INFOS_PARENT = // - PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_PARENT); + PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_PARENT); public static final IDBIndex INDEX_PACKAGE_INFOS_UNIT = // - PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_UNIT); + PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_UNIT); /** * DBTable cdo_branches @@ -103,19 +103,19 @@ public class CDODBSchema public static final IDBTable BRANCHES = INSTANCE.addTable("cdo_branches"); //$NON-NLS-1$ public static final IDBField BRANCHES_ID = // - BRANCHES.addField("id", DBType.INTEGER, true); //$NON-NLS-1$ + BRANCHES.addField("id", DBType.INTEGER, true); //$NON-NLS-1$ public static final IDBField BRANCHES_NAME = // - BRANCHES.addField("name", DBType.VARCHAR); //$NON-NLS-1$ + BRANCHES.addField("name", DBType.VARCHAR); //$NON-NLS-1$ public static final IDBField BRANCHES_BASE_BRANCH_ID = // - BRANCHES.addField("base_id", DBType.INTEGER); //$NON-NLS-1$ + BRANCHES.addField("base_id", DBType.INTEGER); //$NON-NLS-1$ public static final IDBField BRANCHES_BASE_TIMESTAMP = // - BRANCHES.addField("base_time", DBType.BIGINT); //$NON-NLS-1$ + BRANCHES.addField("base_time", DBType.BIGINT); //$NON-NLS-1$ public static final IDBIndex INDEX_BRANCHES_ID = // - BRANCHES.addIndex(IDBIndex.Type.PRIMARY_KEY, BRANCHES_ID); + BRANCHES.addIndex(IDBIndex.Type.PRIMARY_KEY, BRANCHES_ID); public static final String SQL_CREATE_BRANCH = "INSERT INTO " + BRANCHES + " (" + BRANCHES_ID + ", " + BRANCHES_NAME //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ", " + BRANCHES_BASE_BRANCH_ID + ", " + BRANCHES_BASE_TIMESTAMP + ") VALUES (?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -139,33 +139,32 @@ public class CDODBSchema public static final IDBTable COMMIT_INFOS = INSTANCE.addTable("cdo_commit_infos"); //$NON-NLS-1$ public static final IDBField COMMIT_INFOS_TIMESTAMP = // - COMMIT_INFOS.addField("commit_time", DBType.BIGINT, true); //$NON-NLS-1$ + COMMIT_INFOS.addField("commit_time", DBType.BIGINT, true); //$NON-NLS-1$ public static final IDBField COMMIT_INFOS_PREVIOUS_TIMESTAMP = // - COMMIT_INFOS.addField("previous_time", DBType.BIGINT); //$NON-NLS-1$ + COMMIT_INFOS.addField("previous_time", DBType.BIGINT); //$NON-NLS-1$ public static final IDBField COMMIT_INFOS_BRANCH = // - COMMIT_INFOS.addField("branch_id", DBType.INTEGER); //$NON-NLS-1$ + COMMIT_INFOS.addField("branch_id", DBType.INTEGER); //$NON-NLS-1$ public static final IDBField COMMIT_INFOS_USER = // - COMMIT_INFOS.addField("user_id", DBType.VARCHAR); //$NON-NLS-1$ + COMMIT_INFOS.addField("user_id", DBType.VARCHAR); //$NON-NLS-1$ public static final IDBField COMMIT_INFOS_COMMENT = // - COMMIT_INFOS.addField("commit_comment", DBType.VARCHAR); //$NON-NLS-1$ + COMMIT_INFOS.addField("commit_comment", DBType.VARCHAR); //$NON-NLS-1$ public static final IDBIndex INDEX_COMMIT_INFOS_PK = // - COMMIT_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, COMMIT_INFOS_TIMESTAMP); + COMMIT_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, COMMIT_INFOS_TIMESTAMP); public static final IDBIndex INDEX_COMMIT_INFOS_BRANCH = // - COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_BRANCH); + COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_BRANCH); public static final IDBIndex INDEX_COMMIT_INFOS_USER = // - COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_USER); + COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_USER); public static final String SQL_CREATE_COMMIT_INFO = "INSERT INTO " + COMMIT_INFOS + "(" + COMMIT_INFOS_TIMESTAMP //$NON-NLS-1$ //$NON-NLS-2$ + ", " + COMMIT_INFOS_PREVIOUS_TIMESTAMP + ", " + COMMIT_INFOS_BRANCH + ", " + COMMIT_INFOS_USER + ", " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - + COMMIT_INFOS_COMMENT + ") " - + "VALUES (?, ?, ?, ?, ?)"; //$NON-NLS-1$ + + COMMIT_INFOS_COMMENT + ") " + "VALUES (?, ?, ?, ?, ?)"; //$NON-NLS-2$ /** * DBTable cdo_lobs @@ -173,19 +172,19 @@ public class CDODBSchema public static final IDBTable LOBS = INSTANCE.addTable("cdo_lobs"); //$NON-NLS-1$ public static final IDBField LOBS_ID = // - LOBS.addField("id", DBType.VARCHAR, 64, true); //$NON-NLS-1$ + LOBS.addField("id", DBType.VARCHAR, 64, true); //$NON-NLS-1$ public static final IDBField LOBS_SIZE = // - LOBS.addField("lsize", DBType.BIGINT); //$NON-NLS-1$ + LOBS.addField("lsize", DBType.BIGINT); //$NON-NLS-1$ public static final IDBField LOBS_BDATA = // - LOBS.addField("bdata", DBType.BLOB); //$NON-NLS-1$ + LOBS.addField("bdata", DBType.BLOB); //$NON-NLS-1$ public static final IDBField LOBS_CDATA = // - LOBS.addField("cdata", DBType.CLOB); //$NON-NLS-1$ + LOBS.addField("cdata", DBType.CLOB); //$NON-NLS-1$ public static final IDBIndex INDEX_LOBS_ID = // - LOBS.addIndex(IDBIndex.Type.PRIMARY_KEY, LOBS_ID); + LOBS.addIndex(IDBIndex.Type.PRIMARY_KEY, LOBS_ID); public static final String SQL_QUERY_LOBS = "SELECT 1 FROM " + CDODBSchema.LOBS + " WHERE " + CDODBSchema.LOBS_ID //$NON-NLS-1$ //$NON-NLS-2$ + "=?"; //$NON-NLS-1$ diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java index 9efd29ccc8..48df638948 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java @@ -32,6 +32,7 @@ import org.eclipse.emf.cdo.server.db.IMetaDataManager; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.IMappingConstants; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.UnitMappingTable; import org.eclipse.emf.cdo.server.internal.db.messages.Messages; import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.emf.cdo.spi.server.InternalSession; @@ -115,6 +116,8 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl private DurableLockingManager durableLockingManager = new DurableLockingManager(this); + private UnitMappingTable unitMappingTable; + private IMappingStrategy mappingStrategy; private IDBDatabase database; @@ -237,6 +240,11 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl return durableLockingManager; } + public UnitMappingTable getUnitMappingTable() + { + return unitMappingTable; + } + public Timer getConnectionKeepAliveTimer() { return connectionKeepAliveTimer; @@ -640,6 +648,12 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl LifecycleUtil.activate(durableLockingManager); LifecycleUtil.activate(mappingStrategy); + if (repository.isSupportingUnits()) + { + unitMappingTable = new UnitMappingTable(mappingStrategy); + unitMappingTable.activate(); + } + setRevisionTemporality(mappingStrategy.hasAuditSupport() ? RevisionTemporality.AUDITING : RevisionTemporality.NONE); setRevisionParallelism( mappingStrategy.hasBranchingSupport() ? RevisionParallelism.BRANCHING : RevisionParallelism.NONE); @@ -659,6 +673,7 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl @Override protected void doDeactivate() throws Exception { + LifecycleUtil.deactivate(unitMappingTable); LifecycleUtil.deactivate(mappingStrategy); LifecycleUtil.deactivate(durableLockingManager); LifecycleUtil.deactivate(metaDataManager); @@ -961,7 +976,7 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl }; private static final SchemaMigrator[] SCHEMA_MIGRATORS = { NO_MIGRATION_NEEDED, NON_AUDIT_MIGRATION, - LOB_SIZE_MIGRATION, NO_MIGRATION_NEEDED }; + LOB_SIZE_MIGRATION, NO_MIGRATION_NEEDED }; static { 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 834cbca7b9..90514b8911 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.ISession; 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.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; @@ -49,6 +50,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; 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; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager.BranchLoader3; @@ -63,8 +65,11 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; import org.eclipse.emf.cdo.spi.server.InternalCommitContext; import org.eclipse.emf.cdo.spi.server.InternalRepository; +import org.eclipse.emf.cdo.spi.server.InternalUnitManager; +import org.eclipse.emf.cdo.spi.server.InternalUnitManager.InternalObjectAttacher; import org.eclipse.emf.cdo.spi.server.StoreAccessor; +import org.eclipse.net4j.db.BatchedStatement; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.IDBConnection; @@ -118,10 +123,10 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, private ConnectionKeepAliveTask connectionKeepAliveTask; - private Set<CDOID> newObjects = new HashSet<CDOID>(); - private CDOID maxID = CDOID.NULL; + private InternalObjectAttacher objectAttacher; + public DBStoreAccessor(DBStore store, ISession session) throws DBException { super(store, session); @@ -133,17 +138,17 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, } @Override - public DBStore getStore() + public final DBStore getStore() { return (DBStore)super.getStore(); } - public IDBConnection getDBConnection() + public final IDBConnection getDBConnection() { return connection; } - public Connection getConnection() + public final Connection getConnection() { return connection; } @@ -480,17 +485,17 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, { super.applyIDMappings(context, monitor); + DBStore store = getStore(); + IIDHandler idHandler = store.getIDHandler(); + // Remember maxID because it may have to be adjusted if the repository is BACKUP or CLONE. See bug 325097. boolean adjustMaxID = !context.getBranchPoint().getBranch().isLocal() - && getStore().getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE; - - IIDHandler idHandler = getStore().getIDHandler(); + && store.getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE; // Remember CDOIDs of new objects. They are cleared after writeRevisions() for (InternalCDORevision revision : context.getNewObjects()) { CDOID id = revision.getID(); - newObjects.add(id); if (adjustMaxID && idHandler.compare(id, maxID) > 0) { @@ -560,24 +565,52 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, } @Override - protected void writeRevisions(InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor) + protected void writeNewObjectRevisions(InternalCommitContext context, InternalCDORevision[] newObjects, + CDOBranch branch, OMMonitor monitor) + { + writeRevisions(context, true, newObjects, branch, monitor); + } + + @Override + protected void writeDirtyObjectRevisions(InternalCommitContext context, InternalCDORevision[] dirtyObjects, + CDOBranch branch, OMMonitor monitor) + { + writeRevisions(context, false, dirtyObjects, branch, monitor); + } + + protected void writeRevisions(InternalCommitContext context, boolean attachNewObjects, + InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor) { try { monitor.begin(revisions.length); for (InternalCDORevision revision : revisions) { - boolean mapType = newObjects.contains(revision.getID()); - writeRevision(revision, mapType, true, monitor.fork()); + writeRevision(revision, attachNewObjects, true, monitor.fork()); + } + + if (attachNewObjects) + { + InternalRepository repository = getStore().getRepository(); + if (repository.isSupportingUnits()) + { + InternalUnitManager unitManager = repository.getUnitManager(); + objectAttacher = unitManager.attachObjects(context); + } } } finally { - newObjects.clear(); monitor.done(); } } + @Override + protected void writeRevisions(InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor) + { + throw new UnsupportedOperationException(); + } + protected void writeRevision(InternalCDORevision revision, boolean mapType, boolean revise, OMMonitor monitor) { if (TRACER.isEnabled()) @@ -708,6 +741,12 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, getStore().getIDHandler().adjustLastObjectID(maxID); maxID = CDOID.NULL; } + + if (objectAttacher != null) + { + objectAttacher.finishedCommit(true); + objectAttacher = null; + } } finally { @@ -730,6 +769,12 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, @Override protected final void doRollback(IStoreAccessor.CommitContext commitContext) { + if (objectAttacher != null) + { + objectAttacher.finishedCommit(false); + objectAttacher = null; + } + getStore().getMetaDataManager().clearMetaIDMappings(); if (TRACER.isEnabled()) @@ -758,6 +803,7 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, DBStore store = getStore(); connection = store.getDatabase().getConnection(); connectionKeepAliveTask = new ConnectionKeepAliveTask(this); + objectAttacher = null; long keepAlivePeriod = ConnectionKeepAliveTask.EXECUTION_PERIOD; Map<String, String> storeProps = store.getProperties(); @@ -1443,6 +1489,38 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, manager.unlock(this, durableLockingID); } + public List<CDOID> readUnitRoots() + { + UnitMappingTable unitMappingTable = getStore().getUnitMappingTable(); + return unitMappingTable.readUnitRoots(this); + } + + public void readUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler) + { + UnitMappingTable unitMappingTable = getStore().getUnitMappingTable(); + unitMappingTable.readUnitRevisions(this, view, rootID, revisionHandler); + } + + public Object initUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler, Set<CDOID> initializedIDs, + long timeStamp) + { + UnitMappingTable unitMappingTable = getStore().getUnitMappingTable(); + return unitMappingTable.initUnit(this, timeStamp, view, rootID, revisionHandler, initializedIDs); + } + + public void finishUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler, long timeStamp, + Object initResult, List<CDOID> ids) + { + UnitMappingTable unitMappingTable = getStore().getUnitMappingTable(); + unitMappingTable.finishUnit((BatchedStatement)initResult, rootID, ids, timeStamp); + } + + public void writeUnits(Map<CDOID, CDOID> unitMappings, long timeStamp) + { + UnitMappingTable unitMappingTable = getStore().getUnitMappingTable(); + unitMappingTable.writeUnitMappings(this, unitMappings, timeStamp); + } + /** * @author Stefan Winkler */ diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java index 71ad7546e0..77abb2bd05 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java @@ -238,8 +238,11 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager try { - String sql = "INSERT INTO " + CDODBSchema.PACKAGE_UNITS + " VALUES (?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$ + String sql = "INSERT INTO " + CDODBSchema.PACKAGE_UNITS + " (" + CDODBSchema.PACKAGE_UNITS_ID + ", " //$NON-NLS-1$ //$NON-NLS-2$ + + CDODBSchema.PACKAGE_UNITS_ORIGINAL_TYPE + ", " + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + ", " + + CDODBSchema.PACKAGE_UNITS_PACKAGE_DATA + ") VALUES (?, ?, ?, ?)"; DBUtil.trace(sql); + IDBPreparedStatement stmt = connection.prepareStatement(sql, ReuseProbability.MEDIUM); try @@ -311,7 +314,8 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager String parentURI = packageInfo.getParentURI(); String unitID = packageInfo.getPackageUnit().getID(); - String sql = "INSERT INTO " + CDODBSchema.PACKAGE_INFOS + " VALUES (?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$ + String sql = "INSERT INTO " + CDODBSchema.PACKAGE_INFOS + " (" + CDODBSchema.PACKAGE_INFOS_URI + ", " //$NON-NLS-1$ //$NON-NLS-2$ + + CDODBSchema.PACKAGE_INFOS_PARENT + ", " + CDODBSchema.PACKAGE_INFOS_UNIT + ") VALUES (?, ?, ?)"; DBUtil.trace(sql); IDBPreparedStatement stmt = connection.prepareStatement(sql, ReuseProbability.MEDIUM); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java index 9c2b20d146..040285c0db 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java @@ -63,6 +63,7 @@ public class UUIDHandler extends Lifecycle implements IIDHandler public int compare(CDOID id1, CDOID id2) { + // UUIDs are not generated in strictly ordered form. throw new UnsupportedOperationException(); } 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 9552980072..78590284f4 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 @@ -55,6 +55,7 @@ import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.collection.CloseableIterator; import org.eclipse.net4j.util.lifecycle.Lifecycle; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; @@ -828,6 +829,21 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp public abstract IListMapping doCreateFeatureMapMapping(EClass containingClass, EStructuralFeature feature); + @Override + protected void doDeactivate() throws Exception + { + deactivateClassMappings(); + super.doDeactivate(); + } + + protected void deactivateClassMappings() + { + for (IClassMapping classMapping : classMappings.values()) + { + LifecycleUtil.deactivate(classMapping); + } + } + 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 695e803227..b68f84dc8c 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 @@ -13,7 +13,8 @@ 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.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.mapping.IListMapping2; +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.ecore.EClass; @@ -22,7 +23,7 @@ import org.eclipse.emf.ecore.EStructuralFeature; /** * @author Stefan Winkler */ -public abstract class AbstractBasicListTableMapping implements IListMapping2, IMappingConstants +public abstract class AbstractBasicListTableMapping implements IListMapping3, IMappingConstants { private IMappingStrategy mappingStrategy; @@ -70,5 +71,10 @@ public abstract class AbstractBasicListTableMapping implements IListMapping2, IM builder.append(toIndex - 1); } + public void setClassMapping(IClassMapping classMapping) + { + // Subclasses may override. + } + public abstract void rawDeleted(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, int version); } 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 2efd6d6307..31581f12f7 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 @@ -31,6 +31,7 @@ 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.IListMapping; +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; @@ -51,6 +52,7 @@ 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; import org.eclipse.net4j.util.om.trace.ContextTracer; @@ -79,7 +81,7 @@ import java.util.Set; * @author Eike Stepper * @since 2.0 */ -public abstract class AbstractHorizontalClassMapping implements IClassMapping, IMappingConstants +public abstract class AbstractHorizontalClassMapping implements IClassMapping, IMappingConstants, IDeactivateable { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractHorizontalClassMapping.class); @@ -142,7 +144,7 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I primaryKey.addIndexField(branchField); } - table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_ID, ATTRIBUTES_REVISED); + table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_REVISED); } } @@ -175,6 +177,11 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I mapping = mappingStrategy.createListMapping(eClass, feature); } + if (mapping instanceof IListMapping3) + { + ((IListMapping3)mapping).setClassMapping(this); + } + listMappings.add(mapping); // Add field for list sizes @@ -294,9 +301,10 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I } stmt.setMaxRows(1); // Optimization: only 1 row - resultSet = stmt.executeQuery(); - if (!resultSet.next()) + + IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); + if (!readValuesFromResultSet(resultSet, idHandler, revision, false)) { if (TRACER.isEnabled()) { @@ -306,69 +314,95 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I return false; } - revision.setVersion(resultSet.getInt(ATTRIBUTES_VERSION)); + return true; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(resultSet); + } + } - long timeStamp = resultSet.getLong(ATTRIBUTES_CREATED); + /** + * Read the revision's values from the DB. + * + * @return <code>true</code> if the revision has been read successfully.<br> + * <code>false</code> if the revision does not exist in the DB. + */ + protected final boolean readValuesFromResultSet(ResultSet resultSet, IIDHandler idHandler, + InternalCDORevision revision, boolean forUnit) + { + try + { + if (resultSet.next()) + { + long timeStamp = resultSet.getLong(ATTRIBUTES_CREATED); + CDOBranchPoint branchPoint = revision.getBranch().getPoint(timeStamp); - IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); - CDOBranchPoint branchPoint = revision.getBranch().getPoint(timeStamp); + if (forUnit) + { + revision.setID(idHandler.getCDOID(resultSet, ATTRIBUTES_ID)); + } - revision.setBranchPoint(branchPoint); - revision.setRevised(resultSet.getLong(ATTRIBUTES_REVISED)); - revision.setResourceID(idHandler.getCDOID(resultSet, ATTRIBUTES_RESOURCE)); - revision.setContainerID(idHandler.getCDOID(resultSet, ATTRIBUTES_CONTAINER)); - revision.setContainingFeatureID(resultSet.getInt(ATTRIBUTES_FEATURE)); + revision.setBranchPoint(branchPoint); + revision.setVersion(resultSet.getInt(ATTRIBUTES_VERSION)); + revision.setRevised(resultSet.getLong(ATTRIBUTES_REVISED)); + revision.setResourceID(idHandler.getCDOID(resultSet, ATTRIBUTES_RESOURCE)); + revision.setContainerID(idHandler.getCDOID(resultSet, ATTRIBUTES_CONTAINER)); + revision.setContainingFeatureID(resultSet.getInt(ATTRIBUTES_FEATURE)); - for (ITypeMapping mapping : valueMappings) - { - EStructuralFeature feature = mapping.getFeature(); - if (feature.isUnsettable()) + for (ITypeMapping mapping : valueMappings) { - IDBField field = unsettableFields.get(feature); - if (!resultSet.getBoolean(field.getName())) + EStructuralFeature feature = mapping.getFeature(); + if (feature.isUnsettable()) { - // isSet==false -- setValue: null - revision.setValue(feature, null); - continue; + IDBField field = unsettableFields.get(feature); + if (!resultSet.getBoolean(field.getName())) + { + // isSet==false -- setValue: null + revision.setValue(feature, null); + continue; + } } - } - mapping.readValueToRevision(resultSet, revision); - } + mapping.readValueToRevision(resultSet, revision); + } - if (listSizeFields != null) - { - for (Map.Entry<EStructuralFeature, IDBField> listSizeEntry : listSizeFields.entrySet()) + if (listSizeFields != null) { - EStructuralFeature feature = listSizeEntry.getKey(); - IDBField field = listSizeEntry.getValue(); - int size = resultSet.getInt(field.getName()); + for (Map.Entry<EStructuralFeature, IDBField> listSizeEntry : listSizeFields.entrySet()) + { + EStructuralFeature feature = listSizeEntry.getKey(); + IDBField field = listSizeEntry.getValue(); + int size = resultSet.getInt(field.getName()); - // ensure the listSize (TODO: remove assertion) - CDOList list = revision.getList(feature, size); + // ensure the listSize (TODO: remove assertion) + CDOList list = revision.getList(feature, size); - for (int i = 0; i < size; i++) - { - list.add(InternalCDOList.UNINITIALIZED); - } + for (int i = 0; i < size; i++) + { + list.add(InternalCDOList.UNINITIALIZED); + } - if (list.size() != size) - { - Assert.isTrue(false); + if (list.size() != size) + { + Assert.isTrue(false); + } } } + + return true; } - return true; + return false; } catch (SQLException ex) { throw new DBException(ex); } - finally - { - DBUtil.close(resultSet); - } } protected final void readLists(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) @@ -926,6 +960,11 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I protected abstract void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision); + public Exception deactivate() + { + return null; + } + protected static void appendTypeMappingNames(StringBuilder builder, Collection<ITypeMapping> typeMappings) { if (typeMappings != null) diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java index 3583e2e2c5..9e1cdc6240 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java @@ -36,11 +36,14 @@ import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; 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.IListMappingDeltaSupport; +import org.eclipse.emf.cdo.server.db.mapping.IListMappingUnitSupport; 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.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBType; @@ -75,7 +78,8 @@ import java.util.List; * @author Stefan Winkler * @author Lothar Werzinger */ -public class AuditListTableMappingWithRanges extends AbstractBasicListTableMapping implements IListMappingDeltaSupport +public class AuditListTableMappingWithRanges extends AbstractBasicListTableMapping + implements IListMappingDeltaSupport, IListMappingUnitSupport { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AuditListTableMappingWithRanges.class); @@ -84,6 +88,11 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi */ private static final int FINAL_VERSION = Integer.MAX_VALUE; + private static final String SQL_ORDER_BY_INDEX = " ORDER BY " + LIST_IDX; + + private static final boolean CHECK_UNIT_ENTRIES = Boolean + .getBoolean("org.eclipse.emf.cdo.server.db.checkUnitEntries"); + /** * The table of this mapping. */ @@ -97,7 +106,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi // --------- SQL strings - see initSQLStrings() ----------------- private String sqlSelectChunksPrefix; - private String sqlOrderByIndex; + private String sqlSelectUnitEntries; private String sqlInsertEntry; @@ -172,8 +181,6 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi builder.append(">?)"); //$NON-NLS-1$ sqlSelectChunksPrefix = builder.toString(); - sqlOrderByIndex = " ORDER BY " + LIST_IDX; //$NON-NLS-1$ - // ----------------- insert entry ----------------- builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$ builder.append(tableName); @@ -271,6 +278,26 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi sqlDeleteList = builder.toString(); } + @Override + public void setClassMapping(IClassMapping classMapping) + { + InternalRepository repository = (InternalRepository)getMappingStrategy().getStore().getRepository(); + if (repository.isSupportingUnits()) + { + String listTableName = getTable().getName(); + String attributesTableName = classMapping.getDBTables().get(0).getName(); + + sqlSelectUnitEntries = "SELECT " + (CHECK_UNIT_ENTRIES ? ATTRIBUTES_ID + ", " : "") + "cdo_list." + LIST_VALUE + // + " FROM " + listTableName + " cdo_list, " + attributesTableName + ", " + UnitMappingTable.UNITS + // + " WHERE " + UnitMappingTable.UNITS_ELEM + "=" + ATTRIBUTES_ID + // + " AND " + ATTRIBUTES_ID + "=cdo_list." + LIST_REVISION_ID + // + " AND " + UnitMappingTable.UNITS_UNIT + "=?" + // + " AND cdo_list." + LIST_REVISION_VERSION_ADDED + "<=" + ATTRIBUTES_VERSION + // + " AND (cdo_list." + LIST_REVISION_VERSION_REMOVED + " IS NULL OR cdo_list." + LIST_REVISION_VERSION_REMOVED + + ">" + ATTRIBUTES_VERSION + ") ORDER BY cdo_list." + LIST_REVISION_ID + ", cdo_list." + LIST_IDX; + } + } + public Collection<IDBTable> getDBTables() { return Collections.singleton(table); @@ -301,7 +328,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi getFeature().getName(), revision.getID(), revision.getVersion()); } - String sql = sqlSelectChunksPrefix + sqlOrderByIndex; + String sql = sqlSelectChunksPrefix + SQL_ORDER_BY_INDEX; IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sql, ReuseProbability.HIGH); @@ -365,7 +392,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi builder.append(where); } - builder.append(sqlOrderByIndex); + builder.append(SQL_ORDER_BY_INDEX); String sql = builder.toString(); IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); @@ -536,6 +563,259 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi throw new UnsupportedOperationException("Raw deletion does not work in range-based mappings"); } + public ResultSet queryUnitEntries(IDBStoreAccessor accessor, IIDHandler idHandler, CDOID rootID) throws SQLException + { + IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlSelectUnitEntries, + ReuseProbability.MEDIUM); + idHandler.setCDOID(stmt, 1, rootID); + return stmt.executeQuery(); + } + + public void readUnitEntries(ResultSet resultSet, IIDHandler idHandler, CDOID id, MoveableList<Object> list) + throws SQLException + { + int size = list.size(); + for (int i = 0; i < size; i++) + { + resultSet.next(); + + if (CHECK_UNIT_ENTRIES) + { + CDOID checkID = idHandler.getCDOID(resultSet, 1); + if (checkID != id) + { + throw new IllegalStateException("Result set does not deliver expected result"); + } + } + + Object value = typeMapping.readValue(resultSet); + list.set(i, value); + } + } + + private void addEntry(IDBStoreAccessor accessor, CDOID id, int version, int index, Object value) + { + if (TRACER.isEnabled()) + { + TRACER.format("Adding value for feature() {0}.{1} index {2} of {3}v{4} : {5}", //$NON-NLS-1$ + getContainingClass().getName(), getFeature().getName(), index, id, version, value); + } + + IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); + IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlInsertEntry, ReuseProbability.HIGH); + + try + { + int column = 1; + idHandler.setCDOID(stmt, column++, id); + stmt.setInt(column++, version); + stmt.setInt(column++, index); + typeMapping.setValue(stmt, column++, value); + + DBUtil.update(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + catch (IllegalStateException e) + { + throw new DBException(e); + } + finally + { + DBUtil.close(stmt); + } + } + + private void removeEntry(IDBStoreAccessor accessor, CDOID id, int oldVersion, int newVersion, int index) + { + if (TRACER.isEnabled()) + { + TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4}", //$NON-NLS-1$ + getContainingClass().getName(), getFeature().getName(), index, id, newVersion); + } + + IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); + IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlDeleteEntry, ReuseProbability.HIGH); + + try + { + // try to delete a temporary entry first + int column = 1; + idHandler.setCDOID(stmt, column++, id); + stmt.setInt(column++, index); + stmt.setInt(column++, newVersion); + + int result = DBUtil.update(stmt, false); + if (result == 1) + { + if (TRACER.isEnabled()) + { + TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$ + } + } + else if (result > 1) + { + if (TRACER.isEnabled()) + { + TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$ + } + + throw new DBException("Too many results"); //$NON-NLS-1$ + } + else + { + // no temporary entry found, so mark the entry as removed + DBUtil.close(stmt); + stmt = accessor.getDBConnection().prepareStatement(sqlRemoveEntry, ReuseProbability.HIGH); + + column = 1; + stmt.setInt(column++, newVersion); + idHandler.setCDOID(stmt, column++, id); + stmt.setInt(column++, index); + + DBUtil.update(stmt, true); + } + } + catch (SQLException e) + { + if (TRACER.isEnabled()) + { + TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$ + getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage()); + } + + throw new DBException(e); + } + catch (IllegalStateException e) + { + if (TRACER.isEnabled()) + { + TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$ + getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage()); + } + + throw new DBException(e); + } + finally + { + DBUtil.close(stmt); + } + } + + private Object getValue(IDBStoreAccessor accessor, CDOID id, int index) + { + IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); + IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlGetValue, ReuseProbability.HIGH); + Object result = null; + + try + { + int column = 1; + idHandler.setCDOID(stmt, column++, id); + stmt.setInt(column++, index); + + ResultSet resultSet = stmt.executeQuery(); + if (!resultSet.next()) + { + throw new DBException("getValue() expects exactly one result"); + } + + result = typeMapping.readValue(resultSet); + if (TRACER.isEnabled()) + { + TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$ + } + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + DBUtil.close(stmt); + } + + return result; + } + + public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere, + QueryXRefsContext context, String idString) + { + + String tableName = getTable().getName(); + String listJoin = getMappingStrategy().getListJoin("a_t", "l_t"); + + StringBuilder builder = new StringBuilder(); + builder.append("SELECT l_t."); //$NON-NLS-1$ + builder.append(LIST_REVISION_ID); + builder.append(", l_t."); //$NON-NLS-1$ + builder.append(LIST_VALUE); + builder.append(", l_t."); //$NON-NLS-1$ + builder.append(LIST_IDX); + builder.append(" FROM "); //$NON-NLS-1$ + builder.append(tableName); + builder.append(" l_t, ");//$NON-NLS-1$ + builder.append(mainTableName); + builder.append(" a_t WHERE ");//$NON-NLS-1$ + builder.append("a_t.");//$NON-NLS-1$ + builder.append(mainTableWhere); + builder.append(listJoin); + builder.append(" AND "); //$NON-NLS-1$ + builder.append(LIST_VALUE); + builder.append(" IN "); //$NON-NLS-1$ + builder.append(idString); + String sql = builder.toString(); + + if (TRACER.isEnabled()) + { + TRACER.format("Query XRefs (list): {0}", sql); + } + + IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); + IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sql, ReuseProbability.MEDIUM); + ResultSet resultSet = null; + + try + { + resultSet = stmt.executeQuery(); + while (resultSet.next()) + { + CDOID sourceID = idHandler.getCDOID(resultSet, 1); + CDOID targetID = idHandler.getCDOID(resultSet, 2); + int idx = resultSet.getInt(3); + + boolean more = context.addXRef(targetID, sourceID, (EReference)getFeature(), idx); + if (TRACER.isEnabled()) + { + TRACER.format(" add XRef to context: src={0}, tgt={1}, idx={2}", sourceID, targetID, idx); + } + + if (!more) + { + if (TRACER.isEnabled()) + { + TRACER.format(" result limit reached. Ignoring further results."); + } + + return false; + } + } + + return true; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(resultSet); + DBUtil.close(stmt); + } + } + public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, int oldVersion, final int newVersion, long created, CDOListFeatureDelta delta) { @@ -890,227 +1170,4 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi } } } - - private void addEntry(IDBStoreAccessor accessor, CDOID id, int version, int index, Object value) - { - if (TRACER.isEnabled()) - { - TRACER.format("Adding value for feature() {0}.{1} index {2} of {3}v{4} : {5}", //$NON-NLS-1$ - getContainingClass().getName(), getFeature().getName(), index, id, version, value); - } - - IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); - IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlInsertEntry, ReuseProbability.HIGH); - - try - { - int column = 1; - idHandler.setCDOID(stmt, column++, id); - stmt.setInt(column++, version); - stmt.setInt(column++, index); - typeMapping.setValue(stmt, column++, value); - - DBUtil.update(stmt, true); - } - catch (SQLException e) - { - throw new DBException(e); - } - catch (IllegalStateException e) - { - throw new DBException(e); - } - finally - { - DBUtil.close(stmt); - } - } - - private void removeEntry(IDBStoreAccessor accessor, CDOID id, int oldVersion, int newVersion, int index) - { - if (TRACER.isEnabled()) - { - TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4}", //$NON-NLS-1$ - getContainingClass().getName(), getFeature().getName(), index, id, newVersion); - } - - IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); - IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlDeleteEntry, ReuseProbability.HIGH); - - try - { - // try to delete a temporary entry first - int column = 1; - idHandler.setCDOID(stmt, column++, id); - stmt.setInt(column++, index); - stmt.setInt(column++, newVersion); - - int result = DBUtil.update(stmt, false); - if (result == 1) - { - if (TRACER.isEnabled()) - { - TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$ - } - } - else if (result > 1) - { - if (TRACER.isEnabled()) - { - TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$ - } - - throw new DBException("Too many results"); //$NON-NLS-1$ - } - else - { - // no temporary entry found, so mark the entry as removed - DBUtil.close(stmt); - stmt = accessor.getDBConnection().prepareStatement(sqlRemoveEntry, ReuseProbability.HIGH); - - column = 1; - stmt.setInt(column++, newVersion); - idHandler.setCDOID(stmt, column++, id); - stmt.setInt(column++, index); - - DBUtil.update(stmt, true); - } - } - catch (SQLException e) - { - if (TRACER.isEnabled()) - { - TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$ - getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage()); - } - - throw new DBException(e); - } - catch (IllegalStateException e) - { - if (TRACER.isEnabled()) - { - TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$ - getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage()); - } - - throw new DBException(e); - } - finally - { - DBUtil.close(stmt); - } - } - - private Object getValue(IDBStoreAccessor accessor, CDOID id, int index) - { - IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); - IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlGetValue, ReuseProbability.HIGH); - Object result = null; - - try - { - int column = 1; - idHandler.setCDOID(stmt, column++, id); - stmt.setInt(column++, index); - - ResultSet resultSet = stmt.executeQuery(); - if (!resultSet.next()) - { - throw new DBException("getValue() expects exactly one result"); - } - - result = typeMapping.readValue(resultSet); - if (TRACER.isEnabled()) - { - TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$ - } - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - DBUtil.close(stmt); - } - - return result; - } - - public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere, - QueryXRefsContext context, String idString) - { - - String tableName = getTable().getName(); - String listJoin = getMappingStrategy().getListJoin("a_t", "l_t"); - - StringBuilder builder = new StringBuilder(); - builder.append("SELECT l_t."); //$NON-NLS-1$ - builder.append(LIST_REVISION_ID); - builder.append(", l_t."); //$NON-NLS-1$ - builder.append(LIST_VALUE); - builder.append(", l_t."); //$NON-NLS-1$ - builder.append(LIST_IDX); - builder.append(" FROM "); //$NON-NLS-1$ - builder.append(tableName); - builder.append(" l_t, ");//$NON-NLS-1$ - builder.append(mainTableName); - builder.append(" a_t WHERE ");//$NON-NLS-1$ - builder.append("a_t.");//$NON-NLS-1$ - builder.append(mainTableWhere); - builder.append(listJoin); - builder.append(" AND "); //$NON-NLS-1$ - builder.append(LIST_VALUE); - builder.append(" IN "); //$NON-NLS-1$ - builder.append(idString); - String sql = builder.toString(); - - if (TRACER.isEnabled()) - { - TRACER.format("Query XRefs (list): {0}", sql); - } - - IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); - IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sql, ReuseProbability.MEDIUM); - ResultSet resultSet = null; - - try - { - resultSet = stmt.executeQuery(); - while (resultSet.next()) - { - CDOID sourceID = idHandler.getCDOID(resultSet, 1); - CDOID targetID = idHandler.getCDOID(resultSet, 2); - int idx = resultSet.getInt(3); - - boolean more = context.addXRef(targetID, sourceID, (EReference)getFeature(), idx); - if (TRACER.isEnabled()) - { - TRACER.format(" add XRef to context: src={0}, tgt={1}, idx={2}", sourceID, targetID, idx); - } - - if (!more) - { - if (TRACER.isEnabled()) - { - TRACER.format(" result limit reached. Ignoring further results."); - } - - return false; - } - } - - return true; - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - DBUtil.close(resultSet); - DBUtil.close(stmt); - } - } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java index 63d4e1840c..504c82dbe0 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java @@ -20,6 +20,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.revision.CDOList; import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; 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; @@ -35,18 +36,29 @@ import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; 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.IClassMappingUnitSupport; +import org.eclipse.emf.cdo.server.db.mapping.IListMapping; import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport; +import org.eclipse.emf.cdo.server.db.mapping.IListMappingUnitSupport; 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.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; +import org.eclipse.emf.cdo.spi.common.revision.StubCDORevision; +import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.IDBPreparedStatement; import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; +import org.eclipse.net4j.db.IDBResultSet; import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.util.ImplementationError; +import org.eclipse.net4j.util.WrappedException; +import org.eclipse.net4j.util.collection.MoveableList; +import org.eclipse.net4j.util.concurrent.ConcurrencyUtil; +import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; import org.eclipse.net4j.util.om.trace.ContextTracer; @@ -54,28 +66,38 @@ import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EStructuralFeature; +import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; /** * @author Eike Stepper * @since 2.0 */ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping - implements IClassMappingAuditSupport, IClassMappingDeltaSupport + implements IClassMappingAuditSupport, IClassMappingDeltaSupport, IClassMappingUnitSupport { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, HorizontalAuditClassMapping.class); private String sqlInsertAttributes; - private String sqlSelectCurrentAttributes; - - private String sqlSelectAllObjectIDs; + private String sqlSelectAttributesCurrent; private String sqlSelectAttributesByTime; private String sqlSelectAttributesByVersion; + private String sqlSelectUnitCurrent; + + private String sqlSelectUnitByTime; + + private String sqlSelectAllObjectIDs; + private String sqlReviseAttributes; private String sqlRawDeleteAttributes; @@ -98,47 +120,25 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping private void initSQLStrings() { // ----------- Select Revision --------------------------- - StringBuilder builder = new StringBuilder(); - builder.append("SELECT "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_VERSION); - builder.append(", "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_CREATED); - builder.append(", "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_REVISED); - builder.append(", "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_RESOURCE); - builder.append(", "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_CONTAINER); - builder.append(", "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_FEATURE); - appendTypeMappingNames(builder, getValueMappings()); - appendFieldNames(builder, getUnsettableFields()); - appendFieldNames(builder, getListSizeFields()); - builder.append(" FROM "); //$NON-NLS-1$ - builder.append(getTable()); - builder.append(" WHERE "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_ID); - builder.append("=? AND ("); //$NON-NLS-1$ - String sqlSelectAttributesPrefix = builder.toString(); - builder.append(ATTRIBUTES_REVISED); - builder.append("=0)"); //$NON-NLS-1$ - sqlSelectCurrentAttributes = builder.toString(); + String[] strings = buildSQLSelects(false); + String sqlSelectAttributesPrefix = strings[0]; + sqlSelectAttributesCurrent = strings[1]; + sqlSelectAttributesByTime = strings[2]; - builder = new StringBuilder(sqlSelectAttributesPrefix); - builder.append(ATTRIBUTES_CREATED); - builder.append("<=? AND ("); //$NON-NLS-1$ - builder.append(ATTRIBUTES_REVISED); - builder.append("=0 OR "); //$NON-NLS-1$ - builder.append(ATTRIBUTES_REVISED); - builder.append(">=?))"); //$NON-NLS-1$ - sqlSelectAttributesByTime = builder.toString(); - - builder = new StringBuilder(sqlSelectAttributesPrefix); + StringBuilder builder = new StringBuilder(sqlSelectAttributesPrefix); builder.append("ABS("); builder.append(ATTRIBUTES_VERSION); - builder.append(")=?)"); //$NON-NLS-1$ + builder.append(")=?"); //$NON-NLS-1$ sqlSelectAttributesByVersion = builder.toString(); + InternalRepository repository = (InternalRepository)getMappingStrategy().getStore().getRepository(); + if (repository.isSupportingUnits()) + { + strings = buildSQLSelects(true); + sqlSelectUnitCurrent = strings[1]; + sqlSelectUnitByTime = strings[2]; + } + // ----------- Insert Attributes ------------------------- builder = new StringBuilder(); builder.append("INSERT INTO "); //$NON-NLS-1$ @@ -200,6 +200,92 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping sqlRawDeleteAttributes = builder.toString(); } + private String[] buildSQLSelects(boolean forUnits) + { + String[] strings = new String[3]; + + StringBuilder builder = new StringBuilder(); + builder.append("SELECT "); //$NON-NLS-1$ + if (forUnits) + { + builder.append(ATTRIBUTES_ID); + builder.append(", "); //$NON-NLS-1$ + } + + builder.append(ATTRIBUTES_VERSION); + builder.append(", "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_CREATED); + builder.append(", "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_REVISED); + builder.append(", "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_RESOURCE); + builder.append(", "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_CONTAINER); + builder.append(", "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_FEATURE); + appendTypeMappingNames(builder, getValueMappings()); + appendFieldNames(builder, getUnsettableFields()); + appendFieldNames(builder, getListSizeFields()); + builder.append(" FROM "); //$NON-NLS-1$ + builder.append(getTable()); + + if (forUnits) + { + builder.append(", "); //$NON-NLS-1$ + builder.append(UnitMappingTable.UNITS); + builder.append(" WHERE "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_ID); + builder.append("="); //$NON-NLS-1$ + builder.append(UnitMappingTable.UNITS); + builder.append("."); //$NON-NLS-1$ + builder.append(UnitMappingTable.UNITS_ELEM); + builder.append(" AND "); //$NON-NLS-1$ + builder.append(UnitMappingTable.UNITS); + builder.append("."); //$NON-NLS-1$ + builder.append(UnitMappingTable.UNITS_UNIT); + builder.append("=?"); //$NON-NLS-1$ + builder.append(" AND "); //$NON-NLS-1$ + } + else + { + builder.append(" WHERE "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_ID); + builder.append("=? AND "); //$NON-NLS-1$ + } + + strings[0] = builder.toString(); + + builder.append(ATTRIBUTES_REVISED); + builder.append("=0"); //$NON-NLS-1$ + + if (forUnits) + { + builder.append(" ORDER BY "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_ID); + } + + strings[1] = builder.toString(); + + builder = new StringBuilder(strings[0]); + builder.append("("); //$NON-NLS-1$ + builder.append(ATTRIBUTES_CREATED); + builder.append("<=? AND ("); //$NON-NLS-1$ + builder.append(ATTRIBUTES_REVISED); + builder.append("=0 OR "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_REVISED); + builder.append(">=?))"); //$NON-NLS-1$ + + if (forUnits) + { + builder.append(" ORDER BY "); //$NON-NLS-1$ + builder.append(ATTRIBUTES_ID); + } + + strings[2] = builder.toString(); + + return strings; + } + public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); @@ -217,7 +303,7 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping } else { - stmt = accessor.getDBConnection().prepareStatement(sqlSelectCurrentAttributes, ReuseProbability.HIGH); + stmt = accessor.getDBConnection().prepareStatement(sqlSelectAttributesCurrent, ReuseProbability.HIGH); idHandler.setCDOID(stmt, 1, revision.getID()); } @@ -593,6 +679,210 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping return builder.toString(); } + public void readUnitRevisions(IDBStoreAccessor accessor, CDOBranchPoint branchPoint, CDOID rootID, + CDORevisionHandler revisionHandler) throws SQLException + { + DBStore store = (DBStore)getMappingStrategy().getStore(); + InternalRepository repository = store.getRepository(); + CDOBranchPoint head = repository.getBranchManager().getMainBranch().getHead(); + EClass eClass = getEClass(); + + IIDHandler idHandler = store.getIDHandler(); + IDBPreparedStatement stmt = null; + int oldFetchSize = -1; + + try + { + long timeStamp = branchPoint.getTimeStamp(); + if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE) + { + stmt = accessor.getDBConnection().prepareStatement(sqlSelectUnitByTime, ReuseProbability.MEDIUM); + idHandler.setCDOID(stmt, 1, rootID); + stmt.setLong(2, timeStamp); + stmt.setLong(3, timeStamp); + } + else + { + stmt = accessor.getDBConnection().prepareStatement(sqlSelectUnitCurrent, ReuseProbability.HIGH); + idHandler.setCDOID(stmt, 1, rootID); + } + + AsnychronousListFiller listFiller = new AsnychronousListFiller(accessor, rootID, revisionHandler); + ConcurrencyUtil.execute(repository, listFiller); + + oldFetchSize = stmt.getFetchSize(); + stmt.setFetchSize(100000); + IDBResultSet resultSet = stmt.executeQuery(); + + for (;;) + { + InternalCDORevision revision = store.createRevision(eClass, null); + revision.setBranchPoint(head); + + if (!readValuesFromResultSet(resultSet, idHandler, revision, true)) + { + break; + } + + listFiller.schedule(revision); + } + + listFiller.await(); + } + finally + { + if (oldFetchSize != -1) + { + stmt.setFetchSize(oldFetchSize); + } + + DBUtil.close(stmt); + } + } + + private class AsnychronousListFiller implements Runnable + { + private final BlockingQueue<InternalCDORevision> queue = new LinkedBlockingQueue<InternalCDORevision>(); + + private final CountDownLatch latch = new CountDownLatch(1); + + private final IDBStoreAccessor accessor; + + private final CDOID rootID; + + private final DBStore store; + + private final IIDHandler idHandler; + + private final IListMappingUnitSupport[] listMappings; + + private final ResultSet[] resultSets; + + private final CDORevisionHandler revisionHandler; + + private Throwable exception; + + public AsnychronousListFiller(IDBStoreAccessor accessor, CDOID rootID, CDORevisionHandler revisionHandler) + { + this.accessor = accessor; + this.rootID = rootID; + this.revisionHandler = revisionHandler; + + store = (DBStore)accessor.getStore(); + idHandler = store.getIDHandler(); + + List<IListMapping> tmp = getListMappings(); + int size = tmp.size(); + + listMappings = new IListMappingUnitSupport[size]; + resultSets = new ResultSet[size]; + + int i = 0; + for (IListMapping listMapping : tmp) + { + listMappings[i++] = (IListMappingUnitSupport)listMapping; + } + } + + public void schedule(InternalCDORevision revision) + { + queue.offer(revision); + } + + public void await() throws SQLException + { + // Schedule an end marker revision. + schedule(new StubCDORevision(getEClass())); + + try + { + latch.await(); + } + catch (InterruptedException ex) + { + throw new TimeoutRuntimeException(); + } + + if (exception instanceof RuntimeException) + { + throw (RuntimeException)exception; + } + + if (exception instanceof Error) + { + throw (Error)exception; + } + + if (exception instanceof SQLException) + { + throw (SQLException)exception; + } + + if (exception instanceof Exception) + { + throw WrappedException.wrap((Exception)exception); + } + } + + public void run() + { + try + { + while (store.isActive()) + { + InternalCDORevision revision = queue.poll(1, TimeUnit.SECONDS); + if (revision == null) + { + continue; + } + + if (revision instanceof StubCDORevision) + { + return; + } + + readUnitEntries(revision); + } + } + catch (Throwable ex) + { + exception = ex; + } + finally + { + latch.countDown(); + } + } + + private void readUnitEntries(InternalCDORevision revision) throws SQLException + { + CDOID id = revision.getID(); + + for (int i = 0; i < listMappings.length; i++) + { + IListMappingUnitSupport listMapping = listMappings[i]; + EStructuralFeature feature = listMapping.getFeature(); + + MoveableList<Object> list = revision.getList(feature); + int size = list.size(); + if (size != 0) + { + if (resultSets[i] == null) + { + resultSets[i] = listMapping.queryUnitEntries(accessor, idHandler, rootID); + } + + listMapping.readUnitEntries(resultSets[i], idHandler, id, list); + } + } + + synchronized (revisionHandler) + { + revisionHandler.handleRevision(revision); + } + } + } + /** * @author Stefan Winkler */ 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 3a3b6795a2..85c1855bf7 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 @@ -368,6 +368,8 @@ public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMappi { if (hasLists) { + // Reading all list rows of an object is not atomic. + // After all row reads are done, check the revision version again (see below). stmtVersion = accessor.getDBConnection().prepareStatement(sqlSelectCurrentVersion, ReuseProbability.HIGH); stmtVersion.setMaxRows(1); // Optimization: only 1 row idHandler.setCDOID(stmtVersion, 1, id); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java index cade3cb771..5787470f50 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java @@ -21,6 +21,7 @@ import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; +import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBType; @@ -213,7 +214,7 @@ public class ObjectTypeTable extends AbstractObjectTypeMapper implements IMappin { super.doActivate(); - IDBStore store = getMappingStrategy().getStore(); + final IDBStore store = getMappingStrategy().getStore(); final DBType idType = store.getIDHandler().getDBType(); final int idLength = store.getIDColumnLength(); @@ -230,6 +231,12 @@ public class ObjectTypeTable extends AbstractObjectTypeMapper implements IMappin table.addField(ATTRIBUTES_CLASS, idType, idLength); table.addField(ATTRIBUTES_CREATED, DBType.BIGINT); table.addIndex(IDBIndex.Type.PRIMARY_KEY, ATTRIBUTES_ID); + + InternalRepository repository = (InternalRepository)store.getRepository(); + if (repository.isSupportingUnits()) + { + table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_CLASS); + } } }); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/UnitMappingTable.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/UnitMappingTable.java new file mode 100644 index 0000000000..4bdacb754f --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/UnitMappingTable.java @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2010-2014 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + * Stefan Winkler - bug 259402 + * Stefan Winkler - redesign (prepared statements) + * Stefan Winkler - bug 276926 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.server.IView; +import org.eclipse.emf.cdo.server.db.IDBStore; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IIDHandler; +import org.eclipse.emf.cdo.server.db.IMetaDataManager; +import org.eclipse.emf.cdo.server.db.mapping.IClassMappingUnitSupport; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; + +import org.eclipse.net4j.db.BatchedStatement; +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.IDBConnection; +import org.eclipse.net4j.db.IDBDatabase; +import org.eclipse.net4j.db.IDBDatabase.RunnableWithSchema; +import org.eclipse.net4j.db.IDBPreparedStatement; +import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; +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.util.lifecycle.Lifecycle; + +import org.eclipse.emf.ecore.EClass; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public class UnitMappingTable extends Lifecycle implements IMappingConstants +{ + public static final String UNITS = "CDO_UNITS"; //$NON-NLS-1$ + + public static final String UNITS_ELEM = "CDO_ELEM"; //$NON-NLS-1$ + + public static final String UNITS_UNIT = "CDO_UNIT"; //$NON-NLS-1$ + + // public static final String UNITS_CREATED = "CDO_CREATED"; //$NON-NLS-1$ + + private static final String SQL_SELECT_ROOTS = "SELECT DISTINCT " + UNITS_UNIT + " FROM " + UNITS; + + private static final String SQL_INSERT_MAPPINGS = "INSERT INTO " + UNITS + " (" + UNITS_ELEM + ", " + UNITS_UNIT + + ") VALUES (?, ?)"; + + private static final String SQL_SELECT_CLASSES = "SELECT DISTINCT " + ATTRIBUTES_CLASS + " FROM " + UNITS + ", " + + CDODBSchema.CDO_OBJECTS + " WHERE " + UNITS_ELEM + "=" + ATTRIBUTES_ID + " AND " + UNITS_UNIT + "=?"; + + private static final int WRITE_UNIT_MAPPING_BATCH_SIZE = 100000; + + private final IMappingStrategy mappingStrategy; + + private IDBTable table; + + public UnitMappingTable(IMappingStrategy mappingStrategy) + { + this.mappingStrategy = mappingStrategy; + } + + public List<CDOID> readUnitRoots(IDBStoreAccessor accessor) + { + List<CDOID> rootIDs = new ArrayList<CDOID>(); + IIDHandler idHandler = mappingStrategy.getStore().getIDHandler(); + Statement stmt = null; + + try + { + stmt = accessor.getDBConnection().createStatement(); + + if (DBUtil.isTracerEnabled()) + { + DBUtil.trace(stmt.toString()); + } + + ResultSet resultSet = stmt.executeQuery(SQL_SELECT_ROOTS); + while (resultSet.next()) + { + CDOID rootID = idHandler.getCDOID(resultSet, 1); + rootIDs.add(rootID); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(stmt); + } + + return rootIDs; + } + + public void readUnitRevisions(IDBStoreAccessor accessor, IView view, CDOID rootID, CDORevisionHandler revisionHandler) + { + IDBStore store = mappingStrategy.getStore(); + IIDHandler idHandler = store.getIDHandler(); + IMetaDataManager metaDataManager = store.getMetaDataManager(); + + IDBConnection connection = accessor.getDBConnection(); + IDBPreparedStatement stmt = connection.prepareStatement(SQL_SELECT_CLASSES, ReuseProbability.HIGH); + int oldFetchSize = -1; + + try + { + idHandler.setCDOID(stmt, 1, rootID); + + oldFetchSize = stmt.getFetchSize(); + stmt.setFetchSize(100000); + ResultSet resultSet = stmt.executeQuery(); + + while (resultSet.next()) + { + CDOID classID = idHandler.getCDOID(resultSet, 1); + EClass eClass = (EClass)metaDataManager.getMetaInstance(classID); + + IClassMappingUnitSupport classMapping = (IClassMappingUnitSupport)mappingStrategy.getClassMapping(eClass); + classMapping.readUnitRevisions(accessor, view, rootID, revisionHandler); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + if (oldFetchSize != -1) + { + try + { + stmt.setFetchSize(oldFetchSize); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + } + + DBUtil.close(stmt); + } + } + + public BatchedStatement initUnit(IDBStoreAccessor accessor, long timeStamp, IView view, CDOID rootID, + CDORevisionHandler revisionHandler, Set<CDOID> initializedIDs) + { + IIDHandler idHandler = mappingStrategy.getStore().getIDHandler(); + IDBConnection connection = accessor.getDBConnection(); + BatchedStatement stmt = DBUtil.batched(connection.prepareStatement(SQL_INSERT_MAPPINGS, ReuseProbability.HIGH), + WRITE_UNIT_MAPPING_BATCH_SIZE); + + try + { + CDORevision revision = view.getRevision(rootID); + + initUnit(stmt, view, rootID, revisionHandler, initializedIDs, timeStamp, idHandler, revision); + return stmt; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + // Don't close the statement; that's done later in finishUnit(). + } + } + + private void initUnit(BatchedStatement stmt, IView view, CDOID rootID, CDORevisionHandler revisionHandler, + Set<CDOID> initializedIDs, long timeStamp, IIDHandler idHandler, CDORevision revision) throws SQLException + { + revisionHandler.handleRevision(revision); + + CDOID id = revision.getID(); + initializedIDs.add(id); + + writeUnitMapping(stmt, rootID, timeStamp, idHandler, id); + + List<CDORevision> children = CDORevisionUtil.getChildRevisions(revision, view, true); + for (CDORevision child : children) + { + initUnit(stmt, view, rootID, revisionHandler, initializedIDs, timeStamp, idHandler, child); + } + } + + public void finishUnit(BatchedStatement stmt, CDOID rootID, List<CDOID> ids, long timeStamp) + { + IDBStore store = mappingStrategy.getStore(); + IIDHandler idHandler = store.getIDHandler(); + Connection connection = null; + + try + { + connection = stmt.getConnection(); + + for (CDOID id : ids) + { + writeUnitMapping(stmt, rootID, timeStamp, idHandler, id); + } + } + catch (SQLException ex) + { + DBUtil.rollbackSilently(connection); + throw new DBException(ex); + } + finally + { + DBUtil.close(stmt); + } + + try + { + connection.commit(); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + } + + public void writeUnitMappings(IDBStoreAccessor accessor, Map<CDOID, CDOID> unitMappings, long timeStamp) + { + IIDHandler idHandler = mappingStrategy.getStore().getIDHandler(); + IDBConnection connection = accessor.getDBConnection(); + BatchedStatement stmt = DBUtil.batched(connection.prepareStatement(SQL_INSERT_MAPPINGS, ReuseProbability.HIGH), + WRITE_UNIT_MAPPING_BATCH_SIZE); + + try + { + for (Entry<CDOID, CDOID> entry : unitMappings.entrySet()) + { + CDOID id = entry.getKey(); + CDOID rootID = entry.getValue(); + writeUnitMapping(stmt, rootID, timeStamp, idHandler, id); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(stmt); + } + } + + private void writeUnitMapping(BatchedStatement stmt, CDOID rootID, long timeStamp, IIDHandler idHandler, CDOID id) + throws SQLException + { + idHandler.setCDOID(stmt, 1, id); + idHandler.setCDOID(stmt, 2, rootID); + // stmt.setLong(3, timeStamp); + stmt.executeUpdate(); + } + + @Override + protected void doActivate() throws Exception + { + super.doActivate(); + + IDBStore store = mappingStrategy.getStore(); + final DBType idType = store.getIDHandler().getDBType(); + final int idLength = store.getIDColumnLength(); + + IDBDatabase database = store.getDatabase(); + table = database.getSchema().getTable(UNITS); + if (table == null) + { + database.updateSchema(new RunnableWithSchema() + { + public void run(IDBSchema schema) + { + table = schema.addTable(UNITS); + table.addField(UNITS_ELEM, idType, idLength, true); + table.addField(UNITS_UNIT, idType, idLength); + // table.addField(UNITS_CREATED, DBType.BIGINT); + table.addIndex(IDBIndex.Type.PRIMARY_KEY, UNITS_ELEM); + table.addIndex(IDBIndex.Type.NON_UNIQUE, UNITS_UNIT); + } + }); + } + } + + @Override + protected void doDeactivate() throws Exception + { + table = null; + super.doDeactivate(); + } +} |