Uploaded image for project: 'Wicket'
  1. Wicket
  2. WICKET-5736

Atmosphere Eventbus throws Concurrent Modification Exception

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Blocker
    • Resolution: Fixed
    • 6.17.0
    • 6.18.0, 7.0.0-M4
    • wicket-atmosphere
    • None

    Description

      As already commented in WICKET-5619 the problem of Concurrent Modification Exceptions are still valid like you can see on the following description when the exception occurs:

      You have multiple users surfing a page (Page A) which has subscribes for an event (Event A). Now a user (User A) does an action which triggers the Event A to get posted to the Eventbus. While the eventbus posts the event to the registered listeners, a User B leaves the page and unregisters for the event, f.e because he now want's surfs another page, which does not subscribe to the event. Now the ConcurrentModificationException occurs because the unregistering of User B changed the list of listeners while the eventbus is still posting the event to the different listeners. The interesting thing is, that not the initial starter of the event crashes, but all other users which are trying to surf other pages which are listening on the event gets the exception.

      In my opinion this issue can be solved if the line:

       Collection<EventSubscription> eventSubscriptions = subscriptions.get(key);
      subscriptionsForPage = Iterables.filter(eventSubscriptions, new EventFilter(event)); 

      makes an copy of the EventSubscriptions an works on this copy instead on the original list. When the eventbus now trys to post the event on a component which does not exists anymore he could try to unregister the component from the original subscribers list.

      Also:

      Iterable<EventSubscription> subscriptionsForPage;
       		synchronized (this)
       		{
       			key = trackedPages.get(resource.uuid());
      			Collection<EventSubscription> eventSubscriptions = subscriptions.get(key);
      			subscriptionsForPage = Iterables.filter(eventSubscriptions, new EventFilter(event));
       		}
      

      creates a lazy iterator on the the eventSubscriptions, and will be iterated outside the synchronized block.
      You need to create a copy of the eventSubscriptions, because this might be changed during the unregistering process:

      public synchronized void unregister(Component component)
      	{
      		...	
      		Collection<EventSubscription> subscriptionsForPage = subscriptions.get(pageKey);
      		Iterator<EventSubscription> it = subscriptionsForPage.iterator();
      		while (it.hasNext())
      		{
      			if (it.next().getComponentPath().equals(componentPath))
      				it.remove();
      		}
      	}
      

      it.remove() changes the iterator within the lazy Iterator!

      It is possible to have a quick look at it? This problem affected our productive system!

      Attachments

        Activity

          People

            papegaaij Emond Papegaaij
            dke Daniel Kernebeck
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: