-
1. Re: concurrency & transactions question
manik Aug 9, 2010 7:36 AM (in response to ksobolev)Are you using this for a JPA application? If so, you probably want to use Hibernate since Hibernate's 2nd-level-cache integration with Infinispan handles this.
-
2. Re: concurrency & transactions question
ksobolev Aug 9, 2010 11:40 AM (in response to manik)No, I'm using my own persistence layer.
Could you give me any details on how Hibernate+Infinispan handles this? Versioning?
It actually looks very similar to write-skews described in JBossCache docs:
http://docs.jboss.org/jbosscache/3.2.1.GA/userguide_en/html/transactions.html
Section 11.1.1.2.2. Concurrent Writers and Write-Skews
-
3. Re: concurrency & transactions question
johan_andries Aug 10, 2010 4:44 AM (in response to ksobolev)You could probably start a transaction in T2 (which you commit after the put of V1), and do
cache.getAdvancedCache().lock(K);
before you do the c.get(K) operation. That way the put of V2 in T1 (or at least the commit if you do not configure eager locking) will block until the transaction of T2 has finished. See SyncReplLockingTest for an example.
Important remark voor 4.1 RC2: this explicit locking does not seem to work in distributed mode, only local and replicated mode. I should probably modify SyncReplLockingTest to run in distributed mode and submit it as a defect.
Johan.
-
4. Re: concurrency & transactions question
manik Aug 10, 2010 6:11 AM (in response to ksobolev)You can have a look at the source code of the Infinispan 2nd level cache adapter in the Hibernate src tree. It makes use of putForExternalRead(), but also makes use of its own versioning.
To simplify this further there is a JIRA on the roadmap to make internal entry versioning explicit and externally accessible.
-
5. Re: concurrency & transactions question
manik Aug 10, 2010 6:15 AM (in response to johan_andries)Important remark voor 4.1 RC2: this explicit locking does not seem to work in distributed mode, only local and replicated mode. I should probably modify SyncReplLockingTest to run in distributed mode and submit it as a defect.
Yes, please do clone and update the test, and if it still is a defect please report it using JIRA.
-
6. Re: concurrency & transactions question
johan_andries Aug 10, 2010 10:20 AM (in response to manik) -
7. Re: concurrency & transactions question
ksobolev Aug 10, 2010 7:37 PM (in response to manik)I've reviewed it, and as I understand it most of the logic is in the http://fisheye.jboss.org/browse/Hibernate/core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java?r=HEAD
My scenario would be translated to:
- T1: tx.begin()
- T2: cache.get(K) --> miss; causes PutFromLoadValidator.registerPendingPut(K)
- T2: V1 = DB.read(); old state
- T1: DB.write(V2)
- T1: cache.invalidate(K) => PutFromLoadValidator.invalidateKey(K); invalidates T2's pending put
- T1: tx.commit()
- T2: attempt to putFromLoad, but PutFromLoadValidator.acquirePutFromLoadLock returns false
result: cache.get(K) == null
Could you confirm I got it right?
-
8. Re: concurrency & transactions question
manik Aug 11, 2010 6:49 AM (in response to ksobolev)Yep.
-
9. Re: concurrency & transactions question
ksobolev Aug 11, 2010 11:27 AM (in response to manik)Thanks. How about this race then, is it possible?
- T1: tx.begin()
- T1: DB.write(V2)
- T1: cache.invalidate(K)
- T2: cache.get(K) - miss
- T2: V1 = DB.read(); old state (isolation!)
- T2: cache.putFromLoad(K, V1)
- T1: tx.commit()
IMHO invalidate() must block not only previous pending puts, but all future puts as well, untill current tx commits.
In the other words it must ensure that cache.get(K) is null right after tx has ended.
-
10. Re: concurrency & transactions question
manik Aug 11, 2010 12:11 PM (in response to ksobolev)Yes, it will hold on to the write lock until the tx completes.