Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2013-03-06 05:31:46 -0500
committerEike Stepper2013-03-07 08:44:39 -0500
commit4cdc6668f105dc3c1f3be2a679968b9e8c1720b2 (patch)
tree4720cdf8e7a80be9fbc9920fe4ac0f77f405d516
parentcc850b80de62e22e8b567f8d165176b83cbf81fc (diff)
downloadcdo-4cdc6668f105dc3c1f3be2a679968b9e8c1720b2.tar.gz
cdo-4cdc6668f105dc3c1f3be2a679968b9e8c1720b2.tar.xz
cdo-4cdc6668f105dc3c1f3be2a679968b9e8c1720b2.zip
[401763] Make CDO Server more robust against data dictionary changes
https://bugs.eclipse.org/bugs/show_bug.cgi?id=401763
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBDatabase.java3
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBTransaction.java6
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java169
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBTransaction.java62
4 files changed, 205 insertions, 35 deletions
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBDatabase.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBDatabase.java
index a79bf1e563..f1c316eba4 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBDatabase.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBDatabase.java
@@ -11,6 +11,7 @@
package org.eclipse.net4j.db;
import org.eclipse.net4j.db.ddl.IDBSchema;
+import org.eclipse.net4j.util.collection.Closeable;
import org.eclipse.net4j.util.container.IContainer;
/**
@@ -19,7 +20,7 @@ import org.eclipse.net4j.util.container.IContainer;
* @noextend This interface is not intended to be extended by clients.
* @since 4.2
*/
-public interface IDBDatabase extends IContainer<IDBTransaction>
+public interface IDBDatabase extends IContainer<IDBTransaction>, Closeable
{
public static final int DEFAULT_STATEMENT_CACHE_CAPACITY = 200;
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBTransaction.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBTransaction.java
index 5f2e1a3157..42b19fa0f4 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBTransaction.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBTransaction.java
@@ -13,6 +13,8 @@ package org.eclipse.net4j.db;
import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability;
import org.eclipse.net4j.util.collection.Closeable;
+import java.sql.Connection;
+
/**
* @since 4.2
* @author Eike Stepper
@@ -24,7 +26,9 @@ public interface IDBTransaction extends Closeable
{
public IDBDatabase getDatabase();
- public IDBPreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability);
+ public Connection getConnection();
public IDBSchemaTransaction openSchemaTransaction();
+
+ public IDBPreparedStatement prepareStatement(String sql, ReuseProbability reuseProbability);
}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java
index ed44f62b30..4af7eb9d01 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java
@@ -17,10 +17,12 @@ import org.eclipse.net4j.db.IDBDatabase;
import org.eclipse.net4j.db.IDBTransaction;
import org.eclipse.net4j.spi.db.DBAdapter;
import org.eclipse.net4j.spi.db.DBSchema;
+import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.container.SetContainer;
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.LinkedList;
/**
* @author Eike Stepper
@@ -31,19 +33,21 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID
private IDBConnectionProvider connectionProvider;
+ private int statementCacheCapacity = DEFAULT_STATEMENT_CACHE_CAPACITY;
+
private DBSchema schema;
private DBSchemaTransaction schemaTransaction;
- private int statementCacheCapacity = DEFAULT_STATEMENT_CACHE_CAPACITY;
+ private final LinkedList<SchemaAccess> schemaAccessQueue = new LinkedList<SchemaAccess>();
- public DBDatabase(final DBAdapter adapter, IDBConnectionProvider dbConnectionProvider, final String schemaName)
+ public DBDatabase(final DBAdapter adapter, IDBConnectionProvider connectionProvider, final String schemaName)
{
super(IDBTransaction.class);
this.adapter = adapter;
- connectionProvider = dbConnectionProvider;
+ this.connectionProvider = connectionProvider;
- schema = DBUtil.execute(dbConnectionProvider, new RunnableWithConnection<DBSchema>()
+ schema = DBUtil.execute(connectionProvider, new RunnableWithConnection<DBSchema>()
{
public DBSchema run(Connection connection) throws SQLException
{
@@ -52,6 +56,7 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID
});
schema.lock();
+ activate();
}
public DBAdapter getAdapter()
@@ -59,6 +64,21 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID
return adapter;
}
+ public IDBConnectionProvider getConnectionProvider()
+ {
+ return connectionProvider;
+ }
+
+ public int getStatementCacheCapacity()
+ {
+ return statementCacheCapacity;
+ }
+
+ public void setStatementCacheCapacity(int statementCacheCapacity)
+ {
+ this.statementCacheCapacity = statementCacheCapacity;
+ }
+
public DBSchema getSchema()
{
return schema;
@@ -66,6 +86,8 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID
public DBSchemaTransaction openSchemaTransaction()
{
+ beginSchemaAccess(true);
+
DBSchemaTransaction schemaTransaction = new DBSchemaTransaction(this);
this.schemaTransaction = schemaTransaction;
return schemaTransaction;
@@ -73,7 +95,18 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID
public void closeSchemaTransaction()
{
- schemaTransaction = null;
+ try
+ {
+ for (IDBTransaction transaction : getTransactions())
+ {
+ ((DBTransaction)transaction).invalidateStatementCache();
+ }
+ }
+ finally
+ {
+ schemaTransaction = null;
+ endSchemaAccess();
+ }
}
public DBSchemaTransaction getSchemaTransaction()
@@ -81,11 +114,6 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID
return schemaTransaction;
}
- public IDBConnectionProvider getConnectionProvider()
- {
- return connectionProvider;
- }
-
public DBTransaction openTransaction()
{
DBTransaction transaction = new DBTransaction(this);
@@ -103,13 +131,126 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID
return getElements();
}
- public int getStatementCacheCapacity()
+ public boolean isClosed()
{
- return statementCacheCapacity;
+ return !isActive();
}
- public void setStatementCacheCapacity(int statementCacheCapacity)
+ public void close()
+ {
+ deactivate();
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ for (IDBTransaction transaction : getTransactions())
+ {
+ transaction.close();
+ }
+
+ super.doDeactivate();
+ }
+
+ public void beginSchemaAccess(boolean write)
+ {
+ SchemaAccess schemaAccess = null;
+ synchronized (schemaAccessQueue)
+ {
+ if (write)
+ {
+ schemaAccess = new WriteSchemaAccess();
+ schemaAccessQueue.addLast(schemaAccess);
+ }
+ else
+ {
+ if (!schemaAccessQueue.isEmpty())
+ {
+ schemaAccess = schemaAccessQueue.getFirst();
+ if (schemaAccess instanceof ReadSchemaAccess)
+ {
+ ReadSchemaAccess readSchemaAccess = (ReadSchemaAccess)schemaAccess;
+ readSchemaAccess.incrementReaders();
+ }
+ }
+
+ if (schemaAccess == null)
+ {
+ schemaAccess = new ReadSchemaAccess();
+ schemaAccessQueue.addLast(schemaAccess);
+ }
+ }
+ }
+
+ for (;;)
+ {
+ synchronized (schemaAccessQueue)
+ {
+ if (schemaAccessQueue.getFirst() == schemaAccess)
+ {
+ return;
+ }
+
+ try
+ {
+ schemaAccessQueue.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ throw WrappedException.wrap(ex);
+ }
+ }
+ }
+ }
+
+ public void endSchemaAccess()
+ {
+ synchronized (schemaAccessQueue)
+ {
+ SchemaAccess schemaAccess = schemaAccessQueue.getFirst();
+ if (schemaAccess instanceof ReadSchemaAccess)
+ {
+ ReadSchemaAccess readSchemaAccess = (ReadSchemaAccess)schemaAccess;
+ if (readSchemaAccess.decrementReaders())
+ {
+ return;
+ }
+ }
+
+ schemaAccessQueue.removeFirst();
+ schemaAccessQueue.notifyAll();
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public interface SchemaAccess
+ {
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public final class ReadSchemaAccess implements SchemaAccess
+ {
+ private int readers;
+
+ public void incrementReaders()
+ {
+ ++readers;
+ }
+
+ public boolean decrementReaders()
+ {
+ return --readers > 0;
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public final class WriteSchemaAccess implements SchemaAccess
{
- this.statementCacheCapacity = statementCacheCapacity;
}
}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBTransaction.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBTransaction.java
index 1e44b5a670..a8f2309416 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBTransaction.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBTransaction.java
@@ -16,6 +16,7 @@ import org.eclipse.net4j.db.IDBPreparedStatement;
import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability;
import org.eclipse.net4j.db.IDBSchemaTransaction;
import org.eclipse.net4j.db.IDBTransaction;
+import org.eclipse.net4j.util.CheckUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -69,8 +70,17 @@ public final class DBTransaction implements IDBTransaction
return connection;
}
- public IDBPreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability)
+ public IDBSchemaTransaction openSchemaTransaction()
+ {
+ DBSchemaTransaction schemaTransaction = database.openSchemaTransaction();
+ schemaTransaction.setTransaction(this);
+ return schemaTransaction;
+ }
+
+ public IDBPreparedStatement prepareStatement(String sql, ReuseProbability reuseProbability)
{
+ database.beginSchemaAccess(false);
+
DBPreparedStatement preparedStatement = cache.remove(sql);
if (preparedStatement == null)
{
@@ -91,32 +101,46 @@ public final class DBTransaction implements IDBTransaction
public void releasePreparedStatement(DBPreparedStatement preparedStatement)
{
- if (preparedStatement == null)
+ try
{
- // Bug 276926: Silently accept preparedStatement == null and do nothing.
- return;
- }
+ if (preparedStatement == null)
+ {
+ // Bug 276926: Silently accept preparedStatement == null and do nothing.
+ return;
+ }
- checkOuts.remove(preparedStatement);
- preparedStatement.setTouch(++lastTouch);
+ checkOuts.remove(preparedStatement);
+ preparedStatement.setTouch(++lastTouch);
- String sql = preparedStatement.getSQL();
- if (cache.put(sql, preparedStatement) != null)
- {
- throw new IllegalStateException(sql + " already in cache"); //$NON-NLS-1$
- }
+ String sql = preparedStatement.getSQL();
+ if (cache.put(sql, preparedStatement) != null)
+ {
+ throw new IllegalStateException(sql + " already in cache"); //$NON-NLS-1$
+ }
- if (cache.size() > database.getStatementCacheCapacity())
+ if (cache.size() > database.getStatementCacheCapacity())
+ {
+ DBPreparedStatement old = cache.remove(cache.firstKey());
+ DBUtil.close(old.getDelegate());
+ }
+ }
+ finally
{
- DBPreparedStatement old = cache.remove(cache.firstKey());
- DBUtil.close(old.getDelegate());
+ database.endSchemaAccess();
}
}
- public IDBSchemaTransaction openSchemaTransaction()
+ public void invalidateStatementCache()
{
- DBSchemaTransaction schemaTransaction = database.openSchemaTransaction();
- schemaTransaction.setTransaction(this);
- return schemaTransaction;
+ 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);
+ }
+
+ cache.clear();
}
}

Back to the top