[Mulgara-svn] r977 - in branches/mgr-121-lockrecovery: 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

andrae at mulgara.org andrae at mulgara.org
Fri Jun 6 05:41:22 UTC 2008


Author: andrae
Date: 2008-06-05 22:41:21 -0700 (Thu, 05 Jun 2008)
New Revision: 977

Modified:
   branches/mgr-121-lockrecovery/conf/mulgara-config.xml
   branches/mgr-121-lockrecovery/conf/mulgara-embedded.dtd
   branches/mgr-121-lockrecovery/conf/mulgara-embedded.xsd
   branches/mgr-121-lockrecovery/src/jar/query/java/org/mulgara/server/Session.java
   branches/mgr-121-lockrecovery/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/Database.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java
   branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java
   branches/mgr-121-lockrecovery/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java
   branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java
   branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java
   branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java
Log:
Updates from Ronald.

Splits the transaction idle-timeout into a maximum transaction-timeout (meeting JTA requirements); and a
maximum-idle-timeout (meeting more useful requirements).

If a transaction holds the write-lock (irrespective of activity) for longer than the maxTT, the transaction
will be aborted.

If a transaction holds the write-lock, and does not perform an operation for longer than the maxIT, the
transaction will be aborted.

The timeouts have a default value set on the database-instance from the mulgara-conf file.  These defaults can
be overridden on a per-session basis by calling the appropriate set* methods on Session.

Note the idle reaper task runs on a 10s periodic basis, so the transaction abort may occur up to 10s after the
expiry of the timeout proper.



Modified: branches/mgr-121-lockrecovery/conf/mulgara-config.xml
===================================================================
--- branches/mgr-121-lockrecovery/conf/mulgara-config.xml	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/conf/mulgara-config.xml	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/conf/mulgara-embedded.dtd
===================================================================
--- branches/mgr-121-lockrecovery/conf/mulgara-embedded.dtd	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/conf/mulgara-embedded.dtd	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/conf/mulgara-embedded.xsd
===================================================================
--- branches/mgr-121-lockrecovery/conf/mulgara-embedded.xsd	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/conf/mulgara-embedded.xsd	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/src/jar/query/java/org/mulgara/server/Session.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/query/java/org/mulgara/server/Session.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/query/java/org/mulgara/server/Session.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -306,6 +306,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: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -183,6 +183,7 @@
                    null,                            // no security domain
                    new JotmTransactionManagerFactory(),
                    0,                               // default transaction timeout
+                   0,                               // default idle timeout
                    nodePoolFactoryClassName,        // persistent
                    new File(persistenceDirectory, "xaNodePool"),
                    stringPoolFactoryClassName,      // persistent
@@ -1528,9 +1529,10 @@
     logger.info("testConcurrentImplicitRecovery");
     URI fileURI  = new File("data/xatest-model1.rdf").toURI();
 
-    database.setWriteLockTimeout(30000);
+    // test idle timeout
     try {
       Session session1 = database.newSession();
+      session1.setIdleTimeout(10000);
       try {
         session1.createModel(model3URI, null);
         logger.debug("Obtaining autocommit for session1");
@@ -1589,9 +1591,9 @@
         t2.start();
 
         session1.setModel(model3URI, new ModelResource(fileURI));
-        logger.debug("Sleeping for 40sec");
-        Thread.sleep(40000);
-        logger.debug("Slept for 40sec");
+        logger.debug("Sleeping for 20sec");
+        Thread.sleep(20000);
+        logger.debug("Slept for 20sec");
         try {
           t2.join(2000L);
         } catch (InterruptedException ie) {
@@ -1605,6 +1607,8 @@
           session1.commit();
         } catch (QueryException eq) {
           qeThrown = true;
+        } catch (IllegalStateException ise) {
+          qeThrown = true;
         }
 
         assertTrue("Commit should have failed due to lock timeout", qeThrown);
@@ -1617,6 +1621,99 @@
     } catch (Exception e) {
       fail(e);
     }
+
+    // test transaction timeout
+    try {
+      Session session1 = database.newSession();
+      session1.setTransactionTimeout(10000);
+      try {
+        session1.createModel(model3URI, null);
+        logger.debug("Obtaining autocommit for session1");
+        session1.setAutoCommit(false);
+        logger.debug("Obtained autocommit 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");
+                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.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 20sec");
+        Thread.sleep(20000);
+        logger.debug("Slept for 20sec");
+        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());
+
+        boolean qeThrown = false;
+        try {
+          session1.commit();
+        } catch (QueryException eq) {
+          qeThrown = true;
+        } catch (IllegalStateException ise) {
+          qeThrown = true;
+        }
+
+        assertTrue("Commit should have failed due to lock timeout", qeThrown);
+
+        logger.debug("Releasing autocommit for session1");
+        session1.setAutoCommit(true);
+      } finally {
+        session1.close();
+      }
+    } catch (Exception e) {
+      fail(e);
+    }
   }
 
 

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/BasicDatabaseSessionUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -146,6 +146,7 @@
         null,                             // no security domain
         new JotmTransactionManagerFactory(),
         0,                                // default transaction timeout
