[jboss-user] [JBoss Cache: Core Edition] - Re: on child insert parent, child collection updated in DB b
dukehoops
do-not-reply at jboss.com
Thu Mar 5 14:18:27 EST 2009
Ok, I was able to create a multithreaded JUnit test to fail (with just 4 threads).
A race condition seems to arise when multiple threads are trying to modify state of the same cache node(s). Here's the per-user test scenario:
public void run() {
| try {
| for (int i = 0; i < ITERATION_COUNT; i++) {
| login(userName);
| think();
|
| //get users
| getFriends2(userName);
| //readUserSession(userName);
| think();
|
| logout(userName);
| think();
|
| ++completedIterations;
| }
|
| } catch (Throwable t) {
| this.causeOfFailure = t;
| }
| }
If I omit getFriends2() -> test passes. Else, test fails.
If users participating in the test are NOT friends of each other (do not try to read each other's data) then test passes. Else, test fails.
getFriends() includes friends' login status. In other words User A will call User.getSessions() on user B if the 2 are friends.
Let's say user.userSessions#B is not in cache. Then A asks for B's info:
| A gets B's data:
| a1: userB.getSessions(); //will read from DB and put into cache
|
Simultaneously, B logs in:
B.login():
| b1: self.getSessions(); //will read from DB and put into cache
| b2: self.addSession(new UserSession()); //will invalidate user.userSessions#B
Seems like what's happening is that after both TXs are done, it is state from step 'a1' that ends up in cache.
Something like this order:
-a1 starts (cache miss, A is going to DB)
-b1
-b2
-a1 finished (A comes back from DB, inserts empty collection *after* B invalidated node in step b2)
Still not clear what the root cause is here. Some possibilities:
- my code
- hibernate core
- hibernate-jbc integration code
- jbc core
I guess the problem lies either with versioning (either Hibernate versioning or MVCC versioning) or (insufficient?) locking.
Side question on Synchronization ordering:
I looked at BTM source; seems like their Synchronization register is ordered:
| private List keys = new ArrayList();
| private Map objects = new TreeMap();
|
|
| public Scheduler() {
| }
|
| public void add(Object obj, int position) {
| Integer key = new Integer(position);
| List synchronizationsList = (List) objects.get(key);
| if (synchronizationsList == null) {
| if (!keys.contains(key)) {
| keys.add(key);
| Collections.sort(keys);
| }
| synchronizationsList = new ArrayList();
| objects.put(key, synchronizationsList);
| }
| synchronizationsList.add(obj);
| }
You said previously that assumptions around synchronization ordering were fixed for JBossTS and JBC specifically. Was the fix to order synchronizations in TX manager impl?
The reason I ask is that Spring seems to use a Synchronization to close Hibernate Sessions. Is there an expectation that *that* syncrhonization fire *before* JBC's synchronization?
thanks
-nikita
View the original post : http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4215452#4215452
Reply to the post : http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=4215452
More information about the jboss-user
mailing list