jimb@tigris.org writes:
>   Log:
>   Doc fixes --- give a general overview of how trails and
>   svn_fs__retry_txn are supposed to be used.
Ohmigoshogoshogosh.  Thank you, Jim, that's beautiful! :-)
-K
>   +/* "How do I get a trail object?  All these functions in the
>   +   filesystem expect them, and I can't find a function that returns
>   +   one."
>   +
>   +   Well, there isn't a function that returns a trail.  All trails come
>   +   from svn_fs__retry_txn.  Here's how to use that:
>   +
>   +   When using Berkeley DB transactions to protect the integrity of a
>   +   database, there are several things you need to keep in mind:
>   +
>   +   - Any Berkeley DB operation you perform as part of a Berkeley DB
>   +     transaction may return DB_LOCK_DEADLOCK, meaning that your
>   +     operation interferes with some other transaction in progress.
>   +     When this happens, you must abort the transaction, which undoes
>   +     all the changes you've made so far, and try it again.  So every
>   +     piece of code you ever write to bang on the DB needs to be
>   +     wrapped up in a retry loop.
>   +
>   +   - If, while you're doing your database operations, you also change
>   +     some in-memory data structures, then you may want to revert those
>   +     changes if the transaction deadlocks and needs to be retried.
>   +
>   +   - If you get a `real' error (i.e., something other than
>   +     DB_LOCK_DEADLOCK), you must abort your DB transaction, to release
>   +     its locks and return the database to its previous state.
>   +     Similarly, you may want to unroll some changes you've made to
>   +     in-memory data structures.
>   +
>   +   - Since a transaction insulates you from database changes made by
>   +     other processes, it's often possible to cache information about
>   +     database contents while the transaction lasts.  However, this
>   +     cache may become stale once your transaction is over.  So you may
>   +     need to clear your cache once the transaction completes, either
>   +     successfully or unsuccessfully.
>   +
>   +   The `svn_fs__retry_txn' function and its friends help you manage
>   +   all of that, in one nice package.
>   +   
>   +   To use it, write your code in a function like this:
>   +  
>   +       static svn_error_t *
>   +       txn_body_do_my_thing (void *baton,
>   +                             trail_t *trail)
>   +       {
>   +         ... 
>   +         Do everything which needs to be protected by a Berkeley DB
>   +         transaction here.  Use TRAIL->db_txn as your Berkeley DB
>   +         transaction, and do your allocation in TRAIL->pool.  Pass
>   +         TRAIL on through to any functions which require one.
>   +
>   +         If a Berkeley DB operation returns DB_LOCK_DEADLOCK, just
>   +         return that using the normal Subversion error mechanism
>   +         (using DB_ERR, for example); don't write a retry loop.  If you
>   +         encounter some other kind of error, return it in the normal
>   +         fashion.
>   +         ...
>   +       }
>   +
>   +   Now, call svn_fs__retry_txn, passing a pointer to your function as
>   +   an argument:
>   +
>   +       err = svn_fs__retry_txn (fs, txn_body_do_my_thing, baton, pool);
>   +
>   +   This will simply invoke your function `txn_body_do_my_thing',
>   +   passing BATON through unchanged, and providing a fresh TRAIL
>   +   object, containing a Berkeley DB transaction and an APR pool --- a
>   +   subpool of POOL --- you should use.
>   +
>   +   If your function returns a Subversion error wrapping a Berkeley DB
>   +   DB_LOCK_DEADLOCK error, `svn_fs__retry_txn' will abort the trail's
>   +   Berkeley DB transaction for you (thus undoing any database changes
>   +   you've made), free the trail's subpool (thus undoing any allocation
>   +   you may have done), and try the whole thing again with a new trail,
>   +   containing a new Berkeley DB transaction and pool.
>   +
>   +   If your function returns any other kind of Subversion error,
>   +   `svn_fs__retry_txn' will abort the trail's Berkeley DB transaction,
>   +   free the subpool, and return your error to its caller.
>   +
>   +   If, heavens forbid, your function actually succeeds, returning
>   +   SVN_NO_ERROR, `svn_fs__retry_txn' commits the trail's Berkeley DB
>   +   transaction, thus making your DB changes permanent, leaves the
>   +   trail's pool alone, so all the objects it contains are still
>   +   around, and returns SVN_NO_ERROR.
>   +
>   +   If you're making changes to in-memory data structures which should
>   +   be reverted if the transaction doesn't complete successfully, you
>   +   can call `svn_fs__record_undo' as you make your changes to register
>   +   functions that will undo them.  On failure (either due to deadlock
>   +   or a real error), `svn_fs__retry_txn' will invoke your undo
>   +   functions, youngest first, to restore your data structures to the
>   +   state they were in when you started the transaction.
>   +
>   +   If you're caching things in in-memory data structures, which may go
>   +   stale once the transaction is complete, you can call
>   +   `svn_fs__record_completion' to register functions that will clear
>   +   your caches.  When the trail completes, successfully or
>   +   unsuccessfully, `svn_fs__retry_txn' will invoke your completion
>   +   functions, youngest first, to remove whatever cached information
>   +   you like.  */
Received on Sat Oct 21 14:36:23 2006