CME while calculating Group Cache stats

Description

When calculating the size of the cache entries for a Group, a ConcurrentModificationException can occur (when the group is changed by another thread, while the statistics are being calculated:

GroupEventDispatcher.java:157 -  java.util.ConcurrentModificationException         at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)         at java.util.HashMap$KeyIterator.next(HashMap.java:1461)         at org.jivesoftware.openfire.group.Group.getCachedSize(Group.java:328)         at org.jivesoftware.util.cache.CacheSizes.sizeOfAnything(CacheSizes.java:176)         at org.jivesoftware.util.cache.DefaultCache.put(DefaultCache.java:141)         at org.jivesoftware.util.cache.CacheWrapper.put(CacheWrapper.java:150)         at org.jivesoftware.openfire.group.GroupManager$1.memberAdded(GroupManager.java:173)         at org.jivesoftware.openfire.event.GroupEventDispatcher.dispatchEvent(GroupEventDispatcher.java:133)         at org.jivesoftware.openfire.group.Group$MemberCollection.add(Group.java:466)         at org.jivesoftware.openfire.group.Group$MemberCollection.add(Group.java:359)         at com.inteno.iopsys.plugin.devicemanager.HelpdeskAccountPusher.addUserToGroup(HelpdeskAccountPusher.java:142)         at com.inteno.iopsys.plugin.devicemanager.HelpdeskAccountPusher.pushAccount(HelpdeskAccountPusher.java:81)         at com.inteno.iopsys.plugin.devicemanager.HelpdeskAccountPusher$IdentifiedDeviceAccountPusher.anonymousInfoAvailable(HelpdeskAccountPusher.java:191)         at com.inteno.iopsys.common.listener.DeviceIdentifiedEventListenerWrapper.event(DeviceIdentifiedEventListenerWrapper.java:22)         at com.inteno.iopsys.common.listener.DeviceIdentifiedEventListenerWrapper.event(DeviceIdentifiedEventListenerWrapper.java:5)         at com.inteno.iopsys.common.listener.dispatcher.AbstractEventDispatcher$EventThread.run(AbstractEventDispatcher.java:253)         at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)         at java.util.concurrent.FutureTask.run(FutureTask.java:266)         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)         at java.lang.Thread.run(Thread.java:748)

Environment

None

Activity

Show:

Guus der Kinderen November 3, 2017 at 9:38 AM

Making bits of code synchronized probably won't do, as the collections are iterated over in the inline classes that extend from an abstract that's not thread safe.

Copying the sets before iterating over them still would involve iterating over the collection, that might be modified at at time (although chances are slimmer, as we're not otherwise operating on the data).

Should we use a weakly consistent  instead of a fail-fast, implementation? That'd introduce performance changes.

Fixed

Details

Assignee

Reporter

Fix versions

Priority

Created November 3, 2017 at 9:09 AM
Updated November 13, 2017 at 1:42 PM
Resolved November 13, 2017 at 1:42 PM

Flag notifications