+        0,                                // default idle timeout
         nodePoolFactoryClassName,         // persistent
         null,
         stringPoolFactoryClassName,       // persistent

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/Database.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/Database.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/Database.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -260,6 +260,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;
@@ -322,6 +327,7 @@
          uri,        // security domain
          new JotmTransactionManagerFactory(),
          config.getTransactionTimeout(),
+         config.getIdleTimeout(),
          config.getPersistentNodePoolFactory().getType(),
          DatabaseFactory.subdir(
            directory,
@@ -375,9 +381,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>
@@ -415,6 +424,7 @@
                   URI    securityDomainURI,
                   TransactionManagerFactory transactionManagerFactory,
                   int    transactionTimeout,
+                  int    idleTimeout,
                   String persistentNodePoolFactoryClassName,
                   File   persistentNodePoolDirectory,
                   String persistentStringPoolFactoryClassName,
@@ -513,7 +523,8 @@
     // FIXME: Migrate this code inside StringPoolSession.  Pass config to StringPoolSession.
     this.transactionManager = new MulgaraTransactionManager(transactionManagerFactory);
 
-    transactionManager.setTransactionTimeout(transactionTimeout);
+    this.defaultTransactionTimeout = transactionTimeout * 1000L;
+    this.defaultIdleTimeout = idleTimeout * 1000L;
 
     // Enable resolver initialization
     if (logger.isDebugEnabled()) {
@@ -688,6 +699,8 @@
 		    contentHandlers,
         unmodifiableCachedResolverFactorySet,
         temporaryModelTypeURI,
+        defaultTransactionTimeout,
+        defaultIdleTimeout,
         ruleLoaderClassName);
 
     // Updates metadata to reflect bootstrapped system model.
@@ -828,11 +841,6 @@
   }
 
 
-  public void setWriteLockTimeout(long timeout) {
-    transactionManager.setLockTimeout(timeout);
-  }
-
-
   /**
    * Flush all resources associated with the database into a recoverable state.
    */
@@ -900,6 +908,8 @@
         contentHandlers,
         unmodifiableCachedResolverFactorySet,
         temporaryModelTypeURI,
+        defaultTransactionTimeout,
+        defaultIdleTimeout,
         ruleLoaderClassName);
     } catch (ResolverFactoryException e) {
       throw new QueryException("Couldn't create session", e);
@@ -1149,6 +1159,8 @@
           contentHandlers,
           unmodifiableCachedResolverFactorySet,
           temporaryModelTypeURI,
+          defaultTransactionTimeout,
+          defaultIdleTimeout,
           ruleLoaderClassName);
       }
       catch (ResolverFactoryException e) {

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseFactory.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSession.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -117,6 +117,18 @@
   private MulgaraInternalTransactionFactory internalFactory;
   private 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;
 
@@ -160,6 +172,13 @@
    *   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,
@@ -175,6 +194,8 @@
       ContentHandlerManager contentHandlers,
       Set<ResolverFactory> cachedResolverFactorySet,
       URI temporaryModelTypeURI,
+      long transactionTimeout,
+      long idleTimeout,
       String ruleLoaderClassName) throws ResolverFactoryException {
 
     if (logger.isDebugEnabled()) {
@@ -210,6 +231,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 +253,17 @@
     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.transactionTimeout  = defaultTransactionTimeout;
+    this.idleTimeout         = defaultIdleTimeout;
+
     if (logger.isTraceEnabled()) logger.trace("Constructed DatabaseSession");
-
-    // Set the transaction timeout to an hour
-    transactionManager.setTransactionTimeout(3600);
   }
 
 
@@ -259,7 +286,7 @@
     this(transactionManager, securityAdapterList, symbolicTransformationList, resolverSessionFactory,
         systemResolverFactory, temporaryResolverFactory, resolverFactoryList, externalResolverFactoryMap,
         internalResolverFactoryMap, metadata, contentHandlers, cachedResolverFactorySet,
-        temporaryModelTypeURI, "");
+        temporaryModelTypeURI, 0, 0, null);
   }
 
   //
@@ -685,4 +712,20 @@
     assertExternallyManagedXA();
     return externalFactory.getXAResource(this, 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;
+  }
 }

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionListQueryUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -156,6 +156,7 @@
         null, // no security domain
         new JotmTransactionManagerFactory(),
         0, // default transaction timeout
