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