[MUD-Dev] Re: atomic functions

Shawn Halpenny malachai at iname.com
Fri May 1 13:26:32 New Zealand Standard Time 1998


On Fri, May 01, 1998 at 03:11:58PM +0200, Felix A. Croes wrote:
> Shawn Halpenny <malachai at iname.com> wrote:
> 
> > On Thu, Apr 30, 1998 at 03:59:20AM +0200, Felix A. Croes wrote:
> >[...]
> > >     An atomic function is a function that succeeds or fails as a
> > >     whole.  Any runtime error that is not caught within the function
> > >     will lead to the entire function call, with all its effects
> > >     and side-effects, being undone.
> >
> > For me, a function cannot be executed without having a corresponding
> > event:  it is tied tightly to the lockless-ness of the DB commits. 
> > Events accumulate a working set.  If those objects are committed (and
> > they will be if no other event has already finished with its objects
> > and has C&C'd), then the thread that was executing that event
> > effectively "dies" (although it's kept around in a pool for subsequent
> > quick reuse) and the event is no more.
> 
> If I understand you correctly, you use "event" to denote the unit of
> execution as viewed from within the mud, and "thread" for how the
> underlying implementation manages events.  I have been using "thread"
> to mean both, assuming a 1-to-1 mapping, or rather giving the matter
> no thought at all.  To simplify matters, I will adopt your terminology.

Yep.  One event per thread is what it boils down to, so I use event and
thread pretty much interchangeably as well.

> To transplant the idea of atomic functions to your model, in which
> functions are already implicitly atomic, make the following change:
> rather than
> 
> 	atomic foo()
> 	{
> 	    /* code of foo */
> 	}
> 
> use
> 
> 	foo()
> 	{
> 	    /* code fragment 1 */
> 
> 	    atomic {
> 		/* code fragment 2, executed atomically */
> 	    }
> 
> 	    /* code fragment 3 */
> 	}

So atomic fragments are akin to critical sections?  For me, methods can
execute in their own context (essentially the call stack of an event's
processing is an entire critical section).  Since they receive current
copies of any data they touch, rather than having to wait for it to
become available, though, there's no waiting upon entry.  Given the way
I've structured things, atomic fragments don't add much benefit (but see
below).

If you are moving toward a lockless DB scheme, will you still require
atomic fragments?  If you have a 1-to-1 mapping between thread and event,
do the atomic sections only come into play when multiple events are
executing the same method?  Currently, I've got each method executing in
its own stack with local copies of all data.

Explicitly defining an atomic function would require more programmer
work.  In a free user programming environment, I don't want to require
people to decide whether the function they just wrote to make their
sword talk needs to be atomic or have atomic sections within it.  For
now, I'm opting to leave it up to the server to decide the atomicity of
things (which it does by way of the event and DB models).  An
experienced programmer can probably outdo the server if given the
capability to declare atomic blocks, but a newbie would be more
inclined to either not declare them at all (in which case, I'd have to
rely on a system like I've already got in mind) or declare them poorly
and result in performance worse than the server would obtain doing it
itself.  

> > I would consider each executing
> > event method an atomic function as you've described them--all of the
> > effects undone on failed C&C reset the world state for that event to
> > the new current state.  A runtime error in a function essentially
> > amounts to a failed C&C, since the end result is the same:  no changes
> > persist.  However, a failed function will cause the event method in
> > which it was called to not be rescheduled and thus it will not attempt
> > to C&C again.  A C&C failure without a corresponding function error is
> > perfectly acceptable and, in fact, required.  
> 
> In this model, atomic code fragments would still be useless, since
> an error in an atomic fragment would cancel the entire event.  To
> make them meaningful, you would need a way to (optionally) catch
> errors in an event.  That way, individual bits of atomic code could
> fail without the entire event failing.

What happens if there is an error in an atomic fragment, and the rest of
the event requires a result out of that fragment?

[ execution order of atomic fragments ]

> What it actually does is impose an execution order on bits of
> atomically executed code:
> 
> 	foo()
> 	{
> 	    atomic {
> 		/* code fragment 1 */
> 	    }
> 	    atomic {
> 		/* code fragment 2 */
> 	    }
> 	    atomic {
> 		/* code fragment 3 */
> 	    }
> 	}

I see now.  This does not occur between events, but only within the
function itself.

> Now, focusing on atomic code and abstracting from the rest, you can
> map the sequence of code fragments to a sequence of atomic events.

You have much finer granularity than I have.

> Having events execute in parallel and compete for completion is done
> to get the mud to run efficiently on multi-processor architectures.
> But the atomic code property is also desirable from a software design
> point of view, which is why I am trying to separate atomicity and
> events.  It gets especially interesting when you nest atomic code,
> allowing you to make code atomic on several abstraction levels.

One different thing about the system I'm describing is that
events using an intersecting working set don't know that they will fail and
be rescheduled until they all try and C&C.  This is where atomic fragments
could be beneficial since the working set modifications could take place
inside them, waiting on other events as required.  My approach:  if an
event succeeds C&C, other events with intersecting working sets are
notified and immediately rescheduled, rather than waiting until they are
try (and assuredly fail) C&C.  (This has been on the list before, too).

This way, I'm not redoing operations I've already performed and thrown out
to the extent I would if the entire event went through its processing
before finding out it couldn't commit changes.

--
Shawn Halpenny

I know that you believe you understand what you think I said, but,
I am not sure you realize that what you heard is not what I meant.  

--
MUD-Dev: Advancing an unrealised future.



More information about the MUD-Dev mailing list