(fwd) Re: LP: How does it work?

coder at ibm.net coder at ibm.net
Tue Jul 22 21:45:06 CEST 1997


The following applies to the recent lockless DB model discussion:

From: clawrenc at cup.hp.com (Chris Lawrence (Contra))
Newsgroups: rec.games.mud.lp
Subject: Re: LP: How does it work?
Date: 22 Jul 1997 21:31:21 GMT

Apologies for the long quote -- I felt context was needed.

Felix A. Croes (dworkin at nospam.imaginary.com) wrote:
: Chris Lawrence (Contra) <clawrenc at cup.hp.com> wrote:

: > I basically JIT it.
: >
: > I took the approach of doing a quick currency check on the inheritance tree 
: > of an object when a method is called on that object.  If the compiled 
: > inheritance tree is not current, then I recompile the object and move on.
: > Essentially its a JIT, but I short circuit the leaf conditions by having the 
: > list of inheritance changes detect when the number of direct children falls
: > below a set value (or age) and then force recompiles for the remaining 
: > children, (which may spawn new entries for the children of the recompiled 
: > children).  This is done to keep the change efficient for currency checks.
: >
: > The result is that changing root slows down the whole game until the
: > current working set gets recompiled.  The game then operates a slightly 
: > slower rate from there on out for a while as new additions to the working
: > set get recompiled.  Eventually it just all pans out and you're down to 
: > the standard steady rate of recompiles from general user activity.

: Suppose A and B are both at the root of separate inheritance trees.  A calls
: functions in B, or rather, objects inheriting from A call functions in
: objects inheriting from B through the interfaces inherited from A and B.
: Only A calls these functions.

: I want to change the interface of B.  To ensure that calls from A do not go
: awry, I recompile A and B at the same time (or in the same thread without
: any intervening code).  Now assume that this recompile is done from a thread
: which passes through B, a few stack frames back.

:  - If B changes instantly, then the stack frame for the function in B might
:    no longer be valid.
:  - If B changes instantly but the stack frames that use it remain tied to the
:    old version, then a newly changed A might attempt to call a function in 
:    the old B.
:  - If this is solved by postponing the actual replacement of code for A and B
:    until the end of the thread (DGD does this), then JIT compiling
:    reintroduces the problem: not all compilations happen during the same
:    thread, so it is possible for a new A to call a function in an old B.

: How do you deal with the above situation?

Its actually fairly transparent for me as my base server is
multi-threaded.   Taking the relationship between objects A and B etc
as described above:

  I don't share code segments between code segments for MUDlib objects
between threads/events.  This prevents the stack frame problems you
identify (outside of the fact that I don't really run a stack based
system).  Instead,  as each event requests a method from an object a
read only copy of that  object is provided for the event.  This
provides most of the solution for  your last problem (the old code
being called) as a side effect of my lockless  DB system:

  -- When the event which is calling the old version of B terminates
and 
  attempts to commit, it fails due to one of its object dependancies
(B in 
  this case) having changed in the interim.  So, the event fails to
commit 
  and is rescheduled to try again, now with the new versions of the
requisite
  objects.

  -- (This only applies to the case where A references the exact
object which 
  was changed).  When the change to B occurs and is committed, change 
  notification messages are sent to all events which currently
reference B 
  (members of its interested party list).  This acts as an early
warning 
  system to the event that it will likely fail to commit.

This still leaves a corner case open:

  The objects are A, B and C.  

  A and C are children of B.  

  A references methods on C.
  
  An event X is executing which calls A, which in turn calls C.

  B is changed (method code altered).

  The modify B event commits successfully.

The potential problem is that there is an implicit race condition for
which  versions of A and C get loaded.  If A's copy gets referenced
pre-change,  and C's post-change, event X could have two implicitly
different versions  of B loaded.  This gets detected by the JIT code
when C attempts to call  an method inherited from B.  It attempts to
rebuild the inheritance tree  for C, finds that it already has a
state-dated version of B incontext (per  the tags on C), and thus
invalidates the entire event, which dies and  reschedules. 

--
J C Lawrence                               Internet: claw at null.net
----------(*)                              Internet: coder at ibm.net
...Honourary Member of Clan McFud -- Teamer's Avenging Monolith...




More information about the mud-dev-archive mailing list