Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

#14 ConcurrentModificationException in leave()

1.0.5
open
Sven Kaffille
5
2009-12-09
2009-12-09
Amir
No

Hello,
I am testing OpenChord (the test class is attached).
When a peer tries to leave a network containing itself and the bootstrap peer, a ConcurrentModificationException exception is thrown.
This happens because this code in shutDownAll() :
Set<String> keys = proxies.keySet();
for (String key : keys) {
proxies.get(key).disconnect();
}
removes entries from the set while it's iterating on it.
The removal is done inside disconnect:
synchronized (proxies) {
String proxyKey = SocketProxy.createProxyKey(this.urlOfLocalNode, this.nodeURL);
Object o = proxies.remove(proxyKey); // <<<---
}

Leading to:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at de.uniba.wiai.lspi.chord.com.socket.SocketProxy.shutDownAll(SocketProxy.java:177)
at de.uniba.wiai.lspi.chord.com.socket.SocketEndpoint.closeConnections(SocketEndpoint.java:169)
at de.uniba.wiai.lspi.chord.com.Endpoint.disconnect(Endpoint.java:301)
at de.uniba.wiai.lspi.chord.service.impl.NodeImpl.disconnect(NodeImpl.java:151)
at de.uniba.wiai.lspi.chord.service.impl.ChordImpl.leave(ChordImpl.java:681)
at sandbox.test.TestOpenChord.main(TestOpenChord.java:74)

Discussion

  • Amir
    Amir
    2009-12-09

    OpenChord simple test

     
    Attachments
  • Andrei LED
    Andrei LED
    2011-09-18

    I myself stumbled upon this bug and ... it took literally no time to fix it.

    SocketProxy.shutDownAll method implementation should be replaced with following:
    synchronized (proxies)
    {
    Set<String> keys = new HashSet<String> (proxies.keySet());//Copy retirned set to iterate over new collection that isn't modified during the iteration
    for (String key : keys) {
    proxies.get(key).disconnect();
    }
    proxies.clear();
    }

    Explanation is quite trivial: while iterating over a collection you can modify it only using the same iterator and nothing else - but the proxies map is modified in method SocketProxy.disconnect.

    For those who don't know:
    1) for (String key : keys) is exactly the same as
    for (Iterator<String> keysIt = keys.iterator (); keysIt.hasNext ();)
    2) proxies.keySet() returns just a view for the map and nothing more and anychange made in the map is immediatelly reflected in the returned set.