]
Manik Surtani updated JBCACHE-740:
----------------------------------
Attachment: MultithreadedTxTest.java
Optimistic Locking Scheme: Occasional IllegalStateExceptions on
commit
----------------------------------------------------------------------
Key: JBCACHE-740
URL:
http://jira.jboss.com/jira/browse/JBCACHE-740
Project: JBoss Cache
Issue Type: Bug
Security Level: Public(Everyone can see)
Affects Versions: 1.4.0.GA
Environment: Linux 2.6.15-26-686 #1 SMP PREEMPT Thu Aug 3 03:13:28 UTC 2006 i686
GNU/Linux
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)
JOTM 2.0.10
JUnit 3.8.1
Reporter: Carsten Krebs
Assigned To: Manik Surtani
Fix For: 2.0.0.BETA1
Attachments: MultithreadedTxTest.java
The unit test below reproduces "occasional" IllegalStateExceptions (s.b.) on
commiting a transaction. This test tries to modify the same node at the same time by
different threads in different transactions using the optimistic locking scheme.
java.lang.IllegalStateException: there is already a writer holding the lock:
GlobalTransaction:<null>:43
at org.jboss.cache.lock.LockMap.setWriterIfNotNull(LockMap.java:96)
at org.jboss.cache.lock.IdentityLock.acquireWriteLock(IdentityLock.java:204)
at org.jboss.cache.Node.acquireWriteLock(Node.java:431)
at org.jboss.cache.Node.acquire(Node.java:386)
at
org.jboss.cache.interceptors.OptimisticLockingInterceptor.lockNodes(OptimisticLockingInterceptor.java:149)
at
org.jboss.cache.interceptors.OptimisticLockingInterceptor.invoke(OptimisticLockingInterceptor.java:76)
at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:68)
at org.jboss.cache.interceptors.TxInterceptor.runPreparePhase(TxInterceptor.java:804)
at
org.jboss.cache.interceptors.TxInterceptor$LocalSynchronizationHandler.beforeCompletion(TxInterceptor.java:1069)
at
org.jboss.cache.interceptors.OrderedSynchronizationHandler.beforeCompletion(OrderedSynchronizationHandler.java:75)
at org.objectweb.jotm.SubCoordinator.doBeforeCompletion(SubCoordinator.java:1487)
at org.objectweb.jotm.SubCoordinator.commit_one_phase(SubCoordinator.java:416)
at org.objectweb.jotm.TransactionImpl.commit(TransactionImpl.java:239)
at OptimisticLockingTest$Worker.run(OptimisticLockingTest.java:135)
The Cache Config:
-------------------------
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.cache.TreeCache"
name="jboss.cache:service=TreeCache">
<attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
<attribute name="CacheMode">LOCAL</attribute>
</mbean>
</server>
The Unit Test:
-------------------
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import junit.framework.TestCase;
import org.jboss.cache.CacheException;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.TransactionManagerLookup;
import org.jboss.cache.TreeCache;
import org.objectweb.jotm.Current;
import EDU.oswego.cs.dl.util.concurrent.CyclicBarrier;
/**
* OptimisticLockingTest
*/
public class OptimisticLockingTest extends TestCase {
private static final String NODE_PATH = "/path/node";
private static final String KEY = "key";
private static final Current jotm = new Current();
private TreeCache cache;
protected void setUp() throws Exception {
super.setUp();
cache = new TreeCache();
final PropertyConfigurator config = new PropertyConfigurator();
cache.setTransactionManagerLookup(new TransactionManagerLookup() {
public TransactionManager getTransactionManager() throws Exception {
return Current.getTransactionManager();
}
});
config.configure(cache, this.getClass().getResourceAsStream(
"/cache-config.xml"));
cache.startService();
}
public void testSimultanWrite() throws Exception {
for (int i = 2; i < 20; i++) {
System.out.println(">> testing simultaneous writes with " + i
+ " threads...");
testSimultanWrite(i);
}
}
public void testSimultanWrite(final int _numThreads) throws Exception {
final CyclicBarrier barrier = new CyclicBarrier(_numThreads);
Worker[] workers = new Worker[_numThreads];
for (int i = 0; i < workers.length; i++) {
workers[i] = new Worker();
workers[i].barrier = barrier;
workers[i].value = "worker" + i;
if (i == 0) {
workers[i].isMaster = true;
}
workers[i].start();
}
for (int i = 0; i < workers.length; i++) {
workers[i].join();
}
assertNull(workers[0].exception);
for (int i = 0; i < workers.length; i++) {
assertNull("rollback failed", workers[i].rollbackException);
}
for (int i = 1; i < workers.length; i++) {
assertNotNull("missing exception", workers[i].exception);
assertTrue("exception is not of type CacheException",
workers[i].exception.getCause() instanceof CacheException);
}
assertEquals("worker0", cache.get(NODE_PATH, KEY));
cache.getTransactionManager().begin();
cache.remove(NODE_PATH);
cache.getTransactionManager().commit();
}
private class Worker extends Thread {
private CyclicBarrier barrier;
private Exception exception;
private Exception rollbackException;
private String value;
private boolean isMaster;
/**
* @see java.lang.Thread#run()
*/
public void run() {
final TransactionManager txManager = cache.getTransactionManager();
Transaction tx = null;
try {
// wait for all threads started
barrier.barrier();
if (isMaster) {
txManager.begin();
cache.put(NODE_PATH, KEY, value);
// lets the other threads start writing
barrier.barrier();
// wait for other threads to their modification
barrier.barrier();
// commit first
tx = txManager.getTransaction();
tx.commit();
// lets the other threads commit
barrier.barrier();
} else {
// wait for master to start transaction
barrier.barrier();
txManager.begin();
cache.put(NODE_PATH, KEY, value);
// signal modification
barrier.barrier();
// wait for master to commit transaction
barrier.barrier();
tx = txManager.getTransaction();
tx.commit();
}
} catch (Exception e) {
exception = e;
try {
tx.rollback();
} catch (Exception e1) {
rollbackException = e1;
}
}
}
}
}
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: