3 Replies Latest reply on Jan 5, 2015 5:47 AM by Radim Vansa

    Updating integer atomically over multiple JVMs

    Abhishek Agarwal Newbie

      Dear friends,

       

      To narrow down my requirement I need to increment the integer atomically for every key that I put on the cache, across multiple JVMS(we are using tomcat) and i am using Optimistic locking for this.

       

      Ex->

       

      Key1, Initial Value 0

       

      A Thread on JVM1 reads the value as 0

      A Thread on JVM2 also read the value as 0

      JVM1's thread increments to 1

      JVM2's thread also increments to 2

      JVM1's thread tries to update to 2 for key Key1and is succesful

      When JVM2's thread tries to update it 2 it should fail, so this thread will now be reading it again and then increment that.

       

      What I am observing this failure is not always happening.

       

      And its not just multiple JVMs, even when I am testing on a single JVM with multiple threads then also i am observing this issue.

       

      My infinispan configuration with Infinispan 6 is as below. I tried with Infi

       

      ?xml version="1.0" encoding="UTF-8"?>

       

      <infinispan

          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

          xsi:schemaLocation="urn:infinispan:config:6.0 http://www.infinispan.org/schemas/infinispan-config-6.0.xsd"

          xmlns="urn:infinispan:config:6.0">

        <global>

          <transport>

            <properties>

              <property name="configurationFile" value="jgroups-udp.xml"/>

            </properties>

          </transport>

        </global>

       

        <default>

          <!-- Configure an asynchronous replication cache -->

          <clustering mode="replication">

            <sync/>

          </clustering>

        </default>

       

      <namedCache name="samplingBucketsCache">

       

          <transaction

           transactionManagerLookupClass="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup"

           transactionMode="TRANSACTIONAL"    

           lockingMode="OPTIMISTIC"

           useSynchronization="true"

           autoCommit="true"    

           syncRollbackPhase="false"

           syncCommitPhase="false"

           useEagerLocking="false"/>   

          

          <locking writeSkewCheck="true" useLockStriping="false" isolationLevel="REPEATABLE_READ" lockAcquisitionTimeout="3000" />

         

          <versioning enabled="true" versioningScheme="SIMPLE" />    

          <!-- Use the configuration of the default cache as it is -->

        </namedCache>

      </infinispan>

        • 1. Re: Updating integer atomically over multiple JVMs
          Radim Vansa Master

          Your configuration seems correct, the only time when this could give incorrect resutls (with your configuration) is failed commit phase due to network issues (which you can't have on single JVM).

           

          Sounds like you have an unit test, could you share it, possibly with trace level logs on org.infinispan?

          • 2. Re: Re: Updating integer atomically over multiple JVMs
            Abhishek Agarwal Newbie

            Hi Radim,

             

            Thanks a lot for your reply. Please find the logs attached. I have created two threads and each thread reads from the cache for a key. I have used only one key (Key1). If there is no value in the key then it is set to new Integer(0). After the thread reads the value from the cache, I make it to sleep for 1 second so that the chances of two threads reading the same value and the hence the collision are high.

             

            The logs which I have introduced are as

             

            Step1 After Read: <Read Value from cache, if null then 0>

            Step2 After Incr:    <Create a copy of the read value and increment it>

            Step3 After Updt:   <Update on the cache the incremented value and then read it again after successful update>

             

            So I expect when I search for it I should get unique incremental values for log "Step3 After Updt:". But if you see in the attached logs, both the threads are successfully able to update the value to 5. Prior to that in case of any collisions, write skew is detected and hence corresponding exception is thrown.

             

            Please let me know if you need anything else from me.

             

            Regards,

            Abhishek

            • 3. Re: Re: Updating integer atomically over multiple JVMs
              Radim Vansa Master

              Seems like you're using only autocommit transactions, with code like that

               

              int value = cache.get("Key1");

              int oldValue = cache.put("Key1", value + 1);

               

              This does not guarantee atomic increments since only the get() and put() are not in one transaction - each operation is wrapped in its own TX. Sometimes you get WSCExceptions since put() works as tx.begin(); read(Key1); write(Key1, value + 1); tx.end() underhood, and there can be write skew between the read(Key1) and tx.end();. However, in the value=5 case the read returns 5, and when the the tx is committed the value is still 5, therefore, no WSCE is raised.

               

              In order to commit the values atomically, you need to both read and write the entry in single (explicit) transaction, or use replace("Key1", value, value + 1);