summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Winkler2008-12-01 08:31:34 (EST)
committerStefan Winkler2008-12-01 08:31:34 (EST)
commitfd25da3564204637c89de2dd122c25a2514cde7c (patch)
tree0749820a0ae16a3a68d0eb9c9542993319033ccb
parent11ce3e307043cf537508cb79c09c0b7c41aeeaf4 (diff)
downloadcdo-fd25da3564204637c89de2dd122c25a2514cde7c.zip
cdo-fd25da3564204637c89de2dd122c25a2514cde7c.tar.gz
cdo-fd25da3564204637c89de2dd122c25a2514cde7c.tar.bz2
[249681] [DB] Decrease amount of database queries
https://bugs.eclipse.org/bugs/show_bug.cgi?id=249681
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java9
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java7
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java18
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java199
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java41
6 files changed, 236 insertions, 44 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java
index 46a1d73..befb902 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java
@@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.server.db;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
import org.eclipse.emf.cdo.server.internal.db.jdbc.AbstractJDBCDelegate;
@@ -81,6 +82,14 @@ public interface IJDBCDelegate
public Statement getStatement();
/**
+ * Do any outstanding writes (e.g. execute batches). Called any number of times - but at least once immediately before
+ * commit().
+ *
+ * @see IStoreAccessor#write(org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext, OMMonitor)
+ */
+ public void write(OMMonitor monitor);
+
+ /**
* Do a commit on the JDBC connection.
*/
public void commit(OMMonitor monitor);
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 b4ff25f..6bc7c52 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
@@ -591,6 +591,13 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor
}
@Override
+ public void write(CommitContext context, OMMonitor monitor)
+ {
+ super.write(context, monitor);
+ jdbcDelegate.write(monitor);
+ }
+
+ @Override
protected void doActivate() throws Exception
{
LifecycleUtil.activate(jdbcDelegate);
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java
index d2209dd..91f1b38 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java
@@ -118,6 +118,11 @@ public abstract class AbstractJDBCDelegate extends Lifecycle implements IJDBCDel
}
}
+ public void write(OMMonitor monitor)
+ {
+ // Do nothing
+ }
+
public final void commit(OMMonitor monitor)
{
try
@@ -396,5 +401,4 @@ public abstract class AbstractJDBCDelegate extends Lifecycle implements IJDBCDel
releaseStatement(stmt);
}
}
-
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java
index 2fb3f9c..97c85e0 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java
@@ -62,11 +62,6 @@ public class JDBCPerformanceReporter extends Lifecycle implements IJDBCDelegate
this.delegate = delegate;
}
- public void commit(OMMonitor monitor)
- {
- delegate.commit(monitor);
- }
-
public Connection getConnection()
{
return delegate.getConnection();
@@ -99,6 +94,19 @@ public class JDBCPerformanceReporter extends Lifecycle implements IJDBCDelegate
registerCall("insertReferenceDbId", time);
}
+ public void write(OMMonitor monitor)
+ {
+ long time = System.currentTimeMillis();
+ delegate.write(monitor);
+ time = System.currentTimeMillis() - time;
+ registerCall("write", time);
+ }
+
+ public void commit(OMMonitor monitor)
+ {
+ delegate.commit(monitor);
+ }
+
public void rollback()
{
delegate.rollback();
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java
index a37a50e..d0193ed 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java
@@ -22,6 +22,7 @@ import org.eclipse.emf.cdo.spi.common.InternalCDORevision;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBUtil;
import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.net4j.util.ref.ReferenceValueMap;
@@ -32,6 +33,7 @@ import java.sql.Statement;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
/**
* @author Stefan Winkler
@@ -72,6 +74,11 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
private Map<CacheKey, WrappedPreparedStatement> statementCache = null;
/**
+ * Container for dirty statements. A statement is considered 'dirty', if addBatch was called, but not executeBatch.
+ */
+ private Map<CacheKey, PreparedStatement> dirtyStatements = null;
+
+ /**
* This flag determines, if prepared statements should be cached within this delegate. Its value is guessed in
* {@link #postInitConnection()} based on the fact if the JDBC driver supports pooled statements. If it does, caching
* in the delegate is unnecessary.
@@ -96,10 +103,78 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
}
@Override
+ public void write(OMMonitor monitor)
+ {
+ monitor.begin(dirtyStatements.size() + 1);
+ super.write(monitor.fork(1));
+
+ try
+ {
+ for (Entry<CacheKey, PreparedStatement> entry : dirtyStatements.entrySet())
+ {
+ try
+ {
+ int[] results;
+ results = entry.getValue().executeBatch();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Executing batch for {0} [{1}]", entry.getKey().toString(), entry.getValue());
+ }
+
+ for (int result : results)
+ {
+ checkState(result == 1, "Batch execution did not return '1' for " + entry.getKey().toString());
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException("Batch execution failed for " + entry.getKey().toString() + " [" + entry.getValue()
+ + "]", ex);
+ }
+
+ monitor.worked(1);
+ }
+ }
+ finally
+ {
+ if (!cacheStatements)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Closing prepared statements.");
+ }
+
+ for (PreparedStatement ps : dirtyStatements.values())
+ {
+ DBUtil.close(ps);
+ }
+ }
+ else
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Re-caching prepared statements.");
+ }
+
+ for (Entry<CacheKey, PreparedStatement> entry : dirtyStatements.entrySet())
+ {
+ cacheStatement(entry.getKey(), entry.getValue());
+ }
+ }
+
+ dirtyStatements.clear();
+ monitor.done();
+ }
+ }
+
+ @Override
protected void doActivate() throws Exception
{
super.doActivate();
+ dirtyStatements = new ReferenceValueMap.Strong<CacheKey, PreparedStatement>();
+
switch (cachingEnablement)
{
case ENABLED:
@@ -137,6 +212,12 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
@Override
protected void doBeforeDeactivate() throws Exception
{
+ for (PreparedStatement ps : dirtyStatements.values())
+ {
+ DBUtil.close(ps);
+ }
+
+ dirtyStatements.clear();
if (cacheStatements)
{
for (WrappedPreparedStatement ps : statementCache.values())
@@ -150,6 +231,9 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
super.doBeforeDeactivate();
}
+ /**
+ * Implementation of the hook which is called after selects.
+ */
@Override
protected void releaseStatement(Statement stmt)
{
@@ -174,20 +258,24 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
protected void doInsertAttributes(String tableName, CDORevision rev, List<IAttributeMapping> attributeMappings,
boolean withFullRevisionInfo)
{
+ boolean firstBatch = false;
+
InternalCDORevision revision = (InternalCDORevision)rev;
if (attributeMappings == null)
{
attributeMappings = Collections.emptyList();
}
- PreparedStatement stmt = null;
- if (cacheStatements)
+ PreparedStatement stmt = getDirtyStatement(StmtType.INSERT_ATTRIBUTES, tableName);
+ if (stmt == null && cacheStatements)
{
- stmt = getCachedStatement(StmtType.INSERT_ATTRIBUTES, tableName);
+ firstBatch = true;
+ stmt = getAndRemoveCachedStatement(StmtType.INSERT_ATTRIBUTES, tableName);
}
try
{
+ firstBatch = true;
if (stmt == null)
{
StringBuilder sql = new StringBuilder();
@@ -207,11 +295,6 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
sql.append(")");
stmt = getConnection().prepareStatement(sql.toString());
-
- if (cacheStatements)
- {
- cacheStatement(StmtType.INSERT_ATTRIBUTES, tableName, stmt);
- }
}
int col = 1;
@@ -246,43 +329,40 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
}
}
- stmt.execute();
+ if (firstBatch)
+ {
+ addDirtyStatement(StmtType.INSERT_ATTRIBUTES, tableName, stmt);
+ }
+
+ stmt.addBatch();
}
catch (SQLException e)
{
throw new DBException(e);
}
- finally
- {
- if (!cacheStatements)
- {
- DBUtil.close(stmt);
- }
- }
}
@Override
protected void doInsertReference(String tableName, int dbID, long source, int version, int index, long target)
{
- PreparedStatement stmt = null;
- if (cacheStatements)
+ boolean firstBatch = false;
+
+ PreparedStatement stmt = getDirtyStatement(StmtType.INSERT_REFERENCES, tableName);
+ if (stmt == null && cacheStatements)
{
- stmt = getCachedStatement(StmtType.INSERT_REFERENCES, tableName);
+ firstBatch = true;
+ stmt = getAndRemoveCachedStatement(StmtType.INSERT_REFERENCES, tableName);
}
try
{
if (stmt == null)
{
+ firstBatch = true;
StringBuilder sql = new StringBuilder("INSERT INTO ");
sql.append(tableName);
sql.append(dbID != 0 ? SQL_INSERT_REFERENCE_WITH_DBID : SQL_INSERT_REFERENCE);
stmt = getConnection().prepareStatement(sql.toString());
-
- if (cacheStatements)
- {
- cacheStatement(StmtType.INSERT_REFERENCES, tableName, stmt);
- }
}
int idx = 1;
@@ -300,19 +380,17 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
TRACER.trace(stmt.toString());
}
- stmt.execute();
+ if (firstBatch)
+ {
+ addDirtyStatement(StmtType.INSERT_REFERENCES, tableName, stmt);
+ }
+
+ stmt.addBatch();
}
catch (SQLException e)
{
throw new DBException(e);
}
- finally
- {
- if (!cacheStatements)
- {
- DBUtil.close(stmt);
- }
- }
}
@Override
@@ -535,11 +613,47 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
}
/**
+ * Add a dirty statement to the dirty statements container.
+ */
+ private void addDirtyStatement(StmtType type, String subKey, PreparedStatement stmt)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Adding dirty statement: ({0},{1}) -> {2}", type, subKey, stmt);
+ }
+
+ dirtyStatements.put(new CacheKey(type, subKey), stmt);
+ }
+
+ /**
+ * Query the dirty statements container.
+ *
+ * @return
+ */
+ private PreparedStatement getDirtyStatement(StmtType type, String subKey)
+ {
+ return dirtyStatements.get(CacheKey.useOnce(type, subKey));
+ }
+
+ /**
* Cache a prepared statement.
*/
private void cacheStatement(StmtType type, String subKey, PreparedStatement stmt)
{
- statementCache.put(new CacheKey(type, subKey), new WrappedPreparedStatement(stmt));
+ cacheStatement(new CacheKey(type, subKey), stmt);
+ }
+
+ /**
+ * Cache a prepared statement with given key.
+ */
+ private void cacheStatement(CacheKey key, PreparedStatement stmt)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Adding cached statement: {0} -> {1}", key, stmt);
+ }
+
+ statementCache.put(key, new WrappedPreparedStatement(stmt));
}
/**
@@ -556,7 +670,24 @@ public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate
PreparedStatement stmt = wrapped.getWrappedStatement();
if (TRACER.isEnabled())
{
- TRACER.trace("Using cached statement: " + stmt);
+ TRACER.format("Using cached statement: ({0},{1}) -> {2}", type, subKey, stmt);
+ }
+
+ return stmt;
+ }
+
+ private PreparedStatement getAndRemoveCachedStatement(StmtType type, String subKey)
+ {
+ WrappedPreparedStatement wrapped = statementCache.remove(CacheKey.useOnce(type, subKey));
+ if (wrapped == null)
+ {
+ return null;
+ }
+
+ PreparedStatement stmt = wrapped.unwrapStatement();
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing cached statement: ({0},{1}) -> {2}", type, subKey, stmt);
}
return stmt;
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java
index 7efdcb2..e513e74 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/WrappedPreparedStatement.java
@@ -10,7 +10,13 @@
**************************************************************************/
package org.eclipse.emf.cdo.server.internal.db.jdbc;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
import java.sql.PreparedStatement;
+import java.text.MessageFormat;
/**
* Wrapper for a prepared statement that is cleaned up when it is cached in a WeakReferenceCache and gc'd. Note that
@@ -22,11 +28,17 @@ import java.sql.PreparedStatement;
*/
public class WrappedPreparedStatement
{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, WrappedPreparedStatement.class);
+
private PreparedStatement wrappedStatement = null;
public WrappedPreparedStatement(PreparedStatement ps)
{
wrappedStatement = ps;
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Wrapping Statement: {0}", wrappedStatement);
+ }
}
public PreparedStatement getWrappedStatement()
@@ -34,15 +46,36 @@ public class WrappedPreparedStatement
return wrappedStatement;
}
- @Override
- protected void finalize() throws Throwable
+ public PreparedStatement unwrapStatement()
{
- wrappedStatement.close();
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("UnWrapping Statement: {0}", wrappedStatement);
+ }
+
+ PreparedStatement result = wrappedStatement;
+ wrappedStatement = null;
+ return result;
}
@Override
public String toString()
{
- return "[Wrapped " + wrappedStatement.toString() + "]";
+ return MessageFormat.format("Wrapped[{0}]", wrappedStatement);
+ }
+
+ @Override
+ protected void finalize() throws Throwable
+ {
+ if (wrappedStatement != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Closing statement: {0}", wrappedStatement);
+ }
+
+ DBUtil.close(wrappedStatement);
+ wrappedStatement = null;
+ }
}
}