4 Replies Latest reply on Aug 24, 2011 9:35 AM by gabuzo

    Transaction isolation within a single process

    gabuzo

      I'm building an application using an Infinispan cache in transactional mode with atomikos. I wrote a small test to check if I get a correct isolation between transactions occuring at the same time. The test consist in performing the following steps:

       

      1. populate the cache with a single element.
      2. Launch two threads concurrently:
        1. one writer that will get the element, modify it, put it back to the cache and commiting the transaction,
        2. one reader that will get the element and displays it at various moments to check that, until the writer's transaction is committed, no change is visible from another transaction.

       

      The element stored was a very simple java bean with value and the following implementation of toString() to get additional information:

       

      public String toString() {
           return "[" + System.identityHashCode(this) + "] id: " + this.id + ", value: " + this.value;
      }
      

       

       

      The writer code is the following:

      @Transactional(propagation = Propagation.REQUIRES_NEW)
      public void performTrans() throws InterruptedException, BrokenBarrierException {
          LOGGER.info("Wait to start");
          pBarrier.await(); // 1
          final Pojo entity = cache.get(KEY);
          LOGGER.info("Start entity: {}", entity);
          pBarrier.await(); // 2
          entity.setValue(entity.getValue() + 42);
          LOGGER.info("Entity changed wait for reader");
          pBarrier.await(); // 3
          cache.put(KEY, entity);
          LOGGER.info("Entity saved wait for reader");
          pBarrier.await(); // 4
      }
      

       

      The reader code is the following:

      public void performTrans() throws InterruptedException, BrokenBarrierException {
          LOGGER.info("Wait to start");
          pBarrier.await(); // 1
          final Pojo entity = cache.get(KEY);
          LOGGER.info("Start entity: {}", entity);
          pBarrier.await(); // 2
          LOGGER.info("Wait writer to make changes");
          pBarrier.await(); // 3
          LOGGER.info("After change: {}", entity);
          pBarrier.await(); // 4
          Pojo newEntity = cache.get(KEY);
          LOGGER.info("After save: {}", newEntity);
          pBarrier.await(); // 5
          newEntity = cache.get(KEY);
          LOGGER.info("After transaction end: {}", newEntity);
      }
      

       

      And the cache is created with the code below.

              cacheManager = new DefaultCacheManager();
              cacheManager.getDefaultConfiguration().fluent().storeAsBinary();
              final Configuration config = new Configuration().fluent().transactionManagerLookup(this.tmLookup).locking()
                      .isolationLevel(IsolationLevel.READ_COMMITTED).build();
              this.cacheManager.defineConfiguration("Gruik", config);
              this.cache = this.cacheManager.getCache("Gruik");
      

       

      It did  expect to have a different object in the reader thread and the writer thread and to have the changes made into the writer not visible until the end of the writer's transaction. However I get the following output:


      [Reader] - Wait to start
      [Writer] - Wait to start
      [Writer] - Start entity: [19682788] id: 1, value: 666
      [Reader] - Start entity: [19682788] id: 1, value: 666
      [Reader] - Wait writer to make changes
      [Writer] - Entity changed wait for reader
      [Reader] - After change: [19682788] id: 1, value: 708
      [Writer] - Entity saved wait for reader
      [Reader] - After save: [19682788] id: 1, value: 708
      [Reader] - After transaction end: [19682788] id: 1, value: 708
      

       

      We clearly see that both threads share the same objects hence we don't have any isolation between distinct transaction.

       

      I find the behavior quite strange and I'm wondering if I didn't miss something in my Infinispan configuration.

        • 1. Re: Transaction isolation within a single process
          sudheerk84

          Are you sure that the transactions annotation is enabled by registering teh spring annotation processor ?

           

          You can very this is teh logs.

          • 2. Re: Transaction isolation within a single process
            gabuzo

            I'm pretty sure of this. Below is an extract of the logs in DEBUG level:

             

            2011-08-23 18:31:40,216 [Reader] DEBUG o.s.b.f.s.DefaultListableBeanFactory  - Returning cached instance of singleton bean 'transactionManager'
            2011-08-23 18:31:40,216 [Writer] DEBUG o.s.b.f.s.DefaultListableBeanFactory  - Returning cached instance of singleton bean 'transactionManager'
            2011-08-23 18:31:40,216 [Reader] DEBUG atomikos  - getCompositeTransaction() returning NULL!
            2011-08-23 18:31:40,216 [Reader] DEBUG atomikos  - getCompositeTransaction() returning NULL!
            2011-08-23 18:31:40,216 [Reader] DEBUG o.s.t.jta.JtaTransactionManager  - Creating new transaction with name [transaction.Reader.performTrans]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,readOnly; ''
            2011-08-23 18:31:40,216 [Reader] DEBUG atomikos  - getCompositeTransaction() returning NULL!
            2011-08-23 18:31:40,216 [Reader] INFO  atomikos  - createCompositeTransaction ( 300000 ): created new ROOT transaction with id 184.51.43.63.tm0000600066
            2011-08-23 18:31:40,216 [Writer] DEBUG atomikos  - getCompositeTransaction() returning NULL!
            2011-08-23 18:31:40,216 [Writer] DEBUG atomikos  - getCompositeTransaction() returning NULL!
            2011-08-23 18:31:40,216 [Writer] DEBUG o.s.t.jta.JtaTransactionManager  - Creating new transaction with name [transaction.Writer.performTrans]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT; ''
            2011-08-23 18:31:40,216 [Writer] DEBUG atomikos  - getCompositeTransaction() returning NULL!
            2011-08-23 18:31:40,216 [Writer] INFO  atomikos  - createCompositeTransaction ( 300000 ): created new ROOT transaction with id 184.51.43.63.tm0000700066
            2011-08-23 18:31:40,216 [Writer] INFO  transaction.Writer  - Wait to start
            2011-08-23 18:31:40,216 [Reader] INFO  transaction.Reader  - Wait to start
            

             

            You can clearly see that two transactions are created: one for the reader in read only mode and one for the writer.

            1 of 1 people found this helpful
            • 3. Re: Transaction isolation within a single process
              manik

              I suspect I know what is going on and it has to do with referential integrity.  Before I go into more details, if instead of a POJO, you were to use, say, a String, do you have the same problem?

              1 of 1 people found this helpful
              • 4. Re: Transaction isolation within a single process
                gabuzo

                I spend quite some time on debugging, and I eventually find out that the issue is caused by the Pojo being mutable. So it will work with a String as well as any immutable object. I opened an issue https://issues.jboss.org/browse/ISPN-1345 for this.