Converting from FileHandle methods to keywords in preparation for removing FileHandle
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep.pm
1 package DBM::Deep;
2
3 ##
4 # DBM::Deep
5 #
6 # Description:
7 #       Multi-level database module for storing hash trees, arrays and simple
8 #       key/value pairs into FTP-able, cross-platform binary database files.
9 #
10 #       Type `perldoc DBM::Deep` for complete documentation.
11 #
12 # Usage Examples:
13 #       my %db;
14 #       tie %db, 'DBM::Deep', 'my_database.db'; # standard tie() method
15 #       
16 #       my $db = new DBM::Deep( 'my_database.db' ); # preferred OO method
17 #
18 #       $db->{my_scalar} = 'hello world';
19 #       $db->{my_hash} = { larry => 'genius', hashes => 'fast' };
20 #       $db->{my_array} = [ 1, 2, 3, time() ];
21 #       $db->{my_complex} = [ 'hello', { perl => 'rules' }, 42, 99 ];
22 #       push @{$db->{my_array}}, 'another value';
23 #       my @key_list = keys %{$db->{my_hash}};
24 #       print "This module " . $db->{my_complex}->[1]->{perl} . "!\n";
25 #
26 # Copyright:
27 #       (c) 2002-2005 Joseph Huckaby.  All Rights Reserved.
28 #       This program is free software; you can redistribute it and/or 
29 #       modify it under the same terms as Perl itself.
30 ##
31
32 use strict;
33
34 use FileHandle;
35 use Fcntl qw/:flock/;
36 use Digest::MD5 ();
37 use Scalar::Util ();
38 use vars qw/$VERSION/;
39
40 $VERSION = "0.96";
41
42 ##
43 # Set to 4 and 'N' for 32-bit offset tags (default).  Theoretical limit of 4 GB per file.
44 #       (Perl must be compiled with largefile support for files > 2 GB)
45 #
46 # Set to 8 and 'Q' for 64-bit offsets.  Theoretical limit of 16 XB per file.
47 #       (Perl must be compiled with largefile and 64-bit long support)
48 ##
49 #my $LONG_SIZE = 4;
50 #my $LONG_PACK = 'N';
51
52 ##
53 # Set to 4 and 'N' for 32-bit data length prefixes.  Limit of 4 GB for each key/value.
54 # Upgrading this is possible (see above) but probably not necessary.  If you need
55 # more than 4 GB for a single key or value, this module is really not for you :-)
56 ##
57 #my $DATA_LENGTH_SIZE = 4;
58 #my $DATA_LENGTH_PACK = 'N';
59 my ($LONG_SIZE, $LONG_PACK, $DATA_LENGTH_SIZE, $DATA_LENGTH_PACK);
60
61 ##
62 # Maximum number of buckets per list before another level of indexing is done.
63 # Increase this value for slightly greater speed, but larger database files.
64 # DO NOT decrease this value below 16, due to risk of recursive reindex overrun.
65 ##
66 my $MAX_BUCKETS = 16;
67
68 ##
69 # Better not adjust anything below here, unless you're me :-)
70 ##
71
72 ##
73 # Setup digest function for keys
74 ##
75 my ($DIGEST_FUNC, $HASH_SIZE);
76 #my $DIGEST_FUNC = \&Digest::MD5::md5;
77
78 ##
79 # Precalculate index and bucket sizes based on values above.
80 ##
81 #my $HASH_SIZE = 16;
82 my ($INDEX_SIZE, $BUCKET_SIZE, $BUCKET_LIST_SIZE);
83
84 set_digest();
85 #set_pack();
86 #precalc_sizes();
87
88 ##
89 # Setup file and tag signatures.  These should never change.
90 ##
91 sub SIG_FILE  () { 'DPDB' }
92 sub SIG_HASH  () { 'H' }
93 sub SIG_ARRAY () { 'A' }
94 sub SIG_NULL  () { 'N' }
95 sub SIG_DATA  () { 'D' }
96 sub SIG_INDEX () { 'I' }
97 sub SIG_BLIST () { 'B' }
98 sub SIG_SIZE  () {  1  }
99
100 ##
101 # Setup constants for users to pass to new()
102 ##
103 sub TYPE_HASH  () { return SIG_HASH; }
104 sub TYPE_ARRAY () { return SIG_ARRAY; }
105
106 sub new {
107         ##
108         # Class constructor method for Perl OO interface.
109         # Calls tie() and returns blessed reference to tied hash or array,
110         # providing a hybrid OO/tie interface.
111         ##
112         my $class = shift;
113         my $args;
114         if (scalar(@_) > 1) { $args = {@_}; }
115         else { $args = { file => shift }; }
116         
117         ##
118         # Check if we want a tied hash or array.
119         ##
120         my $self;
121         if (defined($args->{type}) && $args->{type} eq TYPE_ARRAY) {
122                 tie @$self, $class, %$args;
123         }
124         else {
125                 tie %$self, $class, %$args;
126         }
127
128         return bless $self, $class;
129 }
130
131 {
132     my @outer_params = qw( type base_offset );
133     sub _init {
134         ##
135         # Setup $self and bless into this class.
136         ##
137         my $class = shift;
138         my $args = shift;
139
140         my $self = {
141             type => TYPE_HASH,
142             base_offset => length(SIG_FILE),
143             root => {
144                 file => undef,
145                 fh => undef,
146                 end => 0,
147                 links => 0,
148                 autoflush => undef,
149                 locking => undef,
150                 volatile => undef,
151                 debug => undef,
152                 mode => 'r+',
153                 filter_store_key => undef,
154                 filter_store_value => undef,
155                 filter_fetch_key => undef,
156                 filter_fetch_value => undef,
157                 autobless => undef,
158                 locked => 0,
159                 %$args,
160             },
161         };
162
163         bless $self, $class;
164
165         foreach my $outer_parm ( @outer_params ) {
166             next unless exists $args->{$outer_parm};
167             $self->{$outer_parm} = $args->{$outer_parm}
168         }
169         
170         if ( exists $args->{root} ) {
171             $self->{root} = $args->{root};
172         }
173         else {
174             # This is cleanup based on the fact that the $args
175             # coming in is for both the root and non-root items
176             delete $self->root->{$_} for @outer_params;
177         }
178         $self->root->{links}++;
179
180         if (!defined($self->fh)) { $self->_open(); }
181
182         return $self;
183     }
184 }
185
186 sub _get_self { tied( %{$_[0]} ) || $_[0] }
187
188 sub TIEHASH {
189     ##
190     # Tied hash constructor method, called by Perl's tie() function.
191     ##
192     my $class = shift;
193     my $args;
194     if (scalar(@_) > 1) { $args = {@_}; }
195     #XXX This use of ref() is bad and is a bug
196     elsif (ref($_[0])) { $args = $_[0]; }
197     else { $args = { file => shift }; }
198     
199     $args->{type} = TYPE_HASH;
200
201     return $class->_init($args);
202 }
203
204 sub TIEARRAY {
205 ##
206 # Tied array constructor method, called by Perl's tie() function.
207 ##
208     my $class = shift;
209     my $args;
210     if (scalar(@_) > 1) { $args = {@_}; }
211     #XXX This use of ref() is bad and is a bug
212         elsif (ref($_[0])) { $args = $_[0]; }
213         else { $args = { file => shift }; }
214         
215         $args->{type} = TYPE_ARRAY;
216         
217         return $class->_init($args);
218 }
219
220 sub DESTROY {
221         ##
222         # Class deconstructor.  Close file handle if there are no more refs.
223         ##
224     my $self = _get_self($_[0]);
225     return unless $self;
226         
227         $self->root->{links}--;
228         
229         if (!$self->root->{links}) {
230                 $self->_close();
231         }
232 }
233
234 sub _open {
235         ##
236         # Open a FileHandle to the database, create if nonexistent.
237         # Make sure file signature matches DeepDB spec.
238         ##
239     my $self = _get_self($_[0]);
240
241         if (defined($self->fh)) { $self->_close(); }
242         
243 #    eval {
244         if (!(-e $self->root->{file}) && $self->root->{mode} eq 'r+') {
245             my $temp = FileHandle->new( $self->root->{file}, 'w' );
246         }
247         
248         #XXX Convert to set_fh()
249         $self->root->{fh} = FileHandle->new( $self->root->{file}, $self->root->{mode} );
250 #    }; if ($@ ) { $self->_throw_error( "Received error: $@\n" ); }
251         if (! defined($self->fh)) {
252                 return $self->_throw_error("Cannot open file: " . $self->root->{file} . ": $!");
253         }
254
255     binmode $self->fh; # for win32
256     if ($self->root->{autoflush}) {
257         $self->fh->autoflush();
258     }
259     
260     my $signature;
261     seek($self->fh, 0, 0);
262     my $bytes_read = read( $self->fh, $signature, length(SIG_FILE));
263     
264     ##
265     # File is empty -- write signature and master index
266     ##
267     if (!$bytes_read) {
268         seek($self->fh, 0, 0);
269         $self->fh->print(SIG_FILE);
270         $self->root->{end} = length(SIG_FILE);
271         $self->_create_tag($self->base_offset, $self->type, chr(0) x $INDEX_SIZE);
272
273         my $plain_key = "[base]";
274         $self->fh->print( pack($DATA_LENGTH_PACK, length($plain_key)) . $plain_key );
275         $self->root->{end} += $DATA_LENGTH_SIZE + length($plain_key);
276         $self->fh->flush();
277
278         return 1;
279     }
280     
281     ##
282     # Check signature was valid
283     ##
284     unless ($signature eq SIG_FILE) {
285         $self->_close();
286         return $self->_throw_error("Signature not found -- file is not a Deep DB");
287     }
288
289     $self->root->{end} = (stat($self->fh))[7];
290         
291     ##
292     # Get our type from master index signature
293     ##
294     my $tag = $self->_load_tag($self->base_offset);
295 #XXX We probably also want to store the hash algorithm name and not assume anything
296     if (!$tag) {
297         return $self->_throw_error("Corrupted file, no master index record");
298     }
299     if ($self->{type} ne $tag->{signature}) {
300         return $self->_throw_error("File type mismatch");
301     }
302     
303     return 1;
304 }
305
306 sub _close {
307         ##
308         # Close database FileHandle
309         ##
310     my $self = _get_self($_[0]);
311         undef $self->root->{fh};
312 }
313
314 sub _create_tag {
315         ##
316         # Given offset, signature and content, create tag and write to disk
317         ##
318         my ($self, $offset, $sig, $content) = @_;
319         my $size = length($content);
320         
321         seek($self->fh, $offset, 0);
322         $self->fh->print( $sig . pack($DATA_LENGTH_PACK, $size) . $content );
323         
324         if ($offset == $self->root->{end}) {
325                 $self->root->{end} += SIG_SIZE + $DATA_LENGTH_SIZE + $size;
326         }
327         
328         return {
329                 signature => $sig,
330                 size => $size,
331                 offset => $offset + SIG_SIZE + $DATA_LENGTH_SIZE,
332                 content => $content
333         };
334 }
335
336 sub _load_tag {
337         ##
338         # Given offset, load single tag and return signature, size and data
339         ##
340         my $self = shift;
341         my $offset = shift;
342         
343         seek($self->fh, $offset, 0);
344         if ($self->fh->eof()) { return undef; }
345         
346         my $sig;
347         read( $self->fh, $sig, SIG_SIZE);
348         
349         my $size;
350         read( $self->fh, $size, $DATA_LENGTH_SIZE);
351         $size = unpack($DATA_LENGTH_PACK, $size);
352         
353         my $buffer;
354         read( $self->fh, $buffer, $size);
355         
356         return {
357                 signature => $sig,
358                 size => $size,
359                 offset => $offset + SIG_SIZE + $DATA_LENGTH_SIZE,
360                 content => $buffer
361         };
362 }
363
364 sub _index_lookup {
365         ##
366         # Given index tag, lookup single entry in index and return .
367         ##
368         my $self = shift;
369         my ($tag, $index) = @_;
370
371         my $location = unpack($LONG_PACK, substr($tag->{content}, $index * $LONG_SIZE, $LONG_SIZE) );
372         if (!$location) { return; }
373         
374         return $self->_load_tag( $location );
375 }
376
377 sub _add_bucket {
378         ##
379         # Adds one key/value pair to bucket list, given offset, MD5 digest of key,
380         # plain (undigested) key and value.
381         ##
382         my $self = shift;
383         my ($tag, $md5, $plain_key, $value) = @_;
384         my $keys = $tag->{content};
385         my $location = 0;
386         my $result = 2;
387
388     my $is_dbm_deep = eval { $value->isa( 'DBM::Deep' ) };
389         my $internal_ref = $is_dbm_deep && ($value->root eq $self->root);
390
391         ##
392         # Iterate through buckets, seeing if this is a new entry or a replace.
393         ##
394         for (my $i=0; $i<$MAX_BUCKETS; $i++) {
395                 my $key = substr($keys, $i * $BUCKET_SIZE, $HASH_SIZE);
396                 my $subloc = unpack($LONG_PACK, substr($keys, ($i * $BUCKET_SIZE) + $HASH_SIZE, $LONG_SIZE));
397                 if (!$subloc) {
398                         ##
399                         # Found empty bucket (end of list).  Populate and exit loop.
400                         ##
401                         $result = 2;
402                         
403             $location = $internal_ref
404                 ? $value->base_offset
405                 : $self->root->{end};
406                         
407                         seek($self->fh, $tag->{offset} + ($i * $BUCKET_SIZE), 0);
408                         $self->fh->print( $md5 . pack($LONG_PACK, $location) );
409                         last;
410                 }
411                 elsif ($md5 eq $key) {
412                         ##
413                         # Found existing bucket with same key.  Replace with new value.
414                         ##
415                         $result = 1;
416                         
417                         if ($internal_ref) {
418                                 $location = $value->base_offset;
419                                 seek($self->fh, $tag->{offset} + ($i * $BUCKET_SIZE), 0);
420                                 $self->fh->print( $md5 . pack($LONG_PACK, $location) );
421                         }
422                         else {
423                                 seek($self->fh, $subloc + SIG_SIZE, 0);
424                                 my $size;
425                                 read( $self->fh, $size, $DATA_LENGTH_SIZE); $size = unpack($DATA_LENGTH_PACK, $size);
426                                 
427                                 ##
428                                 # If value is a hash, array, or raw value with equal or less size, we can
429                                 # reuse the same content area of the database.  Otherwise, we have to create
430                                 # a new content area at the EOF.
431                                 ##
432                                 my $actual_length;
433                 my $r = Scalar::Util::reftype( $value ) || '';
434                 if ( $r eq 'HASH' || $r eq 'ARRAY' ) { $actual_length = $INDEX_SIZE; }
435                                 else { $actual_length = length($value); }
436                                 
437                                 if ($actual_length <= $size) {
438                                         $location = $subloc;
439                                 }
440                                 else {
441                                         $location = $self->root->{end};
442                                         seek($self->fh, $tag->{offset} + ($i * $BUCKET_SIZE) + $HASH_SIZE, 0);
443                                         $self->fh->print( pack($LONG_PACK, $location) );
444                                 }
445                         }
446                         last;
447                 }
448         } # i loop
449         
450         ##
451         # If this is an internal reference, return now.
452         # No need to write value or plain key
453         ##
454         if ($internal_ref) {
455         return $result;
456     }
457         
458         ##
459         # If bucket didn't fit into list, split into a new index level
460         ##
461         if (!$location) {
462                 seek($self->fh, $tag->{ref_loc}, 0);
463                 $self->fh->print( pack($LONG_PACK, $self->root->{end}) );
464                 
465                 my $index_tag = $self->_create_tag($self->root->{end}, SIG_INDEX, chr(0) x $INDEX_SIZE);
466                 my @offsets = ();
467                 
468                 $keys .= $md5 . pack($LONG_PACK, 0);
469                 
470                 for (my $i=0; $i<=$MAX_BUCKETS; $i++) {
471                         my $key = substr($keys, $i * $BUCKET_SIZE, $HASH_SIZE);
472                         if ($key) {
473                                 my $old_subloc = unpack($LONG_PACK, substr($keys, ($i * $BUCKET_SIZE) + $HASH_SIZE, $LONG_SIZE));
474                                 my $num = ord(substr($key, $tag->{ch} + 1, 1));
475                                 
476                                 if ($offsets[$num]) {
477                                         my $offset = $offsets[$num] + SIG_SIZE + $DATA_LENGTH_SIZE;
478                                         seek($self->fh, $offset, 0);
479                                         my $subkeys;
480                                         read( $self->fh, $subkeys, $BUCKET_LIST_SIZE);
481                                         
482                                         for (my $k=0; $k<$MAX_BUCKETS; $k++) {
483                                                 my $subloc = unpack($LONG_PACK, substr($subkeys, ($k * $BUCKET_SIZE) + $HASH_SIZE, $LONG_SIZE));
484                                                 if (!$subloc) {
485                                                         seek($self->fh, $offset + ($k * $BUCKET_SIZE), 0);
486                                                         $self->fh->print( $key . pack($LONG_PACK, $old_subloc || $self->root->{end}) );
487                                                         last;
488                                                 }
489                                         } # k loop
490                                 }
491                                 else {
492                                         $offsets[$num] = $self->root->{end};
493                                         seek($self->fh, $index_tag->{offset} + ($num * $LONG_SIZE), 0);
494                                         $self->fh->print( pack($LONG_PACK, $self->root->{end}) );
495                                         
496                                         my $blist_tag = $self->_create_tag($self->root->{end}, SIG_BLIST, chr(0) x $BUCKET_LIST_SIZE);
497                                         
498                                         seek($self->fh, $blist_tag->{offset}, 0);
499                                         $self->fh->print( $key . pack($LONG_PACK, $old_subloc || $self->root->{end}) );
500                                 }
501                         } # key is real
502                 } # i loop
503                 
504                 $location ||= $self->root->{end};
505         } # re-index bucket list
506         
507         ##
508         # Seek to content area and store signature, value and plaintext key
509         ##
510         if ($location) {
511                 my $content_length;
512                 seek($self->fh, $location, 0);
513                 
514                 ##
515                 # Write signature based on content type, set content length and write actual value.
516                 ##
517         my $r = Scalar::Util::reftype($value) || '';
518                 if ($r eq 'HASH') {
519                         $self->fh->print( TYPE_HASH );
520                         $self->fh->print( pack($DATA_LENGTH_PACK, $INDEX_SIZE) . chr(0) x $INDEX_SIZE );
521                         $content_length = $INDEX_SIZE;
522                 }
523                 elsif ($r eq 'ARRAY') {
524                         $self->fh->print( TYPE_ARRAY );
525                         $self->fh->print( pack($DATA_LENGTH_PACK, $INDEX_SIZE) . chr(0) x $INDEX_SIZE );
526                         $content_length = $INDEX_SIZE;
527                 }
528                 elsif (!defined($value)) {
529                         $self->fh->print( SIG_NULL );
530                         $self->fh->print( pack($DATA_LENGTH_PACK, 0) );
531                         $content_length = 0;
532                 }
533                 else {
534                         $self->fh->print( SIG_DATA );
535                         $self->fh->print( pack($DATA_LENGTH_PACK, length($value)) . $value );
536                         $content_length = length($value);
537                 }
538                 
539                 ##
540                 # Plain key is stored AFTER value, as keys are typically fetched less often.
541                 ##
542                 $self->fh->print( pack($DATA_LENGTH_PACK, length($plain_key)) . $plain_key );
543                 
544                 ##
545                 # If value is blessed, preserve class name
546                 ##
547                 if ( $self->root->{autobless} ) {
548             my $value_class = Scalar::Util::blessed($value);
549             if ( defined $value_class && $value_class ne 'DBM::Deep' ) {
550                 ##
551                 # Blessed ref -- will restore later
552                 ##
553                 $self->fh->print( chr(1) );
554                 $self->fh->print( pack($DATA_LENGTH_PACK, length($value_class)) . $value_class );
555                 $content_length += 1;
556                 $content_length += $DATA_LENGTH_SIZE + length($value_class);
557             }
558             else {
559                 $self->fh->print( chr(0) );
560                 $content_length += 1;
561             }
562         }
563             
564                 ##
565                 # If this is a new content area, advance EOF counter
566                 ##
567                 if ($location == $self->root->{end}) {
568                         $self->root->{end} += SIG_SIZE;
569                         $self->root->{end} += $DATA_LENGTH_SIZE + $content_length;
570                         $self->root->{end} += $DATA_LENGTH_SIZE + length($plain_key);
571                 }
572                 
573                 ##
574                 # If content is a hash or array, create new child DeepDB object and
575                 # pass each key or element to it.
576                 ##
577                 if ($r eq 'HASH') {
578                         my $branch = DBM::Deep->new(
579                                 type => TYPE_HASH,
580                                 base_offset => $location,
581                                 root => $self->root,
582                         );
583                         foreach my $key (keys %{$value}) {
584                                 $branch->{$key} = $value->{$key};
585                         }
586                 }
587                 elsif ($r eq 'ARRAY') {
588                         my $branch = DBM::Deep->new(
589                                 type => TYPE_ARRAY,
590                                 base_offset => $location,
591                                 root => $self->root,
592                         );
593                         my $index = 0;
594                         foreach my $element (@{$value}) {
595                                 $branch->[$index] = $element;
596                                 $index++;
597                         }
598                 }
599                 
600                 return $result;
601         }
602         
603         return $self->_throw_error("Fatal error: indexing failed -- possibly due to corruption in file");
604 }
605
606 sub _get_bucket_value {
607         ##
608         # Fetch single value given tag and MD5 digested key.
609         ##
610         my $self = shift;
611         my ($tag, $md5) = @_;
612         my $keys = $tag->{content};
613         
614         ##
615         # Iterate through buckets, looking for a key match
616         ##
617     BUCKET:
618         for (my $i=0; $i<$MAX_BUCKETS; $i++) {
619                 my $key = substr($keys, $i * $BUCKET_SIZE, $HASH_SIZE);
620                 my $subloc = unpack($LONG_PACK, substr($keys, ($i * $BUCKET_SIZE) + $HASH_SIZE, $LONG_SIZE));
621
622                 if (!$subloc) {
623                         ##
624                         # Hit end of list, no match
625                         ##
626                         return;
627                 }
628
629         if ( $md5 ne $key ) {
630             next BUCKET;
631         }
632
633         ##
634         # Found match -- seek to offset and read signature
635         ##
636         my $signature;
637         seek($self->fh, $subloc, 0);
638         read( $self->fh, $signature, SIG_SIZE);
639         
640         ##
641         # If value is a hash or array, return new DeepDB object with correct offset
642         ##
643         if (($signature eq TYPE_HASH) || ($signature eq TYPE_ARRAY)) {
644             my $obj = DBM::Deep->new(
645                 type => $signature,
646                 base_offset => $subloc,
647                 root => $self->root
648             );
649             
650             if ($self->root->{autobless}) {
651                 ##
652                 # Skip over value and plain key to see if object needs
653                 # to be re-blessed
654                 ##
655                 seek($self->fh, $DATA_LENGTH_SIZE + $INDEX_SIZE, 1);
656                 
657                 my $size;
658                 read( $self->fh, $size, $DATA_LENGTH_SIZE); $size = unpack($DATA_LENGTH_PACK, $size);
659                 if ($size) { seek($self->fh, $size, 1); }
660                 
661                 my $bless_bit;
662                 read( $self->fh, $bless_bit, 1);
663                 if (ord($bless_bit)) {
664                     ##
665                     # Yes, object needs to be re-blessed
666                     ##
667                     my $class_name;
668                     read( $self->fh, $size, $DATA_LENGTH_SIZE); $size = unpack($DATA_LENGTH_PACK, $size);
669                     if ($size) { read( $self->fh, $class_name, $size); }
670                     if ($class_name) { $obj = bless( $obj, $class_name ); }
671                 }
672             }
673             
674             return $obj;
675         }
676         
677         ##
678         # Otherwise return actual value
679         ##
680         elsif ($signature eq SIG_DATA) {
681             my $size;
682             my $value = '';
683             read( $self->fh, $size, $DATA_LENGTH_SIZE); $size = unpack($DATA_LENGTH_PACK, $size);
684             if ($size) { read( $self->fh, $value, $size); }
685             return $value;
686         }
687         
688         ##
689         # Key exists, but content is null
690         ##
691         else { return; }
692         } # i loop
693
694         return;
695 }
696
697 sub _delete_bucket {
698         ##
699         # Delete single key/value pair given tag and MD5 digested key.
700         ##
701         my $self = shift;
702         my ($tag, $md5) = @_;
703         my $keys = $tag->{content};
704         
705         ##
706         # Iterate through buckets, looking for a key match
707         ##
708     BUCKET:
709         for (my $i=0; $i<$MAX_BUCKETS; $i++) {
710                 my $key = substr($keys, $i * $BUCKET_SIZE, $HASH_SIZE);
711                 my $subloc = unpack($LONG_PACK, substr($keys, ($i * $BUCKET_SIZE) + $HASH_SIZE, $LONG_SIZE));
712
713                 if (!$subloc) {
714                         ##
715                         # Hit end of list, no match
716                         ##
717                         return;
718                 }
719
720         if ( $md5 ne $key ) {
721             next BUCKET;
722         }
723
724         ##
725         # Matched key -- delete bucket and return
726         ##
727         seek($self->fh, $tag->{offset} + ($i * $BUCKET_SIZE), 0);
728         $self->fh->print( substr($keys, ($i+1) * $BUCKET_SIZE ) );
729         $self->fh->print( chr(0) x $BUCKET_SIZE );
730         
731         return 1;
732         } # i loop
733
734         return;
735 }
736
737 sub _bucket_exists {
738         ##
739         # Check existence of single key given tag and MD5 digested key.
740         ##
741         my $self = shift;
742         my ($tag, $md5) = @_;
743         my $keys = $tag->{content};
744         
745         ##
746         # Iterate through buckets, looking for a key match
747         ##
748     BUCKET:
749         for (my $i=0; $i<$MAX_BUCKETS; $i++) {
750                 my $key = substr($keys, $i * $BUCKET_SIZE, $HASH_SIZE);
751                 my $subloc = unpack($LONG_PACK, substr($keys, ($i * $BUCKET_SIZE) + $HASH_SIZE, $LONG_SIZE));
752
753                 if (!$subloc) {
754                         ##
755                         # Hit end of list, no match
756                         ##
757                         return;
758                 }
759
760         if ( $md5 ne $key ) {
761             next BUCKET;
762         }
763
764         ##
765         # Matched key -- return true
766         ##
767         return 1;
768         } # i loop
769
770         return;
771 }
772
773 sub _find_bucket_list {
774         ##
775         # Locate offset for bucket list, given digested key
776         ##
777         my $self = shift;
778         my $md5 = shift;
779         
780         ##
781         # Locate offset for bucket list using digest index system
782         ##
783         my $ch = 0;
784         my $tag = $self->_load_tag($self->base_offset);
785         if (!$tag) { return; }
786         
787         while ($tag->{signature} ne SIG_BLIST) {
788                 $tag = $self->_index_lookup($tag, ord(substr($md5, $ch, 1)));
789                 if (!$tag) { return; }
790                 $ch++;
791         }
792         
793         return $tag;
794 }
795
796 sub _traverse_index {
797         ##
798         # Scan index and recursively step into deeper levels, looking for next key.
799         ##
800     my ($self, $offset, $ch, $force_return_next) = @_;
801     $force_return_next = undef unless $force_return_next;
802         
803         my $tag = $self->_load_tag( $offset );
804         
805         if ($tag->{signature} ne SIG_BLIST) {
806                 my $content = $tag->{content};
807                 my $start;
808                 if ($self->{return_next}) { $start = 0; }
809                 else { $start = ord(substr($self->{prev_md5}, $ch, 1)); }
810                 
811                 for (my $index = $start; $index < 256; $index++) {
812                         my $subloc = unpack($LONG_PACK, substr($content, $index * $LONG_SIZE, $LONG_SIZE) );
813                         if ($subloc) {
814                                 my $result = $self->_traverse_index( $subloc, $ch + 1, $force_return_next );
815                                 if (defined($result)) { return $result; }
816                         }
817                 } # index loop
818                 
819                 $self->{return_next} = 1;
820         } # tag is an index
821         
822         elsif ($tag->{signature} eq SIG_BLIST) {
823                 my $keys = $tag->{content};
824                 if ($force_return_next) { $self->{return_next} = 1; }
825                 
826                 ##
827                 # Iterate through buckets, looking for a key match
828                 ##
829                 for (my $i=0; $i<$MAX_BUCKETS; $i++) {
830                         my $key = substr($keys, $i * $BUCKET_SIZE, $HASH_SIZE);
831                         my $subloc = unpack($LONG_PACK, substr($keys, ($i * $BUCKET_SIZE) + $HASH_SIZE, $LONG_SIZE));
832         
833                         if (!$subloc) {
834                                 ##
835                                 # End of bucket list -- return to outer loop
836                                 ##
837                                 $self->{return_next} = 1;
838                                 last;
839                         }
840                         elsif ($key eq $self->{prev_md5}) {
841                                 ##
842                                 # Located previous key -- return next one found
843                                 ##
844                                 $self->{return_next} = 1;
845                                 next;
846                         }
847                         elsif ($self->{return_next}) {
848                                 ##
849                                 # Seek to bucket location and skip over signature
850                                 ##
851                                 seek($self->fh, $subloc + SIG_SIZE, 0);
852                                 
853                                 ##
854                                 # Skip over value to get to plain key
855                                 ##
856                                 my $size;
857                                 read( $self->fh, $size, $DATA_LENGTH_SIZE); $size = unpack($DATA_LENGTH_PACK, $size);
858                                 if ($size) { seek($self->fh, $size, 1); }
859                                 
860                                 ##
861                                 # Read in plain key and return as scalar
862                                 ##
863                                 my $plain_key;
864                                 read( $self->fh, $size, $DATA_LENGTH_SIZE); $size = unpack($DATA_LENGTH_PACK, $size);
865                                 if ($size) { read( $self->fh, $plain_key, $size); }
866                                 
867                                 return $plain_key;
868                         }
869                 } # bucket loop
870                 
871                 $self->{return_next} = 1;
872         } # tag is a bucket list
873         
874         return;
875 }
876
877 sub _get_next_key {
878         ##
879         # Locate next key, given digested previous one
880         ##
881     my $self = _get_self($_[0]);
882         
883         $self->{prev_md5} = $_[1] ? $_[1] : undef;
884         $self->{return_next} = 0;
885         
886         ##
887         # If the previous key was not specifed, start at the top and
888         # return the first one found.
889         ##
890         if (!$self->{prev_md5}) {
891                 $self->{prev_md5} = chr(0) x $HASH_SIZE;
892                 $self->{return_next} = 1;
893         }
894         
895         return $self->_traverse_index( $self->base_offset, 0 );
896 }
897
898 sub lock {
899         ##
900         # If db locking is set, flock() the db file.  If called multiple
901         # times before unlock(), then the same number of unlocks() must
902         # be called before the lock is released.
903         ##
904     my $self = _get_self($_[0]);
905         my $type = $_[1];
906     $type = LOCK_EX unless defined $type;
907         
908         if ($self->root->{locking}) {
909                 if (!$self->root->{locked}) { flock($self->fh, $type); }
910                 $self->root->{locked}++;
911         }
912 }
913
914 sub unlock {
915         ##
916         # If db locking is set, unlock the db file.  See note in lock()
917         # regarding calling lock() multiple times.
918         ##
919     my $self = _get_self($_[0]);
920         
921         if ($self->root->{locking} && $self->root->{locked} > 0) {
922                 $self->root->{locked}--;
923                 if (!$self->root->{locked}) { flock($self->fh, LOCK_UN); }
924         }
925 }
926
927 #XXX These uses of ref() need verified
928 sub _copy_node {
929         ##
930         # Copy single level of keys or elements to new DB handle.
931         # Recurse for nested structures
932         ##
933     my $self = _get_self($_[0]);
934         my $db_temp = $_[1];
935
936         if ($self->type eq TYPE_HASH) {
937                 my $key = $self->first_key();
938                 while ($key) {
939                         my $value = $self->get($key);
940 #XXX This doesn't work with autobless
941                         if (!ref($value)) { $db_temp->{$key} = $value; }
942                         else {
943                                 my $type = $value->type;
944                                 if ($type eq TYPE_HASH) { $db_temp->{$key} = {}; }
945                                 else { $db_temp->{$key} = []; }
946                                 $value->_copy_node( $db_temp->{$key} );
947                         }
948                         $key = $self->next_key($key);
949                 }
950         }
951         else {
952                 my $length = $self->length();
953                 for (my $index = 0; $index < $length; $index++) {
954                         my $value = $self->get($index);
955                         if (!ref($value)) { $db_temp->[$index] = $value; }
956             #XXX NO tests for this code
957                         else {
958                                 my $type = $value->type;
959                                 if ($type eq TYPE_HASH) { $db_temp->[$index] = {}; }
960                                 else { $db_temp->[$index] = []; }
961                                 $value->_copy_node( $db_temp->[$index] );
962                         }
963                 }
964         }
965 }
966
967 sub export {
968         ##
969         # Recursively export into standard Perl hashes and arrays.
970         ##
971     my $self = _get_self($_[0]);
972         
973         my $temp;
974         if ($self->type eq TYPE_HASH) { $temp = {}; }
975         elsif ($self->type eq TYPE_ARRAY) { $temp = []; }
976         
977         $self->lock();
978         $self->_copy_node( $temp );
979         $self->unlock();
980         
981         return $temp;
982 }
983
984 sub import {
985         ##
986         # Recursively import Perl hash/array structure
987         ##
988     #XXX This use of ref() seems to be ok
989         if (!ref($_[0])) { return; } # Perl calls import() on use -- ignore
990         
991     my $self = _get_self($_[0]);
992         my $struct = $_[1];
993         
994     #XXX This use of ref() seems to be ok
995         if (!ref($struct)) {
996                 ##
997                 # struct is not a reference, so just import based on our type
998                 ##
999                 shift @_;
1000                 
1001                 if ($self->type eq TYPE_HASH) { $struct = {@_}; }
1002                 elsif ($self->type eq TYPE_ARRAY) { $struct = [@_]; }
1003         }
1004         
1005     my $r = Scalar::Util::reftype($struct) || '';
1006         if ($r eq "HASH" && $self->type eq TYPE_HASH) {
1007                 foreach my $key (keys %$struct) { $self->put($key, $struct->{$key}); }
1008         }
1009         elsif ($r eq "ARRAY" && $self->type eq TYPE_ARRAY) {
1010                 $self->push( @$struct );
1011         }
1012         else {
1013                 return $self->_throw_error("Cannot import: type mismatch");
1014         }
1015         
1016         return 1;
1017 }
1018
1019 sub optimize {
1020         ##
1021         # Rebuild entire database into new file, then move
1022         # it back on top of original.
1023         ##
1024     my $self = _get_self($_[0]);
1025         if ($self->root->{links} > 1) {
1026                 return $self->_throw_error("Cannot optimize: reference count is greater than 1");
1027         }
1028         
1029         my $db_temp = DBM::Deep->new(
1030                 file => $self->root->{file} . '.tmp',
1031                 type => $self->type
1032         );
1033         if (!$db_temp) {
1034                 return $self->_throw_error("Cannot optimize: failed to open temp file: $!");
1035         }
1036         
1037         $self->lock();
1038         $self->_copy_node( $db_temp );
1039         undef $db_temp;
1040         
1041         ##
1042         # Attempt to copy user, group and permissions over to new file
1043         ##
1044         my @stats = stat($self->fh);
1045         my $perms = $stats[2] & 07777;
1046         my $uid = $stats[4];
1047         my $gid = $stats[5];
1048         chown( $uid, $gid, $self->root->{file} . '.tmp' );
1049         chmod( $perms, $self->root->{file} . '.tmp' );
1050         
1051     # q.v. perlport for more information on this variable
1052     if ( $^O eq 'MSWin32' ) {
1053                 ##
1054                 # Potential race condition when optmizing on Win32 with locking.
1055                 # The Windows filesystem requires that the filehandle be closed 
1056                 # before it is overwritten with rename().  This could be redone
1057                 # with a soft copy.
1058                 ##
1059                 $self->unlock();
1060                 $self->_close();
1061         }
1062         
1063         if (!rename $self->root->{file} . '.tmp', $self->root->{file}) {
1064                 unlink $self->root->{file} . '.tmp';
1065                 $self->unlock();
1066                 return $self->_throw_error("Optimize failed: Cannot copy temp file over original: $!");
1067         }
1068         
1069         $self->unlock();
1070         $self->_close();
1071         $self->_open();
1072         
1073         return 1;
1074 }
1075
1076 sub clone {
1077         ##
1078         # Make copy of object and return
1079         ##
1080     my $self = _get_self($_[0]);
1081         
1082         return DBM::Deep->new(
1083                 type => $self->type,
1084                 base_offset => $self->base_offset,
1085                 root => $self->root
1086         );
1087 }
1088
1089 {
1090     my %is_legal_filter = map {
1091         $_ => ~~1,
1092     } qw(
1093         store_key store_value
1094         fetch_key fetch_value
1095     );
1096
1097     sub set_filter {
1098         ##
1099         # Setup filter function for storing or fetching the key or value
1100         ##
1101         my $self = _get_self($_[0]);
1102         my $type = lc $_[1];
1103         my $func = $_[2] ? $_[2] : undef;
1104         
1105         if ( $is_legal_filter{$type} ) {
1106             $self->root->{"filter_$type"} = $func;
1107             return 1;
1108         }
1109
1110         return;
1111     }
1112 }
1113
1114 ##
1115 # Accessor methods
1116 ##
1117
1118 sub root {
1119         ##
1120         # Get access to the root structure
1121         ##
1122     my $self = _get_self($_[0]);
1123         return $self->{root};
1124 }
1125
1126 sub fh {
1127         ##
1128         # Get access to the raw FileHandle
1129         ##
1130     #XXX It will be useful, though, when we split out HASH and ARRAY
1131     my $self = _get_self($_[0]);
1132         return $self->root->{fh};
1133 }
1134
1135 sub type {
1136         ##
1137         # Get type of current node (TYPE_HASH or TYPE_ARRAY)
1138         ##
1139     my $self = _get_self($_[0]);
1140         return $self->{type};
1141 }
1142
1143 sub base_offset {
1144         ##
1145         # Get base_offset of current node (TYPE_HASH or TYPE_ARRAY)
1146         ##
1147     my $self = _get_self($_[0]);
1148         return $self->{base_offset};
1149 }
1150
1151 sub error {
1152         ##
1153         # Get last error string, or undef if no error
1154         ##
1155         return $_[0]
1156         ? ( _get_self($_[0])->{root}->{error} or undef )
1157         : $@;
1158 }
1159
1160 ##
1161 # Utility methods
1162 ##
1163
1164 sub _throw_error {
1165         ##
1166         # Store error string in self
1167         ##
1168     my $self = _get_self($_[0]);
1169         my $error_text = $_[1];
1170         
1171         $self->root->{error} = $error_text;
1172         
1173         unless ($self->root->{debug}) {
1174         die "DBM::Deep: $error_text\n";
1175     }
1176
1177     warn "DBM::Deep: $error_text\n";
1178         return;
1179 }
1180
1181 sub clear_error {
1182         ##
1183         # Clear error state
1184         ##
1185     my $self = _get_self($_[0]);
1186         
1187         undef $self->root->{error};
1188 }
1189
1190 sub precalc_sizes {
1191         ##
1192         # Precalculate index, bucket and bucket list sizes
1193         ##
1194
1195     #XXX I don't like this ...
1196     set_pack() unless defined $LONG_SIZE;
1197
1198         $INDEX_SIZE = 256 * $LONG_SIZE;
1199         $BUCKET_SIZE = $HASH_SIZE + $LONG_SIZE;
1200         $BUCKET_LIST_SIZE = $MAX_BUCKETS * $BUCKET_SIZE;
1201 }
1202
1203 sub set_pack {
1204         ##
1205         # Set pack/unpack modes (see file header for more)
1206         ##
1207     my ($long_s, $long_p, $data_s, $data_p) = @_;
1208
1209     $LONG_SIZE = $long_s ? $long_s : 4;
1210     $LONG_PACK = $long_p ? $long_p : 'N';
1211
1212     $DATA_LENGTH_SIZE = $data_s ? $data_s : 4;
1213     $DATA_LENGTH_PACK = $data_p ? $data_p : 'N';
1214
1215         precalc_sizes();
1216 }
1217
1218 sub set_digest {
1219         ##
1220         # Set key digest function (default is MD5)
1221         ##
1222     my ($digest_func, $hash_size) = @_;
1223
1224     $DIGEST_FUNC = $digest_func ? $digest_func : \&Digest::MD5::md5;
1225     $HASH_SIZE = $hash_size ? $hash_size : 16;
1226
1227         precalc_sizes();
1228 }
1229
1230 ##
1231 # tie() methods (hashes and arrays)
1232 ##
1233
1234 sub STORE {
1235         ##
1236         # Store single hash key/value or array element in database.
1237         ##
1238     my $self = _get_self($_[0]);
1239         my $key = ($self->root->{filter_store_key} && $self->type eq TYPE_HASH) ? $self->root->{filter_store_key}->($_[1]) : $_[1];
1240     #XXX What is ref() checking here?
1241     #YYY User may be storing a hash, in which case we do not want it run 
1242     #YYY through the filtering system
1243         my $value = ($self->root->{filter_store_value} && !ref($_[2])) ? $self->root->{filter_store_value}->($_[2]) : $_[2];
1244         
1245         my $unpacked_key = $key;
1246         if (($self->type eq TYPE_ARRAY) && ($key =~ /^\d+$/)) { $key = pack($LONG_PACK, $key); }
1247         my $md5 = $DIGEST_FUNC->($key);
1248         
1249         ##
1250         # Make sure file is open
1251         ##
1252         if (!defined($self->fh) && !$self->_open()) {
1253                 return;
1254         }
1255         
1256         ##
1257         # Request exclusive lock for writing
1258         ##
1259         $self->lock( LOCK_EX );
1260
1261         ##
1262         # If locking is enabled, set 'end' parameter again, in case another
1263         # DB instance appended to our file while we were unlocked.
1264         ##
1265         if ($self->root->{locking} || $self->root->{volatile}) {
1266                 $self->root->{end} = (stat($self->fh))[7];
1267         }
1268         
1269         ##
1270         # Locate offset for bucket list using digest index system
1271         ##
1272         my $tag = $self->_load_tag($self->base_offset);
1273         if (!$tag) {
1274                 $tag = $self->_create_tag($self->base_offset, SIG_INDEX, chr(0) x $INDEX_SIZE);
1275         }
1276         
1277         my $ch = 0;
1278         while ($tag->{signature} ne SIG_BLIST) {
1279                 my $num = ord(substr($md5, $ch, 1));
1280                 my $new_tag = $self->_index_lookup($tag, $num);
1281                 if (!$new_tag) {
1282                         my $ref_loc = $tag->{offset} + ($num * $LONG_SIZE);
1283                         seek($self->fh, $ref_loc, 0);
1284                         $self->fh->print( pack($LONG_PACK, $self->root->{end}) );
1285                         
1286                         $tag = $self->_create_tag($self->root->{end}, SIG_BLIST, chr(0) x $BUCKET_LIST_SIZE);
1287                         $tag->{ref_loc} = $ref_loc;
1288                         $tag->{ch} = $ch;
1289                         last;
1290                 }
1291                 else {
1292                         my $ref_loc = $tag->{offset} + ($num * $LONG_SIZE);
1293                         $tag = $new_tag;
1294                         $tag->{ref_loc} = $ref_loc;
1295                         $tag->{ch} = $ch;
1296                 }
1297                 $ch++;
1298         }
1299         
1300         ##
1301         # Add key/value to bucket list
1302         ##
1303         my $result = $self->_add_bucket( $tag, $md5, $key, $value );
1304         
1305         ##
1306         # If this object is an array, and bucket was not a replace, and key is numerical,
1307         # and index is equal or greater than current length, advance length variable.
1308         ##
1309         if (($result == 2) && ($self->type eq TYPE_ARRAY) && ($unpacked_key =~ /^\d+$/) && ($unpacked_key >= $self->FETCHSIZE())) {
1310                 $self->STORESIZE( $unpacked_key + 1 );
1311         }
1312         
1313         $self->unlock();
1314
1315         return $result;
1316 }
1317
1318 sub FETCH {
1319         ##
1320         # Fetch single value or element given plain key or array index
1321         ##
1322     my $self = _get_self($_[0]);
1323
1324     my $key = $_[1];
1325     if ( $self->type eq TYPE_HASH ) {
1326         if ( my $filter = $self->root->{filter_store_key} ) {
1327             $key = $filter->( $key );
1328         }
1329     }
1330     elsif ( $self->type eq TYPE_ARRAY ) { 
1331         if ( $key =~ /^\d+$/ ) {
1332             $key = pack($LONG_PACK, $key);
1333         }
1334     }
1335
1336         my $md5 = $DIGEST_FUNC->($key);
1337
1338         ##
1339         # Make sure file is open
1340         ##
1341         if (!defined($self->fh)) { $self->_open(); }
1342         
1343         ##
1344         # Request shared lock for reading
1345         ##
1346         $self->lock( LOCK_SH );
1347         
1348         my $tag = $self->_find_bucket_list( $md5 );
1349         if (!$tag) {
1350                 $self->unlock();
1351                 return;
1352         }
1353         
1354         ##
1355         # Get value from bucket list
1356         ##
1357         my $result = $self->_get_bucket_value( $tag, $md5 );
1358         
1359         $self->unlock();
1360         
1361     #XXX What is ref() checking here?
1362         return ($result && !ref($result) && $self->root->{filter_fetch_value}) ? $self->root->{filter_fetch_value}->($result) : $result;
1363 }
1364
1365 sub DELETE {
1366         ##
1367         # Delete single key/value pair or element given plain key or array index
1368         ##
1369     my $self = _get_self($_[0]);
1370         my $key = ($self->root->{filter_store_key} && $self->type eq TYPE_HASH) ? $self->root->{filter_store_key}->($_[1]) : $_[1];
1371         
1372         my $unpacked_key = $key;
1373         if (($self->type eq TYPE_ARRAY) && ($key =~ /^\d+$/)) { $key = pack($LONG_PACK, $key); }
1374         my $md5 = $DIGEST_FUNC->($key);
1375
1376         ##
1377         # Make sure file is open
1378         ##
1379         if (!defined($self->fh)) { $self->_open(); }
1380         
1381         ##
1382         # Request exclusive lock for writing
1383         ##
1384         $self->lock( LOCK_EX );
1385         
1386         my $tag = $self->_find_bucket_list( $md5 );
1387         if (!$tag) {
1388                 $self->unlock();
1389                 return;
1390         }
1391         
1392         ##
1393         # Delete bucket
1394         ##
1395         my $result = $self->_delete_bucket( $tag, $md5 );
1396         
1397         ##
1398         # If this object is an array and the key deleted was on the end of the stack,
1399         # decrement the length variable.
1400         ##
1401         if ($result && ($self->type eq TYPE_ARRAY) && ($unpacked_key == $self->FETCHSIZE() - 1)) {
1402                 $self->STORESIZE( $unpacked_key );
1403         }
1404         
1405         $self->unlock();
1406         
1407         return $result;
1408 }
1409
1410 sub EXISTS {
1411         ##
1412         # Check if a single key or element exists given plain key or array index
1413         ##
1414     my $self = _get_self($_[0]);
1415         my $key = ($self->root->{filter_store_key} && $self->type eq TYPE_HASH) ? $self->root->{filter_store_key}->($_[1]) : $_[1];
1416         
1417         if (($self->type eq TYPE_ARRAY) && ($key =~ /^\d+$/)) { $key = pack($LONG_PACK, $key); }
1418         my $md5 = $DIGEST_FUNC->($key);
1419
1420         ##
1421         # Make sure file is open
1422         ##
1423         if (!defined($self->fh)) { $self->_open(); }
1424         
1425         ##
1426         # Request shared lock for reading
1427         ##
1428         $self->lock( LOCK_SH );
1429         
1430         my $tag = $self->_find_bucket_list( $md5 );
1431         
1432         ##
1433         # For some reason, the built-in exists() function returns '' for false
1434         ##
1435         if (!$tag) {
1436                 $self->unlock();
1437                 return '';
1438         }
1439         
1440         ##
1441         # Check if bucket exists and return 1 or ''
1442         ##
1443         my $result = $self->_bucket_exists( $tag, $md5 ) || '';
1444         
1445         $self->unlock();
1446         
1447         return $result;
1448 }
1449
1450 sub CLEAR {
1451         ##
1452         # Clear all keys from hash, or all elements from array.
1453         ##
1454     my $self = _get_self($_[0]);
1455
1456         ##
1457         # Make sure file is open
1458         ##
1459         if (!defined($self->fh)) { $self->_open(); }
1460         
1461         ##
1462         # Request exclusive lock for writing
1463         ##
1464         $self->lock( LOCK_EX );
1465         
1466         seek($self->fh, $self->base_offset, 0);
1467         if ($self->fh->eof()) {
1468                 $self->unlock();
1469                 return;
1470         }
1471         
1472         $self->_create_tag($self->base_offset, $self->type, chr(0) x $INDEX_SIZE);
1473         
1474         $self->unlock();
1475         
1476         return 1;
1477 }
1478
1479 sub FIRSTKEY {
1480         ##
1481         # Locate and return first key (in no particular order)
1482         ##
1483     my $self = _get_self($_[0]);
1484         if ($self->type ne TYPE_HASH) {
1485                 return $self->_throw_error("FIRSTKEY method only supported for hashes");
1486         }
1487
1488         ##
1489         # Make sure file is open
1490         ##
1491         if (!defined($self->fh)) { $self->_open(); }
1492         
1493         ##
1494         # Request shared lock for reading
1495         ##
1496         $self->lock( LOCK_SH );
1497         
1498         my $result = $self->_get_next_key();
1499         
1500         $self->unlock();
1501         
1502         return ($result && $self->root->{filter_fetch_key}) ? $self->root->{filter_fetch_key}->($result) : $result;
1503 }
1504
1505 sub NEXTKEY {
1506         ##
1507         # Return next key (in no particular order), given previous one
1508         ##
1509     my $self = _get_self($_[0]);
1510         if ($self->type ne TYPE_HASH) {
1511                 return $self->_throw_error("NEXTKEY method only supported for hashes");
1512         }
1513         my $prev_key = ($self->root->{filter_store_key} && $self->type eq TYPE_HASH) ? $self->root->{filter_store_key}->($_[1]) : $_[1];
1514         my $prev_md5 = $DIGEST_FUNC->($prev_key);
1515
1516         ##
1517         # Make sure file is open
1518         ##
1519         if (!defined($self->fh)) { $self->_open(); }
1520         
1521         ##
1522         # Request shared lock for reading
1523         ##
1524         $self->lock( LOCK_SH );
1525         
1526         my $result = $self->_get_next_key( $prev_md5 );
1527         
1528         $self->unlock();
1529         
1530         return ($result && $self->root->{filter_fetch_key}) ? $self->root->{filter_fetch_key}->($result) : $result;
1531 }
1532
1533 ##
1534 # The following methods are for arrays only
1535 ##
1536
1537 sub FETCHSIZE {
1538         ##
1539         # Return the length of the array
1540         ##
1541     my $self = _get_self($_[0]);
1542         if ($self->type ne TYPE_ARRAY) {
1543                 return $self->_throw_error("FETCHSIZE method only supported for arrays");
1544         }
1545         
1546         my $SAVE_FILTER = $self->root->{filter_fetch_value};
1547         $self->root->{filter_fetch_value} = undef;
1548         
1549         my $packed_size = $self->FETCH('length');
1550         
1551         $self->root->{filter_fetch_value} = $SAVE_FILTER;
1552         
1553         if ($packed_size) { return int(unpack($LONG_PACK, $packed_size)); }
1554         else { return 0; } 
1555 }
1556
1557 sub STORESIZE {
1558         ##
1559         # Set the length of the array
1560         ##
1561     my $self = _get_self($_[0]);
1562         if ($self->type ne TYPE_ARRAY) {
1563                 return $self->_throw_error("STORESIZE method only supported for arrays");
1564         }
1565         my $new_length = $_[1];
1566         
1567         my $SAVE_FILTER = $self->root->{filter_store_value};
1568         $self->root->{filter_store_value} = undef;
1569         
1570         my $result = $self->STORE('length', pack($LONG_PACK, $new_length));
1571         
1572         $self->root->{filter_store_value} = $SAVE_FILTER;
1573         
1574         return $result;
1575 }
1576
1577 sub POP {
1578         ##
1579         # Remove and return the last element on the array
1580         ##
1581     my $self = _get_self($_[0]);
1582         if ($self->type ne TYPE_ARRAY) {
1583                 return $self->_throw_error("POP method only supported for arrays");
1584         }
1585         my $length = $self->FETCHSIZE();
1586         
1587         if ($length) {
1588                 my $content = $self->FETCH( $length - 1 );
1589                 $self->DELETE( $length - 1 );
1590                 return $content;
1591         }
1592         else {
1593                 return;
1594         }
1595 }
1596
1597 sub PUSH {
1598         ##
1599         # Add new element(s) to the end of the array
1600         ##
1601     my $self = _get_self(shift);
1602         if ($self->type ne TYPE_ARRAY) {
1603                 return $self->_throw_error("PUSH method only supported for arrays");
1604         }
1605         my $length = $self->FETCHSIZE();
1606         
1607         while (my $content = shift @_) {
1608                 $self->STORE( $length, $content );
1609                 $length++;
1610         }
1611 }
1612
1613 sub SHIFT {
1614         ##
1615         # Remove and return first element on the array.
1616         # Shift over remaining elements to take up space.
1617         ##
1618     my $self = _get_self($_[0]);
1619         if ($self->type ne TYPE_ARRAY) {
1620                 return $self->_throw_error("SHIFT method only supported for arrays");
1621         }
1622         my $length = $self->FETCHSIZE();
1623         
1624         if ($length) {
1625                 my $content = $self->FETCH( 0 );
1626                 
1627                 ##
1628                 # Shift elements over and remove last one.
1629                 ##
1630                 for (my $i = 0; $i < $length - 1; $i++) {
1631                         $self->STORE( $i, $self->FETCH($i + 1) );
1632                 }
1633                 $self->DELETE( $length - 1 );
1634                 
1635                 return $content;
1636         }
1637         else {
1638                 return;
1639         }
1640 }
1641
1642 sub UNSHIFT {
1643         ##
1644         # Insert new element(s) at beginning of array.
1645         # Shift over other elements to make space.
1646         ##
1647     my $self = _get_self($_[0]);shift @_;
1648         if ($self->type ne TYPE_ARRAY) {
1649                 return $self->_throw_error("UNSHIFT method only supported for arrays");
1650         }
1651         my @new_elements = @_;
1652         my $length = $self->FETCHSIZE();
1653         my $new_size = scalar @new_elements;
1654         
1655         if ($length) {
1656                 for (my $i = $length - 1; $i >= 0; $i--) {
1657                         $self->STORE( $i + $new_size, $self->FETCH($i) );
1658                 }
1659         }
1660         
1661         for (my $i = 0; $i < $new_size; $i++) {
1662                 $self->STORE( $i, $new_elements[$i] );
1663         }
1664 }
1665
1666 sub SPLICE {
1667         ##
1668         # Splices section of array with optional new section.
1669         # Returns deleted section, or last element deleted in scalar context.
1670         ##
1671     my $self = _get_self($_[0]);shift @_;
1672         if ($self->type ne TYPE_ARRAY) {
1673                 return $self->_throw_error("SPLICE method only supported for arrays");
1674         }
1675         my $length = $self->FETCHSIZE();
1676         
1677         ##
1678         # Calculate offset and length of splice
1679         ##
1680         my $offset = shift || 0;
1681         if ($offset < 0) { $offset += $length; }
1682         
1683         my $splice_length;
1684         if (scalar @_) { $splice_length = shift; }
1685         else { $splice_length = $length - $offset; }
1686         if ($splice_length < 0) { $splice_length += ($length - $offset); }
1687         
1688         ##
1689         # Setup array with new elements, and copy out old elements for return
1690         ##
1691         my @new_elements = @_;
1692         my $new_size = scalar @new_elements;
1693         
1694         my @old_elements = ();
1695         for (my $i = $offset; $i < $offset + $splice_length; $i++) {
1696                 push @old_elements, $self->FETCH( $i );
1697         }
1698         
1699         ##
1700         # Adjust array length, and shift elements to accomodate new section.
1701         ##
1702     if ( $new_size != $splice_length ) {
1703         if ($new_size > $splice_length) {
1704             for (my $i = $length - 1; $i >= $offset + $splice_length; $i--) {
1705                 $self->STORE( $i + ($new_size - $splice_length), $self->FETCH($i) );
1706             }
1707         }
1708         else {
1709             for (my $i = $offset + $splice_length; $i < $length; $i++) {
1710                 $self->STORE( $i + ($new_size - $splice_length), $self->FETCH($i) );
1711             }
1712             for (my $i = 0; $i < $splice_length - $new_size; $i++) {
1713                 $self->DELETE( $length - 1 );
1714                 $length--;
1715             }
1716         }
1717         }
1718         
1719         ##
1720         # Insert new elements into array
1721         ##
1722         for (my $i = $offset; $i < $offset + $new_size; $i++) {
1723                 $self->STORE( $i, shift @new_elements );
1724         }
1725         
1726         ##
1727         # Return deleted section, or last element in scalar context.
1728         ##
1729         return wantarray ? @old_elements : $old_elements[-1];
1730 }
1731
1732 #XXX We don't need to define it.
1733 #XXX It will be useful, though, when we split out HASH and ARRAY
1734 #sub EXTEND {
1735         ##
1736         # Perl will call EXTEND() when the array is likely to grow.
1737         # We don't care, but include it for compatibility.
1738         ##
1739 #}
1740
1741 ##
1742 # Public method aliases
1743 ##
1744 *put = *store = *STORE;
1745 *get = *fetch = *FETCH;
1746 *delete = *DELETE;
1747 *exists = *EXISTS;
1748 *clear = *CLEAR;
1749 *first_key = *FIRSTKEY;
1750 *next_key = *NEXTKEY;
1751 *length = *FETCHSIZE;
1752 *pop = *POP;
1753 *push = *PUSH;
1754 *shift = *SHIFT;
1755 *unshift = *UNSHIFT;
1756 *splice = *SPLICE;
1757
1758 1;
1759
1760 __END__
1761
1762 =head1 NAME
1763
1764 DBM::Deep - A pure perl multi-level hash/array DBM
1765
1766 =head1 SYNOPSIS
1767
1768   use DBM::Deep;
1769   my $db = DBM::Deep->new( "foo.db" );
1770   
1771   $db->{key} = 'value'; # tie() style
1772   print $db->{key};
1773   
1774   $db->put('key', 'value'); # OO style
1775   print $db->get('key');
1776   
1777   # true multi-level support
1778   $db->{my_complex} = [
1779         'hello', { perl => 'rules' }, 
1780         42, 99 ];
1781
1782 =head1 DESCRIPTION
1783
1784 A unique flat-file database module, written in pure perl.  True 
1785 multi-level hash/array support (unlike MLDBM, which is faked), hybrid 
1786 OO / tie() interface, cross-platform FTPable files, and quite fast.  Can 
1787 handle millions of keys and unlimited hash levels without significant 
1788 slow-down.  Written from the ground-up in pure perl -- this is NOT a 
1789 wrapper around a C-based DBM.  Out-of-the-box compatibility with Unix, 
1790 Mac OS X and Windows.
1791
1792 =head1 INSTALLATION
1793
1794 Hopefully you are using CPAN's excellent Perl module, which will download
1795 and install the module for you.  If not, get the tarball, and run these 
1796 commands:
1797
1798         tar zxf DBM-Deep-*
1799         cd DBM-Deep-*
1800         perl Makefile.PL
1801         make
1802         make test
1803         make install
1804
1805 =head1 SETUP
1806
1807 Construction can be done OO-style (which is the recommended way), or using 
1808 Perl's tie() function.  Both are examined here.
1809
1810 =head2 OO CONSTRUCTION
1811
1812 The recommended way to construct a DBM::Deep object is to use the new()
1813 method, which gets you a blessed, tied hash or array reference.
1814
1815         my $db = DBM::Deep->new( "foo.db" );
1816
1817 This opens a new database handle, mapped to the file "foo.db".  If this
1818 file does not exist, it will automatically be created.  DB files are 
1819 opened in "r+" (read/write) mode, and the type of object returned is a
1820 hash, unless otherwise specified (see L<OPTIONS> below).
1821
1822
1823
1824 You can pass a number of options to the constructor to specify things like
1825 locking, autoflush, etc.  This is done by passing an inline hash:
1826
1827         my $db = DBM::Deep->new(
1828                 file => "foo.db",
1829                 locking => 1,
1830                 autoflush => 1
1831         );
1832
1833 Notice that the filename is now specified I<inside> the hash with
1834 the "file" parameter, as opposed to being the sole argument to the 
1835 constructor.  This is required if any options are specified.
1836 See L<OPTIONS> below for the complete list.
1837
1838
1839
1840 You can also start with an array instead of a hash.  For this, you must
1841 specify the C<type> parameter:
1842
1843         my $db = DBM::Deep->new(
1844                 file => "foo.db",
1845                 type => DBM::Deep->TYPE_ARRAY
1846         );
1847
1848 B<Note:> Specifing the C<type> parameter only takes effect when beginning
1849 a new DB file.  If you create a DBM::Deep object with an existing file, the
1850 C<type> will be loaded from the file header, and ignored if it is passed
1851 to the constructor.
1852
1853 =head2 TIE CONSTRUCTION
1854
1855 Alternatively, you can create a DBM::Deep handle by using Perl's built-in
1856 tie() function.  This is not ideal, because you get only a basic, tied hash 
1857 (or array) which is not blessed, so you can't call any functions on it.
1858
1859         my %hash;
1860         tie %hash, "DBM::Deep", "foo.db";
1861         
1862         my @array;
1863         tie @array, "DBM::Deep", "bar.db";
1864
1865 As with the OO constructor, you can replace the DB filename parameter with
1866 a hash containing one or more options (see L<OPTIONS> just below for the
1867 complete list).
1868
1869         tie %hash, "DBM::Deep", {
1870                 file => "foo.db",
1871                 locking => 1,
1872                 autoflush => 1
1873         };
1874
1875 =head2 OPTIONS
1876
1877 There are a number of options that can be passed in when constructing your
1878 DBM::Deep objects.  These apply to both the OO- and tie- based approaches.
1879
1880 =over
1881
1882 =item * file
1883
1884 Filename of the DB file to link the handle to.  You can pass a full absolute
1885 filesystem path, partial path, or a plain filename if the file is in the 
1886 current working directory.  This is a required parameter.
1887
1888 =item * mode
1889
1890 File open mode (read-only, read-write, etc.) string passed to Perl's FileHandle
1891 module.  This is an optional parameter, and defaults to "r+" (read/write).
1892 B<Note:> If the default (r+) mode is selected, the file will also be auto-
1893 created if it doesn't exist.
1894
1895 =item * type
1896
1897 This parameter specifies what type of object to create, a hash or array.  Use
1898 one of these two constants: C<DBM::Deep-E<gt>TYPE_HASH> or C<DBM::Deep-E<gt>TYPE_ARRAY>.
1899 This only takes effect when beginning a new file.  This is an optional 
1900 parameter, and defaults to C<DBM::Deep-E<gt>TYPE_HASH>.
1901
1902 =item * locking
1903
1904 Specifies whether locking is to be enabled.  DBM::Deep uses Perl's Fnctl flock()
1905 function to lock the database in exclusive mode for writes, and shared mode for
1906 reads.  Pass any true value to enable.  This affects the base DB handle I<and 
1907 any child hashes or arrays> that use the same DB file.  This is an optional 
1908 parameter, and defaults to 0 (disabled).  See L<LOCKING> below for more.
1909
1910 =item * autoflush
1911
1912 Specifies whether autoflush is to be enabled on the underlying FileHandle.  
1913 This obviously slows down write operations, but is required if you may have 
1914 multiple processes accessing the same DB file (also consider enable I<locking> 
1915 or at least I<volatile>).  Pass any true value to enable.  This is an optional 
1916 parameter, and defaults to 0 (disabled).
1917
1918 =item * volatile
1919
1920 If I<volatile> mode is enabled, DBM::Deep will stat() the DB file before each
1921 STORE() operation.  This is required if an outside force may change the size of
1922 the file between transactions.  Locking also implicitly enables volatile.  This
1923 is useful if you want to use a different locking system or write your own.  Pass
1924 any true value to enable.  This is an optional parameter, and defaults to 0 
1925 (disabled).
1926
1927 =item * autobless
1928
1929 If I<autobless> mode is enabled, DBM::Deep will preserve blessed hashes, and
1930 restore them when fetched.  This is an B<experimental> feature, and does have
1931 side-effects.  Basically, when hashes are re-blessed into their original
1932 classes, they are no longer blessed into the DBM::Deep class!  So you won't be
1933 able to call any DBM::Deep methods on them.  You have been warned.
1934 This is an optional parameter, and defaults to 0 (disabled).
1935
1936 =item * filter_*
1937
1938 See L<FILTERS> below.
1939
1940 =item * debug
1941
1942 Setting I<debug> mode will make all errors non-fatal, dump them out to
1943 STDERR, and continue on.  This is for debugging purposes only, and probably
1944 not what you want.  This is an optional parameter, and defaults to 0 (disabled).
1945
1946 =item * fh
1947
1948 Instead of passing a file path, you can instead pass a handle to an pre-opened
1949 filehandle.  Note: Beware of using the magick *DATA handle, as this actually 
1950 contains your entire Perl script, as well as the data following the __DATA__
1951 marker.  This will not work, because DBM::Deep uses absolute seek()s into the
1952 file.  Instead, consider reading *DATA into an IO::Scalar handle, then passing
1953 in that.
1954
1955 =back
1956
1957 =head1 TIE INTERFACE
1958
1959 With DBM::Deep you can access your databases using Perl's standard hash/array
1960 syntax.  Because all DBM::Deep objects are I<tied> to hashes or arrays, you can treat
1961 them as such.  DBM::Deep will intercept all reads/writes and direct them to the right
1962 place -- the DB file.  This has nothing to do with the L<TIE CONSTRUCTION> 
1963 section above.  This simply tells you how to use DBM::Deep using regular hashes 
1964 and arrays, rather than calling functions like C<get()> and C<put()> (although those 
1965 work too).  It is entirely up to you how to want to access your databases.
1966
1967 =head2 HASHES
1968
1969 You can treat any DBM::Deep object like a normal Perl hash reference.  Add keys,
1970 or even nested hashes (or arrays) using standard Perl syntax:
1971
1972         my $db = DBM::Deep->new( "foo.db" );
1973         
1974         $db->{mykey} = "myvalue";
1975         $db->{myhash} = {};
1976         $db->{myhash}->{subkey} = "subvalue";
1977
1978         print $db->{myhash}->{subkey} . "\n";
1979
1980 You can even step through hash keys using the normal Perl C<keys()> function:
1981
1982         foreach my $key (keys %$db) {
1983                 print "$key: " . $db->{$key} . "\n";
1984         }
1985
1986 Remember that Perl's C<keys()> function extracts I<every> key from the hash and
1987 pushes them onto an array, all before the loop even begins.  If you have an 
1988 extra large hash, this may exhaust Perl's memory.  Instead, consider using 
1989 Perl's C<each()> function, which pulls keys/values one at a time, using very 
1990 little memory:
1991
1992         while (my ($key, $value) = each %$db) {
1993                 print "$key: $value\n";
1994         }
1995
1996 Please note that when using C<each()>, you should always pass a direct
1997 hash reference, not a lookup.  Meaning, you should B<never> do this:
1998
1999         # NEVER DO THIS
2000         while (my ($key, $value) = each %{$db->{foo}}) { # BAD
2001
2002 This causes an infinite loop, because for each iteration, Perl is calling
2003 FETCH() on the $db handle, resulting in a "new" hash for foo every time, so
2004 it effectively keeps returning the first key over and over again. Instead, 
2005 assign a temporary variable to C<$db->{foo}>, then pass that to each().
2006
2007 =head2 ARRAYS
2008
2009 As with hashes, you can treat any DBM::Deep object like a normal Perl array
2010 reference.  This includes inserting, removing and manipulating elements, 
2011 and the C<push()>, C<pop()>, C<shift()>, C<unshift()> and C<splice()> functions.
2012 The object must have first been created using type C<DBM::Deep-E<gt>TYPE_ARRAY>, 
2013 or simply be a nested array reference inside a hash.  Example:
2014
2015         my $db = DBM::Deep->new(
2016                 file => "foo-array.db",
2017                 type => DBM::Deep->TYPE_ARRAY
2018         );
2019         
2020         $db->[0] = "foo";
2021         push @$db, "bar", "baz";
2022         unshift @$db, "bah";
2023         
2024         my $last_elem = pop @$db; # baz
2025         my $first_elem = shift @$db; # bah
2026         my $second_elem = $db->[1]; # bar
2027         
2028         my $num_elements = scalar @$db;
2029
2030 =head1 OO INTERFACE
2031
2032 In addition to the I<tie()> interface, you can also use a standard OO interface
2033 to manipulate all aspects of DBM::Deep databases.  Each type of object (hash or
2034 array) has its own methods, but both types share the following common methods: 
2035 C<put()>, C<get()>, C<exists()>, C<delete()> and C<clear()>.
2036
2037 =over
2038
2039 =item * put()
2040
2041 Stores a new hash key/value pair, or sets an array element value.  Takes two
2042 arguments, the hash key or array index, and the new value.  The value can be
2043 a scalar, hash ref or array ref.  Returns true on success, false on failure.
2044
2045         $db->put("foo", "bar"); # for hashes
2046         $db->put(1, "bar"); # for arrays
2047
2048 =item * get()
2049
2050 Fetches the value of a hash key or array element.  Takes one argument: the hash
2051 key or array index.  Returns a scalar, hash ref or array ref, depending on the 
2052 data type stored.
2053
2054         my $value = $db->get("foo"); # for hashes
2055         my $value = $db->get(1); # for arrays
2056
2057 =item * exists()
2058
2059 Checks if a hash key or array index exists.  Takes one argument: the hash key 
2060 or array index.  Returns true if it exists, false if not.
2061
2062         if ($db->exists("foo")) { print "yay!\n"; } # for hashes
2063         if ($db->exists(1)) { print "yay!\n"; } # for arrays
2064
2065 =item * delete()
2066
2067 Deletes one hash key/value pair or array element.  Takes one argument: the hash
2068 key or array index.  Returns true on success, false if not found.  For arrays,
2069 the remaining elements located after the deleted element are NOT moved over.
2070 The deleted element is essentially just undefined, which is exactly how Perl's
2071 internal arrays work.  Please note that the space occupied by the deleted 
2072 key/value or element is B<not> reused again -- see L<UNUSED SPACE RECOVERY> 
2073 below for details and workarounds.
2074
2075         $db->delete("foo"); # for hashes
2076         $db->delete(1); # for arrays
2077
2078 =item * clear()
2079
2080 Deletes B<all> hash keys or array elements.  Takes no arguments.  No return 
2081 value.  Please note that the space occupied by the deleted keys/values or 
2082 elements is B<not> reused again -- see L<UNUSED SPACE RECOVERY> below for 
2083 details and workarounds.
2084
2085         $db->clear(); # hashes or arrays
2086
2087 =back
2088
2089 =head2 HASHES
2090
2091 For hashes, DBM::Deep supports all the common methods described above, and the 
2092 following additional methods: C<first_key()> and C<next_key()>.
2093
2094 =over
2095
2096 =item * first_key()
2097
2098 Returns the "first" key in the hash.  As with built-in Perl hashes, keys are 
2099 fetched in an undefined order (which appears random).  Takes no arguments, 
2100 returns the key as a scalar value.
2101
2102         my $key = $db->first_key();
2103
2104 =item * next_key()
2105
2106 Returns the "next" key in the hash, given the previous one as the sole argument.
2107 Returns undef if there are no more keys to be fetched.
2108
2109         $key = $db->next_key($key);
2110
2111 =back
2112
2113 Here are some examples of using hashes:
2114
2115         my $db = DBM::Deep->new( "foo.db" );
2116         
2117         $db->put("foo", "bar");
2118         print "foo: " . $db->get("foo") . "\n";
2119         
2120         $db->put("baz", {}); # new child hash ref
2121         $db->get("baz")->put("buz", "biz");
2122         print "buz: " . $db->get("baz")->get("buz") . "\n";
2123         
2124         my $key = $db->first_key();
2125         while ($key) {
2126                 print "$key: " . $db->get($key) . "\n";
2127                 $key = $db->next_key($key);     
2128         }
2129         
2130         if ($db->exists("foo")) { $db->delete("foo"); }
2131
2132 =head2 ARRAYS
2133
2134 For arrays, DBM::Deep supports all the common methods described above, and the 
2135 following additional methods: C<length()>, C<push()>, C<pop()>, C<shift()>, 
2136 C<unshift()> and C<splice()>.
2137
2138 =over
2139
2140 =item * length()
2141
2142 Returns the number of elements in the array.  Takes no arguments.
2143
2144         my $len = $db->length();
2145
2146 =item * push()
2147
2148 Adds one or more elements onto the end of the array.  Accepts scalars, hash 
2149 refs or array refs.  No return value.
2150
2151         $db->push("foo", "bar", {});
2152
2153 =item * pop()
2154
2155 Fetches the last element in the array, and deletes it.  Takes no arguments.
2156 Returns undef if array is empty.  Returns the element value.
2157
2158         my $elem = $db->pop();
2159
2160 =item * shift()
2161
2162 Fetches the first element in the array, deletes it, then shifts all the 
2163 remaining elements over to take up the space.  Returns the element value.  This 
2164 method is not recommended with large arrays -- see L<LARGE ARRAYS> below for 
2165 details.
2166
2167         my $elem = $db->shift();
2168
2169 =item * unshift()
2170
2171 Inserts one or more elements onto the beginning of the array, shifting all 
2172 existing elements over to make room.  Accepts scalars, hash refs or array refs.  
2173 No return value.  This method is not recommended with large arrays -- see 
2174 <LARGE ARRAYS> below for details.
2175
2176         $db->unshift("foo", "bar", {});
2177
2178 =item * splice()
2179
2180 Performs exactly like Perl's built-in function of the same name.  See L<perldoc 
2181 -f splice> for usage -- it is too complicated to document here.  This method is
2182 not recommended with large arrays -- see L<LARGE ARRAYS> below for details.
2183
2184 =back
2185
2186 Here are some examples of using arrays:
2187
2188         my $db = DBM::Deep->new(
2189                 file => "foo.db",
2190                 type => DBM::Deep->TYPE_ARRAY
2191         );
2192         
2193         $db->push("bar", "baz");
2194         $db->unshift("foo");
2195         $db->put(3, "buz");
2196         
2197         my $len = $db->length();
2198         print "length: $len\n"; # 4
2199         
2200         for (my $k=0; $k<$len; $k++) {
2201                 print "$k: " . $db->get($k) . "\n";
2202         }
2203         
2204         $db->splice(1, 2, "biz", "baf");
2205         
2206         while (my $elem = shift @$db) {
2207                 print "shifted: $elem\n";
2208         }
2209
2210 =head1 LOCKING
2211
2212 Enable automatic file locking by passing a true value to the C<locking> 
2213 parameter when constructing your DBM::Deep object (see L<SETUP> above).
2214
2215         my $db = DBM::Deep->new(
2216                 file => "foo.db",
2217                 locking => 1
2218         );
2219
2220 This causes DBM::Deep to C<flock()> the underlying FileHandle object with exclusive 
2221 mode for writes, and shared mode for reads.  This is required if you have 
2222 multiple processes accessing the same database file, to avoid file corruption.  
2223 Please note that C<flock()> does NOT work for files over NFS.  See L<DB OVER 
2224 NFS> below for more.
2225
2226 =head2 EXPLICIT LOCKING
2227
2228 You can explicitly lock a database, so it remains locked for multiple 
2229 transactions.  This is done by calling the C<lock()> method, and passing an 
2230 optional lock mode argument (defaults to exclusive mode).  This is particularly 
2231 useful for things like counters, where the current value needs to be fetched, 
2232 then incremented, then stored again.
2233
2234         $db->lock();
2235         my $counter = $db->get("counter");
2236         $counter++;
2237         $db->put("counter", $counter);
2238         $db->unlock();
2239
2240         # or...
2241         
2242         $db->lock();
2243         $db->{counter}++;
2244         $db->unlock();
2245
2246 You can pass C<lock()> an optional argument, which specifies which mode to use
2247 (exclusive or shared).  Use one of these two constants: C<DBM::Deep-E<gt>LOCK_EX> 
2248 or C<DBM::Deep-E<gt>LOCK_SH>.  These are passed directly to C<flock()>, and are the 
2249 same as the constants defined in Perl's C<Fcntl> module.
2250
2251         $db->lock( DBM::Deep->LOCK_SH );
2252         # something here
2253         $db->unlock();
2254
2255 If you want to implement your own file locking scheme, be sure to create your
2256 DBM::Deep objects setting the C<volatile> option to true.  This hints to DBM::Deep
2257 that the DB file may change between transactions.  See L<LOW-LEVEL ACCESS> 
2258 below for more.
2259
2260 =head1 IMPORTING/EXPORTING
2261
2262 You can import existing complex structures by calling the C<import()> method,
2263 and export an entire database into an in-memory structure using the C<export()>
2264 method.  Both are examined here.
2265
2266 =head2 IMPORTING
2267
2268 Say you have an existing hash with nested hashes/arrays inside it.  Instead of
2269 walking the structure and adding keys/elements to the database as you go, 
2270 simply pass a reference to the C<import()> method.  This recursively adds 
2271 everything to an existing DBM::Deep object for you.  Here is an example:
2272
2273         my $struct = {
2274                 key1 => "value1",
2275                 key2 => "value2",
2276                 array1 => [ "elem0", "elem1", "elem2" ],
2277                 hash1 => {
2278                         subkey1 => "subvalue1",
2279                         subkey2 => "subvalue2"
2280                 }
2281         };
2282         
2283         my $db = DBM::Deep->new( "foo.db" );
2284         $db->import( $struct );
2285         
2286         print $db->{key1} . "\n"; # prints "value1"
2287
2288 This recursively imports the entire C<$struct> object into C<$db>, including 
2289 all nested hashes and arrays.  If the DBM::Deep object contains exsiting data,
2290 keys are merged with the existing ones, replacing if they already exist.  
2291 The C<import()> method can be called on any database level (not just the base 
2292 level), and works with both hash and array DB types.
2293
2294
2295
2296 B<Note:> Make sure your existing structure has no circular references in it.
2297 These will cause an infinite loop when importing.
2298
2299 =head2 EXPORTING
2300
2301 Calling the C<export()> method on an existing DBM::Deep object will return 
2302 a reference to a new in-memory copy of the database.  The export is done 
2303 recursively, so all nested hashes/arrays are all exported to standard Perl
2304 objects.  Here is an example:
2305
2306         my $db = DBM::Deep->new( "foo.db" );
2307         
2308         $db->{key1} = "value1";
2309         $db->{key2} = "value2";
2310         $db->{hash1} = {};
2311         $db->{hash1}->{subkey1} = "subvalue1";
2312         $db->{hash1}->{subkey2} = "subvalue2";
2313         
2314         my $struct = $db->export();
2315         
2316         print $struct->{key1} . "\n"; # prints "value1"
2317
2318 This makes a complete copy of the database in memory, and returns a reference
2319 to it.  The C<export()> method can be called on any database level (not just 
2320 the base level), and works with both hash and array DB types.  Be careful of 
2321 large databases -- you can store a lot more data in a DBM::Deep object than an 
2322 in-memory Perl structure.
2323
2324
2325
2326 B<Note:> Make sure your database has no circular references in it.
2327 These will cause an infinite loop when exporting.
2328
2329 =head1 FILTERS
2330
2331 DBM::Deep has a number of hooks where you can specify your own Perl function
2332 to perform filtering on incoming or outgoing data.  This is a perfect
2333 way to extend the engine, and implement things like real-time compression or
2334 encryption.  Filtering applies to the base DB level, and all child hashes / 
2335 arrays.  Filter hooks can be specified when your DBM::Deep object is first 
2336 constructed, or by calling the C<set_filter()> method at any time.  There are 
2337 four available filter hooks, described below:
2338
2339 =over
2340
2341 =item * filter_store_key
2342
2343 This filter is called whenever a hash key is stored.  It 
2344 is passed the incoming key, and expected to return a transformed key.
2345
2346 =item * filter_store_value
2347
2348 This filter is called whenever a hash key or array element is stored.  It 
2349 is passed the incoming value, and expected to return a transformed value.
2350
2351 =item * filter_fetch_key
2352
2353 This filter is called whenever a hash key is fetched (i.e. via 
2354 C<first_key()> or C<next_key()>).  It is passed the transformed key,
2355 and expected to return the plain key.
2356
2357 =item * filter_fetch_value
2358
2359 This filter is called whenever a hash key or array element is fetched.  
2360 It is passed the transformed value, and expected to return the plain value.
2361
2362 =back
2363
2364 Here are the two ways to setup a filter hook:
2365
2366         my $db = DBM::Deep->new(
2367                 file => "foo.db",
2368                 filter_store_value => \&my_filter_store,
2369                 filter_fetch_value => \&my_filter_fetch
2370         );
2371         
2372         # or...
2373         
2374         $db->set_filter( "filter_store_value", \&my_filter_store );
2375         $db->set_filter( "filter_fetch_value", \&my_filter_fetch );
2376
2377 Your filter function will be called only when dealing with SCALAR keys or
2378 values.  When nested hashes and arrays are being stored/fetched, filtering
2379 is bypassed.  Filters are called as static functions, passed a single SCALAR 
2380 argument, and expected to return a single SCALAR value.  If you want to
2381 remove a filter, set the function reference to C<undef>:
2382
2383         $db->set_filter( "filter_store_value", undef );
2384
2385 =head2 REAL-TIME ENCRYPTION EXAMPLE
2386
2387 Here is a working example that uses the I<Crypt::Blowfish> module to 
2388 do real-time encryption / decryption of keys & values with DBM::Deep Filters.
2389 Please visit L<http://search.cpan.org/search?module=Crypt::Blowfish> for more 
2390 on I<Crypt::Blowfish>.  You'll also need the I<Crypt::CBC> module.
2391
2392         use DBM::Deep;
2393         use Crypt::Blowfish;
2394         use Crypt::CBC;
2395         
2396         my $cipher = Crypt::CBC->new({
2397                 'key'             => 'my secret key',
2398                 'cipher'          => 'Blowfish',
2399                 'iv'              => '$KJh#(}q',
2400                 'regenerate_key'  => 0,
2401                 'padding'         => 'space',
2402                 'prepend_iv'      => 0
2403         });
2404         
2405         my $db = DBM::Deep->new(
2406                 file => "foo-encrypt.db",
2407                 filter_store_key => \&my_encrypt,
2408                 filter_store_value => \&my_encrypt,
2409                 filter_fetch_key => \&my_decrypt,
2410                 filter_fetch_value => \&my_decrypt,
2411         );
2412         
2413         $db->{key1} = "value1";
2414         $db->{key2} = "value2";
2415         print "key1: " . $db->{key1} . "\n";
2416         print "key2: " . $db->{key2} . "\n";
2417         
2418         undef $db;
2419         exit;
2420         
2421         sub my_encrypt {
2422                 return $cipher->encrypt( $_[0] );
2423         }
2424         sub my_decrypt {
2425                 return $cipher->decrypt( $_[0] );
2426         }
2427
2428 =head2 REAL-TIME COMPRESSION EXAMPLE
2429
2430 Here is a working example that uses the I<Compress::Zlib> module to do real-time
2431 compression / decompression of keys & values with DBM::Deep Filters.
2432 Please visit L<http://search.cpan.org/search?module=Compress::Zlib> for 
2433 more on I<Compress::Zlib>.
2434
2435         use DBM::Deep;
2436         use Compress::Zlib;
2437         
2438         my $db = DBM::Deep->new(
2439                 file => "foo-compress.db",
2440                 filter_store_key => \&my_compress,
2441                 filter_store_value => \&my_compress,
2442                 filter_fetch_key => \&my_decompress,
2443                 filter_fetch_value => \&my_decompress,
2444         );
2445         
2446         $db->{key1} = "value1";
2447         $db->{key2} = "value2";
2448         print "key1: " . $db->{key1} . "\n";
2449         print "key2: " . $db->{key2} . "\n";
2450         
2451         undef $db;
2452         exit;
2453         
2454         sub my_compress {
2455                 return Compress::Zlib::memGzip( $_[0] ) ;
2456         }
2457         sub my_decompress {
2458                 return Compress::Zlib::memGunzip( $_[0] ) ;
2459         }
2460
2461 B<Note:> Filtering of keys only applies to hashes.  Array "keys" are
2462 actually numerical index numbers, and are not filtered.
2463
2464 =head1 ERROR HANDLING
2465
2466 Most DBM::Deep methods return a true value for success, and call die() on
2467 failure.  You can wrap calls in an eval block to catch the die.  Also, the 
2468 actual error message is stored in an internal scalar, which can be fetched by 
2469 calling the C<error()> method.
2470
2471         my $db = DBM::Deep->new( "foo.db" ); # create hash
2472         eval { $db->push("foo"); }; # ILLEGAL -- push is array-only call
2473         
2474         print $db->error(); # prints error message
2475
2476 You can then call C<clear_error()> to clear the current error state.
2477
2478         $db->clear_error();
2479
2480 If you set the C<debug> option to true when creating your DBM::Deep object,
2481 all errors are considered NON-FATAL, and dumped to STDERR.  This is only
2482 for debugging purposes.
2483
2484 =head1 LARGEFILE SUPPORT
2485
2486 If you have a 64-bit system, and your Perl is compiled with both LARGEFILE
2487 and 64-bit support, you I<may> be able to create databases larger than 2 GB.
2488 DBM::Deep by default uses 32-bit file offset tags, but these can be changed
2489 by calling the static C<set_pack()> method before you do anything else.
2490
2491         DBM::Deep::set_pack(8, 'Q');
2492
2493 This tells DBM::Deep to pack all file offsets with 8-byte (64-bit) quad words 
2494 instead of 32-bit longs.  After setting these values your DB files have a 
2495 theoretical maximum size of 16 XB (exabytes).
2496
2497
2498
2499 B<Note:> Changing these values will B<NOT> work for existing database files.
2500 Only change this for new files, and make sure it stays set consistently 
2501 throughout the file's life.  If you do set these values, you can no longer 
2502 access 32-bit DB files.  You can, however, call C<set_pack(4, 'N')> to change 
2503 back to 32-bit mode.
2504
2505
2506
2507 B<Note:> I have not personally tested files > 2 GB -- all my systems have 
2508 only a 32-bit Perl.  However, I have received user reports that this does 
2509 indeed work!
2510
2511 =head1 LOW-LEVEL ACCESS
2512
2513 If you require low-level access to the underlying FileHandle that DBM::Deep uses,
2514 you can call the C<fh()> method, which returns the handle:
2515
2516         my $fh = $db->fh();
2517
2518 This method can be called on the root level of the datbase, or any child
2519 hashes or arrays.  All levels share a I<root> structure, which contains things
2520 like the FileHandle, a reference counter, and all your options you specified
2521 when you created the object.  You can get access to this root structure by 
2522 calling the C<root()> method.
2523
2524         my $root = $db->root();
2525
2526 This is useful for changing options after the object has already been created,
2527 such as enabling/disabling locking, volatile or debug modes.  You can also
2528 store your own temporary user data in this structure (be wary of name 
2529 collision), which is then accessible from any child hash or array.
2530
2531 =head1 CUSTOM DIGEST ALGORITHM
2532
2533 DBM::Deep by default uses the I<Message Digest 5> (MD5) algorithm for hashing
2534 keys.  However you can override this, and use another algorithm (such as SHA-256)
2535 or even write your own.  But please note that DBM::Deep currently expects zero 
2536 collisions, so your algorithm has to be I<perfect>, so to speak.
2537 Collision detection may be introduced in a later version.
2538
2539
2540
2541 You can specify a custom digest algorithm by calling the static C<set_digest()> 
2542 function, passing a reference to a subroutine, and the length of the algorithm's 
2543 hashes (in bytes).  This is a global static function, which affects ALL DBM::Deep 
2544 objects.  Here is a working example that uses a 256-bit hash from the 
2545 I<Digest::SHA256> module.  Please see 
2546 L<http://search.cpan.org/search?module=Digest::SHA256> for more.
2547
2548         use DBM::Deep;
2549         use Digest::SHA256;
2550         
2551         my $context = Digest::SHA256::new(256);
2552         
2553         DBM::Deep::set_digest( \&my_digest, 32 );
2554         
2555         my $db = DBM::Deep->new( "foo-sha.db" );
2556         
2557         $db->{key1} = "value1";
2558         $db->{key2} = "value2";
2559         print "key1: " . $db->{key1} . "\n";
2560         print "key2: " . $db->{key2} . "\n";
2561         
2562         undef $db;
2563         exit;
2564         
2565         sub my_digest {
2566                 return substr( $context->hash($_[0]), 0, 32 );
2567         }
2568
2569 B<Note:> Your returned digest strings must be B<EXACTLY> the number
2570 of bytes you specify in the C<set_digest()> function (in this case 32).
2571
2572 =head1 CIRCULAR REFERENCES
2573
2574 DBM::Deep has B<experimental> support for circular references.  Meaning you
2575 can have a nested hash key or array element that points to a parent object.
2576 This relationship is stored in the DB file, and is preserved between sessions.
2577 Here is an example:
2578
2579         my $db = DBM::Deep->new( "foo.db" );
2580         
2581         $db->{foo} = "bar";
2582         $db->{circle} = $db; # ref to self
2583         
2584         print $db->{foo} . "\n"; # prints "foo"
2585         print $db->{circle}->{foo} . "\n"; # prints "foo" again
2586
2587 One catch is, passing the object to a function that recursively walks the
2588 object tree (such as I<Data::Dumper> or even the built-in C<optimize()> or
2589 C<export()> methods) will result in an infinite loop.  The other catch is, 
2590 if you fetch the I<key> of a circular reference (i.e. using the C<first_key()> 
2591 or C<next_key()> methods), you will get the I<target object's key>, not the 
2592 ref's key.  This gets even more interesting with the above example, where 
2593 the I<circle> key points to the base DB object, which technically doesn't 
2594 have a key.  So I made DBM::Deep return "[base]" as the key name in that 
2595 special case.
2596
2597 =head1 CAVEATS / ISSUES / BUGS
2598
2599 This section describes all the known issues with DBM::Deep.  It you have found
2600 something that is not listed here, please send e-mail to L<jhuckaby@cpan.org>.
2601
2602 =head2 UNUSED SPACE RECOVERY
2603
2604 One major caveat with DBM::Deep is that space occupied by existing keys and
2605 values is not recovered when they are deleted.  Meaning if you keep deleting
2606 and adding new keys, your file will continuously grow.  I am working on this,
2607 but in the meantime you can call the built-in C<optimize()> method from time to 
2608 time (perhaps in a crontab or something) to recover all your unused space.
2609
2610         $db->optimize(); # returns true on success
2611
2612 This rebuilds the ENTIRE database into a new file, then moves it on top of
2613 the original.  The new file will have no unused space, thus it will take up as
2614 little disk space as possible.  Please note that this operation can take 
2615 a long time for large files, and you need enough disk space to temporarily hold 
2616 2 copies of your DB file.  The temporary file is created in the same directory 
2617 as the original, named with a ".tmp" extension, and is deleted when the 
2618 operation completes.  Oh, and if locking is enabled, the DB is automatically 
2619 locked for the entire duration of the copy.
2620
2621
2622
2623 B<WARNING:> Only call optimize() on the top-level node of the database, and 
2624 make sure there are no child references lying around.  DBM::Deep keeps a reference 
2625 counter, and if it is greater than 1, optimize() will abort and return undef.
2626
2627 =head2 AUTOVIVIFICATION
2628
2629 Unfortunately, autovivification doesn't work with tied hashes.  This appears to 
2630 be a bug in Perl's tie() system, as I<Jakob Schmidt> encountered the very same 
2631 issue with his I<DWH_FIle> module (see L<http://search.cpan.org/search?module=DWH_File>),
2632 and it is also mentioned in the BUGS section for the I<MLDBM> module <see 
2633 L<http://search.cpan.org/search?module=MLDBM>).  Basically, on a new db file,
2634 this does not work:
2635
2636         $db->{foo}->{bar} = "hello";
2637
2638 Since "foo" doesn't exist, you cannot add "bar" to it.  You end up with "foo"
2639 being an empty hash.  Try this instead, which works fine:
2640
2641         $db->{foo} = { bar => "hello" };
2642
2643 As of Perl 5.8.7, this bug still exists.  I have walked very carefully through
2644 the execution path, and Perl indeed passes an empty hash to the STORE() method.
2645 Probably a bug in Perl.
2646
2647 =head2 FILE CORRUPTION
2648
2649 The current level of error handling in DBM::Deep is minimal.  Files I<are> checked
2650 for a 32-bit signature when opened, but other corruption in files can cause
2651 segmentation faults.  DBM::Deep may try to seek() past the end of a file, or get
2652 stuck in an infinite loop depending on the level of corruption.  File write
2653 operations are not checked for failure (for speed), so if you happen to run
2654 out of disk space, DBM::Deep will probably fail in a bad way.  These things will 
2655 be addressed in a later version of DBM::Deep.
2656
2657 =head2 DB OVER NFS
2658
2659 Beware of using DB files over NFS.  DBM::Deep uses flock(), which works well on local
2660 filesystems, but will NOT protect you from file corruption over NFS.  I've heard 
2661 about setting up your NFS server with a locking daemon, then using lockf() to 
2662 lock your files, but your milage may vary there as well.  From what I 
2663 understand, there is no real way to do it.  However, if you need access to the 
2664 underlying FileHandle in DBM::Deep for using some other kind of locking scheme like 
2665 lockf(), see the L<LOW-LEVEL ACCESS> section above.
2666
2667 =head2 COPYING OBJECTS
2668
2669 Beware of copying tied objects in Perl.  Very strange things can happen.  
2670 Instead, use DBM::Deep's C<clone()> method which safely copies the object and 
2671 returns a new, blessed, tied hash or array to the same level in the DB.
2672
2673         my $copy = $db->clone();
2674
2675 =head2 LARGE ARRAYS
2676
2677 Beware of using C<shift()>, C<unshift()> or C<splice()> with large arrays.
2678 These functions cause every element in the array to move, which can be murder
2679 on DBM::Deep, as every element has to be fetched from disk, then stored again in
2680 a different location.  This may be addressed in a later version.
2681
2682 =head1 PERFORMANCE
2683
2684 This section discusses DBM::Deep's speed and memory usage.
2685
2686 =head2 SPEED
2687
2688 Obviously, DBM::Deep isn't going to be as fast as some C-based DBMs, such as 
2689 the almighty I<BerkeleyDB>.  But it makes up for it in features like true
2690 multi-level hash/array support, and cross-platform FTPable files.  Even so,
2691 DBM::Deep is still pretty fast, and the speed stays fairly consistent, even
2692 with huge databases.  Here is some test data:
2693         
2694         Adding 1,000,000 keys to new DB file...
2695         
2696         At 100 keys, avg. speed is 2,703 keys/sec
2697         At 200 keys, avg. speed is 2,642 keys/sec
2698         At 300 keys, avg. speed is 2,598 keys/sec
2699         At 400 keys, avg. speed is 2,578 keys/sec
2700         At 500 keys, avg. speed is 2,722 keys/sec
2701         At 600 keys, avg. speed is 2,628 keys/sec
2702         At 700 keys, avg. speed is 2,700 keys/sec
2703         At 800 keys, avg. speed is 2,607 keys/sec
2704         At 900 keys, avg. speed is 2,190 keys/sec
2705         At 1,000 keys, avg. speed is 2,570 keys/sec
2706         At 2,000 keys, avg. speed is 2,417 keys/sec
2707         At 3,000 keys, avg. speed is 1,982 keys/sec
2708         At 4,000 keys, avg. speed is 1,568 keys/sec
2709         At 5,000 keys, avg. speed is 1,533 keys/sec
2710         At 6,000 keys, avg. speed is 1,787 keys/sec
2711         At 7,000 keys, avg. speed is 1,977 keys/sec
2712         At 8,000 keys, avg. speed is 2,028 keys/sec
2713         At 9,000 keys, avg. speed is 2,077 keys/sec
2714         At 10,000 keys, avg. speed is 2,031 keys/sec
2715         At 20,000 keys, avg. speed is 1,970 keys/sec
2716         At 30,000 keys, avg. speed is 2,050 keys/sec
2717         At 40,000 keys, avg. speed is 2,073 keys/sec
2718         At 50,000 keys, avg. speed is 1,973 keys/sec
2719         At 60,000 keys, avg. speed is 1,914 keys/sec
2720         At 70,000 keys, avg. speed is 2,091 keys/sec
2721         At 80,000 keys, avg. speed is 2,103 keys/sec
2722         At 90,000 keys, avg. speed is 1,886 keys/sec
2723         At 100,000 keys, avg. speed is 1,970 keys/sec
2724         At 200,000 keys, avg. speed is 2,053 keys/sec
2725         At 300,000 keys, avg. speed is 1,697 keys/sec
2726         At 400,000 keys, avg. speed is 1,838 keys/sec
2727         At 500,000 keys, avg. speed is 1,941 keys/sec
2728         At 600,000 keys, avg. speed is 1,930 keys/sec
2729         At 700,000 keys, avg. speed is 1,735 keys/sec
2730         At 800,000 keys, avg. speed is 1,795 keys/sec
2731         At 900,000 keys, avg. speed is 1,221 keys/sec
2732         At 1,000,000 keys, avg. speed is 1,077 keys/sec
2733
2734 This test was performed on a PowerMac G4 1gHz running Mac OS X 10.3.2 & Perl 
2735 5.8.1, with an 80GB Ultra ATA/100 HD spinning at 7200RPM.  The hash keys and 
2736 values were between 6 - 12 chars in length.  The DB file ended up at 210MB.  
2737 Run time was 12 min 3 sec.
2738
2739 =head2 MEMORY USAGE
2740
2741 One of the great things about DBM::Deep is that it uses very little memory.
2742 Even with huge databases (1,000,000+ keys) you will not see much increased
2743 memory on your process.  DBM::Deep relies solely on the filesystem for storing
2744 and fetching data.  Here is output from I</usr/bin/top> before even opening a
2745 database handle:
2746
2747           PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND
2748         22831 root      11   0  2716 2716  1296 R     0.0  0.2   0:07 perl
2749
2750 Basically the process is taking 2,716K of memory.  And here is the same 
2751 process after storing and fetching 1,000,000 keys:
2752
2753           PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND
2754         22831 root      14   0  2772 2772  1328 R     0.0  0.2  13:32 perl
2755
2756 Notice the memory usage increased by only 56K.  Test was performed on a 700mHz 
2757 x86 box running Linux RedHat 7.2 & Perl 5.6.1.
2758
2759 =head1 DB FILE FORMAT
2760
2761 In case you were interested in the underlying DB file format, it is documented
2762 here in this section.  You don't need to know this to use the module, it's just 
2763 included for reference.
2764
2765 =head2 SIGNATURE
2766
2767 DBM::Deep files always start with a 32-bit signature to identify the file type.
2768 This is at offset 0.  The signature is "DPDB" in network byte order.  This is
2769 checked when the file is opened.
2770
2771 =head2 TAG
2772
2773 The DBM::Deep file is in a I<tagged format>, meaning each section of the file
2774 has a standard header containing the type of data, the length of data, and then 
2775 the data itself.  The type is a single character (1 byte), the length is a 
2776 32-bit unsigned long in network byte order, and the data is, well, the data.
2777 Here is how it unfolds:
2778
2779 =head2 MASTER INDEX
2780
2781 Immediately after the 32-bit file signature is the I<Master Index> record.  
2782 This is a standard tag header followed by 1024 bytes (in 32-bit mode) or 2048 
2783 bytes (in 64-bit mode) of data.  The type is I<H> for hash or I<A> for array, 
2784 depending on how the DBM::Deep object was constructed.
2785
2786
2787
2788 The index works by looking at a I<MD5 Hash> of the hash key (or array index 
2789 number).  The first 8-bit char of the MD5 signature is the offset into the 
2790 index, multipled by 4 in 32-bit mode, or 8 in 64-bit mode.  The value of the 
2791 index element is a file offset of the next tag for the key/element in question,
2792 which is usually a I<Bucket List> tag (see below).
2793
2794
2795
2796 The next tag I<could> be another index, depending on how many keys/elements
2797 exist.  See L<RE-INDEXING> below for details.
2798
2799 =head2 BUCKET LIST
2800
2801 A I<Bucket List> is a collection of 16 MD5 hashes for keys/elements, plus 
2802 file offsets to where the actual data is stored.  It starts with a standard 
2803 tag header, with type I<B>, and a data size of 320 bytes in 32-bit mode, or 
2804 384 bytes in 64-bit mode.  Each MD5 hash is stored in full (16 bytes), plus
2805 the 32-bit or 64-bit file offset for the I<Bucket> containing the actual data.
2806 When the list fills up, a I<Re-Index> operation is performed (See 
2807 L<RE-INDEXING> below).
2808
2809 =head2 BUCKET
2810
2811 A I<Bucket> is a tag containing a key/value pair (in hash mode), or a
2812 index/value pair (in array mode).  It starts with a standard tag header with
2813 type I<D> for scalar data (string, binary, etc.), or it could be a nested
2814 hash (type I<H>) or array (type I<A>).  The value comes just after the tag
2815 header.  The size reported in the tag header is only for the value, but then,
2816 just after the value is another size (32-bit unsigned long) and then the plain 
2817 key itself.  Since the value is likely to be fetched more often than the plain 
2818 key, I figured it would be I<slightly> faster to store the value first.
2819
2820
2821
2822 If the type is I<H> (hash) or I<A> (array), the value is another I<Master Index>
2823 record for the nested structure, where the process begins all over again.
2824
2825 =head2 RE-INDEXING
2826
2827 After a I<Bucket List> grows to 16 records, its allocated space in the file is
2828 exhausted.  Then, when another key/element comes in, the list is converted to a 
2829 new index record.  However, this index will look at the next char in the MD5 
2830 hash, and arrange new Bucket List pointers accordingly.  This process is called 
2831 I<Re-Indexing>.  Basically, a new index tag is created at the file EOF, and all 
2832 17 (16 + new one) keys/elements are removed from the old Bucket List and 
2833 inserted into the new index.  Several new Bucket Lists are created in the 
2834 process, as a new MD5 char from the key is being examined (it is unlikely that 
2835 the keys will all share the same next char of their MD5s).
2836
2837
2838
2839 Because of the way the I<MD5> algorithm works, it is impossible to tell exactly
2840 when the Bucket Lists will turn into indexes, but the first round tends to 
2841 happen right around 4,000 keys.  You will see a I<slight> decrease in 
2842 performance here, but it picks back up pretty quick (see L<SPEED> above).  Then 
2843 it takes B<a lot> more keys to exhaust the next level of Bucket Lists.  It's 
2844 right around 900,000 keys.  This process can continue nearly indefinitely -- 
2845 right up until the point the I<MD5> signatures start colliding with each other, 
2846 and this is B<EXTREMELY> rare -- like winning the lottery 5 times in a row AND 
2847 getting struck by lightning while you are walking to cash in your tickets.  
2848 Theoretically, since I<MD5> hashes are 128-bit values, you I<could> have up to 
2849 340,282,366,921,000,000,000,000,000,000,000,000,000 keys/elements (I believe 
2850 this is 340 unodecillion, but don't quote me).
2851
2852 =head2 STORING
2853
2854 When a new key/element is stored, the key (or index number) is first ran through 
2855 I<Digest::MD5> to get a 128-bit signature (example, in hex: 
2856 b05783b0773d894396d475ced9d2f4f6).  Then, the I<Master Index> record is checked
2857 for the first char of the signature (in this case I<b>).  If it does not exist,
2858 a new I<Bucket List> is created for our key (and the next 15 future keys that 
2859 happen to also have I<b> as their first MD5 char).  The entire MD5 is written 
2860 to the I<Bucket List> along with the offset of the new I<Bucket> record (EOF at
2861 this point, unless we are replacing an existing I<Bucket>), where the actual 
2862 data will be stored.
2863
2864 =head2 FETCHING
2865
2866 Fetching an existing key/element involves getting a I<Digest::MD5> of the key 
2867 (or index number), then walking along the indexes.  If there are enough 
2868 keys/elements in this DB level, there might be nested indexes, each linked to 
2869 a particular char of the MD5.  Finally, a I<Bucket List> is pointed to, which 
2870 contains up to 16 full MD5 hashes.  Each is checked for equality to the key in 
2871 question.  If we found a match, the I<Bucket> tag is loaded, where the value and 
2872 plain key are stored.
2873
2874
2875
2876 Fetching the plain key occurs when calling the I<first_key()> and I<next_key()>
2877 methods.  In this process the indexes are walked systematically, and each key
2878 fetched in increasing MD5 order (which is why it appears random).   Once the
2879 I<Bucket> is found, the value is skipped the plain key returned instead.  
2880 B<Note:> Do not count on keys being fetched as if the MD5 hashes were 
2881 alphabetically sorted.  This only happens on an index-level -- as soon as the 
2882 I<Bucket Lists> are hit, the keys will come out in the order they went in -- 
2883 so it's pretty much undefined how the keys will come out -- just like Perl's 
2884 built-in hashes.
2885
2886 =head1 CODE COVERAGE
2887
2888 I use B<Devel::Cover> to test the code coverage of my tests, below is the B<Devel::Cover> report on this 
2889 module's test suite.
2890
2891   ---------------------------- ------ ------ ------ ------ ------ ------ ------
2892   File                           stmt   bran   cond    sub    pod   time  total
2893   ---------------------------- ------ ------ ------ ------ ------ ------ ------
2894   blib/lib/DBM/Deep.pm           94.9   84.5   77.8  100.0   11.1  100.0   89.7
2895   Total                          94.9   84.5   77.8  100.0   11.1  100.0   89.7
2896   ---------------------------- ------ ------ ------ ------ ------ ------ ------
2897
2898 =head1 AUTHOR
2899
2900 Joseph Huckaby, L<jhuckaby@cpan.org>
2901
2902 Special thanks to Adam Sah and Rich Gaushell!  You know why :-)
2903
2904 =head1 SEE ALSO
2905
2906 perltie(1), Tie::Hash(3), Digest::MD5(3), Fcntl(3), flock(2), lockf(3), nfs(5),
2907 Digest::SHA256(3), Crypt::Blowfish(3), Compress::Zlib(3)
2908
2909 =head1 LICENSE
2910
2911 Copyright (c) 2002-2005 Joseph Huckaby.  All Rights Reserved.
2912 This is free software, you may use it and distribute it under the
2913 same terms as Perl itself.
2914
2915 =cut