[MUD-Dev] C&C and Event Rescheduling

clawrenc at cup.hp.com clawrenc at cup.hp.com
Tue Aug 26 17:50:21 New Zealand Standard Time 1997

In <33FAFB3C.167EB0E7 at iname.com>, on 08/20/97 
   at 12:35 PM, Shawn Halpenny <malachai at iname.com> said:

>clawrenc at cup.hp.com wrote:

>> >One could use a sort of "super" event that is responsible for the
>> >execution of a series of sub-events, and successful commit of the
>> >super would occur when all the subs themselves committed. 
>> >Unfortunately, the potential for involving a large(r) number of
>> >objects in that super event could cause a lot of failed commits
>> >until this super event drove the thing to single-threading.
>> This is essentially the concept of supporting nested transactions. 
>> its almost inevitable.  I do this implicitly by making every method
>> call effectively a nested transaction.  The result is that each
>> method call inherits the working set of its caller, and commits its
>> working set back to its caller on return.  If it turns out that
>> there is no parent (ie it is the method that started the event),
>> then the working set tries to commit to the DB.

>Yep, that's what I've got in mind right now, although I've one big
>working set that starts empty when the event begins processing, and
>through however many method calls on whichever objects grows larger
>until everyone returns and the entire set commits.  Semantic
>difference--I'm making no distinction of working sets between method
>calls, though the end result is the same.

Truth to tell, that's what I do as an optimisation of the strategy I
detail in the quote.  The effect is the same.  The only runtime
difference is that the working set is an implicit pointer (ala this)
that I pass along with the method calls.

>> Unless you're talking about event synchronisation.  That's a whole
>> different kettle of fish, and one I'm not very happy with at the
>> moment.  I've long wanted to support something equivalent to the
>> ADA synchronise() API, where multiple threads (or in my case
>> events) could all ensure that they don't proceed until all the
>> other members have gotten to that point.

>Nope.  Although, I've turned to thinking that since I currently stamp
>each event with the time (microsecond granularity) at which it is
>posted (no change upon rescheduling), I can only execute an event if
>there are no older events waiting.  I think this will void the entire
>notion of priority, though, since it then becomes impossible for two
>events to be posted at the same time (provided that posting an event
>does not take under a microsecond, something I probably won't have to
>worry about).  Unfortunately, this introduces a useless,
>semi-disguised blocking:  Jane opening a door on one side of the
>world doesn't get executed until Bubba opening one on the other side
>is done first, even though there's no intersection between the
>working sets.  

It does worse that that.  It makes your event model strictly
sequential.  You have reconstructed a single-threaded server. 
Pessimally the entire game will have to lag pending the compleation of
Bubba's single "dig panama canal" event.  Admittedly you don't have
any problems with contending working sets any more -- there is only
ever one executing event and thus one working set which has nothing to
contend with.

>A fix to that lies in what I'd touched on earlier about events
>originating from the same object are executed oldest to newest.  What
>attracts me to this is that I can have method post any number of
>events while it's executing and have the results come out exactly as
>I expect, regardless of scheduling.  Currently, it seems I should
>only allow a method to post a single event during its execution, and
>then chain them together, each spawning the next until everything is

This is sort-of what I do, but not quite.  I have two categories of
events:  events which depend on other event's compleating previously,
and events which have no scheduling requirements.  Currently events
which depend upon the prior compleation of other events are limited to
only depending on events logged by that same event.

Thus event X can execute and log events A, B, C and D, and in doing so
can define that A must not be run until B and D have both C&C'ed, that
B is not dependant on anything, and that D is dependant on C's prior

Note: There is a potential for circular dependancies here.  I check
for it and raise an exception if true.

I explicitly don't allow events to log events that depend upon the
prior C&C of other unrelated events.  This is due to the design
approach that any given event is supposed to be ignorant of the
external event model, and the fact that the requisite events may or
may not have been logged yet (especially if they derive from other
objects).  As such for external synchronising I use event-external

My old intended approach, which is yet incompleat:

  Event X depends on the prior compleation of events Y and Z.

  Events Y and Z may or may have been logged or run yet.

  When X runs it checks for the existance of a named object (Q).  (I
allow objects to be named via an ObjectID<->Alias system).  

  If the object exists, at least one of Y and Z have C&C'ed.  

  Querying the state of Q determines which or if both of Y and Z have

  If Q doesn't exist, or both haven't C&C'ed.  X kills itself and
loggs a new instance of X for a short time into the future.  

My new intended approach:

  Events are objects which exist in the MUD DB much like any other
objects.  As such they can have watchs installed on them.  They are
currently specially excepted from being spoofed however as I've yet to
satisfy myself that that isn't a security whole the size of Jupiter.

  Events can be scheduled as watchers on other events.

  The watch trigger can be "destruction of this event via successful
C&C" or "destruction of this event via C&C failure".

  Executing events can query and poll the DB of previously executed,
pending, and executing events.  

Note: This is starting to sound supsiciously like and OS.  In fact, it
damn near *IS* an OS.  Perhaps this is why Neil wrote the original
version of Shades as a hack on RMS's and its command interpreter -- ie
the MUD command line was the default shell to the OS, and the OS was
the MUD.

>If you use a sequence counter to ensure user commands are executed in
>the order given, is that same functionality available to all other
>events which must execute in proper sequence?  

I currently special case it to be available to all events originating
from player connections.  I don't have it available to other,
internal, events.  If I do move to the above object-event model as
above (which would be a side effect of my moving to a persistant store
model as vs more classical RDBMS model) then this whole charade will
change, and the entire concept of sequence numbers will likely

>If not, how do you
>determine who requires that functionality?  And if it's not
>applicable in all cases, what of the user programmers who don't
>understand why their events aren't always happening in the order
>they've coded them?

The internal call to log a new event has a parameter which is either
NUL or contains a list of other event ID's already logged by the
event.  Its a non-optional parameter.  Conversely, for a player
entering a command which is to be processed in parallel to other
previous or later commands they must specially flag their command as
to be executed in parallel.

J C Lawrence                           Internet: claw at null.net
(Contractor)                           Internet: coder at ibm.net
---------------(*)               Internet: clawrenc at cup.hp.com
...Honorary Member Clan McFUD -- Teamer's Avenging Monolith...

More information about the MUD-Dev mailing list