History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: CACHE-127
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Andres March
Reporter: Kris Jenkins
Votes: 1
Watchers: 4
Operations

If you were logged in you would be able to see more operations.
OSCache

ConcurrentModificationException on flushGroup

Created: 07/Jan/05 09:06 AM   Updated: 19/Apr/05 02:36 PM
Component/s: Base Classes
Affects Version/s: 2.1
Fix Version/s: 2.1.1

File Attachments: 1. Java Source File GroupConcurrencyProblemTestCase.java (1 kb)

Environment:
Redhat 9
Tomcat 5.0.28
Java(TM) 2 Runtime Environment, Standard Edition (build Blackdown-1.4.1-01)


 Description  « Hide
Using oscache 2.1rc1, I think I've stumbled upon a thread-safety issue with AbstractConcurrentReadCache's flushGroup method. Here's the exception:

2004-12-23 16:46:47,413 ERROR [GeneralExceptionHandler] An exception occurred:
java.util.ConcurrentModificationException
   at java.util.HashMap$HashIterator.nextEntry(HashMap.java:762)
   at java.util.HashMap$KeyIterator.next(HashMap.java:798)
   at java.util.AbstractCollection.addAll(AbstractCollection.java:315)
   at java.util.HashSet.<init>(HashSet.java:94)
   at com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache.getGroup(AbstractConcurrentReadCache.java:380)
   at com.opensymphony.oscache.base.Cache.flushGroup(Cache.java:444)
   at com.opensymphony.oscache.base.Cache.flushGroup(Cache.java:431)
   at com.opensymphony.oscache.general.GeneralCacheAdministrator.flushGroup(GeneralCacheAdministrator.java:217)
   at com.bullionvault.site....

Looking at the source, this happens getGroup creates tries to copy a Set of groupEntries:

374
   375 if (groupEntries == null) {
   376 // Not in the map, try the persistence layer
   377 groupEntries = persistRetrieveGroup(groupName);
   378 } else {
   379 // We don't want to give them back the internal Set object
   380 groupEntries = new HashSet(groupEntries);
   381 }
   382
   383 return groupEntries;
   384 }

It seems that HashSet is iterating over groupEntries while they are being modified elsewhere. At least, that what the HashSet docs suggest:

" The iterators returned by this class's iterator method are
   /fail-fast/: if the set is modified at any time after the iterator
   is created, in any way except through the iterator's own remove
   method, the Iterator throws a ConcurrentModificationException."

I'm afraid don't know the code at all, so I can't offer a sensible patch.

 All   Comments   Change History      Sort Order:
Andres March - [14/Jan/05 07:23 PM ]
Could you please try and reproduce this with a Sun 1.4.2 JVM and let me know if it still ocurrs? Also, is there any more info you could give about when this error appears?

Kris Jenkins - [17/Jan/05 01:11 PM ]
I've just tried it with Sun's build: 1.4.2_06-b03 with the same problem. I've just written a test case which reproduces the problem, which I'll attach. Hopefully it will make it easier to diagnose.

Kris Jenkins - [17/Jan/05 01:13 PM ]
Test case which reproduces the exception. If you've got very fast hardware you may need to increase the values in the for loops to recreate the error.

Andres March - [12/Mar/05 01:21 AM ]
Sorry I haven't gotten to this yet. Thanks for the test case. I will look at it now.

Andres March - [17/Mar/05 01:22 AM ]
Synchronized copying of the group entry set since the new HashSet(Collection c) constructor uses the iterator. This may slow things down but it is better than a ConcurrentModificationException. We might have to revisit the code if performance is too adversely impacted.