Apply some changes
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep.pod
index c519335..ea44fc7 100644 (file)
@@ -45,15 +45,113 @@ Windows.
 
 =head1 VERSION DIFFERENCES
 
-B<NOTE>: 0.99_03 has significant file format differences from prior versions.
-THere will be a backwards-compatibility layer in 1.00, but that is slated for
-a later 0.99_x release. This version is B<NOT> backwards compatible with any
-other release of DBM::Deep.
+B<NOTE>: 1.0020 introduces different engines which are backed by different types
+of storage. There is the original storage (called 'File') and a database storage
+(called 'DBI'). q.v. L</PLUGINS> for more information.
 
-B<NOTE>: 0.99_01 and above have significant file format differences from 0.983 and
-before. There will be a backwards-compatibility layer in 1.00, but that is
-slated for a later 0.99_x release. This version is B<NOT> backwards compatible
-with 0.983 and before.
+B<NOTE>: 1.0000 has significant file format differences from prior versions.
+THere is a backwards-compatibility layer at C<utils/upgrade_db.pl>. Files
+created by 1.0000 or higher are B<NOT> compatible with scripts using prior
+versions.
+
+=head1 PLUGINS
+
+DBM::Deep is a wrapper around different storage engines. These are:
+
+=head2 File
+
+This is the traditional storage engine, storing the data to a custom file
+format. The parameters accepted are:
+
+=over 4
+
+=item * file
+
+Filename of the DB file to link the handle to. You can pass a full absolute
+filesystem path, partial path, or a plain filename if the file is in the
+current working directory. This is a required parameter (though q.v. fh).
+
+=item * fh
+
+If you want, you can pass in the fh instead of the file. This is most useful for
+doing something like:
+
+  my $db = DBM::Deep->new( { fh => \*DATA } );
+
+You are responsible for making sure that the fh has been opened appropriately
+for your needs. If you open it read-only and attempt to write, an exception will
+be thrown. If you open it write-only or append-only, an exception will be thrown
+immediately as DBM::Deep needs to read from the fh.
+
+=item * file_offset
+
+This is the offset within the file that the DBM::Deep db starts. Most of the
+time, you will not need to set this. However, it's there if you want it.
+
+If you pass in fh and do not set this, it will be set appropriately.
+
+=item * locking
+
+Specifies whether locking is to be enabled. DBM::Deep uses Perl's flock()
+function to lock the database in exclusive mode for writes, and shared mode
+for reads. Pass any true value to enable. This affects the base DB handle
+I<and any child hashes or arrays> that use the same DB file. This is an
+optional parameter, and defaults to 1 (enabled). See L</LOCKING> below for
+more.
+
+=back
+
+=head2 DBI
+
+This is a storage engine that stores the data in a relational database. Funnily
+enough, this engine doesn't work with transactions (yet) as InnoDB doesn't do
+what DBM::Deep needs it to do.
+
+The parameters accepted are:
+
+=over 4
+
+=item * dbh
+
+This is a DBH that's already been opened with L<DBI/connect>.
+
+=item * dbi
+
+This is a hashref containing:
+
+=over 4
+
+=item * dsn
+
+=item * username
+
+=item * password
+
+=item * connect_args
+
+=back
+
+Theses correspond to the 4 parameters L<DBI/connect> takes.
+
+=back
+
+B<NOTE>: This has only been tested with MySQL (with disappointing results). I
+plan on extending this to work with SQLite and PostgreSQL in the next release.
+Oracle, Sybase, and other engines will come later.
+
+=head2 Planned engines
+
+There are plans to extend this functionality to (at least) the following:
+
+=over 4
+
+=item * BDB (and other hash engines like memcached)
+
+=item * NoSQL engines (such as Tokyo Cabinet)
+
+=item * DBIx::Class (and other ORMs)
+
+=back
 
 =head1 SETUP
 
@@ -70,7 +168,7 @@ method, which gets you a blessed I<and> tied hash (or array) reference.
 This opens a new database handle, mapped to the file "foo.db". If this
 file does not exist, it will automatically be created. DB files are
 opened in "r+" (read/write) mode, and the type of object returned is a
