From 438ab08ce854e83de7b4ef56ee19258520660b85 Mon Sep 17 00:00:00 2001 From: Stefan Winkler Date: Tue, 20 Jul 2010 17:29:36 +0000 Subject: [305962] [DB] Provide a memory sensitive implementation of IObjectTypeCache https://bugs.eclipse.org/bugs/show_bug.cgi?id=305962 --- .../rootfiles/configuration/cdo-server.xml | 8 + .../emf/cdo/server/db/IObjectTypeCache.java | 64 ------ .../emf/cdo/server/db/IObjectTypeMapper.java | 49 +++++ .../cdo/server/db/mapping/IMappingStrategy.java | 14 ++ .../AbstractHorizontalMappingStrategy.java | 61 ++++-- .../horizontal/AbstractObjectTypeMapper.java | 69 ++++++ .../horizontal/DelegatingObjectTypeMapper.java | 133 ++++++++++++ .../HorizontalBranchingClassMapping.java | 2 +- .../db/mapping/horizontal/ObjectTypeCache.java | 241 ++++----------------- .../db/mapping/horizontal/ObjectTypeTable.java | 225 +++++++++++++++++++ 10 files changed, 587 insertions(+), 279 deletions(-) delete mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeMapper.java create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractObjectTypeMapper.java create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java create mode 100644 plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java diff --git a/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml b/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml index 56272de624..c28d860a58 100644 --- a/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml +++ b/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml @@ -27,6 +27,14 @@ + + + diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java deleted file mode 100644 index ae8ed399d8..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2004 - 2010 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 - 271444: [DB] Multiple refactorings bug 271444 - */ -package org.eclipse.emf.cdo.server.db; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.model.CDOClassifierRef; -import org.eclipse.emf.cdo.common.protocol.CDODataInput; -import org.eclipse.emf.cdo.common.protocol.CDODataOutput; - -import org.eclipse.emf.ecore.EClass; - -import java.io.IOException; -import java.sql.Connection; - -/** - * @author Eike Stepper - */ -public interface IObjectTypeCache -{ - /** - * @since 2.0 - */ - public CDOClassifierRef getObjectType(IDBStoreAccessor accessor, CDOID id); - - /** - * @since 3.0 - */ - public void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type); - - /** - * @since 2.0 - */ - public void removeObjectType(IDBStoreAccessor accessor, CDOID id); - - /** - * Return the maximum object id managed by this cache. - * - * @param connection - * the DB connection to use. - * @return the maximum object ID. - * @since 3.0 - */ - public long getMaxID(Connection connection); - - /** - * @since 3.0 - */ - public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) - throws IOException; - - /** - * @since 3.0 - */ - public void rawImport(Connection connection, CDODataInput in) throws IOException; -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeMapper.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeMapper.java new file mode 100644 index 0000000000..2d3e425276 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeMapper.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2004 - 2010 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 - 271444: [DB] Multiple refactorings bug 271444 + */ +package org.eclipse.emf.cdo.server.db; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; + +import org.eclipse.emf.ecore.EClass; + +import java.io.IOException; +import java.sql.Connection; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public interface IObjectTypeMapper +{ + public CDOClassifierRef getObjectType(IDBStoreAccessor accessor, CDOID id); + + public void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type); + + public void removeObjectType(IDBStoreAccessor accessor, CDOID id); + + /** + * Return the maximum object id managed by this cache. + * + * @param connection + * the DB connection to use. + * @return the maximum object ID. + */ + public long getMaxID(Connection connection); + + public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) + throws IOException; + + public void rawImport(Connection connection, CDODataInput in) throws IOException; +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java index 2b09deabda..427c2287cd 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java @@ -82,6 +82,20 @@ public interface IMappingStrategy */ public static final String PROP_FORCE_NAMES_WITH_ID = "forceNamesWithID"; //$NON-NLS-1$ + /** + * Name of the integer property that configures the size of the object type in-memory cache. Possible configuration + * values are: + *
    + *
  • 0 (zero). Don't use memory caching. + *
  • >0. Use memory caching with the cache size given. + *
+ * Default is a memory cache size of 10,000,000. + *

