[Mulgara-svn] r1098 - in trunk: conf src/jar/query/java/org/mulgara/server src/jar/resolver/java/org/mulgara/resolver src/jar/resolver-relational/java/org/mulgara/resolver/relational src/jar/resolver-test/java/org/mulgara/resolver/test src/jar/resolver-view/java/org/mulgara/resolver/view src/jar/server-beep/java/org/mulgara/server/beep src/jar/server-rmi/java/org/mulgara/server/rmi
ronald at mulgara.org
ronald at mulgara.org
Sun Jul 20 13:01:57 UTC 2008
Author: ronald
Date: 2008-07-20 06:01:56 -0700 (Sun, 20 Jul 2008)
New Revision: 1098
Added:
trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolver.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolverFactory.java
Modified:
trunk/conf/mulgara-config.xml
trunk/conf/mulgara-embedded.dtd
trunk/conf/mulgara-embedded.xsd
trunk/src/jar/query/java/org/mulgara/server/Session.java
trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java
trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java
trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/AppendAggregateTuples.java
trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/CacheStatements.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ContentFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ContentHandlerManagerImpl.java
trunk/src/jar/resolver/java/org/mulgara/resolver/CreateDefaultGraphOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactoryInitializer.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseInitializer.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSecurityAdapterInitializer.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/DirectTransitiveFunction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ExhaustiveTransitiveFunction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/GlobalizedAnswer.java
trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java
trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolverFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSession.java
trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSessionFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/JotmTransactionStandaloneTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java
trunk/src/jar/resolver/java/org/mulgara/resolver/LoginOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ModelExistsOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransaction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MutableLocalQueryImpl.java
trunk/src/jar/resolver/java/org/mulgara/resolver/Operation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/PreallocateOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java
trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java
trunk/src/jar/resolver/java/org/mulgara/resolver/StreamContent.java
trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java
trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSessionFactory.java
trunk/src/jar/resolver/java/org/mulgara/resolver/SystemModelSecurityAdapter.java
trunk/src/jar/resolver/java/org/mulgara/resolver/TransitiveFunction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java
trunk/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java
trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java
trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java
trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java
Log:
Merged branch mgr-121-lockrecovery.
This contains three sets of changes:
1. support for idle and transaction timeouts - this closes #121, #122, and #125.
2. synchronization fixes and simplifications for the transactions
3. miscellaneous small fixes to the transactions - this closes #101.
Modified: trunk/conf/mulgara-config.xml
===================================================================
--- trunk/conf/mulgara-config.xml 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/conf/mulgara-config.xml 2008-07-20 13:01:56 UTC (rev 1098)
@@ -55,6 +55,9 @@
<!-- Maximum duration in seconds for transactions, a positive integer -->
<TransactionTimeout>604800</TransactionTimeout> <!-- one week -->
+ <!-- Maximum time in seconds a transaction may be idle, a positive integer -->
+ <IdleTimeout>3600</IdleTimeout> <!-- one hour -->
+
<!--
Database implementation to use, one of:
Modified: trunk/conf/mulgara-embedded.dtd
===================================================================
--- trunk/conf/mulgara-embedded.dtd 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/conf/mulgara-embedded.dtd 2008-07-20 13:01:56 UTC (rev 1098)
@@ -1,4 +1,4 @@
-<!ELEMENT MulgaraConfig (ExternalConfigPaths?, MulgaraHost?, Jetty?, ServerName, RMIPort?, PersistencePath, DefaultGraph?, TransactionTimeout? TripleStoreImplementation, StartupScript?)>
+<!ELEMENT MulgaraConfig (ExternalConfigPaths?, MulgaraHost?, Jetty?, ServerName, RMIPort?, PersistencePath, DefaultGraph?, TransactionTimeout?, IdleTimeout?. TripleStoreImplementation, StartupScript?)>
<!ELEMENT ExternalConfigPaths (MulgaraLogging, WebDefault)>
@@ -27,6 +27,8 @@
<!ELEMENT TransactionTimeout (#PCDATA)>
+ <!ELEMENT IdleTimeout (#PCDATA)>
+
<!ELEMENT TripleStoreImplementation (#PCDATA)>
<!ELEMENT StartupScript (#PCDATA)>
Modified: trunk/conf/mulgara-embedded.xsd
===================================================================
--- trunk/conf/mulgara-embedded.xsd 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/conf/mulgara-embedded.xsd 2008-07-20 13:01:56 UTC (rev 1098)
@@ -93,6 +93,7 @@
</xs:complexType>
</xs:element>
<xs:element name="TransactionTimeout" type="xs:int"/>
+ <xs:element name="IdleTimeout" type="xs:int"/>
<xs:element name="DefaultContentHandler">
<xs:complexType>
<xs:attribute name="type" type="xs:string" use="required"/>
@@ -119,7 +120,8 @@
<xs:element ref="RMIPort" minOccurs="0"/>
<xs:element ref="PersistencePath"/>
<xs:element ref="DefaultGraph" minOccurs="0"/>
- <xs:element ref="TransactionTimeout"/>
+ <xs:element ref="TransactionTimeout" minOccurs="0"/>
+ <xs:element ref="IdleTimeout" minOccurs="0"/>
<xs:element ref="TripleStoreImplementation"/>
<xs:element ref="RelatedQueryHandler"/>
<xs:element ref="SecurityAdapterFactory" minOccurs="0" maxOccurs="unbounded"/>
Modified: trunk/src/jar/query/java/org/mulgara/server/Session.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/server/Session.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/query/java/org/mulgara/server/Session.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -346,6 +346,30 @@
*/
public void login(URI securityDomain, String username, char[] password);
+ /**
+ * The maximum time a transaction may be idle before it is aborted. If not set a default
+ * value is used. This value is only used for new transactions and does not affect any currently
+ * running transactions.
+ *
+ * <p>This currently only affects write transactions.
+ *
+ * @param millis the number of milliseconds, or 0 for the default timeout
+ * @throws QueryException if there was an error talking to the server
+ */
+ public void setIdleTimeout(long millis) throws QueryException;
+
+ /**
+ * The maximum time a transaction may be active (started but neither committed nor rolled back)
+ * before it is aborted. If not set a default value is used. This value is only used for new
+ * transactions and does not affect any currently running transactions.
+ *
+ * <p>This currently only affects write transactions.
+ *
+ * @param millis the number of milliseconds, or 0 for the default timeout
+ * @throws QueryException if there was an error talking to the server
+ */
+ public void setTransactionTimeout(long millis) throws QueryException;
+
/**
* Obtain an XAResource for this Session.
*
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -125,10 +125,15 @@
suite.addTest(new AdvDatabaseSessionUnitTest("testImplicitCommitQuery"));
suite.addTest(new AdvDatabaseSessionUnitTest("testConcurrentExplicitTxn"));
suite.addTest(new AdvDatabaseSessionUnitTest("testConcurrentImplicitTxn"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testConcurrentImplicitRecovery"));
suite.addTest(new AdvDatabaseSessionUnitTest("testPrefixingWithUnbound"));
suite.addTest(new AdvDatabaseSessionUnitTest("testDatabaseDelete"));
suite.addTest(new AdvDatabaseSessionUnitTest("testCreateModel"));
suite.addTest(new AdvDatabaseSessionUnitTest("testInsertionBlankNodes"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testAutoCommitTransactionOps"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitTransactionFailure"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testAutoCommitTransactionFailure"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testSessionClose"));
return suite;
}
@@ -182,6 +187,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
new File(persistenceDirectory, "xaNodePool"),
stringPoolFactoryClassName, // persistent
@@ -199,6 +205,7 @@
database.addResolverFactory("org.mulgara.resolver.url.URLResolverFactory", null);
database.addResolverFactory("org.mulgara.resolver.xsd.XSDResolverFactory", null);
+ database.addResolverFactory("org.mulgara.resolver.MockResolverFactory", null);
}
}
@@ -242,47 +249,9 @@
// Load some test data
Session session = database.newSession();
try {
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
+ compareResults(expectedResults(), answer);
answer.close();
} finally {
session.close();
@@ -292,7 +261,7 @@
}
}
-
+
public void testConcurrentQuery() throws URISyntaxException {
logger.info("Testing concurrentQuery");
@@ -300,45 +269,10 @@
// Load some test data
Session session = database.newSession();
try {
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- Answer answer1 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer1 = session.query(createQuery(modelURI));
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer2 = session.query(createQuery(modelURI));
compareResults(answer1, answer2);
@@ -352,7 +286,7 @@
}
}
-
+
public void testSubqueryQuery() throws URISyntaxException {
logger.info("Testing subqueryQuery");
@@ -427,7 +361,7 @@
}
}
-
+
public void testConcurrentSubqueryQuery() throws URISyntaxException {
logger.info("Testing concurrentSubqueryQuery");
@@ -509,7 +443,7 @@
}
}
-
+
/**
* Note: What this test does is a really bad idea - there is no
* isolation provided as each operation is within its own
@@ -524,32 +458,8 @@
session.createModel(model2URI, null);
try {
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
answer.beforeFirst();
while (answer.next()) {
@@ -560,37 +470,8 @@
}
answer.close();
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(model2URI), // 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, answer2);
+ Answer answer2 = session.query(createQuery(model2URI));
+ compareResults(expectedResults(), answer2);
answer2.close();
session.removeModel(model2URI);
@@ -602,7 +483,7 @@
}
}
-
+
public void testExplicitBasicQuery() throws URISyntaxException {
logger.info("Testing basicQuery");
@@ -611,47 +492,10 @@
Session session = database.newSession();
try {
session.setAutoCommit(false);
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
+ compareResults(expectedResults(), answer);
session.setAutoCommit(true);
@@ -673,39 +517,15 @@
}
}
-
+
public void testAnswerWriteCloseIsolation() throws URISyntaxException {
logger.info("Testing AnswerWriteCloseIsolation");
try {
Session session = database.newSession();
try {
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(systemModelURI), // 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 answer = session.query(createQuery(systemModelURI));
session.setAutoCommit(false);
@@ -721,7 +541,7 @@
}
}
-
+
public void testExplicitIsolationQuery() throws URISyntaxException {
logger.info("testExplicitIsolationQuery");
URI fileURI = new File("data/xatest-model1.rdf").toURI();
@@ -735,76 +555,17 @@
session1.setAutoCommit(false);
session1.setModel(model3URI, new ModelResource(fileURI));
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
session1.setAutoCommit(true);
- selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- 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 = session2.query(createQuery(model3URI));
+ compareResults(expectedResults(), answer);
answer.close();
session1.removeModel(model3URI);
@@ -832,32 +593,8 @@
session1.setAutoCommit(false);
session1.setModel(model3URI, new ModelResource(fileURI));
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
@@ -865,28 +602,8 @@
session1.rollback();
session1.setAutoCommit(true);
- selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- 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 = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -916,145 +633,33 @@
session1.setAutoCommit(false);
session1.setModel(model3URI, new ModelResource(fileURI));
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
session1.commit();
- selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- 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 = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
session1.removeModel(model3URI);
session1.createModel(model3URI, null);
- selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- 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 = session2.query(createQuery(model3URI));
- results = new String[][] {
- { "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);
+ compareResults(expectedResults(), answer);
answer.close();
session1.setAutoCommit(true);
- selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Evaluate the query
- 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 = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
@@ -1082,79 +687,19 @@
session1.createModel(model4URI, null);
session1.setModel(model4URI, new ModelResource(fileURI));
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
// Check data loaded
- Answer answer = session1.query(new Query(
- selectList, // SELECT
- new ModelResource(model4URI), // 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 answer = session1.query(createQuery(model4URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
// Delete all the data from the model
- session2.delete(model4URI, new Query(
- selectList, // SELECT
- new ModelResource(model4URI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- new ArrayList<Order>(), // ORDER BY
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ session2.delete(model4URI, createQuery(model4URI));
// Check all data removed from the model
// This also checks that the delete successfully
// performed the implicit commit.
- answer = session1.query(new Query(
- selectList, // SELECT
- new ModelResource(model4URI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- new ArrayList<Order>(), // ORDER BY
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ answer = session1.query(createQuery(model4URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
@@ -1179,61 +724,38 @@
public void testInsertionBlankNodes()
{
logger.info("testInsertionBlankNodes");
-
+
try {
Session session = database.newSession();
try {
session.createModel(model2URI, null);
session.setAutoCommit(false);
-
+
URIReference refA = new URIReferenceImpl(URI.create("test:a"));
URIReference refP1 = new URIReferenceImpl(URI.create("test:p1"));
URIReference refP2 = new URIReferenceImpl(URI.create("test:p2"));
Literal o1 = new LiteralImpl("o1");
Literal o2 = new LiteralImpl("o2");
BlankNode bn = new VariableNodeImpl("bn");
-
+
Set<Triple> insert1 = new HashSet<Triple>();
insert1.add(new TripleImpl(refA, refP1, bn));
insert1.add(new TripleImpl(bn, refP2, o1));
-
+
Set<Triple> insert2 = new HashSet<Triple>();
insert2.add(new TripleImpl(refA, refP1, bn));
insert2.add(new TripleImpl(bn, refP2, o2));
-
+
session.insert(model2URI, insert1);
session.insert(model2URI, insert2);
session.setAutoCommit(true);
-
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
-
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(model2URI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- new ArrayList<Order>(), // ORDER BY
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
-
+ Answer answer = session.query(createQuery(model2URI));
assertEquals(4, answer.getRowCount());
- }
- finally {
+ } finally {
session.close();
}
- }
- catch (Exception e) {
+ } catch (Exception e) {
fail(e);
}
}
@@ -1267,48 +789,10 @@
tx2Started.notify();
}
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(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 answer = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
session2.commit();
@@ -1389,32 +873,8 @@
try {
Session session2 = database.newSession();
try {
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
-
- List<SelectElement> selectList = new ArrayList<SelectElement>(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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -1445,50 +905,77 @@
try {
Session session2 = database.newSession();
try {
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
+ // Evaluate the query
+ Answer answer = session2.query(createQuery(model3URI));
+ compareResults(expectedResults(), answer);
+ answer.close();
- List<SelectElement> selectList = new ArrayList<SelectElement>(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
+ } finally {
+ session2.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ };
+ t2.start();
+ 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.setAutoCommit(true);
+ session1.removeModel(model3URI);
+
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ /**
+ * Test two simultaneous transactions, the first one obtains the write-lock
+ * and sleeps longer than the recovery timeout.
+ */
+ public void testConcurrentImplicitRecovery() throws URISyntaxException {
+ logger.info("testConcurrentImplicitRecovery");
+ URI fileURI = new File("data/xatest-model1.rdf").toURI();
+
+ // test idle timeout
+ try {
+ Session session1 = database.newSession();
+ session1.setIdleTimeout(1000);
+ try {
+ session1.createModel(model3URI, null);
+ logger.debug("Obtaining autocommit for session1");
+ session1.setAutoCommit(false);
+ logger.debug("Obtained autocommit for session1");
+
+ Thread t2 = new Thread("tx2IdleTest") {
+ public void run() {
+ try {
+ Session session2 = database.newSession();
+ try {
+ logger.debug("Obtaining autocommit for session2");
+ session2.setAutoCommit(false);
+ logger.debug("Obtained autocommit for session2");
+
// 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 answer = session2.query(createQuery(model3URI));
- 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.beforeFirst();
+ assertFalse(answer.next());
answer.close();
+ logger.debug("Releasing autocommit for session2");
+ session2.setAutoCommit(true);
} finally {
session2.close();
}
@@ -1499,6 +986,10 @@
};
t2.start();
+ session1.setModel(model3URI, new ModelResource(fileURI));
+ logger.debug("Sleeping for 1sec");
+ Thread.sleep(1000);
+ logger.debug("Slept for 1sec");
try {
t2.join(2000L);
} catch (InterruptedException ie) {
@@ -1507,18 +998,220 @@
}
assertFalse("second transaction should've terminated", t2.isAlive());
- session1.setAutoCommit(true);
- session1.removeModel(model3URI);
+ rollbackTimedOutTxn(session1);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ // test transaction timeout
+ try {
+ Session session1 = database.newSession();
+ session1.setTransactionTimeout(1000);
+ try {
+ session1.createModel(model3URI, null);
+ logger.debug("Obtaining autocommit for session1");
+ session1.setAutoCommit(false);
+ logger.debug("Obtained autocommit for session1");
+
+ Thread t2 = new Thread("tx2TxToTest") {
+ public void run() {
+ try {
+ Session session2 = database.newSession();
+ try {
+ logger.debug("Obtaining autocommit for session2");
+ session2.setAutoCommit(false);
+ logger.debug("Obtained autocommit for session2");
+
+ // Evaluate the query
+ Answer answer = session2.query(createQuery(model3URI));
+
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ logger.debug("Releasing autocommit for session2");
+ session2.setAutoCommit(true);
+ } finally {
+ session2.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ };
+ t2.start();
+
+ session1.setModel(model3URI, new ModelResource(fileURI));
+ logger.debug("Sleeping for 1sec");
+ Thread.sleep(1000);
+ logger.debug("Slept for 1sec");
+ 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());
+
+ rollbackTimedOutTxn(session1);
} finally {
session1.close();
}
} catch (Exception e) {
fail(e);
}
+
+ // test transaction timeout interrupting active operation
+ try {
+ Session session1 = database.newSession();
+ try {
+ session1.setTransactionTimeout(1000L);
+ session1.setAutoCommit(false);
+ logger.debug("Started transaction for session1");
+
+ URI delayTwoSecs = new URI("foo://mulgara/timeoutTest?active=mr&wait=2000");
+ session1.createModel(delayTwoSecs, new URI(Mulgara.NAMESPACE + "MockModel"));
+
+ try {
+ Answer answer = session1.query(createQuery(delayTwoSecs));
+ fail("query should've gotten interrupted");
+ } catch (QueryException qe) {
+ logger.debug("query was interrupted", qe);
+ }
+
+ rollbackTimedOutTxn(session1);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+
+ // test transaction timeout timing out not-yet-active operation
+ try {
+ Session session1 = database.newSession();
+ try {
+ session1.setTransactionTimeout(1000L);
+ session1.setAutoCommit(false);
+ logger.debug("Started transaction for session1");
+
+ logger.debug("Sleeping for 2sec");
+ Thread.sleep(2000);
+ logger.debug("Slept for 2sec");
+
+ try {
+ Answer answer = session1.query(createQuery(model3URI));
+ fail("query should've gotten interrupted");
+ } catch (QueryException qe) {
+ logger.debug("query was interrupted", qe);
+ }
+
+ rollbackTimedOutTxn(session1);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+
+ // test transaction timeout while operation is waiting for mutex
+ try {
+ final Session session1 = database.newSession();
+ try {
+ session1.setTransactionTimeout(1000L);
+ session1.setAutoCommit(false);
+ logger.debug("Started transaction for session1");
+
+ final URI delayTwoSecs = new URI("foo://mulgara/timeoutTest?active=mr&hardWait=2000");
+ session1.createModel(delayTwoSecs, new URI(Mulgara.NAMESPACE + "MockModel"));
+
+ Thread t2 = new Thread("timeoutTest") {
+ public void run() {
+ try {
+ try {
+ // this acquires mutex and holds it for 2s
+ Answer answer = session1.query(createQuery(delayTwoSecs));
+ Thread.sleep(100L); // allow rollback to proceed
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ fail("query should've gotten interrupted");
+ } catch (TuplesException te) {
+ logger.debug("query was interrupted", te);
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ };
+ t2.start();
+ Thread.sleep(100L);
+
+ // blocks, waiting for mutex; when it does get it, it should rollback or see a rb
+ try {
+ Answer answer = session1.query(createQuery(model3URI));
+ Thread.sleep(100L); // allow rollback to proceed
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ fail("query should've gotten aborted");
+ } catch (QueryException qe) {
+ logger.debug("query was aborted", qe);
+ } catch (TuplesException te) {
+ logger.debug("query was aborted", te);
+ }
+
+ rollbackTimedOutTxn(session1);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+
+ // test transaction timeout on autocommit transaction
+ try {
+ final Session session1 = database.newSession();
+ try {
+ session1.setTransactionTimeout(1000L);
+
+ final URI delayTwoSecs = new URI("foo://mulgara/timeoutTest?active=mr&hardWait=2000");
+ session1.createModel(delayTwoSecs, new URI(Mulgara.NAMESPACE + "MockModel"));
+
+ try {
+ // this acquires mutex and holds it for 2s
+ Answer answer = session1.query(createQuery(delayTwoSecs));
+ Thread.sleep(100L);
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ fail("query should've gotten interrupted");
+ } catch (TuplesException te) {
+ logger.debug("query was interrupted", te);
+ }
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
}
+ private void rollbackTimedOutTxn(Session session) throws QueryException {
+ try {
+ session.commit();
+ fail("Commit should have failed due to transaction timeout");
+ } catch (QueryException qe) {
+ }
+ logger.debug("Rolling back transaction on session");
+ session.rollback();
+ session.setAutoCommit(true);
+ }
+
public void testPrefixingWithUnbound() throws URISyntaxException {
logger.warn("testPrefixingWithUnbound");
URI fileURI = new File("data/prefix-unbound.rdf").toURI();
@@ -1603,10 +1296,408 @@
database = null;
}
+
+ /**
+ * Test various transaction operations in auto-commit mode.
+ */
+ public void testAutoCommitTransactionOps() {
+ logger.info("Testing autoCommitTransactionOps");
+
+ try {
+ Session session = database.newSession();
+ try {
+ // should be a no-op
+ session.setAutoCommit(true);
+
+ // commit should not be allowed
+ try {
+ session.commit();
+ fail("Commit did not fail in auto-commit mode");
+ } catch (QueryException qe) {
+ }
+
+ // rollback should not be allowed
+ try {
+ session.rollback();
+ fail("Rollback did not fail in auto-commit mode");
+ } catch (QueryException qe) {
+ }
+
+ // verify we're still good to go
+ session.query(createQuery(modelURI)).close();
+
+ // verify second setAutoCommit(false) is a no-op
+ session.createModel(model3URI, null);
+ session.setAutoCommit(false);
+ session.setModel(model3URI, new ModelResource(new File("data/xatest-model1.rdf").toURI()));
+ session.setAutoCommit(false);
+ session.commit();
+
+ Answer answer = session.query(createQuery(model3URI));
+ compareResults(expectedResults(), answer);
+ answer.close();
+
+ session.removeModel(model3URI);
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
+ /**
+ * Test various operations after an explicit transaction fails.
+ */
+ public void testExplicitTransactionFailure() {
+ logger.info("Testing transactionExplicitFailure");
+
+ try {
+ // query after failure should fail
+ shouldFailExplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.query(createQuery(modelURI)).close();
+ }
+ }, "Query in failed transaction did not fail");
+
+ // insert after failure should fail
+ shouldFailExplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.insert(modelURI, Collections.singleton((Triple)new TripleImpl(
+ new URIReferenceImpl(URI.create("test:a")),
+ new URIReferenceImpl(URI.create("test:b")),
+ new URIReferenceImpl(URI.create("test:c")))));
+ }
+ }, "Insert in failed transaction did not fail");
+
+ // commit after failure should fail
+ shouldFailExplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.commit();
+ }
+ }, "Commit in failed transaction did not fail");
+
+ // rollback after failure should succeed
+ shouldSucceedExplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.rollback();
+ }
+ });
+
+ // setAutoCommit(false) after failure should fail
+ shouldFailExplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.setAutoCommit(false);
+ }
+ }, "setAutoCommit(false) in failed transaction did not fail");
+
+ // setAutoCommit(true) after failure should succeed
+ shouldSucceedExplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.setAutoCommit(true);
+ }
+ });
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+ private void shouldFailExplicit(TestOp op, String msg) throws Exception {
+ testExplicitTransactionFailureOp(op, true, msg);
+ }
+
+ private void shouldSucceedExplicit(TestOp op) throws Exception {
+ testExplicitTransactionFailureOp(op, false, null);
+ }
+
+ private void testExplicitTransactionFailureOp(TestOp op, boolean shouldFail, String msg) throws Exception {
+ Session session = database.newSession();
+ try {
+ // start tx
+ session.setAutoCommit(false);
+
+ // run bad query -> failed tx
+ try {
+ session.query(createQuery(URI.create("urn:no:such:model")));
+ fail("Bad query failed to throw exception");
+ } catch (QueryException qe) {
+ }
+
+ // run test op, verify it succeeds/fails, and reset
+ if (shouldFail) {
+ try {
+ op.run(session);
+ fail(msg);
+ } catch (QueryException qe) {
+ }
+ session.setAutoCommit(true);
+ } else {
+ op.run(session);
+ }
+
+ // verify we're good to go
+ session.query(createQuery(modelURI)).close();
+
+ session.setAutoCommit(false);
+ session.query(createQuery(modelURI)).close();
+ session.commit();
+ } finally {
+ session.close();
+ }
+ }
+
+ /**
+ * Test various operations after an operation in auto-commit fails.
+ */
+ public void testAutoCommitTransactionFailure() {
+ logger.info("Testing transactionAutoCommitFailure");
+
+ try {
+ // query after failure should succeed
+ shouldSucceedImplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.query(createQuery(modelURI)).close();
+ }
+ });
+
+ // insert after failure should succeed
+ shouldSucceedImplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.insert(modelURI, Collections.singleton((Triple)new TripleImpl(
+ new URIReferenceImpl(URI.create("test:a")),
+ new URIReferenceImpl(URI.create("test:b")),
+ new URIReferenceImpl(URI.create("test:c")))));
+ }
+ });
+
+ // commit should fail
+ shouldFailImplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.commit();
+ }
+ }, "Commit after failed query did not fail");
+
+ // rollback should fail
+ shouldFailImplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.rollback();
+ }
+ }, "Rollback after failed query did not fail");
+
+ // setAutoCommit(false) after failure should succeed
+ shouldSucceedImplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.setAutoCommit(false);
+ session.setAutoCommit(true);
+ }
+ });
+
+ // setAutoCommit(true) after failure should succeed
+ shouldSucceedImplicit(new TestOp() {
+ public void run(Session session) throws Exception {
+ session.setAutoCommit(true);
+ }
+ });
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+ private void shouldFailImplicit(TestOp op, String msg) throws Exception {
+ testImplicitTransactionFailureOp(op, true, msg);
+ }
+
+ private void shouldSucceedImplicit(TestOp op) throws Exception {
+ testImplicitTransactionFailureOp(op, false, null);
+ }
+
+ private void testImplicitTransactionFailureOp(TestOp op, boolean shouldFail, String msg) throws Exception {
+ Session session = database.newSession();
+ try {
+ // run bad query -> failed tx
+ try {
+ session.query(createQuery(URI.create("urn:no:such:model")));
+ fail("Bad query failed to throw exception");
+ } catch (QueryException qe) {
+ }
+
+ // run test op, verify it succeeds/fails
+ if (shouldFail) {
+ try {
+ op.run(session);
+ fail(msg);
+ } catch (QueryException qe) {
+ }
+ } else {
+ op.run(session);
+ }
+
+ // verify we're good to go
+ session.query(createQuery(modelURI)).close();
+
+ session.setAutoCommit(false);
+ session.query(createQuery(modelURI)).close();
+ session.setAutoCommit(true);
+ } finally {
+ session.close();
+ }
+ }
+
+ 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);
+ }
+
+ // test close while operation active in auto-commit
+ try {
+ final Session session1 = database.newSession();
+ final URI delayTwoSecs = new URI("foo://mulgara/closeTest?active=l&hardWait=1000");
+ session1.createModel(delayTwoSecs, new URI(Mulgara.NAMESPACE + "MockModel"));
+
+ final boolean[] closing = new boolean[1];
+
+ try {
+ Thread t1 = new Thread("closeTest") {
+ public void run() {
+ try {
+ Answer answer = session1.query(createQuery(delayTwoSecs));
+ answer.close();
+ synchronized (closing) {
+ assertTrue("close didn't block", closing[0]);
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ };
+ t1.start();
+ Thread.sleep(100L); // give thread some time to start and block
+
+ assertTrue("query should still be active", t1.isAlive());
+
+ synchronized (closing) { closing[0] = true; }
+ session1.close();
+ synchronized (closing) { closing[0] = false; }
+
+ 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 {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
//
// Internal methods
//
+ private Query createQuery(URI model) {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List<SelectElement> selectList = new ArrayList<SelectElement>(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ return new Query(
+ selectList, // SELECT
+ new ModelResource(model), // 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
+ );
+ }
+
+ private String[][] expectedResults() {
+ return new String[][] {
+ { "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" },
+ };
+ }
+
private void compareResults(String[][] expected, Answer answer) throws Exception {
try {
answer.beforeFirst();
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/AppendAggregateTuples.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/AppendAggregateTuples.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/AppendAggregateTuples.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -38,10 +38,8 @@
import org.mulgara.query.rdf.LiteralImpl;
import org.mulgara.resolver.spi.LocalizeException;
import org.mulgara.resolver.spi.ResolverSession;
-import org.mulgara.store.statement.StatementStore;
import org.mulgara.store.tuples.AbstractTuples;
import org.mulgara.store.tuples.Tuples;
-import org.mulgara.store.tuples.TuplesOperations;
import org.mulgara.util.StackTrace;
/**
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -146,6 +146,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
null,
stringPoolFactoryClassName, // persistent
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/BootstrapOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -10,7 +10,6 @@
// Local packages
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.resolver.spi.DatabaseMetadata;
-import org.mulgara.resolver.spi.ResolverSessionFactory;
import org.mulgara.resolver.spi.SingletonStatements;
import org.mulgara.resolver.spi.SystemResolver;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/CacheStatements.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/CacheStatements.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/CacheStatements.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -28,7 +28,6 @@
package org.mulgara.resolver;
// Local packages
-import org.mulgara.query.Cursor;
import org.mulgara.query.TuplesException;
import org.mulgara.query.Variable;
import org.mulgara.resolver.spi.Statements;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ContentFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ContentFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ContentFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -29,9 +29,6 @@
// Java 2 standard packages
import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.MalformedURLException;
-import java.io.File;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Constructor;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ContentHandlerManagerImpl.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ContentHandlerManagerImpl.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ContentHandlerManagerImpl.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -43,7 +43,6 @@
import org.mulgara.content.ContentHandlerManager;
import org.mulgara.content.ContentLoader;
import org.mulgara.content.NotModifiedException;
-import org.mulgara.query.QueryException;
import org.mulgara.resolver.spi.ResolverSession;
import org.mulgara.resolver.spi.Statements;
import org.mulgara.util.StackTrace;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/CreateDefaultGraphOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/CreateDefaultGraphOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/CreateDefaultGraphOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -23,7 +23,6 @@
import org.mulgara.query.*;
import org.mulgara.query.rdf.*;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
import org.mulgara.store.nodepool.NodePool;
/**
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/CreateModelOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -39,7 +39,6 @@
import org.mulgara.query.*;
import org.mulgara.query.rdf.*;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
import org.mulgara.store.nodepool.NodePool;
/**
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/Database.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -50,13 +50,10 @@
import javax.naming.NamingException;
import javax.transaction.SystemException;
-import javax.transaction.TransactionManager;
import org.apache.log4j.Logger;
import org.jrdf.vocabulary.RDF;
-import org.mulgara.content.Content;
import org.mulgara.content.ContentHandler;
-import org.mulgara.query.LocalNode;
import org.mulgara.query.QueryException;
import org.mulgara.query.rdf.Mulgara;
import org.mulgara.resolver.spi.DatabaseMetadata;
@@ -64,7 +61,6 @@
import org.mulgara.resolver.spi.FactoryInitializer;
import org.mulgara.resolver.spi.InitializerException;
import org.mulgara.resolver.spi.LocalizeException;
-import org.mulgara.resolver.spi.Resolver;
import org.mulgara.resolver.spi.ResolverException;
import org.mulgara.resolver.spi.ResolverFactory;
import org.mulgara.resolver.spi.ResolverFactoryException;
@@ -73,15 +69,11 @@
import org.mulgara.resolver.spi.SecurityAdapterFactoryException;
import org.mulgara.resolver.spi.SymbolicTransformation;
import org.mulgara.resolver.spi.SystemResolverFactory;
-import org.mulgara.rules.RuleLoader;
import org.mulgara.server.Session;
import org.mulgara.server.SessionFactory;
import org.mulgara.store.nodepool.NodePool;
import org.mulgara.store.nodepool.NodePoolException;
-import org.mulgara.store.nodepool.NodePoolFactory;
-import org.mulgara.store.stringpool.StringPool;
import org.mulgara.store.stringpool.StringPoolException;
-import org.mulgara.store.stringpool.StringPoolFactory;
import org.mulgara.store.xa.SimpleXARecoveryHandler;
import org.mulgara.store.xa.SimpleXAResourceException;
import org.mulgara.transaction.TransactionManagerFactory;
@@ -246,10 +238,7 @@
private final URI temporaryModelTypeURI;
/**
- * Factory for the {@link #transactionManager}.
- *
- * This only reason we hold a reference to this is so that it can be closed
- * when the database shuts down.
+ * Factory for internal jta TransactionManager's.
*/
private final TransactionManagerFactory transactionManagerFactory;
@@ -261,6 +250,11 @@
*/
private final MulgaraTransactionManager transactionManager;
+ /** the default maximum duration for a transaction, in milli-seconds */
+ private final long defaultTransactionTimeout;
+ /** the default maximum idle time for a transaction, in milli-seconds */
+ private final long defaultIdleTimeout;
+
/** The unique {@link URI} naming this database. Not read in this implementation. */
@SuppressWarnings("unused")
private final URI uri;
@@ -323,6 +317,7 @@
uri, // security domain
new JotmTransactionManagerFactory(),
config.getTransactionTimeout(),
+ config.getIdleTimeout(),
config.getPersistentNodePoolFactory().getType(),
DatabaseFactory.subdir(
directory,
@@ -376,9 +371,12 @@
* database is within, or <code>null</code> if this database is unsecured
* @param transactionManagerFactory the source for the
* {@link TransactionManager}, never <code>null</code>
- * @param transactionTimeout the number of seconds before transactions time
- * out, or zero to take the <var>transactionManagerFactory</var>'s default;
+ * @param transactionTimeout the default number of seconds before transactions
+ * time out, or zero to take the <var>transactionManagerFactory</var>'s default;
* never negative
+ * @param idleTimeout the default number of seconds a transaction may be idle before
+ * it is timed out, or zero to take the <var>transactionManagerFactory</var>'s
+ * default; never negative
* @param persistentNodePoolFactoryClassName the name of a
* {@link NodePoolFactory} implementation which will be used to generate
* persistent local nodes, never <code>null</code>
@@ -416,6 +414,7 @@
URI securityDomainURI,
TransactionManagerFactory transactionManagerFactory,
int transactionTimeout,
+ int idleTimeout,
String persistentNodePoolFactoryClassName,
File persistentNodePoolDirectory,
String persistentStringPoolFactoryClassName,
@@ -512,9 +511,10 @@
assert this.contentHandlers != null;
// FIXME: Migrate this code inside StringPoolSession. Pass config to StringPoolSession.
- this.transactionManager = new MulgaraTransactionManager(transactionManagerFactory);
+ this.transactionManager = new MulgaraTransactionManager();
- transactionManager.setTransactionTimeout(transactionTimeout);
+ this.defaultTransactionTimeout = transactionTimeout * 1000L;
+ this.defaultIdleTimeout = idleTimeout * 1000L;
// Enable resolver initialization
if (logger.isDebugEnabled()) {
@@ -677,6 +677,7 @@
DatabaseSession session = new DatabaseSession(
transactionManager,
+ transactionManagerFactory,
unmodifiableSecurityAdapterList,
unmodifiableSymbolicTransformationList,
spSessionFactory,
@@ -689,6 +690,8 @@
contentHandlers,
unmodifiableCachedResolverFactorySet,
temporaryModelTypeURI,
+ defaultTransactionTimeout,
+ defaultIdleTimeout,
ruleLoaderClassName);
// Updates metadata to reflect bootstrapped system model.
@@ -888,6 +891,7 @@
try {
return new DatabaseSession(
transactionManager,
+ transactionManagerFactory,
unmodifiableSecurityAdapterList,
unmodifiableSymbolicTransformationList,
spSessionFactory,
@@ -900,6 +904,8 @@
contentHandlers,
unmodifiableCachedResolverFactorySet,
temporaryModelTypeURI,
+ defaultTransactionTimeout,
+ defaultIdleTimeout,
ruleLoaderClassName);
} catch (ResolverFactoryException e) {
throw new QueryException("Couldn't create session", e);
@@ -916,6 +922,7 @@
try {
return new LocalJRDFDatabaseSession(
transactionManager,
+ transactionManagerFactory,
unmodifiableSecurityAdapterList,
unmodifiableSymbolicTransformationList,
jrdfSessionFactory,
@@ -1140,6 +1147,7 @@
try {
return new DatabaseSession(
transactionManager,
+ transactionManagerFactory,
Collections.singletonList(
(SecurityAdapter)new SystemModelSecurityAdapter(metadata.getSystemModelNode())
),
@@ -1154,6 +1162,8 @@
contentHandlers,
unmodifiableCachedResolverFactorySet,
temporaryModelTypeURI,
+ defaultTransactionTimeout,
+ defaultIdleTimeout,
ruleLoaderClassName);
}
catch (ResolverFactoryException e) {
@@ -1168,6 +1178,7 @@
try {
return new LocalJRDFDatabaseSession(
transactionManager,
+ transactionManagerFactory,
Collections.singletonList(
new SystemModelSecurityAdapter(metadata.getSystemModelNode())
),
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -100,6 +100,7 @@
uri, // security domain
new JotmTransactionManagerFactory(),
config.getTransactionTimeout(),
+ config.getIdleTimeout(),
config.getPersistentNodePoolFactory().getType(),
subdir(directory, config.getPersistentNodePoolFactory().getDir()),
config.getPersistentStringPoolFactory().getType(),
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactoryInitializer.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactoryInitializer.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactoryInitializer.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -37,8 +37,6 @@
// Local packages
import org.mulgara.resolver.spi.*;
-import org.mulgara.store.nodepool.NodePool;
-import org.mulgara.store.stringpool.StringPool;
/**
* The database initialiser used to provide configuration information to
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseInitializer.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseInitializer.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseInitializer.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -28,7 +28,6 @@
package org.mulgara.resolver;
// Third party packages
-import org.apache.log4j.Logger; // Apache Log4J
// Local packages
import org.mulgara.resolver.spi.*;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseOperationContext.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -66,7 +66,6 @@
import org.mulgara.resolver.spi.TuplesWrapperStatements;
import org.mulgara.resolver.view.ViewMarker;
import org.mulgara.resolver.view.SessionView;
-import org.mulgara.store.nodepool.NodePool;
import org.mulgara.store.tuples.Tuples;
import org.mulgara.store.tuples.TuplesOperations;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSecurityAdapterInitializer.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSecurityAdapterInitializer.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSecurityAdapterInitializer.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -31,13 +31,11 @@
import java.net.URI;
// Third party packages
-import org.apache.log4j.Logger; // Apache Log4J
import org.jrdf.graph.Node;
// Local packages
import org.mulgara.query.QueryException;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
import org.mulgara.server.SessionFactory;
/**
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -44,13 +44,12 @@
import org.jrdf.graph.*;
// Local packages
-import org.mulgara.content.ContentHandler;
import org.mulgara.content.ContentHandlerManager;
import org.mulgara.query.*;
import org.mulgara.resolver.spi.*;
import org.mulgara.rules.*;
import org.mulgara.server.Session;
-import org.mulgara.store.nodepool.NodePool;
+import org.mulgara.transaction.TransactionManagerFactory;
/**
* A database session.
@@ -114,9 +113,21 @@
private final MulgaraTransactionManager transactionManager;
private MulgaraTransactionFactory transactionFactory;
- private MulgaraInternalTransactionFactory internalFactory;
- private MulgaraExternalTransactionFactory externalFactory;
+ private final MulgaraInternalTransactionFactory internalFactory;
+ private final MulgaraExternalTransactionFactory externalFactory;
+ /** the default maximum transaction duration */
+ private final long defaultTransactionTimeout;
+
+ /** the default maximum transaction idle time */
+ private final long defaultIdleTimeout;
+
+ /** the maximum transaction duration */
+ private long transactionTimeout;
+
+ /** the maximum transaction idle time */
+ private long idleTimeout;
+
/** The name of the rule loader to use */
private String ruleLoaderClassName;
@@ -134,6 +145,8 @@
*
* @param transactionManager the source of transactions for this session,
* never <code>null</code>
+ * @param transactionManagerFactory factory for internal jta transaction-manager
+ * for this session, never <code>null</code>
* @param securityAdapterList {@link List} of {@link SecurityAdapter}s to be
* consulted before permitting operations, never <code>null</code>
* @param symbolicTransformationList {@link List} of
@@ -160,9 +173,17 @@
* never <code>null</code>
* @param temporaryModelTypeURI the URI of the model type to use to cache
* external models
+ * @param transactionTimeout the default number of milli-seconds before transactions
+ * time out, or zero to take the <var>transactionManagerFactory</var>'s default;
+ * never negative
+ * @param idleTimeout the default number of milli-seconds a transaction may be idle
+ * before it is timed out, or zero to take the <var>transactionManagerFactory</var>'s
+ * default; never negative
+ * @param ruleLoaderClassName the rule-loader class to use; may be null
* @throws IllegalArgumentException if any argument is <code>null</code>
*/
DatabaseSession(MulgaraTransactionManager transactionManager,
+ TransactionManagerFactory transactionManagerFactory,
List<SecurityAdapter> securityAdapterList,
List<SymbolicTransformation> symbolicTransformationList,
ResolverSessionFactory resolverSessionFactory,
@@ -175,6 +196,8 @@
ContentHandlerManager contentHandlers,
Set<ResolverFactory> cachedResolverFactorySet,
URI temporaryModelTypeURI,
+ long transactionTimeout,
+ long idleTimeout,
String ruleLoaderClassName) throws ResolverFactoryException {
if (logger.isDebugEnabled()) {
@@ -186,6 +209,8 @@
// Validate parameters
if (transactionManager == null) {
throw new IllegalArgumentException("Null 'transactionManager' parameter");
+ } else if (transactionManagerFactory == null) {
+ throw new IllegalArgumentException("Null 'transactionManagerFactory' parameter");
} else if (securityAdapterList == null) {
throw new IllegalArgumentException("Null 'securityAdapterList' parameter");
} else if (symbolicTransformationList == null) {
@@ -210,6 +235,10 @@
throw new IllegalArgumentException("Null 'cachedResolverFactorySet' parameter");
} else if (temporaryModelTypeURI == null) {
throw new IllegalArgumentException("Null 'temporaryModelTypeURI' parameter");
+ } else if (transactionTimeout < 0) {
+ throw new IllegalArgumentException("negative 'transactionTimeout' parameter");
+ } else if (idleTimeout < 0) {
+ throw new IllegalArgumentException("negative 'idleTimeout' parameter");
} else if (ruleLoaderClassName == null) {
ruleLoaderClassName = DUMMY_RULE_LOADER;
}
@@ -228,15 +257,19 @@
this.contentHandlers = contentHandlers;
this.cachedResolverFactorySet = cachedResolverFactorySet;
this.temporaryModelTypeURI = temporaryModelTypeURI;
+ this.defaultTransactionTimeout = transactionTimeout;
+ this.defaultIdleTimeout = idleTimeout;
this.ruleLoaderClassName = ruleLoaderClassName;
this.transactionFactory = null;
- this.internalFactory = null;
+ this.externalFactory = new MulgaraExternalTransactionFactory(this, transactionManager);
+ this.internalFactory =
+ new MulgaraInternalTransactionFactory(this, transactionManager, transactionManagerFactory);
+ this.transactionTimeout = defaultTransactionTimeout;
+ this.idleTimeout = defaultIdleTimeout;
+
if (logger.isTraceEnabled()) logger.trace("Constructed DatabaseSession");
-
- // Set the transaction timeout to an hour
- transactionManager.setTransactionTimeout(3600);
}
@@ -244,6 +277,7 @@
* Non-rule version of the constructor. Accepts all parameters except ruleLoaderClassName.
*/
DatabaseSession(MulgaraTransactionManager transactionManager,
+ TransactionManagerFactory transactionManagerFactory,
List<SecurityAdapter> securityAdapterList,
List<SymbolicTransformation> symbolicTransformationList,
ResolverSessionFactory resolverSessionFactory,
@@ -256,10 +290,10 @@
ContentHandlerManager contentHandlers,
Set<ResolverFactory> cachedResolverFactorySet,
URI temporaryModelTypeURI) throws ResolverFactoryException {
- this(transactionManager, securityAdapterList, symbolicTransformationList, resolverSessionFactory,
+ this(transactionManager, transactionManagerFactory, securityAdapterList, symbolicTransformationList, resolverSessionFactory,
systemResolverFactory, temporaryResolverFactory, resolverFactoryList, externalResolverFactoryMap,
internalResolverFactoryMap, metadata, contentHandlers, cachedResolverFactorySet,
- temporaryModelTypeURI, "");
+ temporaryModelTypeURI, 0, 0, null);
}
//
@@ -556,7 +590,7 @@
if (logger.isDebugEnabled()) logger.debug("setAutoCommit(" + autoCommit + ") called.");
assertInternallyManagedXA();
try {
- internalFactory.setAutoCommit(this, autoCommit);
+ internalFactory.setAutoCommit(autoCommit);
} catch (MulgaraTransactionException em) {
throw new QueryException("Error setting autocommit", em);
}
@@ -567,7 +601,7 @@
logger.debug("Committing transaction");
assertInternallyManagedXA();
try {
- internalFactory.commit(this);
+ internalFactory.commit();
} catch (MulgaraTransactionException em) {
throw new QueryException("Error performing commit", em);
}
@@ -578,7 +612,7 @@
logger.debug("Rollback transaction");
assertInternallyManagedXA();
try {
- internalFactory.rollback(this);
+ internalFactory.rollback();
} catch (MulgaraTransactionException em) {
throw new QueryException("Error performing rollback", em);
}
@@ -588,11 +622,18 @@
public void close() throws QueryException {
logger.debug("Closing session");
try {
- transactionManager.closingSession(this);
- transactionFactory = null;
- } catch (MulgaraTransactionException em2) {
- logger.error("Error force-closing session", em2);
- throw new QueryException("Error force-closing session.", em2);
+ if (transactionFactory != null)
+ transactionFactory.closingSession();
+ } catch (MulgaraTransactionException em) {
+ logger.error("Error force-closing session", em);
+ throw new QueryException("Error force-closing session.", em);
+ } finally {
+ try {
+ transactionManager.closingSession(this);
+ } catch (MulgaraTransactionException em2) {
+ logger.error("Error force-closing session", em2);
+ throw new QueryException("Error force-closing session.", em2);
+ }
}
}
@@ -678,7 +719,7 @@
private void execute(Operation operation, String errorString) throws QueryException {
ensureTransactionFactorySelected();
try {
- MulgaraTransaction transaction = transactionFactory.getTransaction(this, operation.isWriteOperation());
+ MulgaraTransaction transaction = transactionFactory.getTransaction(operation.isWriteOperation());
transaction.execute(operation, metadata);
} catch (MulgaraTransactionException em) {
logger.debug("Error executing operation: " + errorString, em);
@@ -724,8 +765,8 @@
private void assertInternallyManagedXA() throws QueryException {
if (transactionFactory == null) {
- transactionFactory = internalFactory = transactionManager.getInternalFactory();
- } else if (internalFactory == null) {
+ transactionFactory = internalFactory;
+ } else if (transactionFactory != internalFactory) {
throw new QueryException("Attempt to use internal transaction control in externally managed session");
}
}
@@ -733,8 +774,8 @@
private void assertExternallyManagedXA() throws QueryException {
if (transactionFactory == null) {
- transactionFactory = externalFactory = transactionManager.getExternalFactory();
- } else if (externalFactory == null) {
+ transactionFactory = externalFactory;
+ } else if (transactionFactory != externalFactory) {
throw new QueryException("Attempt to use external transaction control in internally managed session");
}
}
@@ -742,15 +783,31 @@
public XAResource getXAResource() throws QueryException {
assertExternallyManagedXA();
- return externalFactory.getXAResource(this, true);
+ return externalFactory.getXAResource(true);
}
public XAResource getReadOnlyXAResource() throws QueryException {
assertExternallyManagedXA();
- return externalFactory.getXAResource(this, false);
+ return externalFactory.getXAResource(false);
}
-
+
+ public void setIdleTimeout(long millis) {
+ idleTimeout = millis > 0 ? millis : defaultIdleTimeout;
+ }
+
+ public void setTransactionTimeout(long millis) {
+ transactionTimeout = millis > 0 ? millis : defaultTransactionTimeout;
+ }
+
+ public long getIdleTimeout() {
+ return idleTimeout;
+ }
+
+ public long getTransactionTimeout() {
+ return transactionTimeout;
+ }
+
public boolean ping() {
return true;
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -156,6 +156,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
null,
stringPoolFactoryClassName, // persistent
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -514,6 +514,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
null,
stringPoolFactoryClassName, // persistent
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -41,9 +41,6 @@
// Locally written packages
import org.mulgara.query.*;
-import org.mulgara.store.StoreException;
-import org.mulgara.store.nodepool.NodePool;
-import org.mulgara.store.stringpool.StringPool;
import org.mulgara.util.FileUtil;
/**
@@ -111,7 +108,7 @@
public void test1Constructor()
{
try {
- new Database(null, null, null, null, 0, null, null, null, null, null,
+ new Database(null, null, null, null, 0, 0, null, null, null, null, null,
null, null, null, null, null, null, null, null, null);
fail("Expected " + IllegalArgumentException.class);
} catch (IllegalArgumentException e) {
@@ -158,6 +155,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
"org.mulgara.store.nodepool.memory.MemoryNodePoolFactory",
null,
"org.mulgara.store.stringpool.memory.MemoryStringPoolFactory",
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/DirectTransitiveFunction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/DirectTransitiveFunction.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/DirectTransitiveFunction.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -42,9 +42,6 @@
import org.mulgara.resolver.spi.LocalizeException;
import org.mulgara.resolver.spi.QueryEvaluationContext;
import org.mulgara.resolver.spi.ResolverSession;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.statement.StatementStoreException;
-import org.mulgara.store.stringpool.StringPool;
import org.mulgara.store.tuples.LiteralTuples;
import org.mulgara.store.tuples.Tuples;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ExhaustiveTransitiveFunction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ExhaustiveTransitiveFunction.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ExhaustiveTransitiveFunction.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -38,9 +38,6 @@
import org.mulgara.query.*;
import org.mulgara.resolver.spi.QueryEvaluationContext;
import org.mulgara.resolver.spi.ResolverSession;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.statement.StatementStoreException;
-import org.mulgara.store.stringpool.StringPool;
import org.mulgara.store.tuples.LiteralTuples;
import org.mulgara.store.tuples.Tuples;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -30,6 +30,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
@@ -104,6 +105,7 @@
suite.addTest(new ExternalTransactionUnitTest("testSimpleOnePhaseCommit"));
suite.addTest(new ExternalTransactionUnitTest("testSimpleTwoPhaseCommit"));
suite.addTest(new ExternalTransactionUnitTest("testBasicQuery"));
+ suite.addTest(new ExternalTransactionUnitTest("testBasicUpdate"));
suite.addTest(new ExternalTransactionUnitTest("testMultipleQuery"));
suite.addTest(new ExternalTransactionUnitTest("testBasicReadOnlyQuery"));
suite.addTest(new ExternalTransactionUnitTest("testConcurrentQuery"));
@@ -120,6 +122,9 @@
suite.addTest(new ExternalTransactionUnitTest("testInternalExternalConcurrentTxnRollback"));
suite.addTest(new ExternalTransactionUnitTest("testExternalInternalConcurrentTxnRollback"));
suite.addTest(new ExternalTransactionUnitTest("testInternalSerialMultipleSessions"));
+ suite.addTest(new ExternalTransactionUnitTest("testTransactionTimeout"));
+ suite.addTest(new ExternalTransactionUnitTest("testTransactionFailure"));
+ suite.addTest(new ExternalTransactionUnitTest("testSessionClose"));
return suite;
}
@@ -176,6 +181,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
new File(persistenceDirectory, "xaNodePool"),
stringPoolFactoryClassName, // persistent
@@ -192,6 +198,7 @@
"org.mulgara.content.rdfxml.RDFXMLContentHandler");
database.addResolverFactory("org.mulgara.resolver.url.URLResolverFactory", null);
+ database.addResolverFactory("org.mulgara.resolver.MockResolverFactory", null);
}
}
@@ -297,49 +304,65 @@
Xid xid = new TestXid(1);
resource.start(xid, XAResource.TMNOFLAGS);
- Variable subjectVariable = new Variable("subject");
- Variable predicateVariable = new Variable("predicate");
- Variable objectVariable = new Variable("object");
+ // Evaluate the query
+ Answer answer = session.query(createQuery(modelURI));
+ compareResults(expectedResults(), answer);
+ answer.close();
- List selectList = new ArrayList(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
+ resource.end(xid, XAResource.TMSUCCESS);
+ resource.commit(xid, true);
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
- // Evaluate the query
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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);
+ public void testBasicUpdate() throws URISyntaxException {
+ logger.info("Testing basicUpdate");
+
+ // straight insert and delete
+ try {
+ DatabaseSession session = (DatabaseSession)database.newSession();
+ try {
+ // start txn
+ XAResource resource = session.getXAResource();
+ Xid xid = new TestXid(1);
+ resource.start(xid, XAResource.TMNOFLAGS);
+
+ session.createModel(model2URI, null);
+
+ // insert data
+ session.insert(model2URI, Collections.singleton(new TripleImpl(
+ new URIReferenceImpl(URI.create("test:a")),
+ new URIReferenceImpl(URI.create("test:b")),
+ new URIReferenceImpl(URI.create("test:c")))));
+
+ // check it
+ Answer answer = session.query(createQuery(model2URI));
+ answer.beforeFirst();
+ assertTrue(answer.next());
+ assertEquals(new URIReferenceImpl(new URI("test:a")), answer.getObject(0));
+ assertEquals(new URIReferenceImpl(new URI("test:b")), answer.getObject(1));
+ assertEquals(new URIReferenceImpl(new URI("test:c")), answer.getObject(2));
+ assertFalse(answer.next());
answer.close();
+ // delete it
+ session.delete(model2URI, Collections.singleton(new TripleImpl(
+ new URIReferenceImpl(URI.create("test:a")),
+ new URIReferenceImpl(URI.create("test:b")),
+ new URIReferenceImpl(URI.create("test:c")))));
+
+ // check it
+ answer = session.query(createQuery(model2URI));
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ session.removeModel(model2URI);
+
resource.end(xid, XAResource.TMSUCCESS);
resource.commit(xid, true);
} finally {
@@ -348,6 +371,59 @@
} catch (Exception e) {
fail(e);
}
+
+ // insert-select and delete-select
+ try {
+ DatabaseSession session = (DatabaseSession)database.newSession();
+ try {
+ // start txn
+ XAResource resource = session.getXAResource();
+ Xid xid = new TestXid(1);
+ resource.start(xid, XAResource.TMNOFLAGS);
+
+ session.createModel(model2URI, null);
+ session.createModel(model3URI, null);
+
+ // insert data
+ session.insert(model2URI, Collections.singleton(new TripleImpl(
+ new URIReferenceImpl(URI.create("test:a")),
+ new URIReferenceImpl(URI.create("test:b")),
+ new URIReferenceImpl(URI.create("test:c")))));
+
+ // insert-select
+ session.insert(model3URI, createQuery(model2URI));
+
+ // check it
+ Answer answer = session.query(createQuery(model3URI));
+ answer.beforeFirst();
+ assertTrue(answer.next());
+ assertEquals(new URIReferenceImpl(new URI("test:a")), answer.getObject(0));
+ assertEquals(new URIReferenceImpl(new URI("test:b")), answer.getObject(1));
+ assertEquals(new URIReferenceImpl(new URI("test:c")), answer.getObject(2));
+ assertFalse(answer.next());
+ answer.close();
+
+ // delete it
+ session.delete(model3URI, createQuery(model2URI));
+
+ // check it
+ answer = session.query(createQuery(model3URI));
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ // clean up
+ session.removeModel(model2URI);
+ session.removeModel(model3URI);
+
+ resource.end(xid, XAResource.TMSUCCESS);
+ resource.commit(xid, true);
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
}
public void testMultipleQuery() throws URISyntaxException {
@@ -360,46 +436,10 @@
Xid xid = new TestXid(1);
resource.start(xid, XAResource.TMNOFLAGS);
try {
- 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 answer1 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer1 = session.query(createQuery(modelURI));
+ Answer answer2 = session.query(createQuery(modelURI));
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
-
compareResults(answer1, answer2);
answer1.close();
@@ -426,47 +466,9 @@
Xid xid = new TestXid(1);
resource.start(xid, XAResource.TMNOFLAGS);
- 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 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
+ compareResults(expectedResults(), answer);
answer.close();
resource.end(xid, XAResource.TMSUCCESS);
@@ -490,47 +492,12 @@
Xid xid2 = new TestXid(2);
resource.start(xid1, XAResource.TMNOFLAGS);
try {
- 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 answer1 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer1 = session.query(createQuery(modelURI));
resource.end(xid1, XAResource.TMSUSPEND);
resource.start(xid2, XAResource.TMNOFLAGS);
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer2 = session.query(createQuery(modelURI));
resource.end(xid2, XAResource.TMSUSPEND);
compareResults(answer1, answer2);
@@ -570,35 +537,11 @@
rwResource.end(xid1, XAResource.TMSUSPEND);
try {
- 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);
-
Xid xid2 = new TestXid(2);
roResource.start(xid2, XAResource.TMNOFLAGS);
// Evaluate the query
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
roResource.end(xid2, XAResource.TMSUSPEND);
answer.beforeFirst();
@@ -618,39 +561,10 @@
Xid xid3 = new TestXid(3);
roResource.start(xid3, XAResource.TMNOFLAGS);
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(model2URI), // 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 answer2 = session.query(createQuery(model2URI));
roResource.end(xid3, XAResource.TMSUSPEND);
- 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, answer2);
+ compareResults(expectedResults(), answer2);
answer2.close();
Xid xid4 = new TestXid(4);
@@ -1068,7 +982,7 @@
// Check committed phase is now updated and write-lock available
rwResource.start(xid3, XAResource.TMNOFLAGS);
assertChangeVisible(session2);
-
+
// Check internal transaction read-only
assertChangeVisible(session1);
@@ -1094,78 +1008,16 @@
}
private void assertChangeVisible(Session session) throws Exception {
- 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 = session.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 answer = session.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
}
private void assertChangeNotVisible(Session session) throws Exception {
- 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 = session.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 answer = session.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
@@ -1207,48 +1059,10 @@
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 answer = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
resource2.end(new TestXid(3), XAResource.TMSUCCESS);
@@ -1345,48 +1159,10 @@
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 answer = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
session2.setAutoCommit(true);
@@ -1480,48 +1256,10 @@
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 answer = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
resource.end(new TestXid(1), XAResource.TMSUCCESS);
@@ -1628,32 +1366,8 @@
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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -1750,32 +1464,8 @@
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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -1871,32 +1561,8 @@
roResource.start(new TestXid(3), XAResource.TMNOFLAGS);
- 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 = session.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 answer = session.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
@@ -1908,28 +1574,9 @@
rwResource.rollback(new TestXid(2));
roResource.start(new TestXid(4), XAResource.TMNOFLAGS);
- selectList = new ArrayList(3);
- selectList.add(subjectVariable);
- selectList.add(predicateVariable);
- selectList.add(objectVariable);
// Evaluate the query
- answer = session.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 = session.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -1950,8 +1597,7 @@
* Tests cleaning up a transaction on close. This test added in the process
* of fixing a bug reported by Ronald on the JTA-beta.
*/
- public void testInternalSerialMultipleSessions() throws URISyntaxException
- {
+ public void testInternalSerialMultipleSessions() throws URISyntaxException {
logger.info("testInternalSerialMultipleSessions");
URI fileURI = new File("data/xatest-model1.rdf").toURI();
@@ -1976,10 +1622,576 @@
}
}
+
+ /**
+ * Test transaction timeout.
+ */
+ public void testTransactionTimeout() throws URISyntaxException {
+ logger.info("testTransactionTimeout");
+ URI fileURI = new File("data/xatest-model1.rdf").toURI();
+
+ // test idle timeout
+ try {
+ Session session1 = database.newSession();
+ session1.setIdleTimeout(1000);
+
+ try {
+ XAResource resource = session1.getXAResource();
+ Xid xid = new TestXid(1);
+ resource.start(xid, XAResource.TMNOFLAGS);
+
+ session1.createModel(model3URI, null);
+
+ resource.end(xid, XAResource.TMSUCCESS);
+ resource.commit(xid, true);
+
+ logger.debug("Starting transaction for session1");
+ resource.start(xid, XAResource.TMNOFLAGS);
+ logger.debug("Started transaction for session1");
+
+ Thread t2 = new Thread("tx2IdleTest") {
+ public void run() {
+ try {
+ Session session2 = database.newSession();
+ try {
+ logger.debug("Obtaining autocommit for session2");
+ session2.setAutoCommit(false);
+ logger.debug("Obtained autocommit for session2");
+
+ // Evaluate the query
+ Answer answer = session2.query(createQuery(model3URI));
+
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ logger.debug("Releasing autocommit for session2");
+ session2.setAutoCommit(true);
+ } finally {
+ session2.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ };
+ t2.start();
+
+ session1.setModel(model3URI, new ModelResource(fileURI));
+ logger.debug("Sleeping for 1sec");
+ Thread.sleep(1000);
+ logger.debug("Slept for 1sec");
+ 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());
+
+ rollbackTimedOutTxn(resource, xid, true);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+
+ // test transaction timeout
+ try {
+ Session session1 = database.newSession();
+ try {
+ XAResource resource = session1.getXAResource();
+ Xid xid = new TestXid(1);
+ resource.start(xid, XAResource.TMNOFLAGS);
+
+ session1.createModel(model3URI, null);
+
+ resource.end(xid, XAResource.TMSUCCESS);
+ resource.commit(xid, true);
+
+ logger.debug("Starting transaction for session1");
+ assertTrue(resource.setTransactionTimeout(1));
+ assertEquals(1, resource.getTransactionTimeout());
+ resource.start(xid, XAResource.TMNOFLAGS);
+ logger.debug("Started transaction for session1");
+
+ Thread t2 = new Thread("tx2Test") {
+ public void run() {
+ try {
+ Session session2 = database.newSession();
+ try {
+ logger.debug("Obtaining autocommit for session2");
+ session2.setAutoCommit(false);
+ logger.debug("Obtained autocommit for session2");
+
+ // Evaluate the query
+ Answer answer = session2.query(createQuery(model3URI));
+
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+
+ logger.debug("Releasing autocommit for session2");
+ session2.setAutoCommit(true);
+ } finally {
+ session2.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ };
+ t2.start();
+
+ session1.setModel(model3URI, new ModelResource(fileURI));
+ logger.debug("Sleeping for 1sec");
+ Thread.sleep(1000);
+ logger.debug("Slept for 1sec");
+ 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());
+
+ rollbackTimedOutTxn(resource, xid, true);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+
+ // test transaction timeout interrupting active operation
+ try {
+ Session session1 = database.newSession();
+ try {
+ XAResource resource = session1.getXAResource();
+
+ assertTrue(resource.setTransactionTimeout(1));
+ assertEquals(1, resource.getTransactionTimeout());
+
+ Xid xid = new TestXid(1);
+ resource.start(xid, XAResource.TMNOFLAGS);
+ logger.debug("Started transaction for session1");
+
+ URI delayTwoSecs = new URI("foo://mulgara/timeoutTest?active=mr&hardWait=2000");
+ session1.createModel(delayTwoSecs, new URI(Mulgara.NAMESPACE + "MockModel"));
+
+ try {
+ Answer answer = session1.query(createQuery(delayTwoSecs));
+ Thread.sleep(100L);
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ fail("query should've gotten interrupted");
+ } catch (TuplesException te) {
+ logger.debug("query was interrupted", te);
+ }
+
+ rollbackTimedOutTxn(resource, xid, true);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+
+ // test transaction timeout while operation is waiting for mutex
+ try {
+ final Session session1 = database.newSession();
+ try {
+ XAResource resource = session1.getXAResource();
+
+ assertTrue(resource.setTransactionTimeout(1));
+ assertEquals(1, resource.getTransactionTimeout());
+
+ Xid xid = new TestXid(1);
+ resource.start(xid, XAResource.TMNOFLAGS);
+ logger.debug("Started transaction for session1");
+
+ final URI delayTwoSecs = new URI("foo://mulgara/timeoutTest?active=mr&hardWait=2000");
+ session1.createModel(delayTwoSecs, new URI(Mulgara.NAMESPACE + "MockModel"));
+
+ Thread t2 = new Thread("timeoutTest") {
+ public void run() {
+ try {
+ try {
+ // this acquires mutex and holds it for 2s
+ Answer answer = session1.query(createQuery(delayTwoSecs));
+ Thread.sleep(100L); // allow rollback to proceed
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ fail("query should've gotten interrupted");
+ } catch (TuplesException te) {
+ logger.debug("query was interrupted", te);
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+ };
+ t2.start();
+ Thread.sleep(100L);
+
+ // blocks, waiting for mutex; when it does get it, it should rollback or see a rb
+ try {
+ Answer answer = session1.query(createQuery(model3URI));
+ Thread.sleep(100L); // allow rollback to proceed
+ answer.beforeFirst();
+ assertFalse(answer.next());
+ answer.close();
+ fail("query should've gotten aborted");
+ } catch (TuplesException te) {
+ logger.debug("query was aborted", te);
+ }
+
+ t2.join(500);
+ assertFalse("timeout-test thread should've terminated", t2.isAlive());
+
+ rollbackTimedOutTxn(resource, xid, true);
+ } finally {
+ session1.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+ private void rollbackTimedOutTxn(XAResource resource, Xid xid, boolean tryCommit) throws XAException {
+ try {
+ resource.end(xid, XAResource.TMSUCCESS);
+ if (tryCommit) {
+ resource.commit(xid, true);
+ fail("Commit should have failed due to transaction timeout");
+ }
+ } catch (XAException xae) {
+ }
+
+ logger.debug("Rolling back transaction");
+ try {
+ resource.rollback(xid);
+ fail("Rollback after timeout should have thrown XA_HEURRB");
+ } catch (XAException xae) {
+ assertEquals("Rollback after timeout should have thrown XA_HEURRB",
+ XAException.XA_HEURRB, xae.errorCode);
+ resource.forget(xid);
+ }
+ }
+
+ /**
+ * Test various operations after a transaction fails.
+ */
+ public void testTransactionFailure() {
+ logger.info("Testing transactionFailure");
+
+ try {
+ // query after failure should fail
+ shouldFailQE(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.query(createQuery(modelURI)).close();
+ }
+ }, "Query in failed transaction did not fail");
+
+ // insert after failure should fail
+ shouldFailQE(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.insert(modelURI, Collections.singleton(new TripleImpl(
+ new URIReferenceImpl(URI.create("test:a")),
+ new URIReferenceImpl(URI.create("test:b")),
+ new URIReferenceImpl(URI.create("test:c")))));
+ }
+ }, "Insert in failed transaction did not fail");
+
+ // start w/o end after failure should fail
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().start(xid, XAResource.TMNOFLAGS);
+ }
+ }, XAException.XAER_DUPID, true, "Start w/o end in failed transaction did not fail");
+
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().start(xid, XAResource.TMRESUME);
+ }
+ // XXX: shouldn't this be XAER_PROTO ?
+ }, XAException.XA_RBROLLBACK, true, "Start w/o end in failed transaction did not fail");
+
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().start(xid, XAResource.TMJOIN);
+ }
+ }, XAException.XAER_PROTO, true, "Start w/o end in failed transaction did not fail");
+
+ // prepare w/o end after failure should fail
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().prepare(xid);
+ }
+ // XXX: shouldn't this be XAER_PROTO ?
+ }, XAException.XA_RBROLLBACK, true, "Prepare w/o end in failed transaction did not fail");
+
+ // commit w/o end after failure should fail
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().commit(xid, true);
+ }
+ // XXX: shouldn't this be XAER_PROTO ?
+ }, XAException.XA_RBROLLBACK, true, "Commit w/o end in failed transaction did not fail");
+
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().commit(xid, false);
+ }
+ // XXX: shouldn't this be XAER_PROTO ?
+ }, XAException.XA_RBROLLBACK, true, "Commit w/o end in failed transaction did not fail");
+
+ // rollback w/o end after failure should fail
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().rollback(xid);
+ }
+ // XXX: shouldn't this be XAER_PROTO ?
+ }, XAException.XA_HEURRB, true, "Rollback w/o end in failed transaction did not fail");
+
+ // prepare after failure should fail
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().prepare(xid);
+ }
+ }, XAException.XA_RBROLLBACK, false, "Prepare in failed transaction did not fail");
+
+ // commit after failure should fail
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().commit(xid, true);
+ }
+ }, XAException.XA_RBROLLBACK, false, "Commit in failed transaction did not fail");
+
+ shouldFailXAErr(new TestOp() {
+ public void run(Session session, Xid xid) throws Exception {
+ session.getXAResource().commit(xid, false);
+ }
+ // XXX: shouldn't this be XAER_PROTO ?
+ }, XAException.XA_RBROLLBACK, false, "Commit w/o prepare in failed transaction did not fail");
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+ private void shouldFailQE(TestOp op, String msg) throws Exception {
+ testTransactionFailureOp(op, true, 0, true, msg);
+ }
+
+ private void shouldFailXAErr(TestOp op, int expXAErr, boolean beforeEnd, String msg) throws Exception {
+ testTransactionFailureOp(op, false, expXAErr, beforeEnd, msg);
+ }
+
+ /*
+ private void shouldSucceed(TestOp op) throws Exception {
+ testTransactionFailureOp(op, false, null);
+ }
+ */
+
+ private void testTransactionFailureOp(TestOp op, boolean shouldFailQE, int expXAErr,
+ boolean beforeEnd, String msg) throws Exception {
+ Session session = database.newSession();
+ try {
+ boolean shouldFail = shouldFailQE || expXAErr != 0;
+
+ // start tx
+ XAResource resource = session.getXAResource();
+
+ Xid xid = new TestXid(1);
+ resource.start(xid, XAResource.TMNOFLAGS);
+
+ // run bad query -> failed tx
+ try {
+ session.query(createQuery(URI.create("urn:no:such:model")));
+ fail("Bad query failed to throw exception");
+ } catch (QueryException qe) {
+ }
+
+ // run test op, verify it succeeds/fails, and reset
+ if (!beforeEnd) {
+ try {
+ resource.end(xid, XAResource.TMSUCCESS);
+ } catch (XAException xae) {
+ if (!isRollback(xae))
+ throw xae;
+ }
+ }
+
+ try {
+ op.run(session, xid);
+ if (shouldFail)
+ fail(msg);
+ } catch (QueryException qe) {
+ if (!shouldFailQE)
+ throw qe;
+ } catch (XAException xae) {
+ assertTrue(msg + ": " + xae.errorCode,
+ xae.errorCode == expXAErr || xae.errorCode == XAException.XAER_NOTA);
+ }
+
+ try {
+ if (beforeEnd) {
+ try {
+ resource.end(xid, XAResource.TMSUCCESS);
+ } catch (XAException xae) {
+ if (!isRollback(xae))
+ throw xae;
+ }
+ }
+
+ try {
+ resource.rollback(xid);
+ } catch (XAException xae) {
+ if (xae.errorCode == XAException.XA_HEURRB)
+ resource.forget(xid);
+ else if (!isRollback(xae))
+ throw xae;
+ }
+ } catch (XAException xae) {
+ if (!shouldFail || xae.errorCode != XAException.XAER_NOTA)
+ throw xae;
+ }
+
+ // verify we're good to go
+ resource.start(xid, XAResource.TMNOFLAGS);
+ session.query(createQuery(modelURI)).close();
+ resource.end(xid, XAResource.TMSUCCESS);
+ resource.commit(xid, true);
+ } finally {
+ session.close();
+ }
+ }
+
+ private static boolean isRollback(XAException xae) {
+ return xae.errorCode >= XAException.XA_RBBASE && xae.errorCode <= XAException.XA_RBEND;
+ }
+
+ private static interface TestOp {
+ 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
//
+ private Query createQuery(URI model) {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List<SelectElement> selectList = new ArrayList<SelectElement>(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ return new Query(
+ selectList, // SELECT
+ new ModelResource(model), // 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
+ );
+ }
+
+ private String[][] expectedResults() {
+ return new String[][] {
+ { "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" },
+ };
+ }
+
private void compareResults(String[][] expected, Answer answer) throws Exception {
try {
answer.beforeFirst();
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/GlobalizedAnswer.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/GlobalizedAnswer.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/GlobalizedAnswer.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -35,7 +35,6 @@
// Locally written packages
import org.mulgara.query.Answer;
-import org.mulgara.query.QueryException;
import org.mulgara.query.TuplesException;
import org.mulgara.query.Variable;
import org.mulgara.resolver.spi.GlobalizeException;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolver.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -31,8 +31,6 @@
// Java 2 standard packages
import javax.transaction.xa.XAResource;
import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Set;
// Third party packages
import org.apache.log4j.Logger; // Apache Log4J
@@ -40,12 +38,10 @@
// Local packages
import org.mulgara.query.*;
import org.mulgara.query.rdf.URIReferenceImpl;
-import org.mulgara.resolver.spi.DummyXAResource;
import org.mulgara.resolver.spi.LocalizeException;
import org.mulgara.resolver.spi.Resolution;
import org.mulgara.resolver.spi.Resolver;
import org.mulgara.resolver.spi.ResolverException;
-import org.mulgara.resolver.spi.ResolverFactory;
import org.mulgara.resolver.spi.ResolverFactoryException;
import org.mulgara.resolver.spi.ResolverSession;
import org.mulgara.resolver.spi.SingletonStatements;
@@ -53,7 +49,6 @@
import org.mulgara.resolver.view.SessionView;
import org.mulgara.resolver.view.ViewMarker;
import org.mulgara.store.nodepool.NodePool;
-import org.mulgara.store.tuples.Tuples;
/**
* Access to models that appear in the system model (<code>#</code>).
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolverFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolverFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/InternalResolverFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -34,7 +34,6 @@
import org.mulgara.resolver.spi.ResolverFactory;
import org.mulgara.resolver.spi.ResolverFactoryException;
import org.mulgara.resolver.spi.ResolverSession;
-import org.mulgara.store.nodepool.NodePool;
/**
* Wrapper around an external {@link ResolverFactory} that applies caching to
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -30,7 +30,6 @@
// Java 2 standard packages
import java.net.URI;
import java.util.Set;
-import java.io.File;
// Third party packages
import org.apache.log4j.Logger;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSessionFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSessionFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/JRDFResolverSessionFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -39,7 +39,6 @@
// Local packages
import org.mulgara.resolver.spi.*;
import org.mulgara.store.nodepool.NodePoolException;
-import org.mulgara.store.stringpool.StringPool;
import org.mulgara.store.stringpool.StringPoolException;
import org.mulgara.store.xa.SimpleXARecoveryHandler;
import org.mulgara.store.xa.SimpleXAResourceException;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/JotmTransactionStandaloneTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/JotmTransactionStandaloneTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/JotmTransactionStandaloneTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -46,16 +46,10 @@
// Locally written packages
import org.mulgara.query.*;
-import org.mulgara.query.rdf.Mulgara;
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.query.rdf.TripleImpl;
import org.mulgara.server.Session;
-import org.mulgara.server.SessionFactory;
-import org.mulgara.server.driver.SessionFactoryFinder;
-import org.mulgara.util.FileUtil;
-import org.mulgara.query.QueryException;
-import org.mulgara.server.JRDFSession;
import org.mulgara.server.SessionFactory;
import org.mulgara.server.driver.SessionFactoryFinder;
@@ -250,47 +244,9 @@
try {
txManager.getTransaction().enlistResource(session.getXAResource());
- 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 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
+ compareResults(expectedResults(), answer);
answer.close();
txManager.commit();
@@ -314,47 +270,9 @@
txManager.getTransaction().enlistResource(session.getXAResource());
txManager.getTransaction().enlistResource(session.getXAResource());
- 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 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
+ compareResults(expectedResults(), answer);
answer.close();
txManager.commit();
@@ -375,45 +293,10 @@
Session session = sessionFactory.newSession();
txManager.getTransaction().enlistResource(session.getXAResource());
try {
- 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 answer1 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer1 = session.query(createQuery(modelURI));
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer2 = session.query(createQuery(modelURI));
compareResults(answer1, answer2);
@@ -438,47 +321,9 @@
try {
txManager.getTransaction().enlistResource(session.getReadOnlyXAResource());
- 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 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
+ compareResults(expectedResults(), answer);
answer.close();
txManager.commit();
@@ -501,51 +346,16 @@
tx1.enlistResource(roResource);
try {
- 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 answer1 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
-
+ Answer answer1 = session.query(createQuery(modelURI));
+
tx1 = txManager.suspend();
txManager.begin();
Transaction tx2 = txManager.getTransaction();
tx2.enlistResource(roResource);
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer2 = session.query(createQuery(modelURI));
tx2 = txManager.suspend();
@@ -576,51 +386,16 @@
tx1.enlistResource(session.getReadOnlyXAResource());
try {
- 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 answer1 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
-
+ Answer answer1 = session.query(createQuery(modelURI));
+
tx1 = txManager.suspend();
txManager.begin();
Transaction tx2 = txManager.getTransaction();
tx2.enlistResource(session.getReadOnlyXAResource());
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // FROM
- new ConstraintImpl(subjectVariable, // WHERE
- predicateVariable,
- objectVariable),
- null, // HAVING
- Collections.singletonList( // ORDER BY
- new Order(subjectVariable, true)
- ),
- null, // LIMIT
- 0, // OFFSET
- new UnconstrainedAnswer() // GIVEN
- ));
+ Answer answer2 = session.query(createQuery(modelURI));
tx2 = txManager.suspend();
@@ -660,35 +435,11 @@
Transaction tx1 = txManager.suspend();
try {
- 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);
-
txManager.begin();
txManager.getTransaction().enlistResource(roResource);
// Evaluate the query
- Answer answer = session.query(new Query(
- selectList, // SELECT
- new ModelResource(modelURI), // 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 answer = session.query(createQuery(modelURI));
Transaction tx2 = txManager.suspend();
@@ -709,40 +460,11 @@
txManager.begin();
txManager.getTransaction().enlistResource(roResource);
- Answer answer2 = session.query(new Query(
- selectList, // SELECT
- new ModelResource(model2URI), // 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 answer2 = session.query(createQuery(model2URI));
Transaction tx3 = txManager.suspend();
- 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, answer2);
+ compareResults(expectedResults(), answer2);
answer2.close();
txManager.begin();
@@ -1185,78 +907,16 @@
}
private void assertChangeVisible(Session session) throws Exception {
- 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 = session.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 answer = session.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
}
private void assertChangeNotVisible(Session session) throws Exception {
- 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 = session.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 answer = session.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
@@ -1298,48 +958,10 @@
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 answer = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
resource2.end(new TestXid(3), XAResource.TMSUCCESS);
@@ -1436,48 +1058,10 @@
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 answer = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
session2.setAutoCommit(true);
@@ -1571,48 +1155,10 @@
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 answer = session2.query(createQuery(model3URI));
- 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);
+ compareResults(expectedResults(), answer);
answer.close();
resource.end(new TestXid(1), XAResource.TMSUCCESS);
@@ -1719,32 +1265,8 @@
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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -1841,32 +1363,8 @@
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 answer = session2.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -1962,32 +1460,8 @@
roResource.start(new TestXid(3), XAResource.TMNOFLAGS);
- 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 = session.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 answer = session.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
answer.close();
@@ -2005,22 +1479,7 @@
selectList.add(objectVariable);
// Evaluate the query
- answer = session.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 = session.query(createQuery(model3URI));
answer.beforeFirst();
assertFalse(answer.next());
@@ -2057,6 +1516,51 @@
// Internal methods
//
+ private Query createQuery(URI model) {
+ Variable subjectVariable = new Variable("subject");
+ Variable predicateVariable = new Variable("predicate");
+ Variable objectVariable = new Variable("object");
+
+ List<SelectElement> selectList = new ArrayList<SelectElement>(3);
+ selectList.add(subjectVariable);
+ selectList.add(predicateVariable);
+ selectList.add(objectVariable);
+
+ return new Query(
+ selectList, // SELECT
+ new ModelResource(model), // 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
+ );
+ }
+
+ private String[][] expectedResults() {
+ return new String[][] {
+ { "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" },
+ };
+ }
+
private void compareResults(String[][] expected, Answer answer) throws Exception {
try {
answer.beforeFirst();
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/LocalJRDFDatabaseSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -30,16 +30,8 @@
// Java 2 standard packages
import java.io.*;
import java.net.URI;
-import java.net.URISyntaxException;
import java.util.*;
-import javax.transaction.xa.XAResource;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-// Java 2 enterprise packages
-import javax.transaction.TransactionManager;
-
// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.*;
@@ -53,6 +45,7 @@
import org.mulgara.resolver.spi.*;
import org.mulgara.server.*;
import org.mulgara.store.statement.StatementStore;
+import org.mulgara.transaction.TransactionManagerFactory;
/**
* A JRDF database session.
@@ -123,6 +116,7 @@
* @throws IllegalArgumentException if any argument is <code>null</code>
*/
LocalJRDFDatabaseSession(MulgaraTransactionManager transactionManager,
+ TransactionManagerFactory transactionManagerFactory,
List securityAdapterList, List symbolicTransformationList,
ResolverSessionFactory resolverSessionFactory,
SystemResolverFactory systemResolverFactory,
@@ -131,8 +125,8 @@
DatabaseMetadata metadata, ContentHandlerManager contentHandlers,
Set cachedResolverFactorySet, URI temporaryModelTypeURI)
throws ResolverFactoryException {
- super(transactionManager, securityAdapterList, symbolicTransformationList,
- resolverSessionFactory,
+ super(transactionManager, transactionManagerFactory, securityAdapterList,
+ symbolicTransformationList, resolverSessionFactory,
systemResolverFactory, temporaryResolverFactory, resolverFactoryList,
externalResolverFactoryMap, internalResolverFactoryMap, metadata,
contentHandlers, cachedResolverFactorySet, temporaryModelTypeURI);
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/LoginOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/LoginOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/LoginOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -36,7 +36,6 @@
// Local packages
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
/**
* An {@link Operation} that implements the {@link Session#login} method.
Copied: trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolver.java (from rev 1097, branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MockResolver.java)
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolver.java (rev 0)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolver.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2008 The Topaz Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ * Contributions:
+ */
+
+package org.mulgara.resolver;
+
+// Java 2 standard packages;
+import java.net.URI;
+
+// Third party packages
+import javax.transaction.xa.XAResource;
+
+import org.apache.log4j.Logger;
+import org.jrdf.graph.Node;
+import org.jrdf.graph.URIReference;
+
+// Locally written packages
+import org.mulgara.query.Constraint;
+import org.mulgara.query.LocalNode;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.TuplesException;
+import org.mulgara.resolver.spi.DummyXAResource;
+import org.mulgara.resolver.spi.EmptyResolution;
+import org.mulgara.resolver.spi.GlobalizeException;
+import org.mulgara.resolver.spi.Resolution;
+import org.mulgara.resolver.spi.Resolver;
+import org.mulgara.resolver.spi.ResolverException;
+import org.mulgara.resolver.spi.ResolverSession;
+import org.mulgara.resolver.spi.Statements;
+
+/**
+ * Simple mock resolver. All operations are dummys: model creation, removing, and modifying are
+ * no-ops, and queries return an empty resolution. The model name is parsed for commands to
+ * execute: the model must have a query string consisting of an '&' separated list of commands
+ * where each command is of the form "name=value" (the value may be empty) (i.e. follow http
+ * query string syntax for parameters).
+ *
+ * <p>Currently the only commands supported: are 'active', 'wait', and 'hardWait':
+ * <dl>
+ * <dt>active</dt>
+ * <dd>the value must be any combination of the characters 'c', 'd', 'm', 'r', 'f', 'n', or
+ * 'l', which stand for 'Resolver.createModel', 'Resolver.dropModel', 'Resolver.modifyModel',
+ * 'Resolver.resolve', 'Answer.beforeFirst', 'Answer.next', and 'Answer.cLose', respectively.
+ * The commands after this one are only executed for these operations. If not specified, the
+ * default is 'cdmrfnl' (i.e. all operations)</dd>
+ * <dt>wait</dt>
+ * <dd>the value is the number of milliseconds to sleep before continuing.</dd>
+ * <dt>hardWait</dt>
+ * <dd>like <var>wait</var>, but ignore interrupts.</dd>
+ * </dl>
+ *
+ * @created 2009-07-05
+ * @author Ronald Tschalär
+ * @copyright ©2008 <a href="http://www.topazproject.org/">Topaz Foundation</a>
+ * @licence Apache License v2.0
+ */
+public class MockResolver implements Resolver {
+ /** Logger */
+ private static Logger logger = Logger.getLogger(MockResolver.class);
+
+ /** The session that this resolver is associated with */
+ private final ResolverSession resolverSession;
+
+ MockResolver(ResolverSession resolverSession) {
+ this.resolverSession = resolverSession;
+ }
+
+ public void createModel(long model, URI modelTypeURI) throws ResolverException {
+ processCommands(model, 'c', ResolverException.class);
+ }
+
+ public XAResource getXAResource() {
+ return new DummyXAResource(10);
+ }
+
+ public void modifyModel(long model, Statements statements, boolean occurs) throws ResolverException {
+ processCommands(model, 'm', ResolverException.class);
+ }
+
+ public void removeModel(long model) throws ResolverException {
+ processCommands(model, 'd', ResolverException.class);
+ }
+
+ public Resolution resolve(Constraint constraint) throws QueryException {
+ long model = ((LocalNode) constraint.getModel()).getValue();
+ processCommands(model, 'r', QueryException.class);
+ return new MockEmptyResolution(constraint, model);
+ }
+
+ public void abort() {}
+
+ private <T extends Throwable> void processCommands(long model, char op, Class<T> exc) throws T {
+ URI modelUri = toURI(model, exc);
+ logger.debug("model-uri='" + modelUri + "', op='" + op + "'");
+
+ String query = modelUri.getQuery();
+ if (query == null) {
+ logger.debug("no query found, no commands");
+ return;
+ }
+
+ for (String param : query.split("&")) {
+ String name = param.substring(0, param.indexOf('='));
+ String value = param.substring(param.indexOf('=') + 1);
+
+ logger.debug("processing command '" + name + "' with value '" + value + "'");
+
+ if (name.equals("active")) {
+ if (value.indexOf(op) < 0) {
+ break;
+ }
+ } else if (name.equals("wait")) {
+ logger.debug("sleeping '" + value + "' milliseconds");
+ try {
+ Thread.sleep(Long.parseLong(value));
+ } catch (InterruptedException ie) {
+ throw MulgaraTransactionFactory.newExceptionOrCause(exc, "sleep interrupted", ie);
+ }
+ } else if (name.equals("hardWait")) {
+ logger.debug("sleeping '" + value + "' milliseconds");
+ long targetDate = System.currentTimeMillis() + Long.parseLong(value);
+ while (true) {
+ long wait = targetDate - System.currentTimeMillis();
+ if (wait <= 0)
+ break;
+ try {
+ Thread.sleep(wait);
+ } catch (InterruptedException ie) {
+ }
+ }
+ } else {
+ logger.info("Unknown command '" + name + "' - ignoring");
+ }
+ }
+ }
+
+ private <T extends Throwable> URI toURI(long model, Class<T> exc) throws T {
+ try {
+ Node globalModel = resolverSession.globalize(model);
+ return ((URIReference) globalModel).getURI();
+ } catch (GlobalizeException ge) {
+ throw MulgaraTransactionFactory.newExceptionOrCause(exc, "Couldn't globalize model", ge);
+ }
+ }
+
+ private class MockEmptyResolution extends EmptyResolution {
+ private final long model;
+
+ public MockEmptyResolution(Constraint constraint, long model) {
+ super(constraint, true);
+ this.model = model;
+ }
+
+ public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
+ processCommands(model, 'f', TuplesException.class);
+ super.beforeFirst(prefix, suffixTruncation);
+ }
+
+ public boolean next() throws TuplesException {
+ processCommands(model, 'n', TuplesException.class);
+ return super.next();
+ }
+
+ public void close() {
+ processCommands(model, 'l', RuntimeException.class);
+ super.close();
+ }
+ }
+}
Copied: trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolverFactory.java (from rev 1097, branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MockResolverFactory.java)
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolverFactory.java (rev 0)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MockResolverFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008 The Topaz Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ * Contributions:
+ */
+
+package org.mulgara.resolver;
+
+// Java 2 standard packages
+import java.net.URI;
+
+// Locally written packages
+import org.mulgara.query.rdf.Mulgara;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.resolver.spi.InitializerException;
+import org.mulgara.resolver.spi.Resolver;
+import org.mulgara.resolver.spi.ResolverException;
+import org.mulgara.resolver.spi.ResolverFactory;
+import org.mulgara.resolver.spi.ResolverFactory.Graph;
+import org.mulgara.resolver.spi.ResolverFactoryException;
+import org.mulgara.resolver.spi.ResolverFactoryInitializer;
+import org.mulgara.resolver.spi.ResolverSession;
+
+/**
+ * Factory for simple mock resolver.
+ *
+ * @created 2009-07-05
+ * @author Ronald Tschalär
+ * @copyright ©2008 <a href="http://www.topazproject.org/">Topaz Foundation</a>
+ * @licence Apache License v2.0
+ */
+public class MockResolverFactory implements ResolverFactory {
+ private static URI modelTypeURI = URI.create(Mulgara.NAMESPACE + "MockModel");
+
+ private MockResolverFactory(ResolverFactoryInitializer resolverFactoryInitializer)
+ throws ResolverException, InitializerException {
+ resolverFactoryInitializer.preallocate(new URIReferenceImpl(modelTypeURI));
+ resolverFactoryInitializer.addModelType(modelTypeURI, this);
+ }
+
+ public void close() { }
+ public void delete() { }
+ public Graph[] getDefaultGraphs() { return null; }
+ public boolean supportsExport() { return true; }
+
+ public static ResolverFactory newInstance(ResolverFactoryInitializer resolverFactoryInitializer)
+ throws ResolverException, InitializerException {
+ return new MockResolverFactory(resolverFactoryInitializer);
+ }
+
+ public Resolver newResolver(boolean canWrite, ResolverSession resolverSession, Resolver systemResolver)
+ throws ResolverFactoryException {
+ return new MockResolver(resolverSession);
+ }
+}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ModelExistsOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ModelExistsOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ModelExistsOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -41,7 +41,6 @@
import org.mulgara.query.*;
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
class ModelExistsOperation implements Operation
{
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/ModifyModelOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -39,7 +39,6 @@
import org.mulgara.query.*;
import org.mulgara.query.rdf.URIReferenceImpl;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
/**
* An {@link Operation} that implements the {@link Session#insert} and
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -32,7 +32,6 @@
// Local packages
import org.mulgara.resolver.spi.DatabaseMetadata;
import org.mulgara.resolver.spi.EnlistableResource;
-import org.mulgara.resolver.spi.ResolverSessionFactory;
import org.mulgara.query.MulgaraTransactionException;
import org.mulgara.query.TuplesException;
@@ -65,9 +64,14 @@
private MulgaraExternalTransactionFactory factory;
private DatabaseOperationContext context;
+ private boolean inXACompletion;
+
private boolean hRollback;
private int heurCode;
private boolean rollback;
+ private String rollbackCause;
+ private boolean completed;
+ private volatile long lastActive;
MulgaraExternalTransaction(MulgaraExternalTransactionFactory factory, Xid xid, DatabaseOperationContext context)
throws QueryException {
@@ -82,9 +86,13 @@
this.xaResources = new HashMap<EnlistableResource, XAResource>();
+ this.inXACompletion = false;
+
this.hRollback = false;
this.heurCode = 0;
this.rollback = false;
+ this.completed = false;
+ this.lastActive = System.currentTimeMillis();
this.context.initiate(this);
}
@@ -107,102 +115,196 @@
public MulgaraTransactionException abortTransaction(String errorMessage, Throwable cause)
throws MulgaraTransactionException {
report("abortTransaction");
+
+ // we should actually already have the mutex, but let's make sure
+ acquireMutex(0L, true, MulgaraTransactionException.class);
try {
- for (EnlistableResource resource : enlisted) {
- try {
- resource.abort();
- } catch (Throwable throw_away) {}
+ if (rollbackCause == null)
+ rollbackCause = errorMessage;
+
+ try {
+ for (EnlistableResource resource : enlisted) {
+ try {
+ resource.abort();
+ } catch (Throwable throw_away) {}
+ }
+ for (EnlistableResource resource : prepared) {
+ try {
+ resource.abort();
+ } catch (Throwable throw_away) {}
+ }
+
+ return new MulgaraTransactionException(errorMessage, cause);
+ } finally {
+ completed = true;
+ factory.transactionComplete(this);
}
- for (EnlistableResource resource : prepared) {
- try {
- resource.abort();
- } catch (Throwable throw_away) {}
- }
-
- return new MulgaraTransactionException(errorMessage, cause);
} finally {
- factory.transactionComplete(this);
+ releaseMutex();
}
}
public void heuristicRollback(String cause) throws MulgaraTransactionException {
- report("heuristicRollback");
- hRollback = true;
+ report("heuristicRollback: " + cause);
+
+ synchronized (factory.getMutexLock()) {
+ if (factory.getMutexHolder() != null && factory.getMutexHolder() != Thread.currentThread()) {
+ if (inXACompletion) {
+ return; // this txn is already being cleaned up, so let it go
+ }
+ }
+
+ factory.acquireMutexWithInterrupt(0L, MulgaraTransactionException.class);
+ inXACompletion = true;
+ }
+
try {
- rollback(xid);
- } catch (XAException xa) {
- throw new MulgaraTransactionException("Failed heuristic rollback", xa);
+ if (hRollback)
+ return;
+ hRollback = true;
+
+ if (rollbackCause == null)
+ rollbackCause = cause;
+
+ try {
+ rollback(xid);
+ } catch (XAException xa) {
+ throw new MulgaraTransactionException("Failed heuristic rollback", xa);
+ } finally {
+ heurCode = heurCode == 0 ? XAException.XA_HEURRB : heurCode;
+ }
} finally {
- heurCode = heurCode == 0 ? XAException.XA_HEURRB : heurCode;
+ releaseMutex();
}
}
public void execute(Operation operation, DatabaseMetadata metadata) throws MulgaraTransactionException {
+ acquireMutex(0, false, MulgaraTransactionException.class);
try {
- operation.execute(context,
- context.getSystemResolver(),
- metadata);
- } catch (Throwable th) {
+ checkActive(MulgaraTransactionException.class);
try {
- rollback(xid);
- } catch (XAException ex) {
- logger.error("Error in rollback after operation failure", ex);
+ long la = lastActive;
+ lastActive = -1;
+
+ operation.execute(context,
+ context.getSystemResolver(),
+ metadata);
+
+ lastActive = (la != -1) ? System.currentTimeMillis() : -1;
+ } catch (Throwable th) {
+ try {
+ heuristicRollback(th.toString());
+ } catch (MulgaraTransactionException ex) {
+ logger.error("Error in rollback after operation failure", ex);
+ }
+ throw new MulgaraTransactionException("Operation failed", th);
}
- throw new MulgaraTransactionException("Operation failed", th);
+ } finally {
+ releaseMutex();
}
}
public AnswerOperationResult execute(AnswerOperation ao) throws TuplesException {
+ acquireMutex(0, false, TuplesException.class);
try {
- ao.execute();
- return ao.getResult();
- } catch (Throwable th) {
+ checkActive(TuplesException.class);
try {
- logger.warn("Error in answer operation triggered rollback", th);
- rollback(xid);
- } catch (XAException ex) {
- logger.error("Error in rollback after answer-operation failure", ex);
+ long la = lastActive;
+ lastActive = -1;
+
+ ao.execute();
+
+ lastActive = (la != -1) ? System.currentTimeMillis() : -1;
+
+ return ao.getResult();
+ } catch (Throwable th) {
+ try {
+ logger.warn("Error in answer operation triggered rollback", th);
+ heuristicRollback(th.toString());
+ } catch (MulgaraTransactionException ex) {
+ logger.error("Error in rollback after answer-operation failure", ex);
+ }
+ throw new TuplesException("Request failed", th);
}
- throw new TuplesException("Request failed", th);
+ } finally {
+ releaseMutex();
}
}
// FIXME: See if we can't rearrange things to allow this to be deleted.
public void execute(TransactionOperation to) throws MulgaraTransactionException {
- to.execute();
+ acquireMutex(0, false, MulgaraTransactionException.class);
+ try {
+ checkActive(MulgaraTransactionException.class);
+
+ long la = lastActive;
+ lastActive = -1;
+
+ to.execute();
+
+ lastActive = (la != -1) ? System.currentTimeMillis() : -1;
+ } finally {
+ releaseMutex();
+ }
}
+ private <T extends Throwable> void checkActive(Class<T> exc) throws T {
+ if (hRollback)
+ throw factory.newException(exc, "Transaction was heuristically rolled back. Reason: " + rollbackCause);
+ if (rollback)
+ throw factory.newException(exc, "Transaction was rolled back. Reason: " + rollbackCause);
+ if (completed)
+ throw factory.newException(exc, "Transaction has been completed");
+ }
+
public void enlist(EnlistableResource enlistable) throws MulgaraTransactionException {
+ acquireMutex(0, false, MulgaraTransactionException.class);
try {
- XAResource res = enlistable.getXAResource();
- for (EnlistableResource eres : enlisted) {
- if (res.isSameRM(xaResources.get(eres))) {
- return;
+ try {
+ XAResource res = enlistable.getXAResource();
+ for (EnlistableResource eres : enlisted) {
+ if (res.isSameRM(xaResources.get(eres))) {
+ return;
+ }
}
+ enlisted.add(enlistable);
+ xaResources.put(enlistable, res);
+ // FIXME: We need to handle this uptodate operation properly - handle
+ // suspension or mid-prepare/commit.
+ // bringUptodate(res);
+ res.start(xid, XAResource.TMNOFLAGS);
+ } catch (XAException ex) {
+ throw new MulgaraTransactionException("Failed to enlist resource", ex);
}
- enlisted.add(enlistable);
- xaResources.put(enlistable, res);
- // FIXME: We need to handle this uptodate operation properly - handle
- // suspension or mid-prepare/commit.
- // bringUptodate(res);
- res.start(xid, XAResource.TMNOFLAGS);
- } catch (XAException ex) {
- throw new MulgaraTransactionException("Failed to enlist resource", ex);
+ } finally {
+ releaseMutex();
}
}
+ public long lastActive() {
+ return lastActive;
+ }
+
//
// Methods used to manage transaction from XAResource.
//
void commit(Xid xid) throws XAException {
report("commit");
- // FIXME: Consider the possiblity prepare failed, or was incomplete.
- for (EnlistableResource er : prepared) {
- xaResources.get(er).commit(xid, false);
- committed.add(er);
+
+ acquireMutex(0, true, XAException.class);
+ try {
+ lastActive = -1;
+
+ // FIXME: Consider the possiblity prepare failed, or was incomplete.
+ for (EnlistableResource er : prepared) {
+ xaResources.get(er).commit(xid, false);
+ committed.add(er);
+ }
+ cleanupTransaction();
+ } finally {
+ releaseMutex();
}
- cleanupTransaction();
}
boolean isHeuristicallyRollbacked() {
@@ -223,11 +325,20 @@
void prepare(Xid xid) throws XAException {
report("prepare");
- for (EnlistableResource er : enlisted) {
- xaResources.get(er).prepare(xid);
- prepared.add(er);
+
+ acquireMutex(0, true, XAException.class);
+ try {
+ long la = lastActive;
+ lastActive = -1;
+
+ for (EnlistableResource er : enlisted) {
+ xaResources.get(er).prepare(xid);
+ prepared.add(er);
+ }
+ lastActive = (la != -1) ? System.currentTimeMillis() : -1;
+ } finally {
+ releaseMutex();
}
- // status = PREPARED; ?
}
/**
@@ -236,77 +347,84 @@
*/
void rollback(Xid xid) throws XAException {
report("rollback");
+
+ acquireMutex(0, true, XAException.class);
try {
- rollback = true;
- Map<EnlistableResource, XAException> rollbackFailed = new HashMap<EnlistableResource, XAException>();
+ lastActive = -1;
+ try {
+ rollback = true;
+ Map<EnlistableResource, XAException> rollbackFailed = new HashMap<EnlistableResource, XAException>();
- for (EnlistableResource er : enlisted) {
- try {
- if (!committed.contains(er)) {
- xaResources.get(er).rollback(xid);
- rollbacked.add(er);
+ for (EnlistableResource er : enlisted) {
+ try {
+ if (!committed.contains(er)) {
+ xaResources.get(er).rollback(xid);
+ rollbacked.add(er);
+ }
+ } catch (XAException ex) {
+ logger.error("Attempt to rollback resource failed", ex);
+ rollbackFailed.put(er, ex);
}
- } catch (XAException ex) {
- logger.error("Attempt to rollback resource failed", ex);
- rollbackFailed.put(er, ex);
}
- }
- if (rollbackFailed.isEmpty()) {
- if (committed.isEmpty()) { // Clean failure and rollback
- return; // SUCCESSFUL ROLLBACK - RETURN
- } else { // No rollback-failure, but partial commit
- heurCode = XAException.XA_HEURMIX;
- throw new XAException(heurCode);
- }
- } else {
- // Something went wrong - start by assuming if one committed all committed
- heurCode = (committed.isEmpty()) ? 0 : XAException.XA_HEURCOM;
- // Then check every rollback failure code for a contradiction to all committed.
- for (XAException xaex : rollbackFailed.values()) {
- switch (xaex.errorCode) {
- case XAException.XA_HEURHAZ:
- case XAException.XAER_NOTA:
- case XAException.XAER_RMERR:
- case XAException.XAER_RMFAIL:
- case XAException.XAER_INVAL:
- case XAException.XAER_PROTO:
- // All these amount to not knowing the result - so we have a hazard
- // unless we already know we have a mixed result.
- if (heurCode != XAException.XA_HEURMIX) {
- heurCode = XAException.XA_HEURHAZ;
- }
- break;
- case XAException.XA_HEURCOM:
- if (!rollbacked.isEmpty() || heurCode == XAException.XA_HEURRB) {
- // We know something else was rollbacked, so we know we have a mixed result.
+ if (rollbackFailed.isEmpty()) {
+ if (committed.isEmpty()) { // Clean failure and rollback
+ return; // SUCCESSFUL ROLLBACK - RETURN
+ } else { // No rollback-failure, but partial commit
+ heurCode = XAException.XA_HEURMIX;
+ throw new XAException(heurCode);
+ }
+ } else {
+ // Something went wrong - start by assuming if one committed all committed
+ heurCode = (committed.isEmpty()) ? 0 : XAException.XA_HEURCOM;
+ // Then check every rollback failure code for a contradiction to all committed.
+ for (XAException xaex : rollbackFailed.values()) {
+ switch (xaex.errorCode) {
+ case XAException.XA_HEURHAZ:
+ case XAException.XAER_NOTA:
+ case XAException.XAER_RMERR:
+ case XAException.XAER_RMFAIL:
+ case XAException.XAER_INVAL:
+ case XAException.XAER_PROTO:
+ // All these amount to not knowing the result - so we have a hazard
+ // unless we already know we have a mixed result.
+ if (heurCode != XAException.XA_HEURMIX) {
+ heurCode = XAException.XA_HEURHAZ;
+ }
+ break;
+ case XAException.XA_HEURCOM:
+ if (!rollbacked.isEmpty() || heurCode == XAException.XA_HEURRB) {
+ // We know something else was rollbacked, so we know we have a mixed result.
+ heurCode = XAException.XA_HEURMIX;
+ } else if (heurCode == 0) {
+ heurCode = XAException.XA_HEURCOM;
+ } // else it's a HEURHAZ or a HEURCOM and stays that way.
+ break;
+ case XAException.XA_HEURRB:
+ if (!committed.isEmpty() || heurCode == XAException.XA_HEURCOM) {
+ heurCode = XAException.XA_HEURMIX;
+ } else if (heurCode == 0) {
+ heurCode = XAException.XA_HEURRB;
+ } // else it's a HEURHAZ or a HEURRB and stays that way.
+ break;
+ case XAException.XA_HEURMIX:
+ // It can't get worse than, we know we have a mixed result.
heurCode = XAException.XA_HEURMIX;
- } else if (heurCode == 0) {
- heurCode = XAException.XA_HEURCOM;
- } // else it's a HEURHAZ or a HEURCOM and stays that way.
- break;
- case XAException.XA_HEURRB:
- if (!committed.isEmpty() || heurCode == XAException.XA_HEURCOM) {
- heurCode = XAException.XA_HEURMIX;
- } else if (heurCode == 0) {
- heurCode = XAException.XA_HEURRB;
- } // else it's a HEURHAZ or a HEURRB and stays that way.
- break;
- case XAException.XA_HEURMIX:
- // It can't get worse than, we know we have a mixed result.
- heurCode = XAException.XA_HEURMIX;
- break;
- default:
- // The codes above are the only codes permitted from a rollback() so
- // anything else indicates a serious error in the resource-manager.
- throw new XAException(XAException.XAER_RMERR);
+ break;
+ default:
+ // The codes above are the only codes permitted from a rollback() so
+ // anything else indicates a serious error in the resource-manager.
+ throw new XAException(XAException.XAER_RMERR);
+ }
}
+
+ throw new XAException(heurCode);
}
-
- throw new XAException(heurCode);
+ } finally {
+ cleanupTransaction();
}
} finally {
- cleanupTransaction();
+ releaseMutex();
}
}
@@ -328,9 +446,22 @@
logger.error("Failed to abort transaction on cleanup failure", em2);
throw new XAException(XAException.XAER_RMFAIL);
}
+ } finally {
+ completed = true;
}
}
+ private <T extends Throwable> void acquireMutex(long timeout, boolean isXACompletion, Class<T> exc) throws T {
+ synchronized (factory.getMutexLock()) {
+ factory.acquireMutex(timeout, exc);
+ inXACompletion = isXACompletion;
+ }
+ }
+
+ private void releaseMutex() {
+ factory.releaseMutex();
+ }
+
private void report(String desc) {
if (logger.isInfoEnabled()) {
logger.info(desc + ": " + System.identityHashCode(this));
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransactionFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -19,9 +19,7 @@
package org.mulgara.resolver;
// Java2 packages
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.HashSet;
import java.util.Set;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
@@ -29,7 +27,6 @@
// Local packages
import org.mulgara.query.MulgaraTransactionException;
import org.mulgara.query.QueryException;
-import org.mulgara.util.Assoc1toNMap;
/**
* Manages external transactions.
@@ -46,41 +43,40 @@
*/
public class MulgaraExternalTransactionFactory extends MulgaraTransactionFactory {
- private Map<DatabaseSession, MulgaraExternalTransaction> associatedTransaction;
- private Assoc1toNMap<DatabaseSession, MulgaraExternalTransaction> sessionXAMap;
+ private final Set<MulgaraExternalTransaction> transactions;
- private Map<DatabaseSession, MulgaraXAResourceContext> xaResources;
+ private final MulgaraXAResourceContext xaResource;
- public MulgaraExternalTransactionFactory(MulgaraTransactionManager manager) {
- super(manager);
+ private MulgaraExternalTransaction associatedTransaction;
- this.associatedTransaction = new HashMap<DatabaseSession, MulgaraExternalTransaction>();
- this.sessionXAMap = new Assoc1toNMap<DatabaseSession, MulgaraExternalTransaction>();
- this.xaResources = new HashMap<DatabaseSession, MulgaraXAResourceContext>();
+ public MulgaraExternalTransactionFactory(DatabaseSession session, MulgaraTransactionManager manager) {
+ super(session, manager);
+
+ this.associatedTransaction = null;
+ this.transactions = new HashSet<MulgaraExternalTransaction>();
+ this.xaResource = new MulgaraXAResourceContext(this, session);
}
- public MulgaraTransaction getTransaction(final DatabaseSession session, boolean write)
- throws MulgaraTransactionException {
- acquireMutex();
+ public MulgaraTransaction getTransaction(boolean write) throws MulgaraTransactionException {
+ acquireMutex(0, MulgaraTransactionException.class);
try {
- MulgaraExternalTransaction xa = associatedTransaction.get(session);
- if (xa == null) {
+ if (associatedTransaction == null) {
throw new MulgaraTransactionException("No externally mediated transaction associated with session");
- } else if (write && xa != writeTransaction) {
+ } else if (write && associatedTransaction != writeTransaction) {
throw new MulgaraTransactionException("RO-transaction associated with session when requesting write operation");
}
- return xa;
+ return associatedTransaction;
} finally {
releaseMutex();
}
}
- protected MulgaraExternalTransaction createTransaction(final DatabaseSession session, Xid xid, boolean write)
+ protected MulgaraExternalTransaction createTransaction(Xid xid, boolean write)
throws MulgaraTransactionException {
- acquireMutex();
+ acquireMutex(0, MulgaraTransactionException.class);
try {
- if (associatedTransaction.get(session) != null) {
+ if (associatedTransaction != null) {
throw new MulgaraTransactionException(
"Attempt to initiate transaction with existing transaction active with session");
}
@@ -89,27 +85,28 @@
}
if (write) {
- runWithoutMutex(new TransactionOperation() {
- public void execute() throws MulgaraTransactionException {
- manager.obtainWriteLock(session);
- }
- });
+ manager.obtainWriteLock(session);
+ MulgaraExternalTransaction xa = null;
try {
- MulgaraExternalTransaction xa = new MulgaraExternalTransaction(this, xid, session.newOperationContext(true));
+ xa = new MulgaraExternalTransaction(this, xid, session.newOperationContext(true));
writeTransaction = xa;
- associatedTransaction.put(session, xa);
- sessionXAMap.put(session, xa);
+ associatedTransaction = xa;
+ transactions.add(xa);
+ transactionCreated(xa);
return xa;
} catch (Throwable th) {
manager.releaseWriteLock(session);
+ if (xa != null)
+ transactionComplete(xa);
throw new MulgaraTransactionException("Error initiating write transaction", th);
}
} else {
try {
MulgaraExternalTransaction xa = new MulgaraExternalTransaction(this, xid, session.newOperationContext(false));
- associatedTransaction.put(session, xa);
- sessionXAMap.put(session, xa);
+ associatedTransaction = xa;
+ transactions.add(xa);
+ transactionCreated(xa);
return xa;
} catch (QueryException eq) {
@@ -121,81 +118,57 @@
}
}
- public Set<MulgaraExternalTransaction> getTransactionsForSession(DatabaseSession session) {
- acquireMutex();
- try {
- Set<MulgaraExternalTransaction> xas = sessionXAMap.getN(session);
- return xas != null ? xas : Collections.<MulgaraExternalTransaction>emptySet();
- } finally {
- releaseMutex();
- }
+ protected Set<MulgaraExternalTransaction> getTransactions() {
+ return transactions;
}
- public XAResource getXAResource(DatabaseSession session, boolean writing) {
- acquireMutex();
+ public XAResource getXAResource(boolean writing) {
+ acquireMutex(0, RuntimeException.class);
try {
- MulgaraXAResourceContext xarc = xaResources.get(session);
- if (xarc == null) {
- xarc = new MulgaraXAResourceContext(this, session);
- xaResources.put(session, xarc);
- }
-
- return xarc.getResource(writing);
+ return xaResource.getResource(writing);
} finally {
releaseMutex();
}
}
- public void closingSession(DatabaseSession session) throws MulgaraTransactionException {
- acquireMutex();
- try {
- try {
- super.closingSession(session);
- } finally {
- xaResources.remove(session);
- }
- } finally {
- releaseMutex();
- }
- }
-
public void transactionComplete(MulgaraExternalTransaction xa)
throws MulgaraTransactionException {
- acquireMutex();
+ acquireMutex(0, MulgaraTransactionException.class);
try {
+ super.transactionComplete(xa);
+
if (xa == null) {
throw new IllegalArgumentException("Null transaction indicated completion");
}
- DatabaseSession session = sessionXAMap.get1(xa);
if (xa == writeTransaction) {
manager.releaseWriteLock(session);
writeTransaction = null;
}
- sessionXAMap.removeN(xa);
- if (associatedTransaction.get(session) == xa) {
- associatedTransaction.remove(session);
+ transactions.remove(xa);
+ if (associatedTransaction == xa) {
+ associatedTransaction = null;
}
} finally {
releaseMutex();
}
}
- public boolean hasAssociatedTransaction(DatabaseSession session) {
- acquireMutex();
+ public boolean hasAssociatedTransaction() {
+ acquireMutex(0, RuntimeException.class);
try {
- return associatedTransaction.get(session) != null;
+ return associatedTransaction != null;
} finally {
releaseMutex();
}
}
- public boolean associateTransaction(DatabaseSession session, MulgaraExternalTransaction xa) {
- acquireMutex();
+ public boolean associateTransaction(MulgaraExternalTransaction xa) {
+ acquireMutex(0, RuntimeException.class);
try {
- if (associatedTransaction.get(session) != null) {
+ if (associatedTransaction != null) {
return false;
} else {
- associatedTransaction.put(session, xa);
+ associatedTransaction = xa;
return true;
}
} finally {
@@ -203,33 +176,34 @@
}
}
- public MulgaraExternalTransaction getAssociatedTransaction(DatabaseSession session) {
- acquireMutex();
+ public MulgaraExternalTransaction getAssociatedTransaction() {
+ acquireMutex(0, RuntimeException.class);
try {
- return associatedTransaction.get(session);
+ return associatedTransaction;
} finally {
releaseMutex();
}
}
- public void disassociateTransaction(DatabaseSession session, MulgaraExternalTransaction xa)
+ public void disassociateTransaction(MulgaraExternalTransaction xa)
throws MulgaraTransactionException {
- acquireMutex();
+ acquireMutex(0, MulgaraTransactionException.class);
try {
- if (associatedTransaction.get(session) == xa) {
- associatedTransaction.remove(session);
+ if (associatedTransaction == xa) {
+ associatedTransaction = null;
}
} finally {
releaseMutex();
}
}
- void abortWriteTransaction() throws MulgaraTransactionException {
- acquireMutex();
+ public void closingSession() throws MulgaraTransactionException {
+ acquireMutexWithInterrupt(0, MulgaraTransactionException.class);
try {
- if (writeTransaction != null) {
- writeTransaction.abortTransaction(new MulgaraTransactionException("Explicit abort requested by write-lock manager"));
- writeTransaction = null;
+ try {
+ super.closingSession();
+ } finally {
+ transactions.clear();
}
} finally {
releaseMutex();
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransaction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransaction.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransaction.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -22,7 +22,6 @@
// Java 2 enterprise packages
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
import javax.transaction.Transaction;
// Third party packages
@@ -82,7 +81,8 @@
private Transaction transaction;
private Thread currentThread;
- private ReentrantLock activationMutex;
+ private volatile long deactivateTime;
+ private boolean inXACompletion;
private State state;
private int inuse;
@@ -103,68 +103,63 @@
this.factory = factory;
this.context = context;
this.enlisted = new HashSet<EnlistableResource>();
- this.activationMutex = new ReentrantLock();
this.currentThread = null;
inuse = 0;
using = 0;
state = State.CONSTRUCTEDUNREF;
rollbackCause = null;
+ deactivateTime = 0;
} finally {
report("Finished Creating Transaction");
}
}
- void activate() throws MulgaraTransactionException {
-// report("Activating Transaction");
+ private void activate() throws MulgaraTransactionException {
+ debugReport("Activating Transaction");
+
try {
- synchronized (this) {
- if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
- }
+ if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
-
- acquireActivationMutex();
- try {
- switch (state) {
- case CONSTRUCTEDUNREF:
- startTransaction();
- inuse = 1;
- state = State.ACTUNREF;
- try {
- context.initiate(this);
- } catch (Throwable th) {
- throw implicitRollback(th);
- }
- break;
- case CONSTRUCTEDREF:
- startTransaction();
- inuse = 1;
- using = 1;
- state = State.ACTREF;
- try {
- context.initiate(this);
- } catch (Throwable th) {
- throw implicitRollback(th);
- }
- break;
- case DEACTREF:
- resumeTransaction();
- inuse = 1;
- state = State.ACTREF;
- break;
- case ACTREF:
- case ACTUNREF:
- inuse++;
- break;
- case FINISHED:
- throw new MulgaraTransactionException("Attempt to activate terminated transaction");
- case FAILED:
- throw new MulgaraTransactionException("Attempt to activate failed transaction", rollbackCause);
- }
- } finally {
- releaseActivationMutex();
+
+ deactivateTime = -1;
+ switch (state) {
+ case CONSTRUCTEDUNREF:
+ startTransaction();
+ inuse = 1;
+ state = State.ACTUNREF;
+ try {
+ context.initiate(this);
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ }
+ break;
+ case CONSTRUCTEDREF:
+ startTransaction();
+ inuse = 1;
+ using = 1;
+ state = State.ACTREF;
+ try {
+ context.initiate(this);
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ }
+ break;
+ case DEACTREF:
+ resumeTransaction();
+ inuse = 1;
+ state = State.ACTREF;
+ break;
+ case ACTREF:
+ case ACTUNREF:
+ inuse++;
+ break;
+ case FINISHED:
+ throw new MulgaraTransactionException("Attempt to activate terminated transaction");
+ case FAILED:
+ throw new MulgaraTransactionException("Attempt to activate failed transaction", rollbackCause);
}
try {
@@ -183,51 +178,45 @@
private void deactivate() throws MulgaraTransactionException {
-// report("Deactivating transaction");
+ debugReport("Deactivating transaction");
try {
- synchronized (this) {
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction not associated with thread");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
- }
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction not associated with thread");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
-
- acquireActivationMutex();
- try {
- switch (state) {
- case ACTUNREF:
- if (inuse == 1) {
- commitTransaction();
- }
+
+ deactivateTime = System.currentTimeMillis();
+ switch (state) {
+ case ACTUNREF:
+ if (inuse == 1) {
+ commitTransaction();
+ }
+ inuse--;
+ break;
+ case ACTREF:
+ if (inuse == 1) {
+ suspendTransaction();
+ }
+ inuse--;
+ break;
+ case CONSTRUCTEDREF:
+ throw new MulgaraTransactionException("Attempt to deactivate uninitiated refed transaction");
+ case CONSTRUCTEDUNREF:
+ throw new MulgaraTransactionException("Attempt to deactivate uninitiated transaction");
+ case DEACTREF:
+ throw new IllegalStateException("Attempt to deactivate unactivated transaction");
+ case FINISHED:
+ if (inuse < 0) {
+ errorReport("Activation count failure - too many deacts - in finished transaction", null);
+ } else {
inuse--;
- break;
- case ACTREF:
- if (inuse == 1) {
- suspendTransaction();
- }
- inuse--;
- break;
- case CONSTRUCTEDREF:
- throw new MulgaraTransactionException("Attempt to deactivate uninitiated refed transaction");
- case CONSTRUCTEDUNREF:
- throw new MulgaraTransactionException("Attempt to deactivate uninitiated transaction");
- case DEACTREF:
- throw new IllegalStateException("Attempt to deactivate unactivated transaction");
- case FINISHED:
- if (inuse < 0) {
- errorReport("Activation count failure - too many deacts - in finished transaction", null);
- } else {
- inuse--;
- }
- break;
- case FAILED:
- // Nothing to do here.
- break;
- }
- } finally {
- releaseActivationMutex();
+ }
+ break;
+ case FAILED:
+ // Nothing to do here.
+ break;
}
} catch (MulgaraTransactionException em) {
throw em;
@@ -243,84 +232,91 @@
// references a transaction object that won't be started/activated
// until it is first used.
public void reference() throws MulgaraTransactionException {
+ report("Referencing Transaction");
+
+ acquireMutex(0, false, MulgaraTransactionException.class);
try {
- report("Referencing Transaction");
-
- synchronized (this) {
+ try {
if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
- }
- switch (state) {
- case CONSTRUCTEDUNREF:
- state = State.CONSTRUCTEDREF;
- break;
- case ACTREF:
- case ACTUNREF:
- using++;
- state = State.ACTREF;
- break;
- case DEACTREF:
- using++;
- break;
- case CONSTRUCTEDREF:
- throw new MulgaraTransactionException("Attempt to reference uninitated transaction twice");
- case FINISHED:
- throw new MulgaraTransactionException("Attempt to reference terminated transaction");
- case FAILED:
- throw new MulgaraTransactionException("Attempt to reference failed transaction", rollbackCause);
+ switch (state) {
+ case CONSTRUCTEDUNREF:
+ state = State.CONSTRUCTEDREF;
+ break;
+ case ACTREF:
+ case ACTUNREF:
+ using++;
+ state = State.ACTREF;
+ break;
+ case DEACTREF:
+ using++;
+ break;
+ case CONSTRUCTEDREF:
+ throw new MulgaraTransactionException("Attempt to reference uninitated transaction twice");
+ case FINISHED:
+ throw new MulgaraTransactionException("Attempt to reference terminated transaction");
+ case FAILED:
+ throw new MulgaraTransactionException("Attempt to reference failed transaction", rollbackCause);
+ }
+ } catch (MulgaraTransactionException em) {
+ throw em;
+ } catch (Throwable th) {
+ report("Error referencing transaction");
+ throw implicitRollback(th);
+ } finally {
+ report("Leaving Reference Transaction");
}
- } catch (MulgaraTransactionException em) {
- throw em;
- } catch (Throwable th) {
- report("Error referencing transaction");
- throw implicitRollback(th);
} finally {
- report("Leaving Reference Transaction");
+ releaseMutex();
}
}
public void dereference() throws MulgaraTransactionException {
report("Dereferencing Transaction");
+
+ acquireMutex(0, false, MulgaraTransactionException.class);
try {
- synchronized (this) {
+ try {
if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
- }
- switch (state) {
- case ACTREF:
- if (using == 1) {
- state = State.ACTUNREF;
- }
- using--;
- break;
- case CONSTRUCTEDREF:
- state = State.CONSTRUCTEDUNREF;
- break;
- case FINISHED:
- case FAILED:
- if (using < 1) {
- errorReport("Reference count failure - too many derefs - in finished transaction", null);
- } else {
+ switch (state) {
+ case ACTREF:
+ if (using == 1) {
+ state = State.ACTUNREF;
+ }
using--;
- }
- break;
- case ACTUNREF:
- throw new IllegalStateException("Attempt to dereference unreferenced transaction");
- case CONSTRUCTEDUNREF:
- throw new MulgaraTransactionException("Attempt to dereference uninitated transaction");
- case DEACTREF:
- throw new IllegalStateException("Attempt to dereference deactivated transaction");
+ break;
+ case CONSTRUCTEDREF:
+ state = State.CONSTRUCTEDUNREF;
+ break;
+ case FINISHED:
+ case FAILED:
+ if (using < 1) {
+ errorReport("Reference count failure - too many derefs - in finished transaction", null);
+ } else {
+ using--;
+ }
+ break;
+ case ACTUNREF:
+ throw new IllegalStateException("Attempt to dereference unreferenced transaction");
+ case CONSTRUCTEDUNREF:
+ throw new MulgaraTransactionException("Attempt to dereference uninitated transaction");
+ case DEACTREF:
+ throw new IllegalStateException("Attempt to dereference deactivated transaction");
+ }
+ } catch (MulgaraTransactionException em) {
+ throw em;
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ } finally {
+ report("Dereferenced Transaction");
}
- } catch (MulgaraTransactionException em) {
- throw em;
- } catch (Throwable th) {
- throw implicitRollback(th);
} finally {
- report("Dereferenced Transaction");
+ releaseMutex();
}
}
@@ -328,9 +324,7 @@
report("Initiating transaction");
try {
transaction = factory.transactionStart(this);
- synchronized (this) {
- currentThread = Thread.currentThread();
- }
+ currentThread = Thread.currentThread();
} catch (Throwable th) {
throw abortTransaction("Failed to start transaction", th);
}
@@ -340,11 +334,9 @@
// report("Resuming transaction");
try {
factory.transactionResumed(this, transaction);
- synchronized (this) {
- currentThread = Thread.currentThread();
- }
+ currentThread = Thread.currentThread();
} catch (Throwable th) {
- abortTransaction("Failed to resume transaction", th);
+ throw abortTransaction("Failed to resume transaction", th);
}
}
@@ -356,9 +348,7 @@
new MulgaraTransactionException("Attempt to suspend unreferenced transaction"));
}
transaction = factory.transactionSuspended(this);
- synchronized (this) {
- currentThread = null;
- }
+ currentThread = null;
state = State.DEACTREF;
} catch (Throwable th) {
throw implicitRollback(th);
@@ -369,35 +359,77 @@
public void commitTransaction() throws MulgaraTransactionException {
report("Committing Transaction");
+ acquireMutex(0, true, MulgaraTransactionException.class);
try {
- transaction.commit();
- } catch (Throwable th) {
- throw implicitRollback(th);
- }
- try {
try {
- transaction = null;
- } finally { try {
- state = State.FINISHED;
- } finally { try {
- context.clear();
- } finally { try {
- enlisted.clear();
- } finally { try {
- factory.transactionComplete(this);
- } finally { try {
- factory = null;
- } finally {
- report("Committed transaction");
- } } } } } }
- } catch (Throwable th) {
- errorReport("Error cleaning up transaction post-commit", th);
- throw new MulgaraTransactionException("Error cleaning up transaction post-commit", th);
+ transaction.commit();
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ }
+ try {
+ try {
+ transaction = null;
+ } finally { try {
+ state = State.FINISHED;
+ } finally { try {
+ context.clear();
+ } finally { try {
+ enlisted.clear();
+ } finally { try {
+ factory.transactionComplete(this);
+ } finally {
+ report("Committed transaction");
+ } } } } }
+ } catch (Throwable th) {
+ errorReport("Error cleaning up transaction post-commit", th);
+ throw new MulgaraTransactionException("Error cleaning up transaction post-commit", th);
+ }
+ } finally {
+ releaseMutex();
}
}
public void heuristicRollback(String cause) throws MulgaraTransactionException {
- implicitRollback(new MulgaraTransactionException(cause));
+ synchronized (factory.getMutexLock()) {
+ if (factory.getMutexHolder() != null && factory.getMutexHolder() != Thread.currentThread()) {
+ if (inXACompletion) {
+ return; // this txn is already being cleaned up, so let it go
+ }
+ }
+
+ factory.acquireMutexWithInterrupt(0L, MulgaraTransactionException.class);
+ inXACompletion = true;
+ }
+
+ try {
+ switch (state) {
+ case DEACTREF:
+ activate();
+ try {
+ implicitRollback(new MulgaraTransactionException(cause));
+ } finally {
+ currentThread = null;
+ }
+ break;
+
+ case ACTUNREF:
+ case ACTREF:
+ implicitRollback(new MulgaraTransactionException(cause));
+ break;
+
+ case CONSTRUCTEDREF:
+ case CONSTRUCTEDUNREF:
+ // no point in starting and then rolling back immediately, so just clean up
+ abortTransaction(cause, new Throwable());
+
+ case FINISHED:
+ case FAILED:
+ // Nothing to do here.
+ return;
+ }
+ } finally {
+ releaseMutex();
+ }
}
/**
@@ -406,39 +438,43 @@
* after all we requested it.
*/
public void explicitRollback() throws MulgaraTransactionException {
- synchronized (this) {
+ acquireMutex(0, true, MulgaraTransactionException.class);
+ try {
if (currentThread == null) {
throw new MulgaraTransactionException("Transaction failed activation check");
} else if (!currentThread.equals(Thread.currentThread())) {
throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
- }
- try {
- switch (state) {
- case ACTUNREF:
- case ACTREF:
- transaction.rollback();
- context.clear();
- enlisted.clear();
- factory.transactionComplete(this);
- state = State.FINISHED;
- break;
- case DEACTREF:
- throw new IllegalStateException("Attempt to rollback unactivated transaction");
- case CONSTRUCTEDREF:
- throw new MulgaraTransactionException("Attempt to rollback uninitiated ref'd transaction");
- case CONSTRUCTEDUNREF:
- throw new MulgaraTransactionException("Attempt to rollback uninitiated unref'd transaction");
- case FINISHED:
- throw new MulgaraTransactionException("Attempt to rollback finished transaction");
- case FAILED:
- throw new MulgaraTransactionException("Attempt to rollback failed transaction");
+ try {
+ switch (state) {
+ case ACTUNREF:
+ case ACTREF:
+ transaction.rollback();
+ context.clear();
+ enlisted.clear();
+ factory.transactionComplete(this);
+ transaction = null;
+ state = State.FINISHED;
+ break;
+ case DEACTREF:
+ throw new IllegalStateException("Attempt to rollback unactivated transaction");
+ case CONSTRUCTEDREF:
+ throw new MulgaraTransactionException("Attempt to rollback uninitiated ref'd transaction");
+ case CONSTRUCTEDUNREF:
+ throw new MulgaraTransactionException("Attempt to rollback uninitiated unref'd transaction");
+ case FINISHED:
+ throw new MulgaraTransactionException("Attempt to rollback finished transaction");
+ case FAILED:
+ throw new MulgaraTransactionException("Attempt to rollback failed transaction");
+ }
+ } catch (MulgaraTransactionException em) {
+ throw em;
+ } catch (Throwable th) {
+ throw implicitRollback(th);
}
- } catch (MulgaraTransactionException em) {
- throw em;
- } catch (Throwable th) {
- throw implicitRollback(th);
+ } finally {
+ releaseMutex();
}
}
@@ -452,18 +488,14 @@
* Post-condition: The transaction is terminated and cleaned up.
*/
@SuppressWarnings("finally")
- MulgaraTransactionException implicitRollback(Throwable cause) throws MulgaraTransactionException {
- try {
- report("Implicit Rollback triggered");
+ private MulgaraTransactionException implicitRollback(Throwable cause) throws MulgaraTransactionException {
+ report("Implicit Rollback triggered");
- synchronized (this) {
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction not associated with thread");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
- }
- }
+ synchronized (factory.getMutexLock()) {
+ inXACompletion = true;
+ }
+ try {
if (rollbackCause != null) {
errorReport("Cascading error, transaction already rolled back", cause);
errorReport("Cascade error, expected initial cause", rollbackCause);
@@ -480,8 +512,7 @@
context.clear();
enlisted.clear();
state = State.FAILED;
- factory.transactionComplete(this);
- factory = null;
+ factory.transactionAborted(this);
return new MulgaraTransactionException("Transaction rollback triggered", cause);
case DEACTREF:
throw new IllegalStateException("Attempt to rollback deactivated transaction");
@@ -529,36 +560,40 @@
*/
public MulgaraTransactionException abortTransaction(String errorMessage, Throwable cause)
throws MulgaraTransactionException {
- // We need to notify the factory here - this is serious, we
- // need to rollback this transaction, but if we have reached here
- // we have failed to obtain a valid transaction to rollback!
+ // we should actually already have the mutex, but let's make sure
+ acquireMutex(0L, true, MulgaraTransactionException.class);
try {
+ // We need to notify the factory here - this is serious, we
+ // need to rollback this transaction, but if we have reached here
+ // we have failed to obtain a valid transaction to rollback!
try {
- errorReport(errorMessage + " - Aborting", cause);
- } finally { try {
- if (transaction != null) {
- transaction.rollback();
- }
- } finally { try {
- factory.transactionAborted(this);
- } finally { try {
- abortEnlistedResources();
- } finally { try {
- context.clear();
- } finally { try {
- enlisted.clear();
- } finally { try {
- transaction = null;
- } finally { try {
- factory = null;
+ try {
+ errorReport(errorMessage + " - Aborting", cause);
+ } finally { try {
+ if (transaction != null) {
+ transaction.rollback();
+ }
+ } finally { try {
+ factory.transactionAborted(this);
+ } finally { try {
+ abortEnlistedResources();
+ } finally { try {
+ context.clear();
+ } finally { try {
+ enlisted.clear();
+ } finally { try {
+ transaction = null;
+ } finally {
+ state = State.FAILED;
+ } } } } } } }
+ return new MulgaraTransactionException(errorMessage + " - Aborting", cause);
+ } catch (Throwable th) {
+ throw new MulgaraTransactionException(errorMessage + " - Failed to abort cleanly", th);
} finally {
- state = State.FAILED;
- } } } } } } } }
- return new MulgaraTransactionException(errorMessage + " - Aborting", cause);
- } catch (Throwable th) {
- throw new MulgaraTransactionException(errorMessage + " - Failed to abort cleanly", th);
+ report("Leaving abortTransaction");
+ }
} finally {
- report("Leaving abortTransaction");
+ releaseMutex();
}
}
@@ -579,105 +614,128 @@
public void execute(Operation operation, DatabaseMetadata metadata) throws MulgaraTransactionException {
report("Executing Operation");
+
+ acquireMutex(0, false, MulgaraTransactionException.class);
try {
- activate();
try {
- operation.execute(context,
- context.getSystemResolver(),
- metadata);
- } catch (Throwable th) {
- throw implicitRollback(th);
+ activate();
+ try {
+ operation.execute(context,
+ context.getSystemResolver(),
+ metadata);
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ } finally {
+ deactivate();
+ }
} finally {
- deactivate();
+ report("Executed Operation");
}
} finally {
- report("Executed Operation");
+ releaseMutex();
}
}
public AnswerOperationResult execute(AnswerOperation ao) throws TuplesException {
debugReport("Executing AnswerOperation");
+
+ acquireMutex(0, false, TuplesException.class);
try {
- activate();
try {
- ao.execute();
- return ao.getResult();
- } catch (Throwable th) {
- throw implicitRollback(th);
+ activate();
+ try {
+ ao.execute();
+ return ao.getResult();
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ } finally {
+ deactivate();
+ }
+ } catch (MulgaraTransactionException em) {
+ throw new TuplesException("Transaction error", em);
} finally {
- deactivate();
+ debugReport("Executed AnswerOperation");
}
- } catch (MulgaraTransactionException em) {
- throw new TuplesException("Transaction error", em);
} finally {
- debugReport("Executed AnswerOperation");
+ releaseMutex();
}
}
public void execute(TransactionOperation to) throws MulgaraTransactionException {
report("Executing TransactionOperation");
+
+ acquireMutex(0, false, MulgaraTransactionException.class);
try {
- activate();
try {
- to.execute();
- } catch (Throwable th) {
- throw implicitRollback(th);
+ activate();
+ try {
+ to.execute();
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ } finally {
+ deactivate();
+ }
} finally {
- deactivate();
+ report("Executed TransactionOperation");
}
} finally {
- report("Executed TransactionOperation");
+ releaseMutex();
}
}
public void enlist(EnlistableResource enlistable) throws MulgaraTransactionException {
+ acquireMutex(0, false, MulgaraTransactionException.class);
try {
- synchronized (this) {
+ try {
if (currentThread == null) {
throw new MulgaraTransactionException("Transaction not associated with thread");
} else if (!currentThread.equals(Thread.currentThread())) {
throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
- }
- if (enlisted.contains(enlistable)) {
- return;
- }
+ if (enlisted.contains(enlistable)) {
+ return;
+ }
- switch (state) {
- case ACTUNREF:
- case ACTREF:
- transaction.enlistResource(enlistable.getXAResource());
- enlisted.add(enlistable);
- break;
- case CONSTRUCTEDREF:
- throw new MulgaraTransactionException("Attempt to enlist resource in uninitated ref'd transaction");
- case CONSTRUCTEDUNREF:
- throw new MulgaraTransactionException("Attempt to enlist resource in uninitated unref'd transaction");
- case DEACTREF:
- throw new MulgaraTransactionException("Attempt to enlist resource in unactivated transaction");
- case FINISHED:
- throw new MulgaraTransactionException("Attempt to enlist resource in finished transaction");
- case FAILED:
- throw new MulgaraTransactionException("Attempt to enlist resource in failed transaction");
+ switch (state) {
+ case ACTUNREF:
+ case ACTREF:
+ transaction.enlistResource(enlistable.getXAResource());
+ enlisted.add(enlistable);
+ break;
+ case CONSTRUCTEDREF:
+ throw new MulgaraTransactionException("Attempt to enlist resource in uninitated ref'd transaction");
+ case CONSTRUCTEDUNREF:
+ throw new MulgaraTransactionException("Attempt to enlist resource in uninitated unref'd transaction");
+ case DEACTREF:
+ throw new MulgaraTransactionException("Attempt to enlist resource in unactivated transaction");
+ case FINISHED:
+ throw new MulgaraTransactionException("Attempt to enlist resource in finished transaction");
+ case FAILED:
+ throw new MulgaraTransactionException("Attempt to enlist resource in failed transaction");
+ }
+ } catch (Throwable th) {
+ throw implicitRollback(th);
}
- } catch (Throwable th) {
- throw implicitRollback(th);
+ } finally {
+ releaseMutex();
}
}
+ public long lastActive() {
+ return deactivateTime;
+ }
+
//
// Used internally
//
private void checkActivated() throws MulgaraTransactionException {
- synchronized (this) {
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction not associated with thread");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
- }
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction not associated with thread");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
switch (state) {
@@ -700,12 +758,15 @@
}
}
- private void acquireActivationMutex() {
- activationMutex.lock();
+ private <T extends Throwable> void acquireMutex(long timeout, boolean isXACompletion, Class<T> exc) throws T {
+ synchronized (factory.getMutexLock()) {
+ factory.acquireMutex(timeout, exc);
+ inXACompletion = isXACompletion;
+ }
}
- private void releaseActivationMutex() {
- activationMutex.unlock();
+ private void releaseMutex() {
+ factory.releaseMutex();
}
protected void finalize() {
@@ -723,7 +784,7 @@
errorReport("Reference counting error in transaction", null);
}
- if (factory != null || transaction != null) {
+ if (transaction != null) {
errorReport("Transaction not terminated properly", null);
}
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraInternalTransactionFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -21,7 +21,6 @@
package org.mulgara.resolver;
// Java2 packages
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -36,7 +35,6 @@
// Local packages
import org.mulgara.query.MulgaraTransactionException;
import org.mulgara.transaction.TransactionManagerFactory;
-import org.mulgara.util.Assoc1toNMap;
import org.mulgara.util.StackTrace;
/**
@@ -58,49 +56,60 @@
private static final Logger logger =
Logger.getLogger(MulgaraInternalTransactionFactory.class.getName());
- private boolean autoCommit;
-
/** Set of sessions whose transactions have been rolledback.*/
- private Set<DatabaseSession> failedSessions;
+ private boolean isFailed;
/** Map of threads to active transactions. */
- private Map<Thread, MulgaraTransaction> activeTransactions;
+ private final Map<Thread, MulgaraTransaction> activeTransactions;
- private Assoc1toNMap<DatabaseSession, MulgaraTransaction> sessionXAMap;
+ /** Are we in auto-commit mode. */
+ public boolean autoCommit;
+ /** All uncompleted transactions (may be more than 1 because of unclosed answers) */
+ public final Set<MulgaraTransaction> transactions;
+
+ /** Currently associated explicit transaction */
+ public MulgaraInternalTransaction explicitXA;
+
private final TransactionManager transactionManager;
- public MulgaraInternalTransactionFactory(MulgaraTransactionManager manager, TransactionManagerFactory transactionManagerFactory) {
- super(manager);
- this.autoCommit = true;
+ public MulgaraInternalTransactionFactory(DatabaseSession session, MulgaraTransactionManager manager,
+ TransactionManagerFactory transactionManagerFactory) {
+ super(session, manager);
- this.failedSessions = new HashSet<DatabaseSession>();
+ this.isFailed = false;
this.activeTransactions = new HashMap<Thread, MulgaraTransaction>();
- this.sessionXAMap = new Assoc1toNMap<DatabaseSession, MulgaraTransaction>();
+ this.autoCommit = true;
+ this.transactions = new HashSet<MulgaraTransaction>();
+ this.explicitXA = null;
this.transactionManager = transactionManagerFactory.newTransactionManager();
+ try {
+ /* "disable" the TM's timeout because we implement timeouts ourselves; we also don't set
+ * it to our timeout because that can interfere with txn cleanup if the TM's timeout has
+ * fired by causing rollback or commit to fail.
+ */
+ this.transactionManager.setTransactionTimeout(Integer.MAX_VALUE);
+ } catch (SystemException es) {
+ logger.warn("Unable to disable transaction timeout on jta tm", es);
+ }
}
- public MulgaraTransaction getTransaction(final DatabaseSession session, boolean write)
- throws MulgaraTransactionException {
- acquireMutex();
+ public MulgaraTransaction getTransaction(boolean write) throws MulgaraTransactionException {
+ acquireMutex(0, MulgaraTransactionException.class);
try {
- if (manager.isHoldingWriteLock(session)) {
- return writeTransaction;
+ if (explicitXA != null) {
+ return explicitXA;
}
try {
MulgaraInternalTransaction transaction;
if (write) {
- runWithoutMutex(new TransactionOperation() {
- public void execute() throws MulgaraTransactionException {
- manager.obtainWriteLock(session);
- }
- });
+ manager.obtainWriteLock(session);
try {
assert writeTransaction == null;
writeTransaction = transaction =
- new MulgaraInternalTransaction(this, session.newOperationContext(true));
+ new MulgaraInternalTransaction(this, session.newOperationContext(true));
} catch (Throwable th) {
manager.releaseWriteLock(session);
throw new MulgaraTransactionException("Error creating write transaction", th);
@@ -109,7 +118,8 @@
transaction = new MulgaraInternalTransaction(this, session.newOperationContext(false));
}
- sessionXAMap.put(session, transaction);
+ transactions.add(transaction);
+ transactionCreated(transaction);
return transaction;
} catch (MulgaraTransactionException em) {
@@ -122,36 +132,25 @@
}
}
- public Set<MulgaraTransaction> getTransactionsForSession(DatabaseSession session) {
- acquireMutex();
- try {
- Set <MulgaraTransaction> xas = sessionXAMap.getN(session);
- return xas == null ? Collections.<MulgaraTransaction>emptySet() : xas;
- } finally {
- releaseMutex();
- }
+ public Set<MulgaraTransaction> getTransactions() {
+ return transactions;
}
- public MulgaraTransaction newMulgaraTransaction(DatabaseOperationContext context)
- throws MulgaraTransactionException {
- return new MulgaraInternalTransaction(this, context);
- }
-
- public void commit(DatabaseSession session) throws MulgaraTransactionException {
- acquireMutex();
+ public void commit() throws MulgaraTransactionException {
+ acquireMutex(0, MulgaraTransactionException.class);
try {
+ if (isFailed) {
+ throw new MulgaraTransactionException("Attempting to commit failed session");
+ } else if (!manager.isHoldingWriteLock(session)) {
+ throw new MulgaraTransactionException(
+ "Attempting to commit while not the current writing transaction");
+ }
+
manager.reserveWriteLock(session);
try {
- if (failedSessions.contains(session)) {
- throw new MulgaraTransactionException("Attempting to commit failed exception");
- } else if (!manager.isHoldingWriteLock(session)) {
- throw new MulgaraTransactionException(
- "Attempting to commit while not the current writing transaction");
- }
-
- setAutoCommit(session, true);
- setAutoCommit(session, false);
+ setAutoCommit(true);
+ setAutoCommit(false);
} finally {
manager.releaseReserve(session);
}
@@ -166,17 +165,18 @@
*
* This needs to be distinguished from an implicit rollback triggered by failure.
*/
- public void rollback(DatabaseSession session) throws MulgaraTransactionException {
- acquireMutex();
+ public void rollback() throws MulgaraTransactionException {
+ acquireMutex(0, MulgaraTransactionException.class);
try {
- manager.reserveWriteLock(session);
- try {
- if (manager.isHoldingWriteLock(session)) {
+ if (manager.isHoldingWriteLock(session)) {
+ manager.reserveWriteLock(session);
+ try {
try {
writeTransaction.execute(new TransactionOperation() {
- public void execute() throws MulgaraTransactionException {
- writeTransaction.heuristicRollback("Explicit Rollback");
- }
+ public void execute() throws MulgaraTransactionException {
+ writeTransaction.dereference();
+ ((MulgaraInternalTransaction)writeTransaction).explicitRollback();
+ }
});
// FIXME: Should be checking status here, not writelock.
if (manager.isHoldingWriteLock(session)) {
@@ -185,47 +185,46 @@
new MulgaraTransactionException("Rollback failed to terminate write transaction"));
}
} finally {
- failedSessions.add(session);
- setAutoCommit(session, false);
+ explicitXA = null;
+ setAutoCommit(false);
}
- } else if (failedSessions.contains(session)) {
- failedSessions.remove(session);
- setAutoCommit(session, false);
- } else {
- throw new MulgaraTransactionException(
- "Attempt to rollback while not in the current writing transaction");
+ } finally {
+ manager.releaseReserve(session);
}
- } finally {
- manager.releaseReserve(session);
+ } else if (isFailed) {
+ explicitXA = null;
+ isFailed = false;
+ setAutoCommit(false);
+ } else {
+ throw new MulgaraTransactionException(
+ "Attempt to rollback while not in the current writing transaction");
}
} finally {
releaseMutex();
}
}
- public void setAutoCommit(DatabaseSession session, boolean autoCommit)
- throws MulgaraTransactionException {
- acquireMutex();
+ public void setAutoCommit(boolean autoCommit) throws MulgaraTransactionException {
+ acquireMutex(0, MulgaraTransactionException.class);
try {
- if (manager.isHoldingWriteLock(session) && failedSessions.contains(session)) {
+ if (manager.isHoldingWriteLock(session) && isFailed) {
writeTransaction.abortTransaction("Session failed and still holding writeLock",
- new MulgaraTransactionException("Failed Session in setAutoCommit"));
+ new MulgaraTransactionException("Failed Session in setAutoCommit"));
}
- if (manager.isHoldingWriteLock(session) || failedSessions.contains(session)) {
+ if (manager.isHoldingWriteLock(session) || isFailed) {
if (autoCommit) {
+ this.autoCommit = true;
+ this.explicitXA = null;
+
// AutoCommit off -> on === branch on current state of transaction.
if (manager.isHoldingWriteLock(session)) {
// Within active transaction - commit and finalise.
try {
- runWithoutMutex(new TransactionOperation() {
+ writeTransaction.execute(new TransactionOperation() {
public void execute() throws MulgaraTransactionException {
- writeTransaction.execute(new TransactionOperation() {
- public void execute() throws MulgaraTransactionException {
- writeTransaction.dereference();
- ((MulgaraInternalTransaction)writeTransaction).commitTransaction();
- }
- });
+ writeTransaction.dereference();
+ ((MulgaraInternalTransaction)writeTransaction).commitTransaction();
}
});
} finally {
@@ -235,20 +234,14 @@
if (manager.isHoldingWriteLock(session)) {
manager.releaseWriteLock(session);
}
- this.autoCommit = true;
}
- } else if (failedSessions.contains(session)) {
+ } else if (isFailed) {
// Within failed transaction - cleanup.
- failedSessions.remove(session);
+ isFailed = false;
}
} else {
if (!manager.isHoldingWriteLock(session)) {
- if (failedSessions.contains(session)) {
- failedSessions.remove(session);
- setAutoCommit(session, false);
- } else {
- throw new IllegalStateException("Can't reach here");
- }
+ throw new MulgaraTransactionException("Attempting set auto-commit false in failed session");
} else {
// AutoCommit off -> off === no-op. Log info.
if (logger.isInfoEnabled()) {
@@ -257,13 +250,15 @@
}
}
} else {
+ explicitXA = null;
if (autoCommit) {
// AutoCommit on -> on === no-op. Log info.
logger.info("Attempting to set autocommit true without setting it false");
} else {
// AutoCommit on -> off == Start new transaction.
- getTransaction(session, true); // Set's writeTransaction.
+ getTransaction(true); // Set's writeTransaction.
writeTransaction.reference();
+ explicitXA = (MulgaraInternalTransaction) writeTransaction;
this.autoCommit = false;
}
}
@@ -277,7 +272,7 @@
//
public Transaction transactionStart(MulgaraTransaction transaction) throws MulgaraTransactionException {
- acquireMutex();
+ acquireMutex(0, MulgaraTransactionException.class);
try {
try {
logger.info("Beginning Transaction");
@@ -304,7 +299,7 @@
public void transactionResumed(MulgaraTransaction transaction, Transaction jtaXA)
throws MulgaraTransactionException {
- acquireMutex();
+ acquireMutex(0, MulgaraTransactionException.class);
try {
if (activeTransactions.get(Thread.currentThread()) != null) {
throw new MulgaraTransactionException(
@@ -312,7 +307,7 @@
} else if (activeTransactions.containsValue(transaction)) {
throw new MulgaraTransactionException("Attempt to resume active transaction");
}
-
+
try {
transactionManager.resume(jtaXA);
activeTransactions.put(Thread.currentThread(), transaction);
@@ -326,7 +321,7 @@
public Transaction transactionSuspended(MulgaraTransaction transaction)
throws MulgaraTransactionException {
- acquireMutex();
+ acquireMutex(0, MulgaraTransactionException.class);
try {
try {
if (transaction != activeTransactions.get(Thread.currentThread())) {
@@ -358,22 +353,34 @@
}
}
+ public void closingSession() throws MulgaraTransactionException {
+ acquireMutexWithInterrupt(0, MulgaraTransactionException.class);
+ try {
+ try {
+ super.closingSession();
+ } finally {
+ transactions.clear();
+ }
+ } finally {
+ releaseMutex();
+ }
+ }
+
public void transactionComplete(MulgaraTransaction transaction) throws MulgaraTransactionException {
- acquireMutex();
+ acquireMutex(0, MulgaraTransactionException.class);
try {
+ super.transactionComplete(transaction);
+
logger.debug("Transaction Complete");
+
if (transaction == writeTransaction) {
- DatabaseSession session = sessionXAMap.get1(transaction);
- if (session == null) {
- throw new MulgaraTransactionException("No associated session found for write transaction");
- }
if (manager.isHoldingWriteLock(session)) {
manager.releaseWriteLock(session);
writeTransaction = null;
}
}
- sessionXAMap.removeN(transaction);
+ transactions.remove(transaction);
activeTransactions.remove(Thread.currentThread());
} finally {
releaseMutex();
@@ -381,12 +388,12 @@
}
public void transactionAborted(MulgaraTransaction transaction) {
- acquireMutex();
+ acquireMutex(0, RuntimeException.class);
try {
try {
// Make sure this cleans up the transaction metadata - this transaction is DEAD!
- if (transaction == writeTransaction) {
- failedSessions.add(sessionXAMap.get1(transaction));
+ if (!autoCommit && transaction == writeTransaction) {
+ isFailed = true;
}
transactionComplete(transaction);
} catch (Throwable th) {
@@ -397,24 +404,4 @@
releaseMutex();
}
}
-
- public void setTransactionTimeout(int transactionTimeout) {
- try {
- transactionManager.setTransactionTimeout(transactionTimeout);
- } catch (SystemException es) {
- logger.warn("Unable to set transaction timeout: " + transactionTimeout, es);
- }
- }
-
- void abortWriteTransaction() throws MulgaraTransactionException {
- acquireMutex();
- try {
- if (writeTransaction != null) {
- writeTransaction.abortTransaction(new MulgaraTransactionException("Explicit abort requested by write-lock manager"));
- writeTransaction = null;
- }
- } finally {
- releaseMutex();
- }
- }
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -22,12 +22,10 @@
// Java 2 enterprise packages
// Third party packages
-import org.apache.log4j.Logger;
// Local packages
import org.mulgara.resolver.spi.DatabaseMetadata;
import org.mulgara.resolver.spi.EnlistableResource;
-import org.mulgara.resolver.spi.ResolverSessionFactory;
import org.mulgara.query.MulgaraTransactionException;
import org.mulgara.query.TuplesException;
@@ -71,6 +69,13 @@
*/
MulgaraTransactionException abortTransaction(String errorMessage, Throwable cause) throws MulgaraTransactionException;
+ /**
+ * Perform a heuristic rollback on the transaction.
+ *
+ * @param cause the reason for the rollback
+ * @throws MulgaraTransactionException if an error is encounted while attempting to roll back;
+ * the transaction will still have been terminated, though.
+ */
void heuristicRollback(String cause) throws MulgaraTransactionException;
/**
@@ -96,4 +101,11 @@
* abort().
*/
public void enlist(EnlistableResource enlistable) throws MulgaraTransactionException;
+
+ /**
+ * Returns the currentTimeMillis when the transaction last used;
+ * -1 if it is currently in use; or
+ * 0 if it has never been used.
+ */
+ public long lastActive();
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -21,24 +21,19 @@
package org.mulgara.resolver;
// Java2 packages
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import javax.transaction.xa.XAResource;
+import java.util.Timer;
+import java.util.TimerTask;
// Third party packages
import org.apache.log4j.Logger;
// Local packages
import org.mulgara.query.MulgaraTransactionException;
-import org.mulgara.server.Session;
-import org.mulgara.transaction.TransactionManagerFactory;
/**
* Manages transactions within Mulgara.
@@ -63,27 +58,55 @@
*/
public abstract class MulgaraTransactionFactory {
- private static final Logger logger =
- Logger.getLogger(MulgaraTransactionFactory.class.getName());
+ private static final Logger logger = Logger.getLogger(MulgaraTransactionFactory.class.getName());
+ private static final Timer reaperTimer = new Timer("Write-lock Reaper", true);
protected final MulgaraTransactionManager manager;
-
+
+ protected final DatabaseSession session;
+
+ private final Map<MulgaraTransaction, XAReaper> timeoutTasks;
+
/**
* Contains a reference the the current writing transaction IFF it is managed
* by this factory. If there is no current writing transaction, or if the
* writing transaction is managed by a different factory then it is null.
+ *
+ * Modifications of this must be holding the mutexLock.
*/
protected MulgaraTransaction writeTransaction;
- private ReentrantLock mutex;
+ private Thread mutexHolder;
+ private int lockCnt;
- protected MulgaraTransactionFactory(MulgaraTransactionManager manager) {
+ protected MulgaraTransactionFactory(DatabaseSession session, MulgaraTransactionManager manager) {
+ this.session = session;
this.manager = manager;
- this.mutex = new ReentrantLock();
+ this.timeoutTasks = new HashMap<MulgaraTransaction, XAReaper>();
+ this.mutexHolder = null;
+ this.lockCnt = 0;
this.writeTransaction = null;
}
+ protected void transactionCreated(MulgaraTransaction transaction) {
+ long idleTimeout = session.getIdleTimeout() > 0 ? session.getIdleTimeout() : 15*60*1000L;
+ long txnTimeout = session.getTransactionTimeout() > 0 ? session.getTransactionTimeout() : 60*60*1000L;
+ long now = System.currentTimeMillis();
+ synchronized (getMutexLock()) {
+ timeoutTasks.put(transaction, new XAReaper(transaction, now + txnTimeout, idleTimeout, now));
+ }
+ }
+
+ protected void transactionComplete(MulgaraTransaction transaction) throws MulgaraTransactionException {
+ synchronized (getMutexLock()) {
+ XAReaper reaper = timeoutTasks.remove(transaction);
+ if (reaper != null) {
+ reaper.cancel();
+ }
+ }
+ }
+
/**
* Obtain a transaction context associated with a DatabaseSession.
*
@@ -94,20 +117,21 @@
* otherwise creates a new transaction context and associates it with the
* session.
*/
- public abstract MulgaraTransaction getTransaction(final DatabaseSession session, boolean write)
+ public abstract MulgaraTransaction getTransaction(boolean write)
throws MulgaraTransactionException;
-
- protected abstract Set<? extends MulgaraTransaction> getTransactionsForSession(DatabaseSession session);
+ protected abstract Set<? extends MulgaraTransaction> getTransactions();
+
/**
* Rollback, or abort all transactions associated with a DatabaseSession.
*
* Will only abort the transaction if the rollback attempt fails.
*/
- public void closingSession(DatabaseSession session) throws MulgaraTransactionException {
- acquireMutex();
- logger.debug("Cleaning up any stale transactions on session close");
+ public void closingSession() throws MulgaraTransactionException {
+ acquireMutex(0, MulgaraTransactionException.class);
try {
+ logger.debug("Cleaning up any stale transactions on session close");
+
Map<MulgaraTransaction, Throwable> requiresAbort = new HashMap<MulgaraTransaction, Throwable>();
try {
Throwable error = null;
@@ -140,7 +164,7 @@
logger.debug("Session does not hold write-lock");
}
- for (MulgaraTransaction transaction : getTransactionsForSession(session)) {
+ for (MulgaraTransaction transaction : new HashSet<MulgaraTransaction>(getTransactions())) {
try {
// This is final so we can create the closure.
final MulgaraTransaction xa = transaction;
@@ -168,12 +192,20 @@
logger.error("Error aborting transactions after heuristic rollback failure on session close", th);
} catch (Throwable throw_away) { }
}
+
+ synchronized (getMutexLock()) {
+ for (XAReaper reaper : timeoutTasks.values()) {
+ reaper.cancel();
+ }
+ timeoutTasks.clear();
+ }
}
} finally {
releaseMutex();
}
}
+
/**
* Abort as many of the transactions as we can.
*/
@@ -211,40 +243,169 @@
}
}
+ /**
+ * Acquire the mutex. The mutex is re-entrant, but {@link #releaseMutex} must be called as many
+ * times as this is called.
+ *
+ * <p>We use our own implementation here (as opposed to, say, java.util.concurrent.Lock) so we
+ * can reliably get the current mutex-owner, and we use a lock around the mutex acquisition and
+ * release to do atomic tests and settting of additional variables associated with the mutex.
+ *
+ * @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 T if the mutex could not be acquired, either due to a timeout or due to an interrupt
+ */
+ public final <T extends Throwable> void acquireMutex(long timeout, Class<T> exc) throws T {
+ synchronized (getMutexLock()) {
+ if (mutexHolder == Thread.currentThread()) {
+ lockCnt++;
+ return;
+ }
+
+ long deadline = System.currentTimeMillis() + timeout;
+
+ while (mutexHolder != null) {
+ long wait = deadline - System.currentTimeMillis();
+ if (timeout == 0) {
+ wait = 0;
+ } else if (wait <= 0) {
+ throw newException(exc, "Timed out waiting to acquire lock");
+ }
+
+ try {
+ getMutexLock().wait(wait);
+ } catch (InterruptedException ie) {
+ throw newExceptionOrCause(exc, "Interrupted while waiting to acquire lock", ie);
+ }
+ }
+
+ mutexHolder = Thread.currentThread();
+ lockCnt = 1;
+ }
+ }
+
+ /**
+ * Acquire the mutex, interrupting the existing holder if 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 T if the mutex could not be acquired, either due to a timeout or due to an interrupt
+ * @see #acquireMutex
+ */
+ public final <T extends Throwable> void acquireMutexWithInterrupt(long timeout, Class<T> exc) throws T {
+ synchronized (getMutexLock()) {
+ if (mutexHolder != null && mutexHolder != Thread.currentThread()) {
+ mutexHolder.interrupt();
+ }
+
+ acquireMutex(timeout, exc);
+ }
+ }
+
+ /**
+ * Release the mutex.
+ *
+ * @throws IllegalStateException is the mutex is not held by the current thread
+ */
+ public final void releaseMutex() {
+ synchronized (getMutexLock()) {
+ if (Thread.currentThread() != mutexHolder) {
+ throw new IllegalStateException("Attempt to release mutex without holding mutex");
+ }
+
+ assert lockCnt > 0;
+ if (--lockCnt <= 0) {
+ mutexHolder = null;
+ getMutexLock().notify();
+ }
+ }
+ }
+
/**
- * Used to replace the built in monitor to allow it to be properly released
- * during potentially blocking operations. All potentially blocking
- * operations involve writes, so in these cases the write-lock is reserved
- * allowing the mutex to be safely released and then reobtained after the
- * blocking operation concludes.
+ * @return the lock used to protect access to and to implement the mutex; must be held as shortly
+ * as possible (no blocking operations)
*/
- protected void acquireMutex() {
- mutex.lock();
+ public final Object getMutexLock() {
+ return session;
}
+ /**
+ * @return the current holder of the mutex, or null if none. Must hold the mutex-lock while
+ * calling this.
+ */
+ public final Thread getMutexHolder() {
+ return mutexHolder;
+ }
- protected void releaseMutex() {
- if (!mutex.isHeldByCurrentThread()) {
- throw new IllegalStateException("Attempt to release mutex without holding mutex");
+ public static <T extends Throwable> T newException(Class<T> exc, String msg) {
+ try {
+ return exc.getConstructor(String.class).newInstance(msg);
+ } catch (Exception e) {
+ throw new Error("Internal error creating " + exc, e);
}
+ }
- mutex.unlock();
+ public 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));
}
- protected void runWithoutMutex(TransactionOperation proc) throws MulgaraTransactionException {
- if (!mutex.isHeldByCurrentThread()) {
- throw new IllegalStateException("Attempt to run procedure without holding mutex");
+ private class XAReaper extends TimerTask {
+ private final MulgaraTransaction transaction;
+ private final long txnDeadline;
+ private final long idleTimeout;
+
+ public XAReaper(MulgaraTransaction transaction, long txnDeadline, long idleTimeout, long lastActive) {
+ this.transaction = transaction;
+ this.txnDeadline = txnDeadline;
+ this.idleTimeout = idleTimeout;
+
+ if (lastActive <= 0)
+ lastActive = System.currentTimeMillis();
+ long nextWakeup = Math.min(txnDeadline, lastActive + idleTimeout);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Transaction-reaper created, txn=" + transaction + ", txnDeadline=" + txnDeadline +
+ ", idleTimeout=" + idleTimeout + ", nextWakeup=" + nextWakeup + ": " +
+ System.identityHashCode(getMutexLock()));
+ }
+
+ reaperTimer.schedule(this, new Date(nextWakeup));
}
- int holdCount = mutex.getHoldCount();
- for (int i = 0; i < holdCount; i++) {
- mutex.unlock();
- }
- try {
- proc.execute();
- } finally {
- for (int i = 0; i < holdCount; i++) {
- mutex.lock();
+
+ public void run() {
+ logger.debug("Transaction-reaper running, txn=" + transaction + ": " + System.identityHashCode(getMutexLock()));
+
+ long lastActive = transaction.lastActive();
+ long now = System.currentTimeMillis();
+
+ synchronized (getMutexLock()) {
+ if (timeoutTasks.remove(transaction) == null)
+ return; // looks like we got cleaned up
+
+ if (now < txnDeadline && ((lastActive <= 0) || (now < lastActive + idleTimeout))) {
+ if (logger.isDebugEnabled())
+ logger.debug("Transaction still active: " + lastActive + " time: " + now + " idle-timeout: " + idleTimeout + " - rescheduling timer");
+
+ timeoutTasks.put(transaction, new XAReaper(transaction, txnDeadline, idleTimeout, lastActive));
+ return;
+ }
}
+
+ final String txnType = (now >= txnDeadline) ? "over-extended" : "inactive";
+ final String toType = (now >= txnDeadline) ? "transaction" : "idle";
+
+ logger.warn("Rolling back " + txnType + " transaction");
+ new Thread(toType + "-timeout executor") {
+ public void run() {
+ try {
+ transaction.heuristicRollback(toType + "-timeout");
+ } catch (MulgaraTransactionException em) {
+ logger.warn("Exception thrown while rolling back " + txnType + " transaction");
+ }
+ }
+ }.start();
}
}
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -30,18 +30,15 @@
// Local packages
import org.mulgara.query.MulgaraTransactionException;
-import org.mulgara.transaction.TransactionManagerFactory;
import org.mulgara.util.StackTrace;
/**
* Manages the Write-Lock.
*
* Manages tracking the ownership of the write-lock.
- * Provides new/existing TransactionContext's to DatabaseSession on request.
- * Note: Returns new context unless Session is currently in a User Demarcated Transaction.
* Provides a facility to trigger a heuristic rollback of any transactions still
* valid on session close.
- * Maintains the write-queue and any timeout algorithm desired.
+ * Maintains the write-queue
*
* @created 2006-10-06
*
@@ -75,29 +72,14 @@
private final ReentrantLock mutex;
private final Condition writeLockCondition;
- private final MulgaraInternalTransactionFactory internalFactory;
- private final MulgaraExternalTransactionFactory externalFactory;
-
- public MulgaraTransactionManager(TransactionManagerFactory transactionManagerFactory) {
+ public MulgaraTransactionManager() {
this.sessionHoldingWriteLock = null;
this.sessionReservingWriteLock = null;
this.mutex = new ReentrantLock();
this.writeLockCondition = this.mutex.newCondition();
-
- this.internalFactory = new MulgaraInternalTransactionFactory(this, transactionManagerFactory);
- this.externalFactory = new MulgaraExternalTransactionFactory(this);
}
- MulgaraInternalTransactionFactory getInternalFactory() {
- return internalFactory;
- }
-
- MulgaraExternalTransactionFactory getExternalFactory() {
- return externalFactory;
- }
-
-
/**
* Obtains the write lock.
*/
@@ -155,10 +137,6 @@
}
- public void setTransactionTimeout(int transactionTimeout) {
- internalFactory.setTransactionTimeout(transactionTimeout);
- }
-
/**
* Used to replace the built in monitor to allow it to be properly released
* during potentially blocking operations. All potentially blocking
@@ -192,11 +170,21 @@
}
boolean writeLockReserved() {
- return sessionReservingWriteLock != null;
+ acquireMutex();
+ try {
+ return sessionReservingWriteLock != null;
+ } finally {
+ releaseMutex();
+ }
}
boolean writeLockReserved(DatabaseSession session) {
- return session == sessionReservingWriteLock;
+ acquireMutex();
+ try {
+ return session == sessionReservingWriteLock;
+ } finally {
+ releaseMutex();
+ }
}
void releaseReserve(DatabaseSession session) {
@@ -229,28 +217,12 @@
}
public void closingSession(DatabaseSession session) throws MulgaraTransactionException {
- // Calls to final fields do not require mutex. As both of these calls
- // potentially call back into the manager, calling these while holding the
- // lock can invalidate lock-ordering and result in a deadlock.
- Throwable error = null;
- try {
- internalFactory.closingSession(session);
- } catch (Throwable th) {
- logger.error("Error signalling session-close to internal xa-factory", th);
- error = (error == null) ? th : error;
- }
-
- try {
- externalFactory.closingSession(session);
- } catch (Throwable th) {
- logger.error("Error signalling session-close to external xa-factory", th);
- error = (error == null) ? th : error;
- }
-
// This code should not be required, but is there to ensure the manager is
// reset regardless of errors in the factories.
acquireMutex();
try {
+ Throwable error = null;
+
if (writeLockReserved(session)) {
try {
releaseReserve(session);
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -24,7 +24,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-import java.util.concurrent.locks.ReentrantLock;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
@@ -79,8 +78,6 @@
private final Assoc1toNMap<MulgaraExternalTransaction, Xid> xa2xid;
- private final ReentrantLock mutex;
-
private final UUID uniqueId;
MulgaraXAResourceContext(MulgaraExternalTransactionFactory factory, DatabaseSession session) {
@@ -88,7 +85,6 @@
this.factory = factory;
this.session = session;
this.xa2xid = new Assoc1toNMap<MulgaraExternalTransaction, Xid>();
- this.mutex = new ReentrantLock();
this.uniqueId = UUID.randomUUID();
}
@@ -114,7 +110,7 @@
* for a call to forget().
*/
public void commit(Xid xid, boolean onePhase) throws XAException {
- acquireMutex();
+ factory.acquireMutex(0, XAException.class);
try {
xid = convertXid(xid);
logger.info("Performing commit: " + parseXid(xid));
@@ -167,7 +163,7 @@
}
}
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
@@ -181,7 +177,7 @@
* In all cases disassociate from current session.
*/
public void end(Xid xid, int flags) throws XAException {
- acquireMutex();
+ factory.acquireMutex(0, XAException.class);
try {
xid = convertXid(xid);
logger.info("Performing end(" + formatFlags(flags) + "): " + parseXid(xid));
@@ -208,18 +204,18 @@
try {
// If XA is currently associated with session, disassociate it.
- factory.disassociateTransaction(session, xa);
+ factory.disassociateTransaction(xa);
} catch (MulgaraTransactionException em) {
logger.error("Error disassociating transaction from session", em);
throw new XAException(XAException.XAER_PROTO);
}
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
public void forget(Xid xid) throws XAException {
- acquireMutex();
+ factory.acquireMutex(0, XAException.class);
try {
xid = convertXid(xid);
logger.info("Performing forget: " + parseXid(xid));
@@ -240,22 +236,22 @@
xa2xid.remove1(xa);
}
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
- public int getTransactionTimeout() {
- acquireMutex();
+ public int getTransactionTimeout() throws XAException {
+ factory.acquireMutex(0, XAException.class);
try {
logger.info("Performing getTransactionTimeout");
- return 3600;
+ return (int) (session.getTransactionTimeout() / 1000);
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
- public boolean isSameRM(XAResource xares) {
- acquireMutex();
+ public boolean isSameRM(XAResource xares) throws XAException {
+ factory.acquireMutex(0, XAException.class);
try {
logger.info("Performing isSameRM");
if (!xares.getClass().equals(MulgaraXAResource.class)) {
@@ -267,13 +263,13 @@
return session == ((MulgaraXAResource)xares).getSession();
}
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
public int prepare(Xid xid) throws XAException {
- acquireMutex();
+ factory.acquireMutex(0, XAException.class);
try {
xid = convertXid(xid);
logger.info("Performing prepare: " + parseXid(xid));
@@ -288,7 +284,7 @@
return XA_OK;
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
@@ -297,19 +293,19 @@
* FIXME: We should at least handle the case where we are asked to recover
* when we haven't crashed.
*/
- public Xid[] recover(int flag) {
- acquireMutex();
+ public Xid[] recover(int flag) throws XAException {
+ factory.acquireMutex(0, XAException.class);
try {
logger.info("Performing recover");
return new Xid[] {};
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
public void rollback(Xid xid) throws XAException {
- acquireMutex();
+ factory.acquireMutex(0, XAException.class);
try {
xid = convertXid(xid);
logger.info("Performing rollback: " + parseXid(xid));
@@ -323,7 +319,7 @@
// transaction. doRollback only throws Heuristic Exceptions.
xa2xid.remove1(xa);
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
@@ -342,19 +338,23 @@
}
- public boolean setTransactionTimeout(int seconds) {
- acquireMutex();
+ public boolean setTransactionTimeout(int seconds) throws XAException {
+ if (seconds < 0)
+ throw new XAException(XAException.XAER_INVAL);
+
+ factory.acquireMutex(0, XAException.class);
try {
logger.info("Performing setTransactionTimeout");
- return false;
+ session.setTransactionTimeout(seconds * 1000L);
+ return true;
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
public void start(Xid xid, int flags) throws XAException {
- acquireMutex();
+ factory.acquireMutex(0, XAException.class);
try {
xid = convertXid(xid);
logger.info("Performing start(" + formatFlags(flags) + "): " + parseXid(xid));
@@ -362,12 +362,12 @@
case TMNOFLAGS:
if (xa2xid.containsN(xid)) {
throw new XAException(XAException.XAER_DUPID);
- } else if (factory.hasAssociatedTransaction(session)) {
+ } else if (factory.hasAssociatedTransaction()) {
throw new XAException(XAException.XA_RBDEADLOCK);
} else {
// FIXME: Need to consider read-only transactions here.
try {
- MulgaraExternalTransaction xa = factory.createTransaction(session, xid, writing);
+ MulgaraExternalTransaction xa = factory.createTransaction(xid, writing);
xa2xid.put(xa, xid);
} catch (MulgaraTransactionException em) {
logger.error("Failed to create transaction", em);
@@ -376,9 +376,9 @@
}
break;
case TMJOIN:
- if (!factory.hasAssociatedTransaction(session)) {
+ if (!factory.hasAssociatedTransaction()) {
throw new XAException(XAException.XAER_NOTA);
- } else if (!factory.getAssociatedTransaction(session).getXid().equals(xid)) {
+ } else if (!factory.getAssociatedTransaction().getXid().equals(xid)) {
throw new XAException(XAException.XAER_OUTSIDE);
}
break;
@@ -389,7 +389,7 @@
} else if (xa.isRollbacked()) {
throw new XAException(XAException.XA_RBROLLBACK);
} else {
- if (!factory.associateTransaction(session, xa)) {
+ if (!factory.associateTransaction(xa)) {
// session already associated with a transaction.
throw new XAException(XAException.XAER_PROTO);
}
@@ -397,7 +397,7 @@
break;
}
} finally {
- releaseMutex();
+ factory.releaseMutex();
}
}
@@ -412,27 +412,7 @@
*/
private DatabaseSession getSession() { return session; }
}
-
- /**
- * Used to replace the built in monitor to allow it to be properly released
- * during potentially blocking operations. All potentially blocking
- * operations involve writes, so in these cases the write-lock is reserved
- * allowing the mutex to be safely released and then reobtained after the
- * blocking operation concludes.
- */
- protected void acquireMutex() {
- mutex.lock();
- }
-
- protected void releaseMutex() {
- if (!mutex.isHeldByCurrentThread()) {
- throw new IllegalStateException("Attempt to release mutex without holding mutex");
- }
-
- mutex.unlock();
- }
-
public static String parseXid(Xid xid) {
return xid.toString();
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MutableLocalQueryImpl.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MutableLocalQueryImpl.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MutableLocalQueryImpl.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -36,7 +36,6 @@
// Java 2 standard packages
// Third party packages
-import org.apache.log4j.Logger;
// Local packages
import org.mulgara.query.*;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/Operation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/Operation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/Operation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -29,9 +29,7 @@
// Local packages
import org.mulgara.resolver.spi.DatabaseMetadata;
-import org.mulgara.resolver.spi.ResolverSessionFactory;
import org.mulgara.resolver.spi.SystemResolver;
-import org.mulgara.server.Session;
/**
* {@link Operation}s correspond to methods of the {@link Session} interface
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/PreallocateOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/PreallocateOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/PreallocateOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -29,12 +29,7 @@
// Java 2 standard packages
import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.util.*;
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.XAResource;
// Third party packages
import org.apache.log4j.Logger;
@@ -42,7 +37,6 @@
// Local packages
import org.mulgara.resolver.spi.DatabaseMetadata;
-import org.mulgara.resolver.spi.ResolverSessionFactory;
import org.mulgara.resolver.spi.SingletonStatements;
import org.mulgara.resolver.spi.SystemResolver;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/QueryOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -37,7 +37,6 @@
// Local packages
import org.mulgara.query.*;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
/**
* An {@link Operation} that implements the {@link Session#query} method.
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/RemoveModelOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -29,34 +29,17 @@
// Java 2 standard packages
import java.io.*;
-import java.net.MalformedURLException;
import java.net.URI;
-import java.net.URISyntaxException;
import java.util.*;
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.XAResource;
-// Java 2 enterprise packages
-import javax.transaction.RollbackException;
-import javax.transaction.Status;
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import javax.transaction.InvalidTransactionException;
-
// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.*;
// Local packages
-import org.mulgara.content.Content;
-import org.mulgara.content.ContentHandler;
-import org.mulgara.content.ContentHandlerManager;
-import org.mulgara.content.ContentLoader;
import org.mulgara.query.*;
import org.mulgara.query.rdf.*;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
import org.mulgara.store.nodepool.NodePool;
/**
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/SetModelOperation.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -29,21 +29,9 @@
// Java 2 standard packages
import java.io.*;
-import java.net.MalformedURLException;
import java.net.URI;
-import java.net.URISyntaxException;
import java.util.*;
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.XAResource;
-// Java 2 enterprise packages
-import javax.transaction.RollbackException;
-import javax.transaction.Status;
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import javax.transaction.InvalidTransactionException;
-
// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.*;
@@ -58,7 +46,6 @@
import org.mulgara.query.*;
import org.mulgara.query.rdf.*;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
/**
* An {@link Operation} that implements the {@link Session#setModel} method.
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/StatusFormat.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -29,7 +29,6 @@
// Java 2 enterprise packages
import javax.transaction.Status;
-import javax.transaction.SystemException;
/**
* Generate a presentation form for a transaction {@link Status}.
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/StreamContent.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/StreamContent.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/StreamContent.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -28,7 +28,6 @@
package org.mulgara.resolver;
// Java 2 standard packages
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -123,6 +123,8 @@
private Object globalLock;
+ private Thread currentThread;
+
StringPoolSession(URI databaseURI,
Set<String> hostnameAliases,
XAStringPool persistentStringPool,
@@ -146,6 +148,7 @@
this.temporaryNodePool = temporaryNodePool;
this.globalLock = globalLock;
this.state = OBTAIN;
+ this.currentThread = null;
}
@@ -154,9 +157,10 @@
//
public Node globalize(long localNode) throws GlobalizeException {
-
// this should not require guarding, as read-only operations will usually not be on the current phase
// any reads on the current phase are about to start failing anyway if the state changes under us
+ // this should not require guarding, as read-only operations will usually not be on the current phase
+ // any reads on the current phase are about to start failing anyway if the state changes under us
if (state == ROLLBACK || state == RELEASE) {
throw new GlobalizeException(localNode, "Attempting to globalize outside transaction.");
}
@@ -200,117 +204,152 @@
}
public long localizePersistent(Node node) throws LocalizeException {
- return localize(node, WRITE | PERSIST);
+ checkCurrentThread();
+ try {
+ return localize(node, WRITE | PERSIST);
+ } finally {
+ releaseCurrentThread();
+ }
}
public long newBlankNode() throws NodePoolException {
- return persistentNodePool.newNode();
+ checkCurrentThread();
+ try {
+ return persistentNodePool.newNode();
+ } finally {
+ releaseCurrentThread();
+ }
}
public void refresh(SimpleXAResource[] resources) throws SimpleXAResourceException {
- if (logger.isDebugEnabled()) {
- logger.debug("Obtaining phase on StringPoolSession " + System.identityHashCode(this));
- }
- this.resources = resources;
+ checkCurrentThread();
+ try {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Obtaining phase on StringPoolSession " + System.identityHashCode(this));
+ }
+ this.resources = resources;
- synchronized (this.globalLock) {
- this.persistentStringPool.refresh();
- this.persistentNodePool.refresh();
- // !!Review: Call rollback on temporary? NB. Can't rollback non XA-SP/NP.
- //this.temporaryStringPool.refresh();
- //this.temporaryNodePool.refresh();
+ synchronized (this.globalLock) {
+ this.persistentStringPool.refresh();
+ this.persistentNodePool.refresh();
+ // !!Review: Call rollback on temporary? NB. Can't rollback non XA-SP/NP.
+ //this.temporaryStringPool.refresh();
+ //this.temporaryNodePool.refresh();
- for (int i = 0; i < this.resources.length; i++) {
- this.resources[i].refresh();
+ for (int i = 0; i < this.resources.length; i++) {
+ this.resources[i].refresh();
+ }
}
+ } finally {
+ releaseCurrentThread();
}
}
public void prepare() throws SimpleXAResourceException {
- synchronized (globalLock) {
- if (logger.isDebugEnabled()) {
- logger.debug("Preparing phase on StringPoolSession " + System.identityHashCode(this) + " SP=" + System.identityHashCode(persistentStringPool));
+ checkCurrentThread();
+ try {
+ synchronized (globalLock) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Preparing phase on StringPoolSession " + System.identityHashCode(this) + " SP=" + System.identityHashCode(persistentStringPool));
+ }
+ if (state == PREPARE) {
+ return;
+ } else if (state != OBTAIN) {
+ throw new SimpleXAResourceException("Attempting to prepare phase without obtaining phase");
+ }
+
+ state = PREPARE;
+
+ persistentStringPool.prepare();
+ persistentNodePool.prepare();
+ for (int i = 0; i < resources.length; i++) {
+ resources[i].prepare();
+ }
}
- if (state == PREPARE) {
- return;
- } else if (state != OBTAIN) {
- throw new SimpleXAResourceException("Attempting to prepare phase without obtaining phase");
- }
-
- state = PREPARE;
-
- persistentStringPool.prepare();
- persistentNodePool.prepare();
- for (int i = 0; i < resources.length; i++) {
- resources[i].prepare();
- }
+ } finally {
+ releaseCurrentThread();
}
}
public void commit() throws SimpleXAResourceException {
- synchronized (globalLock) {
- if (logger.isDebugEnabled()) {
- logger.debug("Committing phase on StringPoolSession " + System.identityHashCode(this));
- }
- if (state == COMMIT) {
- return;
- } else if (state != PREPARE) {
- throw new SimpleXAResourceException("Attempting to commit phase without preparing");
- }
-
- state = COMMIT;
+ checkCurrentThread();
+ try {
+ synchronized (globalLock) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Committing phase on StringPoolSession " + System.identityHashCode(this));
+ }
+ if (state == COMMIT) {
+ return;
+ } else if (state != PREPARE) {
+ throw new SimpleXAResourceException("Attempting to commit phase without preparing");
+ }
+
+ state = COMMIT;
- persistentStringPool.commit();
- persistentNodePool.commit();
- for (int i = 0; i < resources.length; i++) {
- resources[i].commit();
+ persistentStringPool.commit();
+ persistentNodePool.commit();
+ for (int i = 0; i < resources.length; i++) {
+ resources[i].commit();
+ }
}
+ } finally {
+ releaseCurrentThread();
}
}
public void rollback() throws SimpleXAResourceException {
- synchronized (globalLock) {
- if (logger.isDebugEnabled()) {
- logger.debug("Rollback phase on StringPoolSession " + System.identityHashCode(this));
+ checkCurrentThread();
+ try {
+ synchronized (globalLock) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Rollback phase on StringPoolSession " + System.identityHashCode(this));
+ }
+ if (state == RELEASE) {
+ throw new SimpleXAResourceException("Attempting to rollback phase outside transaction");
+ }
+ state = ROLLBACK;
+ persistentStringPool.rollback();
+ persistentNodePool.rollback();
+ for (int i = 0; i < resources.length; i++) {
+ resources[i].rollback();
+ }
}
- if (state == RELEASE) {
- throw new SimpleXAResourceException("Attempting to rollback phase outside transaction");
- }
- state = ROLLBACK;
- persistentStringPool.rollback();
- persistentNodePool.rollback();
- for (int i = 0; i < resources.length; i++) {
- resources[i].rollback();
- }
+ } finally {
+ releaseCurrentThread();
}
}
public void release() throws SimpleXAResourceException {
- synchronized (globalLock) {
- if (logger.isDebugEnabled()) {
- logger.debug("Release phase on StringPoolSession " + System.identityHashCode(this));
+ checkCurrentThread();
+ try {
+ synchronized (globalLock) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Release phase on StringPoolSession " + System.identityHashCode(this));
+ }
+ if (state == RELEASE) {
+ return;
+ } else if (state != COMMIT && state != ROLLBACK) {
+ throw new SimpleXAResourceException("Attempting to release phase without commit or rollback");
+ }
+
+ state = RELEASE;
+
+ persistentStringPool.release();
+ persistentNodePool.release();
+
+ // TODO determine if release() should be called for the temp components.
+ //temporaryStringPool.release();
+ //temporaryNodePool.release();
+ for (int i = 0; i < resources.length; i++) {
+ resources[i].release();
+ }
}
- if (state == RELEASE) {
- return;
- } else if (state != COMMIT && state != ROLLBACK) {
- throw new SimpleXAResourceException("Attempting to release phase without commit or rollback");
- }
-
- state = RELEASE;
-
- persistentStringPool.release();
- persistentNodePool.release();
-
- // TODO determine if release() should be called for the temp components.
- //temporaryStringPool.release();
- //temporaryNodePool.release();
- for (int i = 0; i < resources.length; i++) {
- resources[i].release();
- }
+ } finally {
+ releaseCurrentThread();
}
}
@@ -734,4 +773,25 @@
public long findGNode(SPObject spObject) throws StringPoolException {
return persistentStringPool.findGNode(spObject, persistentNodePool);
}
+
+ /**
+ * Used purely as a sanity check in the hope that we might catch concurrency bugs in higher layers should
+ * they exist.
+ */
+ private void checkCurrentThread() {
+ synchronized(this) {
+ if (currentThread == null || currentThread.equals(Thread.currentThread())) {
+ currentThread = Thread.currentThread();
+ } else {
+ logger.warn("Concurrent Access of StringPoolSession Attempted");
+ throw new IllegalStateException("Concurrent Access of StringPoolSession Attempted");
+ }
+ }
+ }
+
+ private void releaseCurrentThread() {
+ synchronized(this) {
+ currentThread = null;
+ }
+ }
}
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSessionFactory.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSessionFactory.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/StringPoolSessionFactory.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -32,13 +32,7 @@
import java.net.URI;
import java.util.*;
import java.lang.reflect.Method;
-import javax.transaction.xa.XAResource;
-// Java 2 enterprise packages
-import javax.transaction.RollbackException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-
// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.*;
@@ -48,22 +42,13 @@
import org.mulgara.query.*;
import org.mulgara.query.rdf.*;
import org.mulgara.resolver.spi.*;
-import org.mulgara.server.Session;
-import org.mulgara.server.SessionFactory;
-import org.mulgara.store.nodepool.NodePool;
import org.mulgara.store.nodepool.NodePoolException;
import org.mulgara.store.nodepool.NodePoolFactory;
-import org.mulgara.store.statement.StatementStore;
-import org.mulgara.store.stringpool.StringPool;
import org.mulgara.store.stringpool.StringPoolException;
import org.mulgara.store.stringpool.StringPoolFactory;
-import org.mulgara.store.tuples.Tuples;
-import org.mulgara.store.tuples.TuplesOperations;
import org.mulgara.store.xa.SimpleXARecoveryHandler;
-import org.mulgara.store.xa.SimpleXAResource;
import org.mulgara.store.xa.SimpleXAResourceException;
import org.mulgara.store.xa.XANodePool;
-import org.mulgara.store.xa.XAResolverSession;
import org.mulgara.store.xa.XAResolverSessionFactory;
import org.mulgara.store.xa.XAStatementStore;
import org.mulgara.store.xa.XAStringPool;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/SystemModelSecurityAdapter.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/SystemModelSecurityAdapter.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/SystemModelSecurityAdapter.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -29,10 +29,7 @@
// Local packages
import org.mulgara.resolver.spi.NullSecurityAdapter;
-import org.mulgara.resolver.spi.Resolver;
import org.mulgara.resolver.spi.ResolverSession;
-import org.mulgara.resolver.spi.SecurityAdapter;
-import org.mulgara.server.Session;
import org.mulgara.store.nodepool.NodePool;
/**
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/TransitiveFunction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/TransitiveFunction.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/TransitiveFunction.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -37,7 +37,6 @@
// Locally written packages
import org.mulgara.query.*;
-import org.mulgara.store.statement.StatementStoreException;
import org.mulgara.store.tuples.LiteralTuples;
import org.mulgara.store.tuples.Tuples;
import org.mulgara.store.tuples.TuplesOperations;
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -559,6 +559,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
new File(persistenceDirectory, "xaNodePool"),
stringPoolFactoryClassName, // persistent
Modified: trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java
===================================================================
--- trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -235,6 +235,7 @@
null, // no security domain
new JotmTransactionManagerFactory(),
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
new File(persistenceDirectory, "xaNodePool"),
stringPoolFactoryClassName, // persistent
Modified: trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java
===================================================================
--- trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -405,6 +405,7 @@
null, // no security domain
transactionManagerFactory,
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
new File(persistenceDirectory, "xaNodePool"),
stringPoolFactoryClassName, // persistent
Modified: trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java
===================================================================
--- trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -557,6 +557,7 @@
null, // no security domain
transactionManagerFactory,
0, // default transaction timeout
+ 0, // default idle timeout
nodePoolFactoryClassName, // persistent
new File(persistenceDirectory, "xaNodePool"),
stringPoolFactoryClassName, // persistent
Modified: trunk/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java
===================================================================
--- trunk/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -580,4 +580,12 @@
public boolean ping() {
return true;
}
+
+ public void setIdleTimeout(long millis) {
+ throw new UnsupportedOperationException("Timeouts not implemented under beep.");
+ }
+
+ public void setTransactionTimeout(long millis) {
+ throw new UnsupportedOperationException("Timeouts not implemented under beep.");
+ }
}
Modified: trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java
===================================================================
--- trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -347,7 +347,27 @@
*/
public RemoteXAResource getXAResource() throws QueryException, RemoteException;
public RemoteXAResource getReadOnlyXAResource() throws QueryException, RemoteException;
-
+
+ /**
+ * Set the idle timeout for new transactions.
+ *
+ * @param millis the number of milliseconds a transaction may be idle before being aborted,
+ * or 0 to use a default timeout.
+ * @throws QueryException
+ * @throws RemoteException
+ */
+ public void setIdleTimeout(long millis) throws QueryException, RemoteException;
+
+ /**
+ * Set the maximum duration for new transactions.
+ *
+ * @param millis the number of milliseconds a transaction may be open before being aborted,
+ * or 0 to use a default timeout.
+ * @throws QueryException
+ * @throws RemoteException
+ */
+ public void setTransactionTimeout(long millis) throws QueryException, RemoteException;
+
/**
* Test the connectivity of the remote session.
* @return <code>true</code> if connectivity was established.
Modified: trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java
===================================================================
--- trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -693,7 +693,27 @@
throw new QueryException("Java RMI failure", re);
}
}
-
+
+ public void setIdleTimeout(long millis) throws QueryException {
+ try {
+ remoteSession.setIdleTimeout(millis);
+ resetRetries();
+ } catch (RemoteException re){
+ testRetry(re);
+ setIdleTimeout(millis);
+ }
+ }
+
+ public void setTransactionTimeout(long millis) throws QueryException {
+ try {
+ remoteSession.setTransactionTimeout(millis);
+ resetRetries();
+ } catch (RemoteException re){
+ testRetry(re);
+ setTransactionTimeout(millis);
+ }
+ }
+
public boolean ping() throws QueryException {
try {
boolean ping = remoteSession.ping();
Modified: trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java
===================================================================
--- trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java 2008-07-18 13:51:21 UTC (rev 1097)
+++ trunk/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java 2008-07-20 13:01:56 UTC (rev 1098)
@@ -517,7 +517,23 @@
throw convertToQueryException(t);
}
}
-
+
+ public void setIdleTimeout(long millis) throws QueryException, RemoteException {
+ try {
+ session.setIdleTimeout(millis);
+ } catch (Throwable t) {
+ throw convertToQueryException(t);
+ }
+ }
+
+ public void setTransactionTimeout(long millis) throws QueryException, RemoteException {
+ try {
+ session.setTransactionTimeout(millis);
+ } catch (Throwable t) {
+ throw convertToQueryException(t);
+ }
+ }
+
public boolean ping() throws QueryException, RemoteException {
try {
return session.ping();
More information about the Mulgara-svn
mailing list