-hash, unless otherwise specified (see L<OPTIONS> below).
+hash, unless otherwise specified (see L</OPTIONS> below).
 
 You can pass a number of options to the constructor to specify things like
 locking, autoflush, etc. This is done by passing an inline hash (or hashref):
@@ -84,7 +182,7 @@ locking, autoflush, etc. This is done by passing an inline hash (or hashref):
 Notice that the filename is now specified I<inside> the hash with
 the "file" parameter, as opposed to being the sole argument to the
 constructor. This is required if any options are specified.
-See L<OPTIONS> below for the complete list.
+See L</OPTIONS> below for the complete list.
 
 You can also start with an array instead of a hash. For this, you must
 specify the C<type> parameter:
@@ -104,7 +202,7 @@ the wrong type is passed in.
 Alternately, you can create a DBM::Deep handle by using Perl's built-in
 tie() function. The object returned from tie() can be used to call methods,
 such as lock() and unlock(). (That object can be retrieved from the tied
-variable at any time using tied() - please see L<perltie/> for more info.
+variable at any time using tied() - please see L<perltie> for more info.
 
   my %hash;
   my $db = tie %hash, "DBM::Deep", "foo.db";
@@ -113,7 +211,7 @@ variable at any time using tied() - please see L<perltie/> for more info.
   my $db = tie @array, "DBM::Deep", "bar.db";
 
 As with the OO constructor, you can replace the DB filename parameter with
-a hash containing one or more options (see L<OPTIONS> just below for the
+a hash containing one or more options (see L</OPTIONS> just below for the
 complete list).
 
   tie %hash, "DBM::Deep", {
@@ -129,31 +227,6 @@ DBM::Deep objects. These apply to both the OO- and tie- based approaches.
 
 =over
 
-=item * file
-
-Filename of the DB file to link the handle to. You can pass a full absolute
-filesystem path, partial path, or a plain filename if the file is in the
-current working directory. This is a required parameter (though q.v. fh).
-
-=item * fh
-
-If you want, you can pass in the fh instead of the file. This is most useful for doing
-something like:
-
-  my $db = DBM::Deep->new( { fh => \*DATA } );
-
-You are responsible for making sure that the fh has been opened appropriately for your
-needs. If you open it read-only and attempt to write, an exception will be thrown. If you
-open it write-only or append-only, an exception will be thrown immediately as DBM::Deep
-needs to read from the fh.
-
-=item * file_offset
-
-This is the offset within the file that the DBM::Deep db starts. Most of the time, you will
-not need to set this. However, it's there if you want it.
-
-If you pass in fh and do not set this, it will be set appropriately.
-
 =item * type
 
 This parameter specifies what type of object to create, a hash or array. Use
@@ -161,23 +234,14 @@ one of these two constants:
 
 =over 4
 
-=item * C<DBM::Deep-E<gt>TYPE_HASH>
+=item * C<<DBM::Deep->TYPE_HASH>>
 
-=item * C<DBM::Deep-E<gt>TYPE_ARRAY>.
+=item * C<<DBM::Deep->TYPE_ARRAY>>
 
 =back
 
 This only takes effect when beginning a new file. This is an optional
-parameter, and defaults to C<DBM::Deep-E<gt>TYPE_HASH>.
-
-=item * locking
-
-Specifies whether locking is to be enabled. DBM::Deep uses Perl's flock()
-function to lock the database in exclusive mode for writes, and shared mode
-for reads. Pass any true value to enable. This affects the base DB handle
-I<and any child hashes or arrays> that use the same DB file. This is an
-optional parameter, and defaults to 1 (enabled). See L<LOCKING> below for
-more.
+parameter, and defaults to C<<DBM::Deep->TYPE_HASH>>.
 
 =item * autoflush
 
@@ -264,7 +328,7 @@ With DBM::Deep you can access your databases using Perl's standard hash/array
 syntax. Because all DBM::Deep objects are I<tied> to hashes or arrays, you can
 treat them as such. DBM::Deep will intercept all reads/writes and direct them
 to the right place -- the DB file. This has nothing to do with the
-L<TIE CONSTRUCTION> section above. This simply tells you how to use DBM::Deep
+L</TIE CONSTRUCTION> section above. This simply tells you how to use DBM::Deep
 using regular hashes and arrays, rather than calling functions like C<get()>
 and C<put()> (although those work too). It is entirely up to you how to want
 to access your databases.
@@ -307,14 +371,14 @@ hash reference, not a lookup. Meaning, you should B<never> do this:
 This causes an infinite loop, because for each iteration, Perl is calling
 FETCH() on the $db handle, resulting in a "new" hash for foo every time, so
 it effectively keeps returning the first key over and over again. Instead,
-assign a temporary variable to C<$db->{foo}>, then pass that to each().
+assign a temporary variable to C<<$db->{foo}>>, then pass that to each().
 
 =head2 Arrays
 
 As with hashes, you can treat any DBM::Deep object like a normal Perl array
 reference. This includes inserting, removing and manipulating elements,
 and the C<push()>, C<pop()>, C<shift()>, C<unshift()> and C<splice()> functions.
-The object must have first been created using type C<DBM::Deep-E<gt>TYPE_ARRAY>,
+The object must have first been created using type C<<DBM::Deep->TYPE_ARRAY>>,
 or simply be a nested array reference inside a hash. Example:
 
   my $db = DBM::Deep->new(
@@ -326,9 +390,9 @@ or simply be a nested array reference inside a hash. Example:
   push @$db, "bar", "baz";
   unshift @$db, "bah";
 
-  my $last_elem = pop @$db; # baz
-  my $first_elem = shift @$db; # bah
-  my $second_elem = $db->[1]; # bar
+  my $last_elem   = pop @$db;   # baz
+  my $first_elem  = shift @$db; # bah
+  my $second_elem = $db->[1];   # bar
 
   my $num_elements = scalar @$db;
 
@@ -390,23 +454,44 @@ value.
 
   $db->clear(); # hashes or arrays
 
-=item * lock() / unlock()
+=item * lock() / unlock() / lock_exclusive() / lock_shared()
 
-q.v. Locking.
+q.v. L</LOCKING> for more info.
 
 =item * optimize()
 
-Recover lost disk space. This is important to do, especially if you use
-transactions.
+This will compress the datafile so that it takes up as little space as possible.
+There is a freespace manager so that when space is freed up, it is used before
+extending the size of the datafile. But, that freespace just sits in the
+datafile unless C<optimize()> is called.
+
+=item * import()
+
+Unlike simple assignment, C<import()> does not tie the right-hand side. Instead,
+a copy of your data is put into the DB. C<import()> takes either an arrayref (if
+your DB is an array) or a hashref (if your DB is a hash). C<import()> will die
+if anything else is passed in.
 
-=item * import() / export()
+=item * export()
 
-Data going in and out.
+This returns a complete copy of the data structure at the point you do the export.
+This copy is in RAM, not on disk like the DB is.
 
 =item * begin_work() / commit() / rollback()
 
 These are the transactional functions. L</TRANSACTIONS> for more information.
 
+=item * supports( $option )
+
+This returns a boolean depending on if this instance of DBM::Dep supports
+that feature. C<$option> can be one of:
+
+=over 4
+
+=item * transactions
+
+=back
+
 =back
 
 =head2 Hashes
@@ -484,7 +569,7 @@ Returns undef if array is empty. Returns the element value.
 
 Fetches the first element in the array, deletes it, then shifts all the
 remaining elements over to take up the space. Returns the element value. This
-method is not recommended with large arrays -- see L<LARGE ARRAYS> below for
+method is not recommended with large arrays -- see L</LARGE ARRAYS> below for
 details.
 
   my $elem = $db->shift();
@@ -502,7 +587,7 @@ No return value. This method is not recommended with large arrays -- see
 
 Performs exactly like Perl's built-in function of the same name. See L<perldoc
 -f splice> for usage -- it is too complicated to document here. This method is
-not recommended with large arrays -- see L<LARGE ARRAYS> below for details.
+not recommended with large arrays -- see L</LARGE ARRAYS> below for details.
 
 =back
 
@@ -533,8 +618,8 @@ Here are some examples of using arrays:
 =head1 LOCKING
 
 Enable or disable automatic file locking by passing a boolean value to the
-C<locking> parameter when constructing your DBM::Deep object (see L<SETUP>
-        above).
+C<locking> parameter when constructing your DBM::Deep object (see L</SETUP>
+above).
 
   my $db = DBM::Deep->new(
       file => "foo.db",
@@ -544,18 +629,18 @@ C<locking> parameter when constructing your DBM::Deep object (see L<SETUP>
 This causes DBM::Deep to C<flock()> the underlying filehandle with exclusive
 mode for writes, and shared mode for reads. This is required if you have
 multiple processes accessing the same database file, to avoid file corruption.
-Please note that C<flock()> does NOT work for files over NFS. See L<DB OVER
+Please note that C<flock()> does NOT work for files over NFS. See L</DB OVER
 NFS> below for more.
 
 =head2 Explicit Locking
 
 You can explicitly lock a database, so it remains locked for multiple
-actions. This is done by calling the C<lock()> method, and passing an
-optional lock mode argument (defaults to exclusive mode). This is particularly
-useful for things like counters, where the current value needs to be fetched,
-then incremented, then stored again.
+actions. This is done by calling the C<lock_exclusive()> method (for when you
+want to write) or the C<lock_shared()> method (for when you want to read).
+This is particularly useful for things like counters, where the current value
+needs to be fetched, then incremented, then stored again.
 
-  $db->lock();
+  $db->lock_exclusive();
   my $counter = $db->get("counter");
   $counter++;
   $db->put("counter", $counter);
@@ -563,19 +648,15 @@ then incremented, then stored again.
 
   # or...
 
-  $db->lock();
+  $db->lock_exclusive();
   $db->{counter}++;
   $db->unlock();
 
-You can pass C<lock()> an optional argument, which specifies which mode to use
-(exclusive or shared). Use one of these two constants:
-C<DBM::Deep-E<gt>LOCK_EX> or C<DBM::Deep-E<gt>LOCK_SH>. These are passed
-directly to C<flock()>, and are the same as the constants defined in Perl's
-L<Fcntl/> module.
+=head2 Win32/Cygwin
 
-  $db->lock( $db->LOCK_SH );
-  # something here
-  $db->unlock();
+Due to Win32 actually enforcing the read-only status of a shared lock, all
+locks on Win32 and cygwin are exclusive. This is because of how autovivification
+currently works. Hopefully, this will go away in a future release.
 
 =head1 IMPORTING/EXPORTING
 
@@ -652,7 +733,12 @@ way to extend the engine, and implement things like real-time compression or
 encryption. Filtering applies to the base DB level, and all child hashes /
 arrays. Filter hooks can be specified when your DBM::Deep object is first
 constructed, or by calling the C<set_filter()> method at any time. There are
-four available filter hooks, described below:
+four available filter hooks.
+
+=head2 set_filter()
+
+This method takes two paramters - the filter type and the filter subreference.
+The four types are:
 
 =over
 
@@ -700,84 +786,9 @@ remove a filter, set the function reference to C<undef>:
 
   $db->set_filter( "filter_store_value", undef );
 
-=head2 Real-time Encryption Example
-
-Here is a working example that uses the I<Crypt::Blowfish> module to
-do real-time encryption / decryption of keys & values with DBM::Deep Filters.
-Please visit L<http://search.cpan.org/search?module=Crypt::Blowfish> for more
-on I<Crypt::Blowfish>. You'll also need the I<Crypt::CBC> module.
-
-  use DBM::Deep;
-  use Crypt::Blowfish;
-  use Crypt::CBC;
-
-  my $cipher = Crypt::CBC->new({
-      'key'             => 'my secret key',
-      'cipher'          => 'Blowfish',
-      'iv'              => '$KJh#(}q',
-      'regenerate_key'  => 0,
-      'padding'         => 'space',
-      'prepend_iv'      => 0
-  });
-
-  my $db = DBM::Deep->new(
-      file => "foo-encrypt.db",
-      filter_store_key => \&my_encrypt,
-      filter_store_value => \&my_encrypt,
-      filter_fetch_key => \&my_decrypt,
-      filter_fetch_value => \&my_decrypt,
-  );
-
-  $db->{key1} = "value1";
-  $db->{key2} = "value2";
-  print "key1: " . $db->{key1} . "\n";
-  print "key2: " . $db->{key2} . "\n";
-
-  undef $db;
-  exit;
-
-  sub my_encrypt {
-      return $cipher->encrypt( $_[0] );
-  }
-  sub my_decrypt {
-      return $cipher->decrypt( $_[0] );
-  }
+=head2 Examples
 
-=head2 Real-time Compression Example
-
-Here is a working example that uses the I<Compress::Zlib> module to do real-time
-compression / decompression of keys & values with DBM::Deep Filters.
-Please visit L<http://search.cpan.org/search?module=Compress::Zlib> for
-more on I<Compress::Zlib>.
-
-  use DBM::Deep;
-  use Compress::Zlib;
-
-  my $db = DBM::Deep->new(
-      file => "foo-compress.db",
-      filter_store_key => \&my_compress,
-      filter_store_value => \&my_compress,
-      filter_fetch_key => \&my_decompress,
-      filter_fetch_value => \&my_decompress,
-  );
-
-  $db->{key1} = "value1";
-  $db->{key2} = "value2";
-  print "key1: " . $db->{key1} . "\n";
-  print "key2: " . $db->{key2} . "\n";
-
-  undef $db;
-  exit;
-
-  sub my_compress {
-      return Compress::Zlib::memGzip( $_[0] ) ;
-  }
-  sub my_decompress {
-      return Compress::Zlib::memGunzip( $_[0] ) ;
-  }
-
-B<Note:> Filtering of keys only applies to hashes. Array "keys" are
-actually numerical index numbers, and are not filtered.
+Please read L<DBM::Deep::Manual> for examples of filters.
 
 =head1 ERROR HANDLING
 
@@ -797,7 +808,7 @@ DBM::Deep by default uses 32-bit file offset tags, but these can be changed
 by specifying the 'pack_size' parameter when constructing the file.
 
   DBM::Deep->new(
-      filename  => $filename,
+      file      => $filename,
       pack_size => 'large',
   );
 
@@ -805,7 +816,7 @@ This tells DBM::Deep to pack all file offsets with 8-byte (64-bit) quad words
 instead of 32-bit longs. After setting these values your DB files have a
 theoretical maximum size of 16 XB (exabytes).
 
-You can also use C<pack_size =E<gt> 'small'> in order to use 16-bit file
+You can also use C<<pack_size => 'small'>> in order to use 16-bit file
 offsets.
 
 B<Note:> Changing these values will B<NOT> work for existing database files.
@@ -814,8 +825,8 @@ the file's header and cannot be changed for the life of the file. These
 parameters are per-file, meaning you can access 32-bit and 64-bit files, as
 you choose.
 
-B<Note:> We have not personally tested files larger than 4 GB -- all my
-systems have only a 32-bit Perl. However, I have received user reports that
+B<Note:> We have not personally tested files larger than 4 GB -- all our
+systems have only a 32-bit Perl. However, we have received user reports that
 this does indeed work.
 
 =head1 LOW-LEVEL ACCESS
@@ -838,58 +849,9 @@ such as enabling/disabling locking. You can also store your own temporary user
 data in this structure (be wary of name collision), which is then accessible from
 any child hash or array.
 
-=head1 CUSTOM DIGEST ALGORITHM
-
-DBM::Deep by default uses the I<Message Digest 5> (MD5) algorithm for hashing
-keys. However you can override this, and use another algorithm (such as SHA-256)
-or even write your own. But please note that DBM::Deep currently expects zero
-collisions, so your algorithm has to be I<perfect>, so to speak. Collision
-detection may be introduced in a later version.
-
-You can specify a custom digest algorithm by passing it into the parameter
-list for new(), passing a reference to a subroutine as the 'digest' parameter,
-and the length of the algorithm's hashes (in bytes) as the 'hash_size'
-parameter. Here is a working example that uses a 256-bit hash from the
-I<Digest::SHA256> module. Please see
-L<http://search.cpan.org/search?module=Digest::SHA256> for more information.
-
-  use DBM::Deep;
-  use Digest::SHA256;
-
-  my $context = Digest::SHA256::new(256);
-
-  my $db = DBM::Deep->new(
-      filename => "foo-sha.db",
-      digest => \&my_digest,
-      hash_size => 32,
-  );
-
-  $db->{key1} = "value1";
-  $db->{key2} = "value2";
-  print "key1: " . $db->{key1} . "\n";
-  print "key2: " . $db->{key2} . "\n";
-
-  undef $db;
-  exit;
-
-  sub my_digest {
-      return substr( $context->hash($_[0]), 0, 32 );
-  }
-
-B<Note:> Your returned digest strings must be B<EXACTLY> the number
-of bytes you specify in the hash_size parameter (in this case 32).
-
-B<Note:> If you do choose to use a custom digest algorithm, you must set it
-every time you access this file. Otherwise, the default (MD5) will be used.
-
 =head1 CIRCULAR REFERENCES
 
-B<NOTE>: DBM::Deep 0.99_03 has turned off circular references pending
-evaluation of some edge cases. I hope to be able to re-enable circular
-references in a future version after 1.00. This means that circular references
-are B<NO LONGER> available.
-
-DBM::Deep has B<experimental> support for circular references. Meaning you
+DBM::Deep has full support for circular references. Meaning you
 can have a nested hash key or array element that points to a parent object.
 This relationship is stored in the DB file, and is preserved between sessions.
 Here is an example:
@@ -902,14 +864,32 @@ Here is an example:
   print $db->{foo} . "\n"; # prints "bar"
   print $db->{circle}->{foo} . "\n"; # prints "bar" again
 
+This also works as expected with array and hash references. So, the following
+works as expected:
+
+  $db->{foo} = [ 1 .. 3 ];
+  $db->{bar} = $db->{foo};
+
+  push @{$db->{foo}}, 42;
+  is( $db->{bar}[-1], 42 ); # Passes
+
+This, however, does I<not> extend to assignments from one DB file to another.
+So, the following will throw an error:
+
+  my $db1 = DBM::Deep->new( "foo.db" );
+  my $db2 = DBM::Deep->new( "bar.db" );
+
+  $db1->{foo} = [];
+  $db2->{foo} = $db1->{foo}; # dies
+
 B<Note>: Passing the object to a function that recursively walks the
 object tree (such as I<Data::Dumper> or even the built-in C<optimize()> or
 C<export()> methods) will result in an infinite loop. This will be fixed in
-a future release.
+a future release by adding singleton support.
 
 =head1 TRANSACTIONS
 
-New in 0.99_01 is ACID transactions. Every DBM::Deep object is completely
+As of 1.0000, DBM::Deep hass ACID transactions. Every DBM::Deep object is completely
 transaction-ready - it is not an option you have to turn on. You do have to
 specify how many transactions may run simultaneously (q.v. L</num_txns>).
 
@@ -936,48 +916,6 @@ the transaction.
 Transactions in DBM::Deep are done using a variant of the MVCC method, the
 same method used by the InnoDB MySQL engine.
 
-=head1 PERFORMANCE
-
-Because DBM::Deep is a conncurrent datastore, every change is flushed to disk
-immediately and every read goes to disk. This means that DBM::Deep functions
-at the speed of disk (generally 10-20ms) vs. the speed of RAM (generally
-50-70ns), or at least 150-200x slower than the comparable in-memory
-datastructure in Perl.
-
-There are several techniques you can use to speed up how DBM::Deep functions.
-
-=over 4
-
-=item * Put it on a ramdisk
-
-The easiest and quickest mechanism to making DBM::Deep run faster is to create
-a ramdisk and locate the DBM::Deep file there. Doing this as an option may
-become a feature of DBM::Deep, assuming there is a good ramdisk wrapper on CPAN.
-
-=item * Work at the tightest level possible
-
-It is much faster to assign the level of your db that you are working with to
-an intermediate variable than to re-look it up every time. Thus
-
-  # BAD
-  while ( my ($k, $v) = each %{$db->{foo}{bar}{baz}} ) {
-    ...
-  }
-
-  # GOOD
-  my $x = $db->{foo}{bar}{baz};
-  while ( my ($k, $v) = each %$x ) {
-    ...
-  }
-
-=item * Make your file as tight as possible
-
-If you know that you are not going to use more than 65K in your database,
-consider using the C<pack_size =E<gt> 'small'> option. This will instruct
-DBM::Deep to use 16bit addresses, meaning that the seek times will be less.
-
-=back
-
 =head1 MIGRATION
 
 As of 1.0000, the file format has changed. Furthermore, DBM::Deep is now
@@ -991,7 +929,7 @@ of every version prior to the current version.
 =head1 TODO
 
 The following are items that are planned to be added in future releases. These
-are separate from the L<CAVEATS, ISSUES & BUGS> below.
+are separate from the L</CAVEATS, ISSUES & BUGS> below.
 
 =head2 Sub-Transactions
 
@@ -1002,7 +940,7 @@ immediately, please submit many testcases.
 
 =head2 Caching
 
-If a user is willing to assert upon opening the file that this process will be
+If a client is willing to assert upon opening the file that this process will be
 the only consumer of that datafile, then there are a number of caching
 possibilities that can be taken advantage of. This does, however, mean that
 DBM::Deep is more vulnerable to losing data due to unflushed changes. It also
@@ -1017,13 +955,6 @@ substr, the STM capabilities of DBM::Deep could be used within a
 single-process. I have no idea how I'd specify this, though. Suggestions are
 welcome.
 
-=head2 Importing using Data::Walker
-
-Right now, importing is done using C<Clone::clone()> to make a complete copy
-in memory, then tying that copy. It would be much better to use
-L<Data::Walker/> to walk the data structure instead, particularly in the case
-of large datastructures.
-
 =head2 Different contention resolution mechanisms
 
 Currently, the only contention resolution mechanism is last-write-wins. This
@@ -1084,7 +1015,7 @@ all to support a feature that has never been requested.
 
 =item * CODE
 
-L<Data::Dump::Streamer/> provides a mechanism for serializing coderefs,
+L<Data::Dump::Streamer> provides a mechanism for serializing coderefs,
 including saving off all closure state. This would allow for DBM::Deep to
 store the code for a subroutine. Then, whenever the subroutine is read, the
 code could be C<eval()>'ed into being. However, just as for SCALAR and REF,
@@ -1093,6 +1024,14 @@ the reference. Again, this would generally be considered a feature.
 
 =back
 
+=head2 External references and transactions
+
+If you do C<<my $x = $db->{foo};>>, then start a transaction, $x will be
+referencing the database from outside the transaction. A fix for this (and other
+issues with how external references into the database) is being looked into. This
+is the skipped set of tests in t/39_singletons.t and a related issue is the focus
+of t/37_delete_edge_cases.t
+
 =head2 File corruption
 
 The current level of error handling in DBM::Deep is minimal. Files I<are> checked
@@ -1111,7 +1050,7 @@ NFS. I've heard about setting up your NFS server with a locking daemon, then
 using C<lockf()> to lock your files, but your mileage may vary there as well.
 From what I understand, there is no real way to do it. However, if you need
 access to the underlying filehandle in DBM::Deep for using some other kind of
-locking scheme like C<lockf()>, see the L<LOW-LEVEL ACCESS> section above.
+locking scheme like C<lockf()>, see the L</LOW-LEVEL ACCESS> section above.
 
 =head2 Copying Objects
 
@@ -1121,8 +1060,28 @@ returns a new, blessed and tied hash or array to the same level in the DB.
 
   my $copy = $db->clone();
 
-B<Note>: Since clone() here is cloning the object, not the database location, any
-modifications to either $db or $copy will be visible to both.
+B<Note>: Since clone() here is cloning the object, not the database location,
+any modifications to either $db or $copy will be visible to both.
+
+=head2 Stale References
+
+If you take a reference to an array or hash from the database, it is tied
+to the database itself. This means that if the datum in question is subsequentl
+an invalid location and unpredictable things will happen if you try to use
+it.
+
+So a seemingly innocuous piece of code like this:
+
+  my %hash = %{ $db->{some_hash} };
+
+can fail if another process deletes or clobbers C<< $db->{some_hash} >>
+while the data are being extracted, since S<C<%{ ... }>> is not atomic.
+(This actually happened.) The solution is to lock the database before
+reading the data:
+
+  $db->lock_exclusive;
+  my %hash = %{ $db->{some_hash} };
+  $db->unlock;
 
 =head2 Large Arrays
 
@@ -1131,12 +1090,17 @@ These functions cause every element in the array to move, which can be murder
 on DBM::Deep, as every element has to be fetched from disk, then stored again in
 a different location. This will be addressed in a future version.
 
+This has been somewhat addressed so that the cost is constant, regardless of
+what is stored at those locations. So, small arrays with huge data structures in
+them are faster. But, large arrays are still large.
+
 =head2 Writeonly Files
 
-If you pass in a filehandle to new(), you may have opened it in either a readonly or
-writeonly mode. STORE will verify that the filehandle is writable. However, there
-doesn't seem to be a good way to determine if a filehandle is readable. And, if the
-filehandle isn't readable, it's not clear what will happen. So, don't do that.
+If you pass in a filehandle to new(), you may have opened it in either a
+readonly or writeonly mode. STORE will verify that the filehandle is writable.
+However, there doesn't seem to be a good way to determine if a filehandle is
+readable. And, if the filehandle isn't readable, it's not clear what will
+happen. So, don't do that.
 
 =head2 Assignments Within Transactions
 
@@ -1161,19 +1125,19 @@ reference to be imported in order to explicitly leave it untied.
 
 =head1 CODE COVERAGE
 
-B<Devel::Cover> is used to test the code coverage of the tests. Below is the
-B<Devel::Cover> report on this distribution's test suite.
+L<Devel::Cover> is used to test the code coverage of the tests. Below is the
+L<Devel::Cover> report on this distribution's test suite.
 
-  ---------------------------- ------ ------ ------ ------ ------ ------ ------
-  File                           stmt   bran   cond    sub    pod   time  total
-  ---------------------------- ------ ------ ------ ------ ------ ------ ------
-  blib/lib/DBM/Deep.pm           96.8   87.9   90.5  100.0   89.5    4.5   95.2
-  blib/lib/DBM/Deep/Array.pm    100.0   94.3  100.0  100.0  100.0    4.8   98.7
-  blib/lib/DBM/Deep/Engine.pm    97.2   86.4   86.0  100.0    0.0   56.8   91.0
-  blib/lib/DBM/Deep/File.pm      98.1   83.3   66.7  100.0    0.0   31.4   88.0
-  blib/lib/DBM/Deep/Hash.pm     100.0  100.0  100.0  100.0  100.0    2.5  100.0
-  Total                          97.7   88.1   86.6  100.0   31.6  100.0   93.0
-  ---------------------------- ------ ------ ------ ------ ------ ------ ------
+  ------------------------------------------ ------ ------ ------ ------ ------
+  File                                         stmt   bran   cond    sub  total
+  ------------------------------------------ ------ ------ ------ ------ ------
+  blib/lib/DBM/Deep.pm                         97.2   90.9   83.3  100.0   95.4
+  blib/lib/DBM/Deep/Array.pm                  100.0   95.7  100.0  100.0   99.0
+  blib/lib/DBM/Deep/Engine.pm                  95.6   84.7   81.6   98.4   92.5
+  blib/lib/DBM/Deep/File.pm                    97.2   81.6   66.7  100.0   91.9
+  blib/lib/DBM/Deep/Hash.pm                   100.0  100.0  100.0  100.0  100.0
+  Total                                        96.7   87.5   82.2   99.2   94.1
+  ------------------------------------------ ------ ------ ------ ------ ------
 
 =head1 MORE INFORMATION
 
@@ -1181,7 +1145,7 @@ Check out the DBM::Deep Google Group at L<http://groups.google.com/group/DBM-Dee
 or send email to L<DBM-Deep@googlegroups.com>. You can also visit #dbm-deep on
 irc.perl.org
 
-The source code repository is at L<http://svn.perl.org/modules/DBM-Deep>
+The source code repository is at L<http://github.com/robkinyon/dbm-deep>
 
 =head1 MAINTAINERS