Guus der Kinderen created DIRMINA-1110:
------------------------------------------

             Summary: Ordered Executors concurrency
                 Key: DIRMINA-1110
                 URL: https://issues.apache.org/jira/browse/DIRMINA-1110
             Project: MINA
          Issue Type: Improvement
    Affects Versions: 2.1.2
            Reporter: Guus der Kinderen
         Attachments: mina-ordered-executors.patch

MINA contains two ThreadPoolExecutor implementations that maintains the order 
of IoEvents per session:
* OrderedThreadPoolExecutor
* PriorityThreadPoolExecutor

This issue applies to both.

A private class called {{SessionTasksQueue}} (confusingly using different names 
in both implementations, which is an undesired side-effect having code 
duplication) is used to represent the ordered collection of events to be 
processed for each individual session. It also contains a boolean that 
represents the state of the queue prior to addition of the task: 'true' if the 
collection was empty ("processing complete"), otherwise 'false'. This queue is 
stored as an attribute on the session.

An {{IoEvent}} is _scheduled_ for execution by being passed to the {{execute}} 
method. "Scheduling" an {{IoEvent}} involves identifying the session that it 
belongs to, and placing it in its SessionTaskQueue. Finally, the session itself 
is, conditionally (more in this later), placed in a queue named 
{{waitingSessions}}.

The {{IoEvent}} execution itself is implemented by {{Runnable}} implementations 
called {{Worker}}. These workers take their workload from the 
{{waitingSessions}} queue, doing blocking polls.

The placing of the Session on the {{waitingSessions}} queue depends on the 
state of the {{SessionTasksQueue}}. If it was empty ("processingComplete"), the 
session is placed on the {{waitingSessions}} queue. There is comment that 
describes this as follows:

{quote}As the tasksQueue was empty, the task has been executed immediately, so 
we can move the session to the queue of sessions waiting for completion.{quote}

As an aside: I believe this comment to be misleading: there's no guarantee that 
the task has actually been executed immediately, as workers might still be 
working on other threads. On top of that, as both the production on, and 
consumption of that queue is guarded by the same mutex, I think it's quite 
impossible that the task has already been executed. A more proper comment would 
be:

{quote}Processing of the tasks queue of this session is currently not scheduled 
or underway. As new tasks have now been added, the session needs to be offered 
for processing.{quote}

The determination if the session needs to be offered up for processing is based 
on an evaluation of the state of the {{sessionTasksQueue}} that happens under a 
mutex. The actual offer of the session for processing (adding the session to 
the {{waitingSessions}} queue, is not. We believe, but have not been able to 
conclusively prove, that this can lead to concurrency issues, where a session 
might not be queued, even though it has tasks to be executed. Nonetheless, we 
suggest moving the addition of the session to  {{waitingSessions}} into the 
guarded code block. At the very least, this reduces code complexity.

The patch attached to this issue applies this change. It also changes the name 
of the Session tasks queue in {{PriorityThreadPoolExecutor}}, to match the name 
used in {{OrderedThreadPoolExecutor}}





--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to