Replacement of TaskManager with ExecutorService.
ServiceDiscoveryManager:
1.Complex dependency relationships.
2.Dependency is the exception, not the norm, existing runAfter(List
task, int position) implementations, changed to dependsOn(CacheTask t),
iteration being performed by the caller rather than the task implementation.
3.Used a wrapper ExecutorService to customise FutureTask to implement
Observer call backs to notify dependant waiting tasks.
4.In addition to call backs, implemented subscriber to allow tasks to
fire off new tasks and notify their dependants to wait for these also.
5.Dependant tasks manage a small lists of tasks they’re waiting to be
notified for completion, when the last precedent task is removed, the
dependant task is submitted to the executor.
Fixed a number of race conditions that were revealed as a result of
replacing TaskManager. TaskManager masks data races by making code that
submit and polls tasks relatively single threaded. The multiple threads
in TaskManager were useful to hand off network calls.
Reggie:
1.Many dependencies, with a simple relationship, to quote Patricia:
EventTask - run after EventTask for same listener, "Keep events
going to the same listener ordered";
2.Not suited to the call back implementation in SDM.
3.Better suited to a simple priority queue, for tasks that were
dependant to be executed in order, but only dependant tasks, those tasks
with the same listener.
4.Dependant tasks must be single threaded.
5.Rather than have many single threaded executors, I used a number of
priority queues, one for each listener, that utilise call backs to
remove a task after it completes, preventing execution of dependant tasks.
6.Although dependency relationships have been preserved, tests expect
remote event listeners to be notified in the order they register with
the ServiceRegistrar, this behaves as expected with TaskManager, but
ExecutorService is asynchronous and listeners are notified out of order.
Yes that's right, to be compliant with qa tests, not only must events
for each listener be ordered, but the listeners themselves must be
notified in the order or their registration with the lookup service.
7.In the new implementation, Events are still ordered correctly to each
listener, it’s just the first listener that registered may not be
notified first when an event occurs because of the asynchronous nature
of ExecutorService implementations, unlike TaskManager.
8.We need to consider the impact of maintaining 100% backward compatible
behaviour on performance and complexity. This can be managed by ensuring
there is a bottleneck in the ExecutorService, by limiting performance,
order of notification to listeners is preserved. A fixed length queue
with an ExecutorService that only creates new threads once the queue is
full should do the trick.
a.This may sound brittle, but it’s the same guarantee that TaskManager
provided, so the default ExecutorService can be performance limited just
like TaskManager.
b.For those who want to tune for all out performance and don’t care
which listener is notified first, they can configure their own
ExecutorService implementation.
c.The complex option of creating dependency links between listeners
harms performance, so there’s no point introducing this type of
dependency as it forces everyone’s performance to suffer on the altar of
compatibility.
What are your thoughts?
Peter.