[Mulgara-svn] r1061 - branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver
ronald at mulgara.org
ronald at mulgara.org
Mon Jul 7 12:54:27 UTC 2008
Author: ronald
Date: 2008-07-07 05:54:26 -0700 (Mon, 07 Jul 2008)
New Revision: 1061
Modified:
branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java
branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java
branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java
Log:
On session close, interrupt anybody active on the session. This kicks out
waiters for the write-lock, thus preventing a problem under heavy load
where writers are queued up waiting for the lock, and then even though the
client terminates these waiters will each get the write-lock and then hang
around until the transaction timeout kills them, thereby rendering mulgara
useless for updates for an extended period until the queue has been drained.
Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2008-07-07 12:54:19 UTC (rev 1060)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2008-07-07 12:54:26 UTC (rev 1061)
@@ -133,6 +133,7 @@
suite.addTest(new AdvDatabaseSessionUnitTest("testAutoCommitTransactionOps"));
suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitTransactionFailure"));
suite.addTest(new AdvDatabaseSessionUnitTest("testAutoCommitTransactionFailure"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testSessionClose"));
return suite;
}
@@ -1420,11 +1421,65 @@
}
}
-
private static interface TestOp {
public void run(Session session) throws Exception;
}
+ /**
+ * Test session close on still-active session.
+ */
+ public void testSessionClose() {
+ logger.info("Testing sessionClose");
+
+ // test close while waiting for write-lock
+ try {
+ Session session1 = database.newSession();
+ session1.setAutoCommit(false);
+
+ try {
+ final Session session2 = database.newSession();
+
+ Thread t1 = new Thread("closeTest") {
+ public void run() {
+ try {
+ session2.setAutoCommit(false);
+ fail("Acquired write-lock unexpectedly");
+ } catch (QueryException qe) {
+ logger.debug("Caught expected exception", qe);
+ } finally {
+ try {
+ session2.close();
+ } catch (QueryException qe) {
+ logger.debug("Caught expected exception", qe);
+ }
+ }
+ }
+ };
+ t1.start();
+ Thread.sleep(100L); // give thread some time to start and block
+
+ assertTrue("second session should still be active", t1.isAlive());
+
+ session2.close();
+
+ try {
+ t1.join(100L);
+ } catch (InterruptedException ie) {
+ logger.error("wait for thread-termination interrupted", ie);
+ fail(ie);
+ }
+ assertFalse("second session should've terminated", t1.isAlive());
+
+ } finally {
+ logger.debug("Releasing autocommit for session1");
+ session1.setAutoCommit(true);
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
//
// Internal methods
//
Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java 2008-07-07 12:54:19 UTC (rev 1060)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java 2008-07-07 12:54:26 UTC (rev 1061)
@@ -122,6 +122,7 @@
suite.addTest(new ExternalTransactionUnitTest("testInternalSerialMultipleSessions"));
suite.addTest(new ExternalTransactionUnitTest("testTransactionTimeout"));
suite.addTest(new ExternalTransactionUnitTest("testTransactionFailure"));
+ suite.addTest(new ExternalTransactionUnitTest("testSessionClose"));
return suite;
}
@@ -1887,6 +1888,71 @@
public void run(Session session, Xid xid) throws Exception;
}
+
+ /**
+ * Test session close on still-active session.
+ */
+ public void testSessionClose() {
+ logger.info("Testing sessionClose");
+
+ // test close while waiting for write-lock
+ try {
+ Session session1 = database.newSession();
+
+ XAResource resource1 = session1.getXAResource();
+ Xid xid1 = new TestXid(1);
+ resource1.start(xid1, XAResource.TMNOFLAGS);
+
+ try {
+ final Session session2 = database.newSession();
+
+ Thread t1 = new Thread("closeTest") {
+ public void run() {
+ try {
+ XAResource resource2 = session2.getXAResource();
+ Xid xid2 = new TestXid(2);
+ resource2.start(xid2, XAResource.TMNOFLAGS);
+
+ fail("Acquired write-lock unexpectedly");
+ } catch (XAException xae) {
+ logger.debug("Caught expected exception", xae);
+ } catch (QueryException qe) {
+ logger.error("Caught unexpected exception", qe);
+ fail("Caught unexpected exception " + qe);
+ } finally {
+ try {
+ session2.close();
+ } catch (QueryException qe) {
+ logger.debug("Caught expected exception", qe);
+ }
+ }
+ }
+ };
+ t1.start();
+ Thread.sleep(100L); // give thread some time to start and block
+
+ assertTrue("second session should still be active", t1.isAlive());
+
+ session2.close();
+
+ try {
+ t1.join(100L);
+ } catch (InterruptedException ie) {
+ logger.error("wait for thread-termination interrupted", ie);
+ fail(ie);
+ }
+ assertFalse("second session should've terminated", t1.isAlive());
+
+ } finally {
+ logger.debug("closing session1");
+ resource1.end(xid1, XAResource.TMSUCCESS);
+ resource1.commit(xid1, true);
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
//
// Internal methods
//
Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java 2008-07-07 12:54:19 UTC (rev 1060)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java 2008-07-07 12:54:26 UTC (rev 1061)
@@ -203,7 +203,7 @@
}
public void closingSession() throws MulgaraTransactionException {
- acquireMutex(0, MulgaraTransactionException.class);
+ acquireMutexWithInterrupt(0, MulgaraTransactionException.class);
try {
try {
super.closingSession();
Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java 2008-07-07 12:54:19 UTC (rev 1060)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java 2008-07-07 12:54:26 UTC (rev 1061)
@@ -346,7 +346,7 @@
}
public void closingSession() throws MulgaraTransactionException {
- acquireMutex(0, MulgaraTransactionException.class);
+ acquireMutexWithInterrupt(0, MulgaraTransactionException.class);
try {
try {
super.closingSession();
Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java 2008-07-07 12:54:19 UTC (rev 1060)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java 2008-07-07 12:54:26 UTC (rev 1061)
@@ -272,7 +272,7 @@
try {
getMutexLock().wait(wait);
} catch (InterruptedException ie) {
- throw exc.cast(newException(exc, "Interrupted while waiting to acquire lock").initCause(ie));
+ throw newExceptionOrCause(exc, "Interrupted while waiting to acquire lock", ie);
}
}
@@ -282,6 +282,25 @@
}
/**
+ * Acquire the mutex, interrupting the existing holder is there is one.
+ *
+ * @param timeout how many milliseconds to wait for the mutex, or 0 to wait indefinitely
+ * @param T the type of exception to throw on failure
+ * @throws Exception if the mutex could not be acquired, either due to a timeout or due to an
+ * interrupt
+ * @see #acquireMutex
+ */
+ public <T extends Throwable> void acquireMutexWithInterrupt(long timeout, Class<T> exc) throws T {
+ synchronized (getMutexLock()) {
+ if (getMutexHolder() != null && getMutexHolder() != Thread.currentThread()) {
+ getMutexHolder().interrupt();
+ }
+
+ acquireMutex(timeout, exc);
+ }
+ }
+
+ /**
* Release the mutex.
*
* @throws IllegalStateException is the mutex is not held by the current thread
@@ -316,7 +335,7 @@
return mutexHolder;
}
- private static <T> T newException(Class<T> exc, String msg) {
+ private static <T extends Throwable> T newException(Class<T> exc, String msg) {
try {
return exc.getConstructor(String.class).newInstance(msg);
} catch (Exception e) {
@@ -324,6 +343,12 @@
}
}
+ private static <T extends Throwable> T newExceptionOrCause(Class<T> exc, String msg, Throwable cause) {
+ if (exc.isAssignableFrom(cause.getClass()))
+ return exc.cast(cause);
+ return exc.cast(newException(exc, msg).initCause(cause));
+ }
+
private class IdleReaper extends TimerTask {
public IdleReaper(Timer timer, long periodMillis) {
logger.info("Idle-reaper created: " + System.identityHashCode(this));
More information about the Mulgara-svn
mailing list