ConcurrentModificationException in TransactionTable
tokobayashi Mar 16, 2005 10:56 PMHi,
I put jboss-cache.jar of JBossCache1.2.1 into JBoss4.0.0. And I tested a web-application in the JBoss with heavy load.
environment:
Redhat Enterprise 3.0
JDK 1.4.2
JBoss 4.0.0?with jboss-cache.jar of JBossCache1.2.1?
2 node cluster
load-balanced by Apache2+mod_jk2
http session replication enabled
replication-trigger SET
replication-granularity SESSION
I got the following Exception.
2005-03-17 11:30:25,703 ERROR [org.jgroups.blocks.RpcDispatcher] failed invoking method java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:782) at java.util.HashMap$EntryIterator.next(HashMap.java:824) at org.jboss.cache.TransactionTable.getLocalTransaction(TransactionTable.java:71) at org.jboss.cache.interceptors.ReplicationInterceptor.replicate(ReplicationInterceptor.java:187) at org.jboss.cache.TreeCache._replicate(TreeCache.java:2682) at sun.reflect.GeneratedMethodAccessor74.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at org.jgroups.blocks.MethodCall.invoke(MethodCall.java:236) at org.jgroups.blocks.RpcDispatcher.handle(RpcDispatcher.java:220) at org.jgroups.blocks.RequestCorrelator.handleRequest(RequestCorrelator.java:615) at org.jgroups.blocks.RequestCorrelator.receiveMessage(RequestCorrelator.java:512) at org.jgroups.blocks.RequestCorrelator.receive(RequestCorrelator.java:326) at org.jgroups.blocks.MessageDispatcher$ProtocolAdapter.handleUp(MessageDispatcher.java:722) at org.jgroups.blocks.MessageDispatcher$ProtocolAdapter.access$300(MessageDispatcher.java:554) at org.jgroups.blocks.MessageDispatcher$1.run(MessageDispatcher.java:691) at java.lang.Thread.run(Thread.java:534)
I checked org.jboss.cache.TransactionTable.
tx_map is synchronized in getLocalTransaction(GlobalTransaction gtx), but tx_map may be modified in put(Transaction tx, GlobalTransaction gtx) or remove(Transaction tx).
I guess some synchronized blocks are needed like:
public void put(Transaction tx, GlobalTransaction gtx) { if(tx == null) { log.error("key (Transaction) is null"); return; } synchronized(tx_map) { tx_map.put(tx, gtx); } }
public GlobalTransaction remove(Transaction tx) { if(tx == null) return null; GlobalTransaction gtx = null; synchronized(tx_map) { gtx = (GlobalTransaction)tx_map.remove(tx); } return gtx; }
Is this irrelevant ?