On Thursday, October 2, 2003, at 04:29 AM, Dirk Olmes wrote:
> When EOF saves changes to the database, all peer EditingContexts are
> notified and try to merge the changes written to database back into
> their existing
> EOs. To ensure object graph consistency this notification has to be
> delivered
> synchronously because if it was delivered from a different thread the
> point
> in time that object graph synchronization occurred was undefined.
Actually my primary motivation for asynchronous notifications was to
use it for the newly developed snapshot cache. In scenario when
DataContext #1 commits changes, it synchronizes committed snapshots
with parent snapshot cache (not via events, but simply via a method
call), and then snapshot cache sends an asynchronous change event to
all child contexts #2, #3, etc., allowing all children to update their
objects state, and without having the calling DataContext wait till all
events are processed.
Now that you've mentioned the same scenario as an example of the
opposite approach... it got me thinking... And it looks like the main
problem is not so much synchronization within single event dispatch
timeframe, but rather avoiding race conditions when multiple events
come at almost the same time. This may result in a newer event being
processed by some listeners before an older event arrives, thus leading
to unpredictable (and surely inconsistent) object state.
First thing that comes to mind is having an event queue similar to AWT
event queue (see some discussion on that below).
> So I guess we have to rework the existing notification mechanism to be
> able
> to work in both modes: synchronous and asynchronous, right?
Yeah, looks like we will need to do some changes. But with all the
analysis above, two main requirements seem to be the following:
1. Immediately unblock the calling thread that generated the event.
2. Dispatch events coming from multiple threads in some predictable
order.
Third requirement (multithreaded dispatch of a *single* event) doesn't
seem right to me now. Such dispatch can result in an uncontrollable
spawning of threads, and generally serves very little purpose. If it
happens that each listener takes an extended period of time to process
the event, thus holding this particular dispatch, I guess it will be up
to the listener to fork a new thread... At least for now we can live
without (3).
Also, I don't know if we have a case for turning (1) into a synchronous
dispatch? I hope not.
So back to dispatch flow. Assuming we have multiple "post" threads and
a single "dispatch" thread, I can see the following steps:
1. "Post" thread calls "EventManager.postEvent"
2. EventManager appends the event to the queue (which is of course
FIFO) and releases "post" thread, notifying "dispatch" thread.
3. "Dispatch" thread awakes (or finishes processing previous entry),
takes the first entry in the queue and dispatches to listeners,
4. If queue is not empty, "dispatch" thread goes to step 3, otherwise
it goes to sleep.
Should be rather simple to implement - a big while loop with a
queue.wait() in it, everything is synchronized on a list representing
the queue.
Now the question is - how do we organize such queues within
Eventmanager? I guess by EventSubject?
Andrus
P.S. My discussion of snapshot updates has one gaping hole (though not
directly related to event dispatch mechanism, just to commit
concurrency in general). If DC2 commits its changes after DC1 (and
potentially overriding some of DC1 changes), this doesn't guarantee
that snapshot event from DC2 gets dispatched after to the one from DC1,
since we are not locking the stack for commit.... I guess this was one
of the reasons EOF was always single threaded :-)... Anyway, just
wanted to post this problem for the record... The solution would
require some sort of write lock or smart merging algorithm... Then
there is remote snapshot notifications... :-)
This archive was generated by hypermail 2.0.0 : Fri Oct 03 2003 - 01:42:32 EDT