3.5: (2006-08-16):

    * Fix a bug introduced in version 3.4 that could, under certain conditions,
      allow conflicts to be missed.  In particular, if the last strong reference
      to a Persistent instance was removed, a conflict involving that instance
      would be missed.  The fix involves changing the Persistent.__getattr__
      so that it calls the 'note_access' method on the Connection.
      This method creates a strong reference to the Persistent instance by
      adding it to a 'recent_objects' set.  Objects are eventually removed from
      the recent_objects set when they are converted into ghosts in the cache's
      shrink() method.  Since a set() is used for recent_objects, all Persistent
      instances *must* now be hashable.  PersistentSet instances were not, and
      that has been changed.

    * Revise the cache code.  It now uses a WeakValueDict instead of a plain dict
      to hold the references.  This simplifies the code because we no longer need
      to call the weakref instances directly.  It also helps the cache shrinking
      loop because the weakref callbacks have an immediate impact on the size of
      the mapping.

    * Remove the ghost_fraction attribute from the Cache.  It is no longer used
      in shrink().

    * Rename the Persistent '_p_touched' attribute to '_p_serial'.  This is
      set, on every attribute access, to the value of the Connection's
      'transaction_serial' attribute (which was formerly named 'sync_count').

    * Add a bulk_load() method to Storage.  The ClientStorage implementation
      reduces avoids latency delays be retrieving many object records with
      a single request to the server.

    * Add Connection.get_crawler().  This returns a generator for the sequence
      of objects reachable from a given start OID.  The crawler uses the
      new bulk_load() method for speed.  It can be used, with some care, to
      initialize the object cache.

    * Remove Connection.cache_get() and Connection.cache_set().

    * Use set instead of Set throughout.  This means that Durus now requires
      Python version >= 2.4.

    * Add the ability to set the owner, group, and umask when a unix domain
      socket is used for a server.

    * Attempt to clean up stale socket files when starting a server on a
      unix domain socket.

    * Move some repeated code related to addresses and sockets into a
      SocketAddress class and subclasses HostPortAddress and
      UnixDomainSocketAddress.

    * In the server, add support for a protocol verification command.
      Use this in the client constructor to allow orderly behavior if
      the client and the server do not implement the same protocol.

    * Add a server command for allocating blocks of oids.

    * Add client support for maintaining and drawing from a pool of oids
      allocated by the server.  This reduces the number of commands that
      must be sent to the server during a commit.

    * Add support for recycling allocated oids when there is a conflict during
      a commit.

    * Make sure that the FileStorage constructor can work if the named file
      exists, but is empty.

    * Initialize sync_count to 1 so that new ghosts, for which _p_touched
      is initialized to 0, never appear to have been accessed since the last
      transaction.

    * Move some logic used for unpickling references to the connection cache
      so that it can be faster.  Add Cache.get_instance() for this purpose.
      Add Connection.get_cache() so that the ObjectReader can use it.


3.4.1: (2006-05-18):

    * Fix a memory leak that was in the 3.4 tarball until 2006-05-12.

    * Fix doc string errors.

    * Fix initialization of _p_touched in python version of PersistentBase
      to agree with the C implementation.

3.4: (2006-05-11): 28347

    * Refine the conflict avoidance and cache aging behavior.  Now conflicts
      don't occur unless there is an invalid object for which this Connection
      has actually accessed an attribute since the last call to commit() or
      abort().  The Connection saves a "sync_count" on every commit() or abort().
      On every access to (an ordinary) attribute of a Persistent instance,
      the _p_touched is set to be the Connection's sync_count.
      To make this possible without any significant performance penalty,
      the _p_connection and other '_p_' attributes are moved from
      Persistent to PersistentBase and implemented in C.
      Also, a ConnectionBase class is implemented in C so that the
      sync_count, which is needed so frequently, can be accessed directly
      in the C implementation of PersistentBase.

      Since we now know which instances have actually been accessed since the
      last commit() or abort(), the Connection no longer need to maintain the
      set of loaded_oids.  The cache manager can use the _p_touched to
      distinguish less recently used instances.

      The Cache class has a new ghost_fraction attribute.  The value of
      this attribute defaults to 0.5 and can be any number between 0 and 1.
      Higher values make the cache more aggressive about ghosting objects
      as it tries to reduce the cache size.

      The Cache "held" attribute is removed, along with the hold() method.

    * Added a history.py module that defines HistoryConnection, a Connection
      subclass that supports time-travel in a read-only FileStorage file.
      The class provides next() and previous() methods for stepping
      among the stored transactions.  It also provides next_instance(obj)
      and previous_instance(obj) for moving to to a transaction where
      obj has a state that is different from the current state.
      Note that packing a FileStorage consolidates the transactions, so
      the HistoryConnection can only move among the transactions since
      the last pack.

    * Make the durus client run in a __console__ module.  This makes it
      behave a little more like the regular Python interpreter.

    * Add support for running the durus client/server connections through
      unix domain sockets.  The ClientStorage and StorageServer constructors
      accept an "address" keyword argument.  If the address value can be
      a (host, port) tuple or else a string giving a path use for the
      unix domain socket.  The separate "host" and "port" keyword parameters
      are still supported, but they may be removed in future releases.  If your
      code calls these constructors, please change it to use the "address"
      keyword.

    * Change the recv() function used in the client/server to read in chunks
      of at most 1 million bytes.  This avoids a malloc error observed when
      running test/stress.py on an OS X machine with python 2.4.2.

    * Make the durus server a little tougher.  If it gets an unknown command,
      it now logs the error and closes the connection instead of crashing.

    * Add Storage.pack() and Storage.get_size().