+ * + * @since 4.0 + */ + public static final String PROP_OBJECT_TYPE_CACHE_SIZE = "objectTypeCacheSize"; //$NON-NLS-1$ + /** * @return the store, this MappingStrategy instance belongs to. */ 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 61d1569278..8c9ce196ff 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 @@ -22,7 +22,7 @@ import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IObjectTypeCache; +import org.eclipse.emf.cdo.server.db.IObjectTypeMapper; import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; import org.eclipse.emf.cdo.server.db.mapping.IListMapping; import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; @@ -62,24 +62,24 @@ public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingS private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractHorizontalMappingStrategy.class); /** - * The associated object type cache. + * The associated object type mapper. */ - private IObjectTypeCache objectTypeCache; + private IObjectTypeMapper objectTypeMapper; public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id) { - return objectTypeCache.getObjectType(accessor, id); + return objectTypeMapper.getObjectType(accessor, id); } public void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type) { - objectTypeCache.putObjectType(accessor, timeStamp, id, type); + objectTypeMapper.putObjectType(accessor, timeStamp, id, type); } public long[] repairAfterCrash(IDBAdapter dbAdapter, Connection connection) { long minLocalID = getMinLocalID(connection); - long maxID = objectTypeCache.getMaxID(connection); + long maxID = objectTypeMapper.getMaxID(connection); long[] result = { minLocalID, maxID }; return result; @@ -173,7 +173,7 @@ public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingS } out.writeBoolean(false); - objectTypeCache.rawExport(connection, out, fromCommitTime, toCommitTime); + objectTypeMapper.rawExport(connection, out, fromCommitTime, toCommitTime); } protected void rawExportList(CDODataOutput out, Connection connection, IListMapping listMapping, IDBTable attrTable, @@ -211,7 +211,7 @@ public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingS } } - objectTypeCache.rawImport(connection, in); + objectTypeMapper.rawImport(connection, in); } protected void rawImportReviseOldRevisions(Connection connection, IDBTable table) @@ -242,28 +242,59 @@ public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingS protected void doActivate() throws Exception { super.doActivate(); - if (objectTypeCache == null) + if (objectTypeMapper == null) { - objectTypeCache = createObjectTypeCache(); - LifecycleUtil.activate(objectTypeCache); + objectTypeMapper = createObjectTypeMapper(); + LifecycleUtil.activate(objectTypeMapper); } } @Override protected void doDeactivate() throws Exception { - LifecycleUtil.deactivate(objectTypeCache); - objectTypeCache = null; + LifecycleUtil.deactivate(objectTypeMapper); + objectTypeMapper = null; super.doDeactivate(); } - private IObjectTypeCache createObjectTypeCache() + private IObjectTypeMapper createObjectTypeMapper() { - ObjectTypeCache cache = new ObjectTypeCache(); + ObjectTypeTable table = new ObjectTypeTable(); + table.setMappingStrategy(this); + + int cacheSize = getObjectTypeCacheSize(); + if (cacheSize == 0) + { + return table; + } + + ObjectTypeCache cache = new ObjectTypeCache(cacheSize); cache.setMappingStrategy(this); + cache.setDelegate(table); return cache; } + private int getObjectTypeCacheSize() + { + int objectTypeCacheSize = ObjectTypeCache.DEFAULT_CACHE_CAPACITY; + + Object value = getProperties().get(PROP_OBJECT_TYPE_CACHE_SIZE); + if (value != null) + { + try + { + int intValue = Integer.parseInt((String)value); + objectTypeCacheSize = intValue; + } + catch (NumberFormatException e) + { + OM.LOG.warn("Malformed configuration option for object type cache size. Using default."); + } + } + + return objectTypeCacheSize; + } + /** * This is an intermediate implementation. It should be changed after classmappings support a general way to implement * queries ... diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractObjectTypeMapper.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractObjectTypeMapper.java new file mode 100644 index 0000000000..9e3b4d8090 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractObjectTypeMapper.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2004 - 2010 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.server.db.IMetaDataManager; +import org.eclipse.emf.cdo.server.db.IObjectTypeMapper; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; + +import org.eclipse.net4j.util.lifecycle.Lifecycle; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public abstract class AbstractObjectTypeMapper extends Lifecycle implements IObjectTypeMapper +{ + private IMappingStrategy mappingStrategy; + + private IMetaDataManager metaDataManager; + + public AbstractObjectTypeMapper() + { + } + + public IMappingStrategy getMappingStrategy() + { + return mappingStrategy; + } + + public void setMappingStrategy(IMappingStrategy mappingStrategy) + { + this.mappingStrategy = mappingStrategy; + } + + public IMetaDataManager getMetaDataManager() + { + return metaDataManager; + } + + @Override + protected void doBeforeActivate() throws Exception + { + super.doBeforeActivate(); + checkState(mappingStrategy, "mappingStrategy"); //$NON-NLS-1$ + } + + @Override + protected void doActivate() throws Exception + { + metaDataManager = getMappingStrategy().getStore().getMetaDataManager(); + } + + @Override + protected void doDeactivate() throws Exception + { + metaDataManager = null; + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java new file mode 100644 index 0000000000..14c09c96a8 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2004 - 2010 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.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IObjectTypeMapper; + +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; + +import org.eclipse.emf.ecore.EClass; + +import java.io.IOException; +import java.sql.Connection; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public abstract class DelegatingObjectTypeMapper extends AbstractObjectTypeMapper +{ + public static final int DEFAULT_CACHE_CAPACITY = 10000000; + + private IObjectTypeMapper delegate; + + public DelegatingObjectTypeMapper() + { + } + + public IObjectTypeMapper getDelegate() + { + return delegate; + } + + public void setDelegate(IObjectTypeMapper delegate) + { + this.delegate = delegate; + } + + public CDOClassifierRef getObjectType(IDBStoreAccessor accessor, CDOID id) + { + long longId = CDOIDUtil.getLong(id); + Long type = doGetObjectType(longId); + if (type != null) + { + long classID = type; + EClass eClass = (EClass)getMetaDataManager().getMetaInstance(classID); + return new CDOClassifierRef(eClass); + } + + return delegate.getObjectType(accessor, id); + } + + public void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type) + { + long longId = CDOIDUtil.getLong(id); + long classID = getMetaDataManager().getMetaID(type); + doPutObjectType(longId, classID); + + delegate.putObjectType(accessor, timeStamp, id, type); + } + + public void removeObjectType(IDBStoreAccessor accessor, CDOID id) + { + long longId = CDOIDUtil.getLong(id); + doRemoveObjectType(longId); + + delegate.removeObjectType(accessor, id); + } + + public long getMaxID(Connection connection) + { + Long maxID = doGetMaxID(); + if (maxID != null) + { + return maxID; + } + + return delegate.getMaxID(connection); + } + + public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) + throws IOException + { + delegate.rawExport(connection, out, fromCommitTime, toCommitTime); + } + + public void rawImport(Connection connection, CDODataInput in) throws IOException + { + delegate.rawImport(connection, in); + } + + @Override + protected void doBeforeActivate() throws Exception + { + super.doBeforeActivate(); + checkState(delegate, "delegate"); + } + + @Override + protected void doActivate() throws Exception + { + super.doActivate(); + LifecycleUtil.activate(delegate); + } + + @Override + protected void doDeactivate() throws Exception + { + LifecycleUtil.deactivate(delegate); + super.doDeactivate(); + } + + protected abstract Long doGetObjectType(long id); + + protected abstract void doPutObjectType(long id, long type); + + protected abstract void doRemoveObjectType(long id); + + protected abstract Long doGetMaxID(); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java index 8d19c3213f..8cd4d6a00e 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java @@ -590,7 +590,7 @@ public class HorizontalBranchingClassMapping extends AbstractHorizontalClassMapp CDOID id = revision.getID(); if (accessor.isNewObject(id)) { - // put new objects into objectTypeCache + // put new objects into objectTypeMapper long timeStamp = revision.getTimeStamp(); HorizontalBranchingMappingStrategy mappingStrategy = (HorizontalBranchingMappingStrategy)getMappingStrategy(); mappingStrategy.putObjectType(accessor, timeStamp, id, getEClass()); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java index e160bd376d..9b37195972 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java @@ -7,244 +7,87 @@ * * 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.id.CDOIDUtil; -import org.eclipse.emf.cdo.common.model.CDOClassifierRef; -import org.eclipse.emf.cdo.common.protocol.CDODataInput; -import org.eclipse.emf.cdo.common.protocol.CDODataOutput; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IMetaDataManager; -import org.eclipse.emf.cdo.server.db.IObjectTypeCache; -import org.eclipse.emf.cdo.server.db.IPreparedStatementCache; -import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; -import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; -import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.DBType; -import org.eclipse.net4j.db.DBUtil; -import org.eclipse.net4j.db.IDBAdapter; -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.util.lifecycle.Lifecycle; -import org.eclipse.net4j.util.lifecycle.LifecycleUtil; - -import org.eclipse.emf.ecore.EClass; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; /** * @author Eike Stepper - * @since 2.0 + * @since 4.0 */ -public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache +public class ObjectTypeCache extends DelegatingObjectTypeMapper { - private static final String SQL_STATE_UNIQUE_KEY_VIOLATION = "23001"; - - private IMappingStrategy mappingStrategy; - - private IDBTable table; - - private IDBField idField; - - private IDBField typeField; - - private IDBField timeField; - - private String sqlDelete; + public static final int DEFAULT_CACHE_CAPACITY = 10000000; - private String sqlInsert; + private Map memoryCache; - private String sqlSelect; + private int cacheSize; - private IMetaDataManager metaDataManager; - - public ObjectTypeCache() - { - } - - public IMappingStrategy getMappingStrategy() + public ObjectTypeCache(int cacheSize) { - return mappingStrategy; + this.cacheSize = cacheSize; } - public void setMappingStrategy(IMappingStrategy mappingStrategy) + @Override + protected Long doGetObjectType(long id) { - this.mappingStrategy = mappingStrategy; + return memoryCache.get(id); } - public final CDOClassifierRef getObjectType(IDBStoreAccessor accessor, CDOID id) - { - IPreparedStatementCache statementCache = accessor.getStatementCache(); - PreparedStatement stmt = null; - - try - { - stmt = statementCache.getPreparedStatement(sqlSelect, ReuseProbability.MAX); - stmt.setLong(1, CDOIDUtil.getLong(id)); - DBUtil.trace(stmt.toString()); - ResultSet resultSet = stmt.executeQuery(); - - if (!resultSet.next()) - { - DBUtil.trace("ClassID for CDOID " + id + " not found"); //$NON-NLS-1$ //$NON-NLS-2$ - return null; - } - - long classID = resultSet.getLong(1); - EClass eClass = (EClass)metaDataManager.getMetaInstance(classID); - return new CDOClassifierRef(eClass); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - statementCache.releasePreparedStatement(stmt); - } - } - - public final void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type) - { - PreparedStatement stmt = null; - - try - { - stmt = accessor.getStatementCache().getPreparedStatement(sqlInsert, ReuseProbability.MAX); - stmt.setLong(1, CDOIDUtil.getLong(id)); - stmt.setLong(2, metaDataManager.getMetaID(type)); - stmt.setLong(3, timeStamp); - DBUtil.trace(stmt.toString()); - int result = stmt.executeUpdate(); - - if (result != 1) - { - throw new DBException("Object type could not be inserted: " + id); //$NON-NLS-1$ - } - } - catch (SQLException ex) - { - // Unique key violation can occur in rare cases (merging new objects from other branches) - if (!SQL_STATE_UNIQUE_KEY_VIOLATION.equals(ex.getSQLState())) - { - throw new DBException(ex); - } - } - finally - { - accessor.getStatementCache().releasePreparedStatement(stmt); - } - } - - public final void removeObjectType(IDBStoreAccessor accessor, CDOID id) + @Override + protected void doPutObjectType(long id, long type) { - PreparedStatement stmt = null; - - try - { - stmt = accessor.getStatementCache().getPreparedStatement(sqlDelete, ReuseProbability.MAX); - stmt.setLong(1, CDOIDUtil.getLong(id)); - DBUtil.trace(stmt.toString()); - int result = stmt.executeUpdate(); - - if (result != 1) - { - throw new DBException("Object type could not be deleted: " + id); //$NON-NLS-1$ - } - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - accessor.getStatementCache().releasePreparedStatement(stmt); - } + memoryCache.put(id, type); } - public long getMaxID(Connection connection) + @Override + protected void doRemoveObjectType(long id) { - return DBUtil.selectMaximumLong(connection, idField); + memoryCache.remove(id); } - public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) - throws IOException + @Override + protected Long doGetMaxID() { - String where = " WHERE " + timeField + " BETWEEN " + fromCommitTime + " AND " + toCommitTime; - DBUtil.serializeTable(out, connection, table, null, where); + return null; } - public void rawImport(Connection connection, CDODataInput in) throws IOException + @Override + protected void doActivate() throws Exception { - DBUtil.deserializeTable(in, connection, table); + super.doActivate(); + memoryCache = Collections.synchronizedMap(new MemoryCache(cacheSize)); } @Override - protected void doBeforeActivate() throws Exception + protected void doDeactivate() throws Exception { - super.doBeforeActivate(); - checkState(mappingStrategy, "mappingStrategy"); //$NON-NLS-1$ + memoryCache = null; + super.doDeactivate(); } - @Override - protected void doActivate() throws Exception + /** + * @author Stefan Winkler + */ + private static final class MemoryCache extends LinkedHashMap { - metaDataManager = getMappingStrategy().getStore().getMetaDataManager(); - - IDBSchema schema = mappingStrategy.getStore().getDBSchema(); - table = schema.addTable(CDODBSchema.CDO_OBJECTS); - idField = table.addField(CDODBSchema.ATTRIBUTES_ID, DBType.BIGINT); - typeField = table.addField(CDODBSchema.ATTRIBUTES_CLASS, DBType.BIGINT); - timeField = table.addField(CDODBSchema.ATTRIBUTES_CREATED, DBType.BIGINT); - table.addIndex(IDBIndex.Type.UNIQUE, idField); + private static final long serialVersionUID = 1L; - IDBStoreAccessor writer = getMappingStrategy().getStore().getWriter(null); - Connection connection = writer.getConnection(); - IDBAdapter dbAdapter = mappingStrategy.getStore().getDBAdapter(); + private int capacity; - Statement statement = null; - try - { - statement = connection.createStatement(); - dbAdapter.createTable(table, statement); - connection.commit(); - } - catch (SQLException ex) + public MemoryCache(int capacity) { - connection.rollback(); - throw new DBException(ex); + super(capacity, 0.75f, true); + this.capacity = capacity; } - finally + + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { - DBUtil.close(statement); - LifecycleUtil.deactivate(writer); // Don't let the null-context accessor go to the pool! + return size() > capacity; } - - sqlSelect = "SELECT " + typeField + " FROM " + table + " WHERE " + idField + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - sqlInsert = "INSERT INTO " + table + "(" + idField + "," + typeField + "," + timeField + ") VALUES (?, ?, ?)"; - sqlDelete = "DELETE FROM " + table + " WHERE " + idField + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - @Override - protected void doDeactivate() throws Exception - { - table = null; - idField = null; - typeField = null; - super.doDeactivate(); } } 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 new file mode 100644 index 0000000000..5a32ef6638 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java @@ -0,0 +1,225 @@ +/** + * Copyright (c) 2004 - 2010 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.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.IDBAdapter; +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.util.lifecycle.LifecycleUtil; + +import org.eclipse.emf.ecore.EClass; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public class ObjectTypeTable extends AbstractObjectTypeMapper +{ + private static final String SQL_STATE_UNIQUE_KEY_VIOLATION = "23001"; + + private IDBTable table; + + private IDBField idField; + + private IDBField typeField; + + private IDBField timeField; + + private String sqlDelete; + + private String sqlInsert; + + private String sqlSelect; + + public ObjectTypeTable() + { + } + + public final CDOClassifierRef getObjectType(IDBStoreAccessor accessor, CDOID id) + { + IPreparedStatementCache statementCache = accessor.getStatementCache(); + PreparedStatement stmt = null; + + try + { + stmt = statementCache.getPreparedStatement(sqlSelect, ReuseProbability.MAX); + stmt.setLong(1, CDOIDUtil.getLong(id)); + DBUtil.trace(stmt.toString()); + ResultSet resultSet = stmt.executeQuery(); + + if (!resultSet.next()) + { + DBUtil.trace("ClassID for CDOID " + id + " not found"); //$NON-NLS-1$ //$NON-NLS-2$ + return null; + } + + long classID = resultSet.getLong(1); + EClass eClass = (EClass)getMetaDataManager().getMetaInstance(classID); + return new CDOClassifierRef(eClass); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + statementCache.releasePreparedStatement(stmt); + } + } + + public final void putObjectType(IDBStoreAccessor accessor, long timeStamp, CDOID id, EClass type) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlInsert, ReuseProbability.MAX); + stmt.setLong(1, CDOIDUtil.getLong(id)); + stmt.setLong(2, getMetaDataManager().getMetaID(type)); + stmt.setLong(3, timeStamp); + DBUtil.trace(stmt.toString()); + int result = stmt.executeUpdate(); + + if (result != 1) + { + throw new DBException("Object type could not be inserted: " + id); //$NON-NLS-1$ + } + } + catch (SQLException ex) + { + // Unique key violation can occur in rare cases (merging new objects from other branches) + if (!SQL_STATE_UNIQUE_KEY_VIOLATION.equals(ex.getSQLState())) + { + throw new DBException(ex); + } + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + public final void removeObjectType(IDBStoreAccessor accessor, CDOID id) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlDelete, ReuseProbability.MAX); + stmt.setLong(1, CDOIDUtil.getLong(id)); + DBUtil.trace(stmt.toString()); + int result = stmt.executeUpdate(); + + if (result != 1) + { + throw new DBException("Object type could not be deleted: " + id); //$NON-NLS-1$ + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + public long getMaxID(Connection connection) + { + return DBUtil.selectMaximumLong(connection, idField); + } + + public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) + throws IOException + { + String where = " WHERE " + timeField + " BETWEEN " + fromCommitTime + " AND " + toCommitTime; + DBUtil.serializeTable(out, connection, table, null, where); + } + + public void rawImport(Connection connection, CDODataInput in) throws IOException + { + DBUtil.deserializeTable(in, connection, table); + } + + @Override + protected void doActivate() throws Exception + { + super.doActivate(); + + IDBSchema schema = getMappingStrategy().getStore().getDBSchema(); + table = schema.addTable(CDODBSchema.CDO_OBJECTS); + idField = table.addField(CDODBSchema.ATTRIBUTES_ID, DBType.BIGINT); + typeField = table.addField(CDODBSchema.ATTRIBUTES_CLASS, DBType.BIGINT); + timeField = table.addField(CDODBSchema.ATTRIBUTES_CREATED, DBType.BIGINT); + table.addIndex(IDBIndex.Type.UNIQUE, idField); + + IDBStoreAccessor writer = getMappingStrategy().getStore().getWriter(null); + Connection connection = writer.getConnection(); + IDBAdapter dbAdapter = getMappingStrategy().getStore().getDBAdapter(); + + Statement statement = null; + try + { + statement = connection.createStatement(); + dbAdapter.createTable(table, statement); + connection.commit(); + } + catch (SQLException ex) + { + connection.rollback(); + throw new DBException(ex); + } + finally + { + DBUtil.close(statement); + LifecycleUtil.deactivate(writer); // Don't let the null-context accessor go to the pool! + } + + sqlSelect = "SELECT " + typeField + " FROM " + table + " WHERE " + idField + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + sqlInsert = "INSERT INTO " + table + "(" + idField + "," + typeField + "," + timeField + ") VALUES (?, ?, ?)"; + sqlDelete = "DELETE FROM " + table + " WHERE " + idField + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + @Override + protected void doDeactivate() throws Exception + { + table = null; + idField = null; + typeField = null; + super.doDeactivate(); + } +} -- cgit v1.2.3