X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBM%2FDeep.pm;h=395aefda21df7dc22056251a5d2c5a2102abbce1;hb=15d754ddb85bbacab5748d2fc02f21b5debd48c3;hp=75aee67487b725716c521253bc1d4f5cdbe55b07;hpb=86867f3a6f23efdf7c7290f5a0b7a69f5f39834f;p=dbsrgits%2FDBM-Deep.git diff --git a/lib/DBM/Deep.pm b/lib/DBM/Deep.pm index 75aee67..395aefd 100644 --- a/lib/DBM/Deep.pm +++ b/lib/DBM/Deep.pm @@ -129,7 +129,7 @@ sub _init { $self->{$param} = $args->{$param}; } - $self->{engine}->setup_fh( $self ); + $self->_engine->setup_fh( $self ); $self->{fileobj}->set_db( $self ); @@ -277,7 +277,7 @@ sub optimize { $self->unlock(); $self->_fileobj->close; $self->_fileobj->open; - $self->{engine}->setup_fh( $self ); + $self->_engine->setup_fh( $self ); return 1; } @@ -342,6 +342,11 @@ sub commit { # Accessor methods ## +sub _engine { + my $self = $_[0]->_get_self; + return $self->{engine}; +} + sub _fileobj { my $self = $_[0]->_get_self; return $self->{fileobj}; @@ -464,9 +469,9 @@ sub STORE { ## $self->lock( LOCK_EX ); - my $md5 = $self->{engine}{digest}->($key); + my $md5 = $self->_engine->{digest}->($key); - my $tag = $self->{engine}->find_bucket_list( $self->_base_offset, $md5, { create => 1 } ); + my $tag = $self->_engine->find_blist( $self->_base_offset, $md5, { create => 1 } ); # User may be storing a hash, in which case we do not want it run # through the filtering system @@ -477,7 +482,7 @@ sub STORE { ## # Add key/value to bucket list ## - $self->{engine}->add_bucket( $tag, $md5, $key, $value, undef, $orig_key ); + $self->_engine->add_bucket( $tag, $md5, $key, $value, undef, $orig_key ); $self->unlock(); @@ -491,14 +496,14 @@ sub FETCH { my $self = shift->_get_self; my ($key, $orig_key) = @_; - my $md5 = $self->{engine}{digest}->($key); + my $md5 = $self->_engine->{digest}->($key); ## # Request shared lock for reading ## $self->lock( LOCK_SH ); - my $tag = $self->{engine}->find_bucket_list( $self->_base_offset, $md5 );#, { create => 1 } ); + my $tag = $self->_engine->find_blist( $self->_base_offset, $md5 );#, { create => 1 } ); #XXX This needs to autovivify if (!$tag) { $self->unlock(); @@ -508,7 +513,7 @@ sub FETCH { ## # Get value from bucket list ## - my $result = $self->{engine}->get_bucket_value( $tag, $md5, $orig_key ); + my $result = $self->_engine->get_bucket_value( $tag, $md5, $orig_key ); $self->unlock(); @@ -545,9 +550,9 @@ sub DELETE { ## $self->lock( LOCK_EX ); - my $md5 = $self->{engine}{digest}->($key); + my $md5 = $self->_engine->{digest}->($key); - my $tag = $self->{engine}->find_bucket_list( $self->_base_offset, $md5 ); + my $tag = $self->_engine->find_blist( $self->_base_offset, $md5 ); if (!$tag) { $self->unlock(); return; @@ -556,13 +561,13 @@ sub DELETE { ## # Delete bucket ## - my $value = $self->{engine}->get_bucket_value( $tag, $md5 ); + my $value = $self->_engine->get_bucket_value( $tag, $md5 ); if (defined $value && !ref($value) && $self->_fileobj->{filter_fetch_value}) { $value = $self->_fileobj->{filter_fetch_value}->($value); } - my $result = $self->{engine}->delete_bucket( $tag, $md5, $orig_key ); + my $result = $self->_engine->delete_bucket( $tag, $md5, $orig_key ); ## # If this object is an array and the key deleted was on the end of the stack, @@ -581,14 +586,14 @@ sub EXISTS { my $self = shift->_get_self; my ($key) = @_; - my $md5 = $self->{engine}{digest}->($key); + my $md5 = $self->_engine->{digest}->($key); ## # Request shared lock for reading ## $self->lock( LOCK_SH ); - my $tag = $self->{engine}->find_bucket_list( $self->_base_offset, $md5 ); + my $tag = $self->_engine->find_blist( $self->_base_offset, $md5 ); if (!$tag) { $self->unlock(); @@ -601,7 +606,7 @@ sub EXISTS { ## # Check if bucket exists and return 1 or '' ## - my $result = $self->{engine}->bucket_exists( $tag, $md5 ) || ''; + my $result = $self->_engine->bucket_exists( $tag, $md5 ) || ''; $self->unlock(); @@ -636,11 +641,30 @@ sub CLEAR { ## $self->lock( LOCK_EX ); + if ( $self->_type eq TYPE_HASH ) { + my $key = $self->first_key; + while ( $key ) { + my $next_key = $self->next_key( $key ); + my $md5 = $self->_engine->{digest}->($key); + my $tag = $self->_engine->find_blist( $self->_base_offset, $md5 ); + $self->_engine->delete_bucket( $tag, $md5, $key ); + $key = $next_key; + } + } + else { + my $size = $self->FETCHSIZE; + for my $key ( map { pack ( $self->_engine->{long_pack}, $_ ) } 0 .. $size - 1 ) { + my $md5 = $self->_engine->{digest}->($key); + my $tag = $self->_engine->find_blist( $self->_base_offset, $md5 ); + $self->_engine->delete_bucket( $tag, $md5, $key ); + } + $self->STORESIZE( 0 ); + } #XXX This needs updating to use _release_space - $self->{engine}->write_tag( - $self->_base_offset, $self->_type, - chr(0)x$self->{engine}{index_size}, - ); +# $self->_engine->write_tag( +# $self->_base_offset, $self->_type, +# chr(0)x$self->_engine->{index_size}, +# ); $self->unlock(); @@ -670,10 +694,10 @@ DBM::Deep - A pure perl multi-level hash/array DBM use DBM::Deep; my $db = DBM::Deep->new( "foo.db" ); - $db->{key} = 'value'; # tie() style + $db->{key} = 'value'; print $db->{key}; - $db->put('key' => 'value'); # OO style + $db->put('key' => 'value'); print $db->get('key'); # true multi-level support @@ -682,33 +706,29 @@ DBM::Deep - A pure perl multi-level hash/array DBM 42, 99, ]; -=head1 DESCRIPTION + tie my %db, 'DBM::Deep', 'foo.db'; + $db{key} = 'value'; + print $db{key}; -A unique flat-file database module, written in pure perl. True -multi-level hash/array support (unlike MLDBM, which is faked), hybrid -OO / tie() interface, cross-platform FTPable files, and quite fast. Can -handle millions of keys and unlimited hash levels without significant -slow-down. Written from the ground-up in pure perl -- this is NOT a -wrapper around a C-based DBM. Out-of-the-box compatibility with Unix, -Mac OS X and Windows. + tied(%db)->put('key' => 'value'); + print tied(%db)->get('key'); -=head1 VERSION DIFFERENCES - -B: 0.99_01 and above have significant file format differences from 0.98 and -before. While attempts have been made to be backwards compatible, no guarantees. +=head1 DESCRIPTION -=head1 INSTALLATION +A unique flat-file database module, written in pure perl. True multi-level +hash/array support (unlike MLDBM, which is faked), hybrid OO / tie() +interface, cross-platform FTPable files, ACID transactions, and is quite fast. +Can handle millions of keys and unlimited levels without significant +slow-down. Written from the ground-up in pure perl -- this is NOT a wrapper +around a C-based DBM. Out-of-the-box compatibility with Unix, Mac OS X and +Windows. -Hopefully you are using Perl's excellent CPAN module, which will download -and install the module for you. If not, get the tarball, and run these -commands: +=head1 VERSION DIFFERENCES - tar zxf DBM-Deep-* - cd DBM-Deep-* - perl Makefile.PL - make - make test - make install +B: 0.99_01 and above have significant file format differences from 0.983 and +before. There will be a backwards-compatibility layer in 1.00, but that is +slated for a later 0.99_x release. This version is B backwards compatible +with 0.983 and before. =head1 SETUP @@ -718,7 +738,7 @@ Perl's tie() function. Both are examined here. =head2 OO CONSTRUCTION The recommended way to construct a DBM::Deep object is to use the new() -method, which gets you a blessed, tied hash or array reference. +method, which gets you a blessed I tied hash (or array) reference. my $db = DBM::Deep->new( "foo.db" ); @@ -728,11 +748,11 @@ opened in "r+" (read/write) mode, and the type of object returned is a hash, unless otherwise specified (see L below). You can pass a number of options to the constructor to specify things like -locking, autoflush, etc. This is done by passing an inline hash: +locking, autoflush, etc. This is done by passing an inline hash (or hashref): my $db = DBM::Deep->new( - file => "foo.db", - locking => 1, + file => "foo.db", + locking => 1, autoflush => 1 ); @@ -741,8 +761,6 @@ the "file" parameter, as opposed to being the sole argument to the constructor. This is required if any options are specified. See L below for the complete list. - - You can also start with an array instead of a hash. For this, you must specify the C parameter: @@ -760,8 +778,8 @@ the wrong type is passed in. Alternately, you can create a DBM::Deep handle by using Perl's built-in tie() function. The object returned from tie() can be used to call methods, -such as lock() and unlock(), but cannot be used to assign to the DBM::Deep -file (as expected with most tie'd objects). +such as lock() and unlock(). (That object can be retrieved from the tied +variable at any time using tied() - please see L for more info. my %hash; my $db = tie %hash, "DBM::Deep", "foo.db"; @@ -804,6 +822,11 @@ needs. If you open it read-only and attempt to write, an exception will be throw open it write-only or append-only, an exception will be thrown immediately as DBM::Deep needs to read from the fh. +=item * audit_file / audit_fh + +These are just like file/fh, except for auditing. Please see L for +more information. + =item * file_offset This is the offset within the file that the DBM::Deep db starts. Most of the time, you will @@ -829,11 +852,12 @@ parameter, and defaults to CTYPE_HASH>. =item * locking -Specifies whether locking is to be enabled. DBM::Deep uses Perl's Fnctl flock() -function to lock the database in exclusive mode for writes, and shared mode for -reads. Pass any true value to enable. This affects the base DB handle I that use the same DB file. This is an optional -parameter, and defaults to 0 (disabled). See L below for more. +Specifies whether locking is to be enabled. DBM::Deep uses Perl's flock() +function to lock the database in exclusive mode for writes, and shared mode +for reads. Pass any true value to enable. This affects the base DB handle +I that use the same DB file. This is an +optional parameter, and defaults to 0 (disabled). See L below for +more. =item * autoflush @@ -889,7 +913,7 @@ You can even step through hash keys using the normal Perl C function: Remember that Perl's C function extracts I key from the hash and pushes them onto an array, all before the loop even begins. If you have an -extra large hash, this may exhaust Perl's memory. Instead, consider using +extremely large hash, this may exhaust Perl's memory. Instead, consider using Perl's C function, which pulls keys/values one at a time, using very little memory: @@ -936,7 +960,8 @@ or simply be a nested array reference inside a hash. Example: In addition to the I interface, you can also use a standard OO interface to manipulate all aspects of DBM::Deep databases. Each type of object (hash or array) has its own methods, but both types share the following common methods: -C, C, C, C and C. +C, C, C, C and C. C and +C are aliases to C and C, respectively. =over @@ -998,7 +1023,8 @@ q.v. Locking. =item * optimize() -Recover lost disk space. +Recover lost disk space. This is important to do, especially if you use +transactions. =item * import() / export() @@ -1207,7 +1233,8 @@ The C method can be called on any database level (not just the base level), and works with both hash and array DB types. B Make sure your existing structure has no circular references in it. -These will cause an infinite loop when importing. +These will cause an infinite loop when importing. There are plans to fix this +in a later release. =head2 EXPORTING @@ -1235,7 +1262,8 @@ large databases -- you can store a lot more data in a DBM::Deep object than an in-memory Perl structure. B Make sure your database has no circular references in it. -These will cause an infinite loop when exporting. +These will cause an infinite loop when exporting. There are plans to fix this +in a later release. =head1 FILTERS @@ -1495,6 +1523,41 @@ object tree (such as I or even the built-in C or C methods) will result in an infinite loop. This will be fixed in a future release. +=head1 AUDITING + +New in 0.99_01 is the ability to audit your databases actions. By passing in +audit_file (or audit_fh) to the constructor, all actions will be logged to +that file. The format is one that is suitable for eval'ing against the +database to replay the actions. Please see t/33_audit_trail.t for an example +of how to do this. + +=head1 TRANSACTIONS + +New in 0.99_01 is ACID transactions. Every DBM::Deep object is completely +transaction-ready - it is not an option you have to turn on. Three new methods +have been added to support them. They are: + +=over 4 + +=item * begin_work() + +This starts a transaction. + +=item * commit() + +This applies the changes done within the transaction to the mainline and ends +the transaction. + +=item * rollback() + +This discards the changes done within the transaction to the mainline and ends +the transaction. + +=back + +Transactions in DBM::Deep are done using the MVCC method, the same method used +by the InnoDB MySQL table type. + =head1 CAVEATS / ISSUES / BUGS This section describes all the known issues with DBM::Deep. It you have found @@ -1814,30 +1877,32 @@ built-in hashes. =head1 CODE COVERAGE -We use B to test the code coverage of our tests, below is the -B report on this module's test suite. +B is used to test the code coverage of the tests. Below is the +B report on this distribution's test suite. - ----------------------------------- ------ ------ ------ ------ ------ ------ - File stmt bran cond sub time total - ----------------------------------- ------ ------ ------ ------ ------ ------ - blib/lib/DBM/Deep.pm 94.9 80.6 73.0 100.0 37.9 90.4 - blib/lib/DBM/Deep/Array.pm 100.0 91.1 100.0 100.0 18.2 98.1 - blib/lib/DBM/Deep/Engine.pm 98.9 87.3 80.0 100.0 34.2 95.2 - blib/lib/DBM/Deep/Hash.pm 100.0 87.5 100.0 100.0 9.7 97.3 - Total 97.9 85.9 79.7 100.0 100.0 94.3 - ----------------------------------- ------ ------ ------ ------ ------ ------ + ---------------------------- ------ ------ ------ ------ ------ ------ ------ + File stmt bran cond sub pod time total + ---------------------------- ------ ------ ------ ------ ------ ------ ------ + blib/lib/DBM/Deep.pm 96.2 89.0 75.0 95.8 89.5 36.0 92.9 + blib/lib/DBM/Deep/Array.pm 96.1 88.3 100.0 96.4 100.0 15.9 94.7 + blib/lib/DBM/Deep/Engine.pm 96.6 86.6 89.5 100.0 0.0 20.0 91.0 + blib/lib/DBM/Deep/File.pm 99.4 88.3 55.6 100.0 0.0 19.6 89.5 + blib/lib/DBM/Deep/Hash.pm 98.5 83.3 100.0 100.0 100.0 8.5 96.3 + Total 96.9 87.4 81.2 98.0 38.5 100.0 92.1 + ---------------------------- ------ ------ ------ ------ ------ ------ ------ =head1 MORE INFORMATION Check out the DBM::Deep Google Group at L -or send email to L. +or send email to L. You can also visit #dbm-deep on +irc.perl.org -=head1 AUTHORS - -Joseph Huckaby, L +=head1 MAINTAINERS Rob Kinyon, L +Originally written by Joseph Huckaby, L + Special thanks to Adam Sah and Rich Gaushell! You know why :-) =head1 SEE ALSO