3.3: (2006-03-15): 28065

    * Keep strong references to objects until we decide that they haven't
      been recently touched.  This limits the impact of the Python
      garbage collector.

    * Change the FileStorage class as needed to agree with the magic
      header string found in an existing file.  Do this no matter which
      of the constructors (FileStorage, FileStorage1, or FileStorage2)
      is called to create the instance.  Before this change, opening an
      an existing file with the FileStorage2 constructor (instead of
      the generic FileStorage constructor), raised an exception.

    * Adjust logging.

      Before this change, the server logs the class of each object
      when it is loaded if the logginglevel is at level 5 or below.
      This changes that threshhold to level 4.

      Now, when the logging level is 5 or below, the server prints
      a census of objects loaded since the last commit or abort.
      This can make it easier to understand patterns of cache misses.

    * Add dummy new_oid() and get_packer() methods to the Storage class
      for documentation.

3.2: (2006-02-01): r27892

    * Add 5 iteration methods to BTree.
      __reversed__() for reverse iteration of keys.
      items_backward() for reverse iteration of items.
      items_from() for iterations starting at a given key.
      items_backward_from() for reverse iterations from a given key.
      items_range() for iterations of items with keys in a given range.

    * Add __nonzero__ and setdefault methods to BTree

    * Change the name of BTree's get_count method to __len__.

    * Add setuptools support (when installed) to setup.py.

    * Remove convert_zodb.py script, rather than fix/maintain it.

3.1: (2005-10-18): r27556

    * Add PersistentSet.  (Applications that use the persistent_set
      must use Python versions >= 2.4).

    * Add MemoryStorage, an in-memory storage for testing purposes.

3.0: (2005-09-08): r27334

    * Fix bug in utility function (touch_every_reference()) added in 3.0a.

    * Replace ._p_changed = 1 to ._p_note_change() in btree.py.

3.0a: (2005-08-09): r27118

    * Revise packed record format to write records where the instance state is
      compressed using zlib.  This reduces the size of stored files and the
      number of bytes of data transmitted during load/store operations.

    * Add a FileStorage2 file format.  The new format does not need or store
      transaction identifiers.  It also includes a pre-built index of the
      object records written at the time of the last pack.  This results in
      a faster start-up.  Conversion is not automatic, though.
      A convert_file_storage.py is included with this release to make it simple
      to convert a file to either format.

    * Add stress testing client stress.py.

    * When the state of a ghost can't be loaded because it has been
      removed by a pack (from another connection), make the error be a
      ReadConflictError instead of a DurusKeyError.

    * Implement an incremental pack.  The storage server can now serve
      clients while packing the database.

    * Add gen_every_instance() utility to durus.connection.

    * Add touch_every_reference() utility function to durus.connection.

    * Remove the use of tids from Connection, ClientStorage, and
      StorageServer.  The StorageServer now sends STATUS_INVALID for
      requests to load object records that are known to be invalid for
      that client.  Change Storage.load() so that the return value is
      a tid-less object-record.  The client/server protocol also
      changes to stop transmitting tids as part of the response for
      sync and commit requests.  Storage.sync() now returns only a
      list of oids.  Storage.end() now returns None.

2.0 (2005-4-26) r26653:

    * The only change is in the license.  The new license is the GPL-compatible
      version of the CNRI Open Source License.

1.5 (2005-3-07) r26296:

    * A small change makes Persistent instances pickle-able.

1.4 (2005-1-14) r25851:

    * Revise serialize.py to avoid using cPickle.noload(), which can't handle
      a dict subclass.

    * Add a --startup option to the durus command line tool.

1.3 (2004-12-10) r25746:

    * Use 'b' in file modes.

    * Continue to rename the open packed file on POSIX systems.

    * Convert tests to sancho's new utest format.

    * Improve test coverage for FileStorage.

    * Lower the priority of Sync logging.

    * Show host and port when client fails to connect.

1.2 (2004-09-08) r25044:

    * Add durus command line tool.

    * Add btree module.

    * Update pack() so that it works on Windows and so that it gets a lock
      again after the pack is completed.

1.1 (2004-08-05) r24872:

    * Provide a close() method for FileStorage.  Call appropriate win32
      unlock function.

    * Remember to lock the new file created by pack().  Unlock the
      old file.


1.0 (2004-07-31) r24846:

    * Fix obscure bug in storage_server during logging.

    * Repaired example in README.txt.

    * Added FAQ.

    * Made ProtocolError inherit from DurusError.

    * Added fsync() after writing transaction data.


0.1 (2004-07-27) r24791:

    * Initial Release
