[MUD-Dev] Event Handling
Jon A. Lambert
jlsysinc at ix.netcom.com
Mon Jan 12 22:37:04 CET 1998
On 6 Jan 98 at 17:03, JC Lawrence wrote:
> On Mon, 5 Jan 1998 09:10:52 PST8PDT
> Vadim Tkachenko<vadimt at 4cs.com> wrote:
> > Jon A. Lambert wrote:
>
> >> Variations on event-driven design
>
> > Can you please elaborate on that?
>
> There are a couple base models going about the list. Jon and I have
> some of the more intricate designs. I'll let Jon describe his.
>
Alrighty! A request to delve back into the low-level nitty gritty details.
I posted some definitions in another message and I won't elaborate on them
here except to state that event-driven systems may be single-threaded or
multi-threaded. They may even be soft-threaded (cf. Cynbe ru Taren's MUQ).
This is rather obvious since ColdX, MudOS and some others implement
mechanisms for event processing. They are hybrids of the procedural and
event models.
JC's model and my own are hybrids of all three models, but at the language
or mudlib programming model they will likely exhibit the traits of a
concurrent processing model. Invariably we touch on threads and data
concurrency/consistency that one might serialize and largely ignore in a
single-threaded event-driven system. So...here is how I stand right now...
> To describe my system loosely, and briefly:
>
> The server is heavily multi-threaded (I think the idle-state is over
> 50 threads currently).
>
My model currently has a fixed pool of threads and is strongly
partitioned and layered.
Network subsystem - 1 thread to listen for connections and
1 thread per connection. Threads are created and destroyed
as needed. May be a good candidate for pooling later...
Dispatcher - 1 thread - pops events off the queue and places in proper
Executor class.
Executor - 6 threads - 3 for normal activity, 1 real-time monitor
thread, 1 low-priority and 1 lazy priority(*) thread
Object manager - consists of 4 threads , Lock subsystem, Cache
subsystem, Database subsystem and Logging subsystem.
> All events are processed aynchoinously and in parallel.
>
Nod. 'cept mine are asynchronous. :P
> The server is lockless.
I do object locking. My model is based on IBM's DB2 which will attempt to
spin-lock an object. A lock is attempted several times for a brief
duration (milli-seconds). If failure occurs, the event is rescheduled.
Logging is very very DB2ish also. The primary purpose of logging is
recovery from literally pulling the plug and insuring backups maintain
data synchronization.
> I don't guarantee order of execution of two unrelated events.
>
> The base design:
>
> Events are logged with the Dispatchor in the Event List as a tuple
> of an object:method call, various arguments, various ownership data,
> and either a state time the event is to start execution, or a
> percentage chance value that the event will start execution within any
> given minute.
>
Similarly I keep Object:method and parameter stack, the event state time
and an event class (0-3) indicator - 0 is monitor class, 1 is normal class,
2 is low-level and 3 is lazy priority. (*)Lazy priority threads bypass all
object locking read or write, they simply do not care about data integrity.
This is used for low-level SIM processes, which do tallying of current
state. My event queue object is ordered at insert.
> The Dispatchor procresss the Event List, sending ripe events to the
> Executor.
>
> The Executor receives the ripe events from the Dispatchor and stores
> them in priority order in teh Event Queue.
>
> The Excutor processes the events in priority order by handing them
> for processing to to the Event Pool, a dynamically sized pool of
> threads.
>
I'm a bit different here also. The Dispatcher places the event data in
the appropriate Executor data area and starts the Executor thread.
Executor threads will generate events which are inserted into the Event
queue by the executing thread.
> Events that fail to commit are rescheduled with the Executor at a
> different priority.
>
Nod. My priority does not change however, the state time is incremented.
> Event's have no effect upon the DB or state until and unless they
> commit.
>
Upon an executor threads successful termination pointers are swizzled in
the cache and locks are freed. Upon unsuccessful termination locks are
freed. Each event is equivalent to a application consistent transaction.
The Object cache contains two copies of objects (before/after) when write
locks are requested.
BTW, I have flipped my language model around. Instead of writing
specialized _event_ methods, I have two forms of method calls. One will
cause the method to be immediately invoked, the other schedules the
call as an event w/time and class. Seems to make lib programming much
easier. Also, I have given up all attempts to pre-bind methods at compile
time to the objects they may be interested in (a way of pre-locking at
execution start up). The dynamic nature of the object requests makes this
just silly.
Comments, criticisms, or vicious personal attacks welcome. :)
--
Jon A. Lambert
"Everything that deceives may be said to enchant" - Plato
More information about the mud-dev-archive
mailing list