[Mulgara-svn] r600 - branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver

andrae at mulgara.org andrae at mulgara.org
Wed Dec 5 10:10:05 UTC 2007


Author: andrae
Date: 2007-12-05 04:10:04 -0600 (Wed, 05 Dec 2007)
New Revision: 600

Modified:
   branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
   branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java
   branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
Log:
Introduces tests of the interaction between internal and external transactions -
and includes a fix for a bug in the internal-rollback logic that was introduced
in the split.

Three sets of tests left before I consider the JTA-branch to be ready for beta.
- Invalid JTA calls (both parameters and state)
- Remote isSameRM()
- end-to-end JOTM.



Modified: branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
===================================================================
--- branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java	2007-12-04 21:41:42 UTC (rev 599)
+++ branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java	2007-12-05 10:10:04 UTC (rev 600)
@@ -113,6 +113,12 @@
     suite.addTest(new ExternalTransactionUnitTest("testExplicitIsolationQuerySingleSession"));
     suite.addTest(new ExternalTransactionUnitTest("testConcurrentExplicitTxn"));
     suite.addTest(new ExternalTransactionUnitTest("testExplicitRollbackIsolationQuery"));
+    suite.addTest(new ExternalTransactionUnitTest("testExternalInternalIsolation"));
+    suite.addTest(new ExternalTransactionUnitTest("testInternalExternalIsolation"));
+    suite.addTest(new ExternalTransactionUnitTest("testInternalExternalConcurrentTxn"));
+    suite.addTest(new ExternalTransactionUnitTest("testExternalInternalConcurrentTxn"));
+    suite.addTest(new ExternalTransactionUnitTest("testInternalExternalConcurrentTxnRollback"));
+    suite.addTest(new ExternalTransactionUnitTest("testExternalInternalConcurrentTxnRollback"));
 
     return suite;
   }
