4 Replies Latest reply on Mar 6, 2007 10:38 AM by manik

    JBossCache 1.3 - CacheStoreInterceptor does not commit trans

    arcpanda

      I am using JBossCache 1.3 SP4 with weblogic 8.1 SP4. JBossCache has been configured to use org.jboss.cache.GenericTransactionManagerLookup - so that the transaction Manager of weblogic would be used. I am also using a JDBC Cache Loader configuration

      In my code, I have enclosed treeCache.put in a transaction i.e.

      tx.begin();
      treeCache.put(.....);
      tx.commit();


      What I observe is that even after commit(), records do not get inserted into database. This is causing a problem next time I try to insert any node on the same branch.

      I did some debugging by checking the source code of the JBossCache. I find the following code in CacheStoreInterceptor.invoke() -


      if (log.isTraceEnabled()) {
       log.trace("CacheStoreInterceptor called with meth " + m);
       }
      
       if (tx_mgr != null && tx_mgr.getTransaction() != null) {
       // we have a tx running.
       log.trace("transactional so don't put stuff in the cloader yet.");
       GlobalTransaction gtx = getInvocationContext().getGlobalTransaction();
       if (TreeCache.commitMethod.equals(meth)) {
       if (getInvocationContext().isTxHasMods()) {
       // this is a commit call.
       if (log.isTraceEnabled()) log.trace("Calling loader.commit() for gtx " + gtx);
       // sync call (a write) on the loader
       List fqnsModified = getFqnsFromModificationList(tx_table.get(gtx).getModifications());
       obtainLoaderLocks(fqnsModified);
       try
       {
       loader.commit(gtx);
       }
       finally
       {
       releaseLoaderLocks(fqnsModified);
       preparingTxs.remove(gtx);
       }
       if (cache.getUseInterceptorMbeans()&& statsEnabled) {
       Integer puts = (Integer)m_txStores.get(gtx);
       if (puts != null)
       m_cacheStores = m_cacheStores + puts.intValue();
       m_txStores.remove(gtx);
       }
       }
       else {
       log.trace("Commit called with no modifications; ignoring.");
       }
       }



      I turned debug logging on and I observed that the following is printed

      org.jboss.cache.interceptors.CacheStoreInterceptor CacheStoreInterceptor called with meth commit(GlobalTransaction:<127.0.0.1:2081>:1)


      However, the next debug output was

      org.jboss.cache.interceptors.PessimisticLockInterceptor PessimisticLockInterceptor invoked for method commit(GlobalTransaction:<127.0.0.1:2081>:1)


      Calling loader.commit()
      was never printed!!!This means that the commit is not being called for the loader and the records are not getting stored into the database. This observation tallies with the results I am getting

      Is this a known bug??? If so and if you are planning to fix the problem, I hope it is released in a future release of JBossCache 1.3 itself since I am not planning to upgrade to 1.4

        • 1. Re: JBossCache 1.3 - CacheStoreInterceptor does not commit t
          arcpanda

          I want to add also that the problem does not occur if I don't use transactions at all since then records are inserted and committed directly in the database. However, this is not the preferred solution at all for me!

          • 2. Re: JBossCache 1.3 - CacheStoreInterceptor does not commit t
            manik

            I presume you don't even see the output from

            log.trace("transactional so don't put stuff in the cloader yet.");
            


            Do you have a simple unit test that recreates this?

            Also, I know you don't wish to upgrade to 1.4.x (although I recommend it for various other reasons), could you try this there as well and see if the problem still exists?

            Thanks,

            • 3. Re: JBossCache 1.3 - CacheStoreInterceptor does not commit t
              arcpanda

              Yippppeeeeeeeee!!!!

              I have solved the problem!!!

              Actually I should have used an XADataSource for the underlying database to use global transactions for the cache.

              The clue of the problem was in comments of TxInterceptor.RemoteSynchronizationHandler.afterCompletion()

              - // this should really not be done here -
              // it is supposed to be post commit not actually run the commit


              Actually in 2-phase commit, the transaction would already have been committed, so there is no way that connection.commit() would be called in CacheStoreInterceptor.

              I would recommend that this should be included as a part of the faq or jboss cache tutorials - that whenever we are using a backing store with application server's TransactionManager, we should always use an XADataSource.

              <attribute name="CacheLoaderConfiguration">
               <config>
               <passivation>false</passivation>
               <preload>/</preload>
               <shared>true</shared>
               <cacheloader>
               <class>org.jboss.cache.loader.JDBCCacheLoader</class>
               <properties>
               cache.jdbc.table.name=jbosscache
               cache.jdbc.table.create=true
               cache.jdbc.table.drop=false
               cache.jdbc.table.primarykey=jbosscache_pk
               cache.jdbc.fqn.column=fqn
               cache.jdbc.fqn.type=varchar(255)
               cache.jdbc.node.column=node
               cache.jdbc.node.type=blob
               cache.jdbc.parent.column=parent
               cache.jdbc.datasource=AshleyCacheDataSource
               </properties>
               <async>false</async>
               <fetchPersistentState>true</fetchPersistentState>
               <ignoreModifications>false</ignoreModifications>
               </cacheloader>
               </config>
               </attribute>



              OR

              <attribute name="CacheLoaderConfiguration">
               <config>
               <passivation>false</passivation>
               <preload>/</preload>
               <shared>true</shared>
               <cacheloader>
               <class>org.jboss.cache.loader.JDBCCacheLoader</class>
               <properties>
               cache.jdbc.table.name=jbosscache
               cache.jdbc.table.create=true
               cache.jdbc.table.drop=false
               cache.jdbc.table.primarykey=jbosscache_pk
               cache.jdbc.fqn.column=fqn
               cache.jdbc.fqn.type=varchar(255)
               cache.jdbc.node.column=node
               cache.jdbc.node.type=blob
               cache.jdbc.parent.column=parent
               cache.jdbc.driver=oracle.jdbc.xa.client.OracleXADataSource
               cache.jdbc.url=jdbc:oracle:thin:@localhost:1521:ACRMDEV
               cache.jdbc.user=FASTDEV
               cache.jdbc.password=fastdev123$
               </properties>
               <async>false</async>
               <fetchPersistentState>true</fetchPersistentState>
               <ignoreModifications>false</ignoreModifications>
               </cacheloader>
               </config>
               </attribute>


              Took me 2 days for this problem but I must say it was a wonderful experience and great sleuthing ;)

              • 4. Re: JBossCache 1.3 - CacheStoreInterceptor does not commit t
                manik

                :-) Glad you solved your problem. And thanks for the tip re: XADataSources - will certainly add it to the FAQs.