=head1 NAME
DBM::Deep::Cookbook
=head1 DESCRIPTION
This is the Cookbook for L. It contains useful tips and tricks,
plus some examples of how to do common tasks.
=head1 RECIPES
=head2 UTF8 data
When you're using UTF8 data, you may run into the "Wide character in print"
warning. To fix that in 5.8+, do the following:
my $db = DBM::Deep->new( ... );
binmode $db->_fh, ":utf8";
In 5.6, you will have to do the following:
my $db = DBM::Deep->new( ... );
$db->set_filter( 'store_value' => sub { pack "U0C*", unpack "C*", $_[0] } );
$db->set_filter( 'retrieve_value' => sub { pack "C*", unpack "U0C*", $_[0] } );
In a future version, you will be able to specify C 1> and
L will do these things for you.
=head2 Real-time Encryption Example
B: This is just an example of how to write a filter. This most
definitely should B be taken as a proper way to write a filter that does
encryption.
Here is a working example that uses the I module to
do real-time encryption / decryption of keys & values with DBM::Deep Filters.
Please visit L for more
on I. You'll also need the I module.
use DBM::Deep;
use Crypt::Blowfish;
use Crypt::CBC;
my $cipher = Crypt::CBC->new({
'key' => 'my secret key',
'cipher' => 'Blowfish',
'iv' => '$KJh#(}q',
'regenerate_key' => 0,
'padding' => 'space',
'prepend_iv' => 0
});
my $db = DBM::Deep->new(
file => "foo-encrypt.db",
filter_store_key => \&my_encrypt,
filter_store_value => \&my_encrypt,
filter_fetch_key => \&my_decrypt,
filter_fetch_value => \&my_decrypt,
);
$db->{key1} = "value1";
$db->{key2} = "value2";
print "key1: " . $db->{key1} . "\n";
print "key2: " . $db->{key2} . "\n";
undef $db;
exit;
sub my_encrypt {
return $cipher->encrypt( $_[0] );
}
sub my_decrypt {
return $cipher->decrypt( $_[0] );
}
=head2 Real-time Compression Example
Here is a working example that uses the I module to do real-time
compression / decompression of keys & values with DBM::Deep Filters.
Please visit L for
more on I.
use DBM::Deep;
use Compress::Zlib;
my $db = DBM::Deep->new(
file => "foo-compress.db",
filter_store_key => \&my_compress,
filter_store_value => \&my_compress,
filter_fetch_key => \&my_decompress,
filter_fetch_value => \&my_decompress,
);
$db->{key1} = "value1";
$db->{key2} = "value2";
print "key1: " . $db->{key1} . "\n";
print "key2: " . $db->{key2} . "\n";
undef $db;
exit;
sub my_compress {
return Compress::Zlib::memGzip( $_[0] ) ;
}
sub my_decompress {
return Compress::Zlib::memGunzip( $_[0] ) ;
}
B Filtering of keys only applies to hashes. Array "keys" are
actually numerical index numbers, and are not filtered.
=head1 Custom Digest Algorithm
DBM::Deep by default uses the I (MD5) algorithm for hashing
keys. However you can override this, and use another algorithm (such as SHA-256)
or even write your own. But please note that DBM::Deep currently expects zero
collisions, so your algorithm has to be I, so to speak. Collision
detection may be introduced in a later version.
You can specify a custom digest algorithm by passing it into the parameter
list for new(), passing a reference to a subroutine as the 'digest' parameter,
and the length of the algorithm's hashes (in bytes) as the 'hash_size'
parameter. Here is a working example that uses a 256-bit hash from the
I module. Please see
L for more information.
use DBM::Deep;
use Digest::SHA256;
my $context = Digest::SHA256::new(256);
my $db = DBM::Deep->new(
filename => "foo-sha.db",
digest => \&my_digest,
hash_size => 32,
);
$db->{key1} = "value1";
$db->{key2} = "value2";
print "key1: " . $db->{key1} . "\n";
print "key2: " . $db->{key2} . "\n";
undef $db;
exit;
sub my_digest {
return substr( $context->hash($_[0]), 0, 32 );
}
B Your returned digest strings must be B the number
of bytes you specify in the hash_size parameter (in this case 32). Undefined
behavior will occur otherwise.
B If you do choose to use a custom digest algorithm, you must set it
every time you access this file. Otherwise, the default (MD5) will be used.
=head1 PERFORMANCE
Because DBM::Deep is a conncurrent datastore, every change is flushed to disk
immediately and every read goes to disk. This means that DBM::Deep functions
at the speed of disk (generally 10-20ms) vs. the speed of RAM (generally
50-70ns), or at least 150-200x slower than the comparable in-memory
datastructure in Perl.
There are several techniques you can use to speed up how DBM::Deep functions.
=over 4
=item * Put it on a ramdisk
The easiest and quickest mechanism to making DBM::Deep run faster is to create
a ramdisk and locate the DBM::Deep file there. Doing this as an option may
become a feature of DBM::Deep, assuming there is a good ramdisk wrapper on CPAN.
=item * Work at the tightest level possible
It is much faster to assign the level of your db that you are working with to
an intermediate variable than to re-look it up every time. Thus
# BAD
while ( my ($k, $v) = each %{$db->{foo}{bar}{baz}} ) {
...
}
# GOOD
my $x = $db->{foo}{bar}{baz};
while ( my ($k, $v) = each %$x ) {
...
}
=item * Make your file as tight as possible
If you know that you are not going to use more than 65K in your database,
consider using the C 'small'> option. This will instruct
DBM::Deep to use 16bit addresses, meaning that the seek times will be less.
=back
=cut