Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_534438_Test.java70
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBConnection.java70
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java12
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java22
5 files changed, 167 insertions, 12 deletions
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 d56e94911c..ab3396f098 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
@@ -77,6 +77,11 @@ public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingS
{
}
+ public IObjectTypeMapper getObjectTypeMapper()
+ {
+ return objectTypeMapper;
+ }
+
public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id)
{
return objectTypeMapper.getObjectType(accessor, id);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_534438_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_534438_Test.java
new file mode 100644
index 0000000000..837d2ad32b
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_534438_Test.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.server.internal.db.DBStore;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalMappingStrategy;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.model1.Supplier;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.view.CDOQuery;
+
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+
+import org.eclipse.emf.ecore.resource.Resource;
+
+import java.util.List;
+
+/**
+ * Bug 534438: Too many errors like java.lang.IllegalStateException: SELECT CDO_CLASS FROM CDO_OBJECTS WHERE CDO_ID=? already in cache.
+ *
+ * @author Eike Stepper
+ */
+public class Bugzilla_534438_Test extends AbstractCDOTest
+{
+ public void testDBConnectionUsedByMultipleThreads() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ for (int i = 0; i < 1000; i++)
+ {
+ CDOResource resource = transaction.createResource(getResourcePath("resource-" + i + "-fill.transformation"));
+ resource.getContents().add(getModel1Factory().createSupplier());
+ }
+
+ transaction.commit();
+
+ // Clear revision cache to force ObjectTypeTable to be used.
+ clearCache(getRepository().getRevisionManager());
+
+ // Clear object type cache to force ObjectTypeTable to be used.
+ AbstractHorizontalMappingStrategy mappingStrategy = (AbstractHorizontalMappingStrategy)((DBStore)getRepository().getStore()).getMappingStrategy();
+ LifecycleUtil.deactivate(mappingStrategy.getObjectTypeMapper());
+ LifecycleUtil.activate(mappingStrategy.getObjectTypeMapper());
+
+ CDOQuery query = transaction.createQuery("ocl", "Supplier.allInstances()->select( o | o.oclAsType(ecore::EObject).eResource()."
+ + "oclAsType(eresource::CDOResource).name.endsWith('-fill.transformation'))", getModel1Package().getSupplier());
+
+ List<Supplier> result = query.getResult();
+ msg(result.size());
+
+ for (Supplier supplier : result)
+ {
+ Resource resource = supplier.eResource();
+ resource.delete(null);
+ }
+
+ transaction.commit();
+ }
+}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBConnection.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBConnection.java
index 13e66b454d..1024b9e6a0 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBConnection.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBConnection.java
@@ -18,13 +18,13 @@ import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability;
import org.eclipse.net4j.db.IDBSchemaTransaction;
import org.eclipse.net4j.db.jdbc.DelegatingConnection;
import org.eclipse.net4j.util.CheckUtil;
+import org.eclipse.net4j.util.collection.HashBag;
+import org.eclipse.net4j.util.om.OMPlatform;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
import java.util.TreeMap;
/**
@@ -32,12 +32,16 @@ import java.util.TreeMap;
*/
public final class DBConnection extends DelegatingConnection implements IDBConnection
{
+ private static final boolean VALIDATE_CHECKOUTS = OMPlatform.INSTANCE.isProperty("org.eclipse.net4j.internal.db.DBConnection.VALIDATE_CHECKOUTS");
+
private final TreeMap<String, DBPreparedStatement> cache = new TreeMap<String, DBPreparedStatement>();
- private final Set<DBPreparedStatement> checkOuts = new HashSet<DBPreparedStatement>();
+ private HashBag<DBPreparedStatement> checkOuts;
private final DBDatabase database;
+ private int cacheSize;
+
private int lastTouch;
private boolean closed;
@@ -47,6 +51,11 @@ public final class DBConnection extends DelegatingConnection implements IDBConne
super(delegate);
this.database = database;
+ if (VALIDATE_CHECKOUTS)
+ {
+ checkOuts = new HashBag<DBPreparedStatement>();
+ }
+
try
{
delegate.setAutoCommit(false);
@@ -141,8 +150,22 @@ public final class DBConnection extends DelegatingConnection implements IDBConne
throw new DBException(ex);
}
}
+ else
+ {
+ --cacheSize;
- checkOuts.add(preparedStatement);
+ DBPreparedStatement nextCached = preparedStatement.getNextCached();
+ if (nextCached != null)
+ {
+ cache.put(sql, nextCached);
+ preparedStatement.setNextCached(null);
+ }
+ }
+
+ if (VALIDATE_CHECKOUTS)
+ {
+ checkOuts.add(preparedStatement);
+ }
}
return preparedStatement;
@@ -172,19 +195,33 @@ public final class DBConnection extends DelegatingConnection implements IDBConne
synchronized (this)
{
- checkOuts.remove(preparedStatement);
+ if (VALIDATE_CHECKOUTS)
+ {
+ checkOuts.remove(preparedStatement);
+ }
+
preparedStatement.setTouch(++lastTouch);
String sql = preparedStatement.getSQL();
- if (cache.put(sql, preparedStatement) != null)
+ DBPreparedStatement cached = cache.put(sql, preparedStatement);
+ if (cached != null)
{
- throw new IllegalStateException(sql + " already in cache"); //$NON-NLS-1$
+ preparedStatement.setNextCached(cached);
}
- if (cache.size() > database.getStatementCacheCapacity())
+ if (++cacheSize > database.getStatementCacheCapacity())
{
- DBPreparedStatement old = cache.remove(cache.firstKey());
+ String firstKey = cache.firstKey();
+ DBPreparedStatement old = cache.remove(firstKey);
+ DBPreparedStatement nextCached = old.getNextCached();
+
DBUtil.close(old.getDelegate());
+ --cacheSize;
+
+ if (nextCached != null)
+ {
+ cache.put(firstKey, nextCached);
+ }
}
}
}
@@ -198,16 +235,25 @@ public final class DBConnection extends DelegatingConnection implements IDBConne
{
synchronized (this)
{
- CheckUtil.checkState(checkOuts.isEmpty(), "Statements are checked out: " + checkOuts);
+ if (VALIDATE_CHECKOUTS)
+ {
+ CheckUtil.checkState(checkOuts.isEmpty(), "Statements are checked out: " + checkOuts);
+ }
// Close all statements in the cache, then clear the cache.
for (DBPreparedStatement preparedStatement : cache.values())
{
- PreparedStatement delegate = preparedStatement.getDelegate();
- DBUtil.close(delegate);
+ while (preparedStatement != null)
+ {
+ PreparedStatement delegate = preparedStatement.getDelegate();
+ DBUtil.close(delegate);
+
+ preparedStatement = preparedStatement.getNextCached();
+ }
}
cache.clear();
+ cacheSize = 0;
}
}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java
index 19fceabfd1..92252658c4 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java
@@ -30,6 +30,8 @@ public class DBPreparedStatement extends DelegatingPreparedStatement implements
private int touch;
+ private DBPreparedStatement nextCached;
+
public DBPreparedStatement(DBConnection transaction, String sql, ReuseProbability reuseProbability, PreparedStatement delegate)
{
super(delegate, transaction);
@@ -71,6 +73,16 @@ public class DBPreparedStatement extends DelegatingPreparedStatement implements
this.touch = touch;
}
+ public DBPreparedStatement getNextCached()
+ {
+ return nextCached;
+ }
+
+ public void setNextCached(DBPreparedStatement nextCached)
+ {
+ this.nextCached = nextCached;
+ }
+
public int compareTo(IDBPreparedStatement o)
{
int result = reuseProbability.compareTo(o.getReuseProbability());
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
index 3b4814eb8c..ceb96f9f90 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
@@ -226,6 +226,28 @@ public final class ReflectUtil
}
}
+ /**
+ * @since 3.8
+ */
+ public static String dumpThread()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ Thread thread = Thread.currentThread();
+ builder.append(thread);
+ builder.append(StringUtil.NL);
+
+ StackTraceElement[] stackTrace = thread.getStackTrace();
+ for (int i = 2; i < stackTrace.length; i++)
+ {
+ StackTraceElement stackTraceElement = stackTrace[i];
+ builder.append("\tat " + stackTraceElement); //$NON-NLS-1$
+ builder.append(StringUtil.NL);
+ }
+
+ return builder.toString();
+ }
+
public static void printStackTrace(PrintStream out, StackTraceElement[] stackTrace)
{
for (int i = 2; i < stackTrace.length; i++)

Back to the top