[Mulgara-svn] r520 - branches/nw-interface/src/jar/itql/java/org/mulgara/itql
pag at mulgara.org
pag at mulgara.org
Tue Nov 6 21:45:44 UTC 2007
Author: pag
Date: 2007-11-06 15:45:44 -0600 (Tue, 06 Nov 2007)
New Revision: 520
Modified:
branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlAutoInterpreter.java
Log:
Added a lot of state management to handle entering and leaving transactions correctly, and committing and rolling back while there.
Modified: branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlAutoInterpreter.java
===================================================================
--- branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlAutoInterpreter.java 2007-11-06 21:42:26 UTC (rev 519)
+++ branches/nw-interface/src/jar/itql/java/org/mulgara/itql/TqlAutoInterpreter.java 2007-11-06 21:45:44 UTC (rev 520)
@@ -109,7 +109,7 @@
// set up a connection, if required
Connection conn = establishConnection(cmd);
handleResult(cmd.execute(conn), cmd);
- updateOnConnectionState(conn);
+ updateConnectionsForTx(conn, cmd);
lastMessage = cmd.getResultMessage();
} catch (Exception e) {
lastException = e;
@@ -143,12 +143,14 @@
/**
* Perform any actions required on the update of the state of a connection.
+ * Most commands will skip through this method. Only transaction commands do anything.
* @param conn The connection whose state needs checking.
* @throws QueryException Can be caused by a failed change into a transaction.
*/
- void updateOnConnectionState(Connection conn) throws QueryException {
- // check if the transaction state changed.
+ void updateConnectionsForTx(Connection conn, Command cmd) throws QueryException {
+ // check if the transaction state changed. This will happen for setAutocommit operations.
if (inTransaction == conn.getAutoCommit()) {
+ assert cmd instanceof org.mulgara.query.operation.SetAutoCommit;
// update the client state
inTransaction = !conn.getAutoCommit();
if (inTransaction) {
@@ -159,6 +161,9 @@
for (Connection c: transConnections) c.setAutoCommit(true);
transConnections.clear();
}
+ } else if (cmd.isTxOperation()) {
+ // this is a commit or rollback. Inform every connection we've used in this transaction.
+ operateOnTxConnections(cmd);
}
}
@@ -177,6 +182,7 @@
* Close any resources that are still in use.
*/
public void close() {
+ transConnections.clear();
connectionFactory.closeAll();
}
@@ -214,35 +220,48 @@
private Connection establishConnection(Command cmd) throws ConnectionException, QueryException {
URI serverUri = cmd.getServerURI();
- if (serverUri == null && cmd.isLocalOperation()) {
+ // check for server operations where we don't know the server
+ if (serverUri == null && !cmd.isLocalOperation()) {
// no server URI, but not local. Get a connection for a null URI
+ // eg. select .... from <file:///...>
Connection connection = connectionFactory.newConnection(serverUri);
configureForTransaction(connection);
return connection;
}
- return establishConnection(cmd.getServerURI());
+ // go the normal route for getting a connection for a given server location
+ return establishConnection(serverUri);
}
+
/**
* Returns a connection to the server with the given URI.
* NB: Not for general use. Available to ItqlInterpreterBean only to support
* legacy requests to get a session.
- * @param serverUri The URI for the server to get a connection to.
+ * @param serverUri The URI for the server to get a connection to. <code>null</code> for
+ * Local operations that do not require a server.
* @return A connection to the server, cached if available.
* @throws ConnectionException It was not possible to create a connection to the described server.
* @throws QueryException There is a transaction underway, but the new connection cannot turn off autocommit.
*/
Connection establishConnection(URI serverUri) throws ConnectionException, QueryException {
+ // get a new connection, or use the local one for non-server operations
Connection connection = (serverUri == null) ? localStateConnection : connectionFactory.newConnection(serverUri);
+ // update the connection if it needs to enter a current transaction
configureForTransaction(connection);
return connection;
}
+ /**
+ * Set up the given connection for a current transaction, if one is active at the moment.
+ * @param connection The connection to configure. The dummy connection is not configured.
+ * @throws QueryException An error while setting up the connection for the transaction.
+ */
private void configureForTransaction(Connection connection) throws QueryException {
// If in a transaction, turn off autocommit - ignore the dummy connection
if (inTransaction && connection.getAutoCommit() && connection != localStateConnection) {
+ assert !(connection instanceof DummyConnection);
connection.setAutoCommit(false);
assert !transConnections.contains(connection);
transConnections.add(connection);
@@ -290,7 +309,7 @@
/**
- * Commits all connections that started on a transaction. This oeprates directly
+ * Commits all connections that started on a transaction. This operates directly
* on all known transacted connections.
* @deprecated This is only for manual transactions managed from ItqlInterpreterBean.
* @throws QueryException One of the connections could not be successfully committed.
@@ -323,7 +342,38 @@
}
}
+
/**
+ * This method wraps the simple loop of applying a command to all transaction connections.
+ * The wrapping is done to attempt the operation on all connections, despite exceptions
+ * being thrown.
+ * @param cmd The operation to execute on the transaction connections.
+ * @throws QueryException If there was an error applying the operation. If multiple
+ * errors occur, then this will be the first one.
+ */
+ private void operateOnTxConnections(Command cmd) throws QueryException {
+ // used to record the first exception, if there is one.
+ QueryException qe = null;
+
+ // perform operation on all transaction connections. Catch and log exceptions.
+ for (Connection c: transConnections) {
+ try {
+ cmd.execute(c);
+ } catch (QueryException e) {
+ if (qe == null) qe = e;
+ else logger.error("Discarding subsequent exception during operation: " + cmd.getClass().getSimpleName(), e);
+ } catch (Exception e) {
+ String opName = cmd.getClass().getSimpleName();
+ if (qe == null) qe = new QueryException("Unexpected exception during " + opName, e);
+ else logger.error("Discarding subsequent unexpected exception during operation: " + cmd.getClass().getSimpleName(), e);
+ }
+ }
+ // if an exception was recorded, then throw it
+ if (qe != null) throw qe;
+ }
+
+
+ /**
* Enumerates a set of operations that can be performed to end a transaction.
*/
private enum TxEndOp {
@@ -343,13 +393,13 @@
*/
private void handleEndOfTx(TxEndOp op) throws QueryException {
if (inTransaction) {
- // Commit all outstanding transactions.
+ // Operate on all outstanding transactions.
Iterator<Connection> c = transConnections.iterator();
while (c.hasNext()) {
Session s = c.next().getSession();
if (s != null) op.execute(s);
else logger.warn("Found transaction on a connection with no session.");
- // now get rid of the commited connection
+ // now get rid of the commited/rolled-back connection
c.remove();
}
// will only get here once all connections were successfully processed.
More information about the Mulgara-svn
mailing list