docs/source/transactions.rst @ 19fc4b6444f5

Buffer input and output.
author Steve Losh <steve@stevelosh.com>
date Wed, 31 Aug 2011 18:50:12 -0400
parents 2e42d7f29dde
children (none)
Transactions
============

There are two main types of data you'll want to observe with your bots: chunks and
entities.  A ``World`` object contains two maps: one of entities and one of chunks.

Each of these maps is a ref, and each of the entries in each map is also a ref.  This
may seem excessive -- why not simply make each map a ref *or* each entry a ref?

Top-Level Refs
--------------

The maps themselves clearly need to be refs so that multiple bots sharing the same
world can update them safely.

Entry Refs
----------

To understand the reason for making each entity a ref consider a bot with the
following goal:

"Find all the hostile mobs.  Pick the one with the lowest health and attack it."

Now imagine that during the process of picking a mob to kill the bot received an
update about one of the peaceful entities.

If the entries of the map were not themselves refs the bot would *have* to
synchronize on the entire map.  This peaceful entity update would cause a retry of
the transaction even though the bot doesn't care about peaceful entities at all!

Making each entity its own ref means we can do the following:

* Inside of a dosync:
    * Find all the hostile mobs.
    * ``ensure`` on all of them.
    * Perform our calculations.

This lets us ignore updates to peaceful mobs, but retry when a hostile mob is updated
(perhaps someone else has killed one).  Keeping the "find mobs" step inside the
dosync ensures that if a mob despawns we will be looking at an accurate list the next
time we retry.

Note that if a new hostile mob is spawned it will not cause a retry.  If you are
performing an action that needs perfectly accurate data you can always synchronize
on the maps themselves, but be aware that this will probably not be very performant.

Entity Despawns
---------------

This also reveals the reason for the ``:despawned`` entry in an ``Entity`` object: if
we simply removed the entity from the map when it despawned any transactions
depending on that entity wouldn't be restarted.  Setting the ``:despawned`` value on
an entity modifies it and triggers appropriate retries.