+        0, // default idle timeout
         nodePoolFactoryClassName, // persistent
         null,
         stringPoolFactoryClassName, // persistent

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseSessionUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -514,6 +514,7 @@
         null,                            // no security domain
         new JotmTransactionManagerFactory(),
         0,                               // default transaction timeout
+        0,                               // default idle timeout
         nodePoolFactoryClassName,        // persistent
         null,
         stringPoolFactoryClassName,      // persistent

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/DatabaseUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -111,7 +111,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 +158,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: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/ExternalTransactionUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -176,6 +176,7 @@
                    null,                            // no security domain
                    new JotmTransactionManagerFactory(),
                    0,                               // default transaction timeout
+                   0,                               // default idle timeout
                    nodePoolFactoryClassName,        // persistent
                    new File(persistenceDirectory, "xaNodePool"),
                    stringPoolFactoryClassName,      // persistent

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -81,7 +81,9 @@
   private final MulgaraExternalTransactionFactory externalFactory;
 
   private final Timer reaperTimer;
-  private LockReaper reaperTask;
+  private IdleReaper idleReaperTask;
+  private long idleTimout;
+  private LockReaper lockReaperTask;
 
   public MulgaraTransactionManager(TransactionManagerFactory transactionManagerFactory) {
     this.sessionHoldingWriteLock = null;
@@ -94,7 +96,7 @@
     this.externalFactory = new MulgaraExternalTransactionFactory(this);
 
     this.reaperTimer = new Timer("Write-lock Reaper", true);
-    this.reaperTask = new LockReaper(reaperTimer, 900000); // 15 minutes inactivity.
+    this.idleReaperTask = new IdleReaper(reaperTimer, 10*1000L);        // check every 10 seconds
   }
 
 
@@ -130,6 +132,9 @@
       }
       sessionHoldingWriteLock = session;
       factoryWithWriteTransaction = factory;
+      this.idleTimout = session.getIdleTimeout() > 0 ? session.getIdleTimeout() : 15*60*1000L;
+      this.lockReaperTask =
+          new LockReaper(reaperTimer, session.getTransactionTimeout() > 0 ? session.getTransactionTimeout() : 60*60*1000L);
     } finally {
       releaseMutex();
     }
@@ -159,6 +164,7 @@
       }
       sessionHoldingWriteLock = null;
       factoryWithWriteTransaction = null;
+      lockReaperTask.cancel();
       writeLockCondition.signal();
     } finally {
       releaseMutex();
@@ -171,15 +177,6 @@
   }
 
 
