4 Replies Latest reply on Jul 16, 2011 4:31 PM by shahinaskari

    Avoid locking in non-distributed transactional cache

    shahinaskari

      I am using Inifinispan as a local, non-distributed cache in a stateless session bean inside of AS 6.0.0 to cache versioned records from the database.  The cache is configured to take part in the container managed transaction.  The data is being put in the cache at both db read and db write time.  To avoid any race conditions that can leave the cache out of sync with the db, I am making use of get(), replace() and putIfAbsent() API to get the old version of any key being updated, perform a version check and ensure the data being put into cache is replacing the expected old value from the time of the version check.

       

      Having said all this, in the transactional mode, the get/replace and putIfAbsent are locking rows while the transaction is open which essentially means I'm doing pessimistic locking and since not all keys are present I can easily get deadlocks. 

       

      My questions is, is there an interface I can use to do the version validation at prepare time in order to avoid the deadlocks, or a better way to perform the version checks of the records I'm putting in the cache?

       

      I know there is some discussion about optimistic locks in version 5.1, however I'm still not sure this is exactly what I need as they are mainly concentrating on the distributed node locking.  I am currently using Infinispan 'Ursus' 4.2.0.FINAL as part of JBoss AS 6.0.0 Final.

       

      I have tried to read as much as I can in the docs and forum but I'm sure this answer is just hiding from me, so I apologize if I missed an existing post on this.

       

      This is my cache configuration (tx lookup class is dummy so I can run my test case outside of the AS server):

       

       

      <?xml version="1.0" encoding="UTF-8"?>
      <infinispan xmlns="urn:infinispan:config:4.2">
                <global>
                          <transport clusterName="Test" />
                          <globalJmxStatistics enabled="true" />
                </global>
      
                <namedCache name="test">
                          <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
                                    lockAcquisitionTimeout="15000" useLockStriping="false" />
                          <eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU" />
                          <expiration maxIdle="100000" />
      
                          <transaction
                                    transactionManagerLookupClass="org.infinispan.transaction.lookup.DummyTransactionManagerLookup"
                                    syncRollbackPhase="false" syncCommitPhase="false" useEagerLocking="false" />
                </namedCache>
      </infinispan>
      
      

       

      Thanks,

      Shahin

        • 1. Re: Avoid locking in non-distributed transactional cache
          pmuir

          Mircea or Sanne can add more, but this is under discussion at the moment (atomic operations in transactions). See Optimistic locking in Infinispan for some info and also this thread

          1 of 1 people found this helpful
          • 2. Re: Avoid locking in non-distributed transactional cache
            shahinaskari

            Thank you for that.  Will keep an eye on that development.  In the mean time is there an extension point in the stack which will allow me to act on the pending transactional changes with visibility into the actual values from outside of the transaction in the prepare step?  Hopefully I would be able to clean up the bad versions or fail the transaction at that point?

            • 3. Re: Avoid locking in non-distributed transactional cache
              sannegrinovero

              Hi,

              as explained in the thread linked by Pete, we're questioning the safety of using atomic operations during a transaction: while that thread is mostly concerned about REPEATABLE_READ, similar problems apply to READ_COMMITTED. You shoud apply changes to the cache in a "post commit" sync, so you should record changes during the transaction and apply them on commit: in fact that's what the Hibernate second level cache does.

              Was using Hibernate not an option? It's designed to facilitate these things, as it's in his very nature to record the changes you intend to make and reorganize the entities dirty state on commit time using databases, transactions and caches in proper way.

               

              If you can't use it, I'd suggest having a look into the sources of the Hibernate second level cache implementation using Infinispan; you could code something similar applying your changes to the cache during a transaction sync, and using appropriate flags for it:

               

              cache.withFlags(Flag.SKIP_LOCKING).putIfAbsent( k, v );

               

              A nice consequence on applying all changes atomically in the end is that you don't need locks at all

              1 of 1 people found this helpful
              • 4. Re: Avoid locking in non-distributed transactional cache
                shahinaskari

                Thank you for that.  I already have a similar implementation, was hoping to do away with my own.  The hibernate implementation is a good pointer, unfortunately I can't use the entire stack but maybe looking at that implemntation would be very usefull.  Thank you.