How Transience Works

  The object responsible for managing the expiration of "transient"
  objects is the TransientObjectContainer, the class definition for
  which is located in
  Products.Transience.Transience.TransientObjectContainer.  An
  instance of this class is found in the default Zope installation at
  /temp_folder/session_data.

  The TransientObjectContainer (TOC) holds Transient Objects (TOs).

  A TO is obtained via its container via a call to
  TOC.new_or_existing(key), where "key" is usually the "browser id"
  associated with a visitor (See Products.Session.BrowserIdManager).

  If the TOC has a "current" TO corresponding to "key", it is
  returned.

  If the TOC does not have a "current" TO corresponding to "key", (due
  to the expiration of the TO or because it never existed in the first
  place) a "new" TO is manufactured and returned.

Timeslices

  Transience defines the notion of a "timeslice".  A "timeslice" is an
  integer that represents some "slice" of time, defined by a "period".
  For example, if a period is 20 seconds long, three ordered time
  slices might be expressed as 0, 20, and 40.  The next timeslice
  would be 60, and so on.  For an absolute time to "belong" to a
  timeslice, it would need to be equal to or greater than one
  timeslice integer, but less than the subsequent timeslice integer.

Data Structures Maintained by a Transient Object Container

  The TOC maintains three important kinds of data structures:

  - a "_data" structure, which is an IOBTree mapping a "timeslice"
    integer to a "bucket" (see next bullet for definition of bucket).

  - One or more "buckets", which are OOBTree objects which map a "key"
    (usually browser id) to a TransientObject.  Buckets are stored
    inside of the "_data" structure.  There is a concept of a
    "current" bucket, which is the bucket that is contained within the
    _data structured with a key equal to the "current" timeslice.
    A current bucket must always exist (this is an invariant).

  - A "max_timeslice" integer, which is equal to the "largest"
    timeslice for which there exists a bucket in the _data structure.
    This is an optimization given that key operations against BTrees
    can be slow and could cause conflicts (the same could be achieved
    via _data.maxKey() otherwise).

  When a Transient Object is created via new_or_existing, it is added
  to the "current" bucket.  As time goes by, the bucket to which the
  TO was added ceases to be the "current" bucket.  If the transient
  object is "accessed" (it is called up out of the TOC via the TOC's
  'get' method), it is again moved to the "current" bucket defined by
  the current time's timeslice.

  During the course of normal operations, a TransientObject will move
  from an "old" bucket to the "current" bucket many times, as long as
  it continues to be accessed.  It is possible for a TransientObject
  to never expire, as long as it is called up out of its TOC often
  enough.

  If a TransientObject is not accessed in the period of time defined by
  the TOC's "timeout", it is eventually garbage collected.

How the TransientObjectContainer Determines if a TransientObject is "Current"

  All "current" timeslice buckets (as specified by the timeout) are
  searched for the transient object, most recent bucket first.

Housekeeping: Finalization, Garbage Collection, and Bucket
Replentishing

  The TOC performs "finalization", "garbage collection", and "bucket
  replentishing".  It typically performs these tasks "in-band"
  (although it is possible to do the housekeeping tasks "out of band"
  as well: see the methods of the Transient Object Container with
  "housekeep" in their names).  "In band" housekeeping implies that
  the TOC does not maintain a separate thread or process that wakes up
  every so often to clean up.  Instead, during the course of normal
  operations, the TOC opportunistically performs housekeeping functions.

  Finalization is defined as optionally calling a function at bucket
  expiration time against all transient objects contained within that
  bucket.  The optional function call is user-defined, but it is
  managed by the "notifyDel" method of the TOC.

  Garbage collection is defined as deleting "expired" buckets in the
  _data structure (the _data structure maps a timeslice to a bucket).
  Typically this is done by throwing away one or more buckets in the
  _data structure after they expire.

  Bucket replentishing is defined as the action of (opportunistically)
  creating more buckets to insert into the the _data structure,
  replacing ones that are deleted during garbage collection.  The act
  of deleting a bucket does not necessarily imply that a new bucket
  will be immediately created thereafter.  We create new buckets in
  batches to reduce the possibility of conflicts.

  Finalization is attempted on every call to the transience machinery
  to make TOs appear to expire "on time".  Garbage collection and
  replentishment is performed on a somewhat random basis to avoid
  unnecessary conflicts.

Goals

 - A low number of ZODB conflict errors (which reduce performance).

 - Stability.

To Do

  - Testing under ZEO.