@@ -843,17 +849,17 @@
 
     try {
       Session session = database.newSession();
-      XAResource roResource = session.getReadOnlyXAResource();
-      XAResource rwResource = session.getXAResource();
-      Xid xid1 = new TestXid(1); // Initial create model.
-      Xid xid2 = new TestXid(2); // Started before setModel.
-      Xid xid3 = new TestXid(3); // setModel.
-      Xid xid4 = new TestXid(4); // Started before setModel prepares
-      Xid xid5 = new TestXid(5); // Started before setModel commits
-      Xid xid6 = new TestXid(6); // Started after setModel commits
-      Xid xid7 = new TestXid(7); // Final remove model.
+      try {
+        XAResource roResource = session.getReadOnlyXAResource();
+        XAResource rwResource = session.getXAResource();
+        Xid xid1 = new TestXid(1); // Initial create model.
+        Xid xid2 = new TestXid(2); // Started before setModel.
+        Xid xid3 = new TestXid(3); // setModel.
+        Xid xid4 = new TestXid(4); // Started before setModel prepares
+        Xid xid5 = new TestXid(5); // Started before setModel commits
+        Xid xid6 = new TestXid(6); // Started after setModel commits
+        Xid xid7 = new TestXid(7); // Final remove model.
 
-      try {
         rwResource.start(xid1, XAResource.TMNOFLAGS);
         session.createModel(model3URI, null);
         rwResource.end(xid1, XAResource.TMSUCCESS);
@@ -946,6 +952,146 @@
     }
   }
 
+  public void testExternalInternalIsolation() throws URISyntaxException
+  {
+    logger.info("testExplicitIsolationQuery");
+    URI fileURI  = new File("data/xatest-model1.rdf").toURI();
+
+    try {
+      Session session1 = database.newSession();
+      try {
+        Session session2 = database.newSession();
+        try {
+          XAResource roResource = session1.getReadOnlyXAResource();
+          XAResource rwResource = session1.getXAResource();
+          Xid xid1 = new TestXid(1); // Initial create model.
+          Xid xid2 = new TestXid(2); // Main Test.
+          Xid xid3 = new TestXid(3); // Cleanup test.
+
+          rwResource.start(xid1, XAResource.TMNOFLAGS);
+          session1.createModel(model3URI, null);
+          rwResource.end(xid1, XAResource.TMSUCCESS);
+          rwResource.commit(xid1, true);
+
+          // Nothing visible.
+          assertChangeNotVisible(session2);
+
+          // Perform update
+          rwResource.start(xid2, XAResource.TMNOFLAGS);
+          session1.setModel(model3URI, new ModelResource(fileURI));
+          rwResource.end(xid2, XAResource.TMSUSPEND);
+
+          // Check uncommitted change not visible
+          assertChangeNotVisible(session2);
+
+          // Check micro-commit visible to current-phase
+          rwResource.start(xid2, XAResource.TMRESUME);
+          assertChangeVisible(session1);
+          // Perform prepare
+          rwResource.end(xid2, XAResource.TMSUCCESS);
+          rwResource.prepare(xid2);
+
+          // Check original phase unaffected
+          assertChangeNotVisible(session2);
+
+          // Do commit
+          rwResource.commit(xid2, false);
+
+          // Check committed phase is now updated
+          assertChangeVisible(session2);
+
+          // Cleanup database
+          session2.removeModel(model3URI);
+        } finally {
+          session2.close();
+        }
+      } finally {
+        session1.close();
+      }
+    } catch (Exception e) {
+      fail(e);
+    }
+  }
+
+  public void testInternalExternalIsolation() throws URISyntaxException
+  {
+    logger.info("testExplicitIsolationQuery");
+    URI fileURI  = new File("data/xatest-model1.rdf").toURI();
+
+    try {
+      Session session1 = database.newSession();
+      try {
+        Session session2 = database.newSession();
+        try {
+          XAResource roResource = session2.getReadOnlyXAResource();
+          XAResource rwResource = session2.getXAResource();
+          Xid xid1 = new TestXid(1); // Pre-update
+          Xid xid2 = new TestXid(2); // Post-update/Pre-commit
+          Xid xid3 = new TestXid(3); // Post-commit
+
+          session1.createModel(model3URI, null);
+
+          // Nothing visible.
+          roResource.start(xid1, XAResource.TMNOFLAGS);
+          assertChangeNotVisible(session2);
+          roResource.end(xid1, XAResource.TMSUSPEND);
+
+          // Perform update with autocommit off
+          session1.setAutoCommit(false);
+          session1.setModel(model3URI, new ModelResource(fileURI));
+
+          // Check uncommitted change not visible
+          roResource.start(xid2, XAResource.TMNOFLAGS);
+          assertChangeNotVisible(session2);
+          roResource.end(xid2, XAResource.TMSUSPEND);
+
+          // Check original phase unaffected.
+          roResource.start(xid1, XAResource.TMRESUME);
+          assertChangeNotVisible(session2);
+          roResource.end(xid1, XAResource.TMSUSPEND);
+
+          // Check micro-commit visible to current-phase
+          assertChangeVisible(session1);
+          session1.setAutoCommit(true);
+
+          // Check original phase unaffected
+          roResource.start(xid1, XAResource.TMRESUME);
+          assertChangeNotVisible(session2);
+          roResource.end(xid1, XAResource.TMSUSPEND);
+
+          // Check pre-commit phase unaffected
+          roResource.start(xid2, XAResource.TMRESUME);
+          assertChangeNotVisible(session2);
+          roResource.end(xid2, XAResource.TMSUSPEND);
+
+          // Check committed phase is now updated and write-lock available
+          rwResource.start(xid3, XAResource.TMNOFLAGS);
+          assertChangeVisible(session2);
+          
+          // Check internal transaction read-only
+          assertChangeVisible(session1);
+
+          // Cleanup transactions.
+          rwResource.end(xid3, XAResource.TMSUCCESS);
+          roResource.end(xid2, XAResource.TMSUCCESS);
+          roResource.end(xid1, XAResource.TMSUCCESS);
+          roResource.commit(xid1, true);
+          roResource.commit(xid2, true);
+          rwResource.commit(xid3, true);
+
+          // Cleanup database (check write-lock available again)
+          session1.removeModel(model3URI);
+        } finally {
+          session2.close();
+        }
+      } finally {
+        session1.close();
+      }
+    } catch (Exception e) {
+      fail(e);
+    }
+  }
+
   private void assertChangeVisible(Session session) throws Exception {
     Variable subjectVariable   = new Variable("subject");
     Variable predicateVariable = new Variable("predicate");
@@ -1163,6 +1309,547 @@
     }
   }
 