-  public void setLockTimeout(long timeout) {
-    acquireMutex();
-    try {
-      reaperTask.setTimeout(timeout);
-    } finally {
-      releaseMutex();
-    }
-  }
-
   /**
    * Used to replace the built in monitor to allow it to be properly released
    * during potentially blocking operations.  All potentially blocking
@@ -302,39 +299,25 @@
     }
   }
 
-  class LockReaper extends TimerTask {
-    private final long MIN_PERIOD = 30000;
-
-    private Timer timer;
-    protected long timeoutMillis;
-
-    private boolean die;
-
-    public LockReaper(Timer timer, long timeoutMillis) {
-      logger.info("Lock-reaper created: " + System.identityHashCode(this));
-      this.timer = timer;
-      this.timeoutMillis = (timeoutMillis > MIN_PERIOD) ? timeoutMillis : MIN_PERIOD; 
-      this.die = false;
-      schedule();
+  private class IdleReaper extends TimerTask {
+    public IdleReaper(Timer timer, long periodMillis) {
+      logger.info("Idle-reaper created: " + System.identityHashCode(this));
+      timer.schedule(this, periodMillis, periodMillis);
     }
 
     public void run() {
-      logger.warn("Lock-reaper running");
+      logger.debug("Idle-reaper running");
       acquireMutex();
 
       try {
-        if (die) {
-          logger.info("Lock-reaper dying on request: " + System.identityHashCode(this));
-          return;
-        }
-
         if (factoryWithWriteTransaction != null) {
           long lastActive = factoryWithWriteTransaction.getLastActiveHoldingLock();
-          if ((lastActive > 0) && (lastActive < System.currentTimeMillis() - timeoutMillis)) {
+          if ((lastActive > 0) && (lastActive < System.currentTimeMillis() - idleTimout)) {
             logger.warn("Reclaiming writelock from inactive transaction");
             factoryWithWriteTransaction.abortWriteTransaction();
           } else {
-            logger.debug("Transaction still active: " + lastActive + " time: " + System.currentTimeMillis() + " timeout: " + timeoutMillis);
+            if (logger.isDebugEnabled())
+              logger.debug("Transaction still active: " + lastActive + " time: " + System.currentTimeMillis() + " timeout: " + idleTimout);
           }
         } else {
           logger.debug("No write-lock held.");
@@ -342,53 +325,38 @@
       } catch (MulgaraTransactionException em) {
         logger.warn("Exception thrown while reclaiming writelock from inactive transaction");
       } finally {
-        try {
-          if (!die) {
-            logger.debug("Rescheduling lock-reaper: " + System.identityHashCode(this));
-            schedule();
-          } else {
-            logger.debug("Not rescheduling lock-reaper on request: " + System.identityHashCode(this));
-          }
-        } finally {
-          releaseMutex();
-        }
+        releaseMutex();
       }
     }
+  }
 
-    public void setTimeout(long timeout) {
-      acquireMutex();
-      try {
-        reaperTask = new LockReaper(timer, timeout);
-        this.die = true;
-      } finally {
-        releaseMutex();
-      }
+  private class LockReaper extends TimerTask {
+    private boolean die = false;
+
+    public LockReaper(Timer timer, long timeoutMillis) {
+      logger.debug("Lock-reaper created: " + System.identityHashCode(this));
+      timer.schedule(this, timeoutMillis);
     }
 
-    public long getTimeout() {
+    public boolean cancel() {
+      die = true;
+      return super.cancel();
+    }
+
+    public void run() {
       acquireMutex();
+
       try {
-        return timeoutMillis;
+        if (die)
+          return;       // we were cancelled after being scheduled but before mutex was acquired
+
+        logger.warn("Reclaiming writelock from over-extended transaction");
+        factoryWithWriteTransaction.abortWriteTransaction();
+      } catch (MulgaraTransactionException em) {
+        logger.warn("Exception thrown while reclaiming writelock from over-extended transaction", em);
       } finally {
         releaseMutex();
       }
     }
-
-    private void schedule() {
-      long timeout = timeoutMillis;
-
-      if (factoryWithWriteTransaction != null) {
-        long lastActive = factoryWithWriteTransaction.getLastActiveHoldingLock();
-
-        if (lastActive > 0) {
-          timeout = timeoutMillis - (System.currentTimeMillis() - lastActive);
-        }
-      }
-        
-      timeout =  (timeout > MIN_PERIOD) ? timeout : MIN_PERIOD; 
-
-      logger.warn("Scheduling lock-reaper to run in: " + timeout + "ms");
-      timer.schedule(this, timeout);
-    }
   }
 }

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -248,7 +248,7 @@
       acquireMutex();
       try {
         logger.info("Performing getTransactionTimeout");
-        return 3600;
+        return (int) (session.getTransactionTimeout() / 1000);
       } finally {
         releaseMutex();
       }
@@ -342,11 +342,15 @@
     }
 
 
-    public boolean setTransactionTimeout(int seconds) {
+    public boolean setTransactionTimeout(int seconds) throws XAException {
+      if (seconds < 0)
+        throw new XAException(XAException.XAER_INVAL);
+
       acquireMutex();
       try {
         logger.info("Performing setTransactionTimeout");
-        return false;
+        session.setTransactionTimeout(seconds * 1000L);
+        return true;
       } finally {
         releaseMutex();
       }

Modified: branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver/java/org/mulgara/resolver/XADatabaseSessionUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver-relational/java/org/mulgara/resolver/relational/RelationalResolverUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver-test/java/org/mulgara/resolver/test/TestResolverUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/resolver-view/java/org/mulgara/resolver/view/ViewResolverUnitTest.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -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: branches/mgr-121-lockrecovery/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/server-beep/java/org/mulgara/server/beep/BEEPSession.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -546,4 +546,12 @@
  public XAResource getReadOnlyXAResource() throws QueryException {
    throw new QueryException("External transactions not implemented under Beep");
  }
+
+  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: branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSession.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -308,4 +308,24 @@
    */
   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;
 }

Modified: branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/RemoteSessionWrapperSession.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -627,4 +627,24 @@
       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);
+    }
+  }
 }

Modified: branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java
===================================================================
--- branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java	2008-06-06 04:50:54 UTC (rev 976)
+++ branches/mgr-121-lockrecovery/src/jar/server-rmi/java/org/mulgara/server/rmi/SessionWrapperRemoteSession.java	2008-06-06 05:41:21 UTC (rev 977)
@@ -476,7 +476,22 @@
     }
   }
 
+  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);
+    }
+  }
+
   // Construct an exception chain that will pass over RMI.
   protected Throwable mapThrowable(Throwable t) {
     Throwable cause = t.getCause();




More information about the Mulgara-svn mailing list