+  /**
+   * Test two simultaneous transactions, in two threads. The second one should block
+   * until the first one sets auto-commit back to true.
+   */
+  public void testExternalInternalConcurrentTxn() throws URISyntaxException
+  {
+    logger.info("testConcurrentExplicitTxn");
+    URI fileURI  = new File("data/xatest-model1.rdf").toURI();
+
+    try {
+      Session session1 = database.newSession();
+      try {
+        XAResource resource1 = session1.getXAResource();
+        resource1.start(new TestXid(1), XAResource.TMNOFLAGS);
+        session1.createModel(model3URI, null);
+        resource1.end(new TestXid(1), XAResource.TMSUCCESS);
+        resource1.commit(new TestXid(1), true);
+
+        resource1.start(new TestXid(2), XAResource.TMNOFLAGS);
+        session1.setModel(model3URI, new ModelResource(fileURI));
+
+        final boolean[] tx2Started = new boolean[] { false };
+
+        Thread t2 = new Thread("tx2Test") {
+          public void run() {
+            try {
+              Session session2 = database.newSession();
+              try {
+                session2.setAutoCommit(false);
+
+                synchronized (tx2Started) {
+                  tx2Started[0] = true;
+                  tx2Started.notify();
+                }
+
+                Variable subjectVariable   = new Variable("subject");
+                Variable predicateVariable = new Variable("predicate");
+                Variable objectVariable    = new Variable("object");
+
+                List selectList = new ArrayList(3);
+                selectList.add(subjectVariable);
+                selectList.add(predicateVariable);
+                selectList.add(objectVariable);
+
+                // Evaluate the query
+                Answer answer = session2.query(new Query(
+                  selectList,                                       // SELECT
+                  new ModelResource(model3URI),                      // FROM
+                  new ConstraintImpl(subjectVariable,               // WHERE
+                                 predicateVariable,
+                                 objectVariable),
+                  null,                                             // HAVING
+                  Arrays.asList(new Order[] {                       // ORDER BY
+                    new Order(subjectVariable, true),
+                    new Order(predicateVariable, true),
+                    new Order(objectVariable, true)
+                  }),
+                  null,                                             // LIMIT
+                  0,                                                // OFFSET
+                  new UnconstrainedAnswer()                         // GIVEN
+                ));
+
+                String[][] results = {
+                  { "test:s01", "test:p01", "test:o01" },
+                  { "test:s01", "test:p02", "test:o01" },
+                  { "test:s01", "test:p02", "test:o02" },
+                  { "test:s01", "test:p03", "test:o02" },
+                  { "test:s02", "test:p03", "test:o02" },
+                  { "test:s02", "test:p04", "test:o02" },
+                  { "test:s02", "test:p04", "test:o03" },
+                  { "test:s02", "test:p05", "test:o03" },
+                  { "test:s03", "test:p01", "test:o01" },
+                  { "test:s03", "test:p05", "test:o03" },
+                  { "test:s03", "test:p06", "test:o01" },
+                  { "test:s03", "test:p06", "test:o03" },
+                };
+                compareResults(results, answer);
+                answer.close();
+
+                session2.setAutoCommit(true);
+              } finally {
+                session2.close();
+              }
+            } catch (Exception e) {
+              fail(e);
+            }
+          }
+        };
+        t2.start();
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+          }
+          assertFalse("second transaction should still be waiting for write lock", tx2Started[0]);
+        }
+
+        resource1.commit(new TestXid(2), true);
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+            assertTrue("second transaction should've started", tx2Started[0]);
+          }
+        }
+
+        try {
+          t2.join(2000L);
+        } catch (InterruptedException ie) {
+          logger.error("wait for tx2-terminated interrupted", ie);
+          fail(ie);
+        }
+        assertFalse("second transaction should've terminated", t2.isAlive());
+
+        resource1.start(new TestXid(4), XAResource.TMNOFLAGS);
+        session1.removeModel(model3URI);
+        resource1.end(new TestXid(4), XAResource.TMSUCCESS);
+        resource1.commit(new TestXid(4), true);
+
+      } finally {
+        session1.close();
+      }
+    } catch (Exception e) {
+      fail(e);
+    }
+  }
+
+
+  /**
+   * Test two simultaneous transactions, in two threads. The second one should block
+   * until the first one sets auto-commit back to true.
+   */
+  public void testInternalExternalConcurrentTxn() throws URISyntaxException
+  {
+    logger.info("testConcurrentExplicitTxn");
+    URI fileURI  = new File("data/xatest-model1.rdf").toURI();
+
+    try {
+      Session session1 = database.newSession();
+      try {
+        session1.createModel(model3URI, null);
+
+        session1.setAutoCommit(false);
+        session1.setModel(model3URI, new ModelResource(fileURI));
+
+        final boolean[] tx2Started = new boolean[] { false };
+
+        Thread t2 = new Thread("tx2Test") {
+          public void run() {
+            try {
+              Session session2 = database.newSession();
+              try {
+                XAResource resource = session2.getXAResource();
+                resource.start(new TestXid(1), XAResource.TMNOFLAGS);
+
+                synchronized (tx2Started) {
+                  tx2Started[0] = true;
+                  tx2Started.notify();
+                }
+
+                Variable subjectVariable   = new Variable("subject");
+                Variable predicateVariable = new Variable("predicate");
+                Variable objectVariable    = new Variable("object");
+
+                List selectList = new ArrayList(3);
+                selectList.add(subjectVariable);
+                selectList.add(predicateVariable);
+                selectList.add(objectVariable);
+
+                // Evaluate the query
+                Answer answer = session2.query(new Query(
+                  selectList,                                       // SELECT
+                  new ModelResource(model3URI),                      // FROM
+                  new ConstraintImpl(subjectVariable,               // WHERE
+                                 predicateVariable,
+                                 objectVariable),
+                  null,                                             // HAVING
+                  Arrays.asList(new Order[] {                       // ORDER BY
+                    new Order(subjectVariable, true),
+                    new Order(predicateVariable, true),
+                    new Order(objectVariable, true)
+                  }),
+                  null,                                             // LIMIT
+                  0,                                                // OFFSET
+                  new UnconstrainedAnswer()                         // GIVEN
+                ));
+
+                String[][] results = {
+                  { "test:s01", "test:p01", "test:o01" },
+                  { "test:s01", "test:p02", "test:o01" },
+                  { "test:s01", "test:p02", "test:o02" },
+                  { "test:s01", "test:p03", "test:o02" },
+                  { "test:s02", "test:p03", "test:o02" },
+                  { "test:s02", "test:p04", "test:o02" },
+                  { "test:s02", "test:p04", "test:o03" },
+                  { "test:s02", "test:p05", "test:o03" },
+                  { "test:s03", "test:p01", "test:o01" },
+                  { "test:s03", "test:p05", "test:o03" },
+                  { "test:s03", "test:p06", "test:o01" },
+                  { "test:s03", "test:p06", "test:o03" },
+                };
+                compareResults(results, answer);
+                answer.close();
+
+                resource.end(new TestXid(1), XAResource.TMSUCCESS);
+                resource.rollback(new TestXid(1));
+              } finally {
+                session2.close();
+              }
+            } catch (Exception e) {
+              fail(e);
+            }
+          }
+        };
+        t2.start();
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+          }
+          assertFalse("second transaction should still be waiting for write lock", tx2Started[0]);
+        }
+
+        session1.commit();
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+          }
+          assertFalse("second transaction should still be waiting for write lock", tx2Started[0]);
+        }
+
+        session1.setAutoCommit(true);
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+            assertTrue("second transaction should've started", tx2Started[0]);
+          }
+        }
+
+        try {
+          t2.join(2000L);
+        } catch (InterruptedException ie) {
+          logger.error("wait for tx2-terminated interrupted", ie);
+          fail(ie);
+        }
+        assertFalse("second transaction should've terminated", t2.isAlive());
+
+        session1.removeModel(model3URI);
+      } finally {
+        session1.close();
+      }
+    } catch (Exception e) {
+      fail(e);
+    }
+  }
+
+  /**
+   * Test two simultaneous transactions, in two threads. The second one should block
+   * until the first one sets auto-commit back to true.
+   */
+  public void testExternalInternalConcurrentTxnRollback() throws URISyntaxException
+  {
+    logger.info("testConcurrentExplicitTxn");
+    URI fileURI  = new File("data/xatest-model1.rdf").toURI();
+
+    try {
+      Session session1 = database.newSession();
+      try {
+        XAResource resource1 = session1.getXAResource();
+        resource1.start(new TestXid(1), XAResource.TMNOFLAGS);
+        session1.createModel(model3URI, null);
+        resource1.end(new TestXid(1), XAResource.TMSUCCESS);
+        resource1.commit(new TestXid(1), true);
+
+        resource1.start(new TestXid(2), XAResource.TMNOFLAGS);
+        session1.setModel(model3URI, new ModelResource(fileURI));
+
+        final boolean[] tx2Started = new boolean[] { false };
+
+        Thread t2 = new Thread("tx2Test") {
+          public void run() {
+            try {
+              Session session2 = database.newSession();
+              try {
+                session2.setAutoCommit(false);
+
+                synchronized (tx2Started) {
+                  tx2Started[0] = true;
+                  tx2Started.notify();
+                }
+
+                Variable subjectVariable   = new Variable("subject");
+                Variable predicateVariable = new Variable("predicate");
+                Variable objectVariable    = new Variable("object");
+
+                List selectList = new ArrayList(3);
+                selectList.add(subjectVariable);
+                selectList.add(predicateVariable);
+                selectList.add(objectVariable);
+
+                // Evaluate the query
+                Answer answer = session2.query(new Query(
+                  selectList,                                       // SELECT
+                  new ModelResource(model3URI),                      // FROM
+                  new ConstraintImpl(subjectVariable,               // WHERE
+                                 predicateVariable,
+                                 objectVariable),
+                  null,                                             // HAVING
+                  Arrays.asList(new Order[] {                       // ORDER BY
+                    new Order(subjectVariable, true),
+                    new Order(predicateVariable, true),
+                    new Order(objectVariable, true)
+                  }),
+                  null,                                             // LIMIT
+                  0,                                                // OFFSET
+                  new UnconstrainedAnswer()                         // GIVEN
+                ));
+
+                answer.beforeFirst();
+                assertFalse(answer.next());
+                answer.close();
+
+                session2.setAutoCommit(true);
+              } finally {
+                session2.close();
+              }
+            } catch (Exception e) {
+              fail(e);
+            }
+          }
+        };
+        t2.start();
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+          }
+          assertFalse("second transaction should still be waiting for write lock", tx2Started[0]);
+        }
+
+        resource1.rollback(new TestXid(2));
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+            assertTrue("second transaction should've started", tx2Started[0]);
+          }
+        }
+
+        try {
+          t2.join(2000L);
+        } catch (InterruptedException ie) {
+          logger.error("wait for tx2-terminated interrupted", ie);
+          fail(ie);
+        }
+        assertFalse("second transaction should've terminated", t2.isAlive());
+
+        resource1.start(new TestXid(4), XAResource.TMNOFLAGS);
+        session1.removeModel(model3URI);
+        resource1.end(new TestXid(4), XAResource.TMSUCCESS);
+        resource1.commit(new TestXid(4), true);
+
+      } finally {
+        session1.close();
+      }
+    } catch (Exception e) {
+      fail(e);
+    }
+  }
+
+
+  /**
+   * Test two simultaneous transactions, in two threads. The second one should block
+   * until the first one sets auto-commit back to true.
+   */
+  public void testInternalExternalConcurrentTxnRollback() throws URISyntaxException
+  {
+    logger.info("testConcurrentExplicitTxn");
+    URI fileURI  = new File("data/xatest-model1.rdf").toURI();
+
+    try {
+      Session session1 = database.newSession();
+      try {
+        session1.createModel(model3URI, null);
+
+        session1.setAutoCommit(false);
+        session1.setModel(model3URI, new ModelResource(fileURI));
+
+        final boolean[] tx2Started = new boolean[] { false };
+
+        Thread t2 = new Thread("tx2Test") {
+          public void run() {
+            try {
+              Session session2 = database.newSession();
+              try {
+                XAResource resource = session2.getXAResource();
+                resource.start(new TestXid(1), XAResource.TMNOFLAGS);
+
+                synchronized (tx2Started) {
+                  tx2Started[0] = true;
+                  tx2Started.notify();
+                }
+
+                Variable subjectVariable   = new Variable("subject");
+                Variable predicateVariable = new Variable("predicate");
+                Variable objectVariable    = new Variable("object");
+
+                List selectList = new ArrayList(3);
+                selectList.add(subjectVariable);
+                selectList.add(predicateVariable);
+                selectList.add(objectVariable);
+
+                // Evaluate the query
+                Answer answer = session2.query(new Query(
+                  selectList,                                       // SELECT
+                  new ModelResource(model3URI),                      // FROM
+                  new ConstraintImpl(subjectVariable,               // WHERE
+                                 predicateVariable,
+                                 objectVariable),
+                  null,                                             // HAVING
+                  Arrays.asList(new Order[] {                       // ORDER BY
+                    new Order(subjectVariable, true),
+                    new Order(predicateVariable, true),
+                    new Order(objectVariable, true)
+                  }),
+                  null,                                             // LIMIT
+                  0,                                                // OFFSET
+                  new UnconstrainedAnswer()                         // GIVEN
+                ));
+
+                answer.beforeFirst();
+                assertFalse(answer.next());
+                answer.close();
+
+                resource.end(new TestXid(1), XAResource.TMFAIL);
+                resource.rollback(new TestXid(1));
+              } finally {
+                session2.close();
+              }
+            } catch (Exception e) {
+              fail(e);
+            }
+          }
+        };
+        t2.start();
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+          }
+          assertFalse("second transaction should still be waiting for write lock", tx2Started[0]);
+        }
+
+        session1.rollback();
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+          }
+          assertFalse("second transaction should still be waiting for write lock", tx2Started[0]);
+        }
+
+        session1.setAutoCommit(true);
+
+        synchronized (tx2Started) {
+          if (!tx2Started[0]) {
+            try {
+              tx2Started.wait(2000L);
+            } catch (InterruptedException ie) {
+              logger.error("wait for tx2-started interrupted", ie);
+              fail(ie);
+            }
+            assertTrue("second transaction should've started", tx2Started[0]);
+          }
+        }
+
+        try {
+          t2.join(2000L);
+        } catch (InterruptedException ie) {
+          logger.error("wait for tx2-terminated interrupted", ie);
+          fail(ie);
+        }
+        assertFalse("second transaction should've terminated", t2.isAlive());
+
+        session1.removeModel(model3URI);
+      } finally {
+        session1.close();
+      }
+    } catch (Exception e) {
+      fail(e);
+    }
+  }
+
+
   public void testExplicitRollbackIsolationQuery() throws URISyntaxException {
     logger.info("testExplicitRollbackIsolationQuery");
     URI fileURI  = new File("data/xatest-model1.rdf").toURI();

Modified: branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java
===================================================================
--- branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java	2007-12-04 21:41:42 UTC (rev 599)
+++ branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java	2007-12-05 10:10:04 UTC (rev 600)
@@ -242,8 +242,19 @@
             failedSessions.remove(session);
           }
         } else {
-          logger.info("Attempt to set autocommit false twice");
-          // AutoCommit off -> off === no-op. Log info.
+          if (!manager.isHoldingWriteLock(session)) {
+            if (failedSessions.contains(session)) {
+              failedSessions.remove(session);
+              setAutoCommit(session, false);
+            } else {
+              throw new IllegalStateException("Can't reach here");
+            }
+          } else {
+            // AutoCommit off -> off === no-op. Log info.
+            if (logger.isInfoEnabled()) {
+              logger.info("Attempt to set autocommit false twice", new Throwable());
+            }
+          }
         }
       } else {
         if (autoCommit) {

Modified: branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java	2007-12-04 21:41:42 UTC (rev 599)
+++ branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java	2007-12-05 10:10:04 UTC (rev 600)
@@ -115,6 +115,9 @@
         }
       }
 
+      if (logger.isDebugEnabled()) {
+        logger.debug("Obtaining write lock", new Throwable());
+      }
       sessionHoldingWriteLock = session;
     } finally {
       releaseMutex();
@@ -140,6 +143,9 @@
       if (sessionHoldingWriteLock != session) {
         throw new MulgaraTransactionException("Attempted to release write lock being held by another session");
       }
+      if (logger.isDebugEnabled()) {
+        logger.debug("Releasing writelock", new Throwable());
+      }
       sessionHoldingWriteLock = null;
       writeLockCondition.signal();
     } finally {




More information about the Mulgara-svn mailing list