package TDB_FileX; use common::sense; use Exporter (); use XSLoader (); our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. our %EXPORT_TAGS = ( flags => [qw( ALLOW_NESTING BIGENDIAN CLEAR_IF_FIRST CONVERT DEFAULT DISALLOW_NESTING INCOMPATIBLE_HASH INTERNAL MUTEX_LOCKING NOLOCK NOMMAP NOSYNC SEQNUM VOLATILE )], insert => [qw( INSERT MODIFY REPLACE )], error => [qw( SUCCESS ERR_CORRUPT ERR_EXISTS ERR_IO ERR_LOCK ERR_LOCK_TIMEOUT ERR_NOEXIST ERR_NOLOCK ERR_OOM ERR_EINVAL ERR_RDONLY )], debug => [qw( DEBUG_FATAL DEBUG_ERROR DEBUG_WARNING DEBUG_TRACE} )], ); our @EXPORT_OK; Exporter::export_ok_tags qw(flags insert error debug); $EXPORT_TAGS{all} = \@EXPORT_OK; our $VERSION = '0.97'; XSLoader::load __PACKAGE__, $VERSION; 1; __END__ =head1 NAME TDB_FileX - Perl access to the trivial database library =head1 SYNOPSIS use TDB_FileX; # tie interface tie %hash, TDB_FileX => $filename, hash_size => 8000, mutex => 1, ; $hash{key} = 'value'; while (my ($k, $v) = each %hash) { print "$k -> $v\n" } # OO interface my $tdb = TDB_FileX->open ($filename, flags => TDB_FileX::CLEAR_IF_FIRST) or die $!; $tdb->store (key => 'value') or die $tdb->errorstr; $tdb->traverse (sub { print "$_[0] -> $_[1]\n" }); =head1 DESCRIPTION TDB is a simple database similar to GDBM, but allows multiple simultaneous writers. It's main drawback is the need to manually configure a hash table size in advance - see the C option for C. TDB_FileX provides a simple C interface, similar to DB_File and friends; and an object-oriented interface, which provides access to most of the functions in the TDB library. =head1 ERROR HANDLKING The TDB C API is not well designed - among other things, error handling is a bit erratic. Many functions that normally should just work are marked with a [CROAK] - these will throw an exception on error, the exception string being the error message. C<$!> is set to the numerical error value in that case (and will stringify into the wrong OS-error string, so don't do that!). This is so that you can concentrate on the important parts, while there are still no silent unexpected errors. The other functions will not generally croak - check their description for details on how errors are handled. =head2 FUNCTIONS =over 4 =item $tdb = tie %hash, TDB_FileX => $path[ , key => value...] =item $tdb = TDB_FileX->open ($path[, key => value...]) TDB_FileX constructor (same as C). Opens $path and returns a TDB_FileX object. The same arguments may be passed to the C function. On error, C is returned. To open a tdb file that is created and used by another application (maximising compatibility): my $tdb = TDB_FileX->open ($path, log_cb => sub { warn $_[1] }) or die "$path: failed to open\n"; To open a tdb file with good performance for many thousands of large keys, maybe not compatible to others: my $tdb = TDB_FileX->open ($path, hash_size => 10000, hash => "xxh3", mutex => 1, nocow => 1, log_cb => sub { warn $_[1] }, ) or die "$path: failed to open\n"; A number of key-value pairs are accepted, with hopefully sensible defaults for most of these (but you should consider at least setting C if you want to store more than a thousand or so pairs, and C if you want to take advantage of much faster locking. =over =item tdb_flags => $flags (default: C) A set of flags that influence the behaviour and format of the database. See tdb_open(3) for the meanings and possible values (note that the C prefix has to be removed, see the L section for a list. =item open_flags => $flags (default: C) Standard open flags, as used in C. =item mode => $mode (default: C<0666>) Standard file open mode, as use din C. Only used when creating the database file. =item hash_size => $int (default: internal to libtdb, but normally C<131>) The size of the internal hash table - only used when creating the database. The default is usually very low and only good for a few thousand keys. As a rule of thumb, it should be at least one percent of the number of keys you plan to store, e.g. for C<800000> keys you should use around a size of C<8000>. Every hash entry is only 4 octets, os usually it isn't an issue to make the hash table too large. To give you an idea of the performance, I inserted about 600000 records, 3GB of data, into a TDB file, using different hash sizes. size time 131 160s 256 85s 1024 12s 4096 5s 8192 4s As you can see, the default hash table size for this case caused it to use 40 times the time to insert than a larger hash table, the optimum being around 75 keys per hash entry. But the databse easily was cached in memory. If that is not the case, you might want to consider a hash table that is larger than the number of keys you want to store - each hash slot only uses 4 octets. =item log_cb => $cb->($level, $msg) Sets a code reference that is called with a message and a log level (lower means more important, there are C, C, C and C). Unlike the "debug" in the name might indicate, if you want to find out why, for instance, you could not open a database, you need to use a logging callback. =item hash => $hash (default: C) Selects a hash function to use. =over =item C<"default"> or C Use autodetection and use either C<"jenkins"> or the original tdb hash function. =item C<"jenkins"> The jenkins hash function. Relatively fast, and recommended for modern tdb databases that need to be interoperable between implementations. =item C<"fnv1ax"> The FNV1-A hash with 32 bit post-mixing. Pretty good and verxy fast for keys up to 10-20 octets. =item C<"xxh3"> The XXH3 hash. Very good and fast especially for long keys. =item C<1> .. C<4> Specify one of up to four custom hash functions (see L). =back =item mutex => $bool (default: C<0>) TDB can take advantage of fast interprocess mutexes, which can be orders of magnitude faster than the syscall-based locking used by default, but only works on the same machine. Normally, you need to call C and set the C flag if support is indicated. This option, when enabled, enables C if it is supported by the platform - which involves a fork when opening the database. When disabled, it will remove the flag. It is recommended to keep this one, but enabling this changes the format of the database, so might not be an option if interoperability with other programs is required. =item nocow => $bool (default: C<0>) Set the no-copy-on-write flag I this flag is true, C contains C and this is supported on the platform and filesystem. Copy-on-write filesystems have to make a copy of every block written to, which can both be costly and can cause massive fragmentation of the database file. Setting the no-copy-on-write flag (same as C) disables this, usually at the expense of data protection (checksumming), reducing the safety to the level of a normal filesystem such as ext4. This is best effort and usually only takes effect when the database is initially created. If it fails, TDB_FileX will simply continue. Correctness should not be affected either way. =back There is no explicit close function. The database is closed implicitly when there are no remaining references. =item $tdb->store ($key, $value[, $flag=REPLACE]) [CROAK] Store $value in the database with key w$key. The $flag defaults to C, but can also be C or C, see tdb_store(3) for details. =item $tdb->append ($key, $value) [CROAK] Appends $data to the data already stored for $key, or creates a new entry with it. =item $tdb->fetch ($key) Fetch the value associated with $key, or C if it is not found (or on any error). =item $tdb->delete ($key) [CROAK] Delete the value associated with $key. On failure, a perl false is returned. See Lerror> and Lerrorstr> for the reason. =item $bool = $tdb->exists ($key) Return true if the $key is found, false otherwise. =item $tdb->firstkey Return the key of the first value in the database. Returns C on failure or if there are no keys in the database. See tdb_firstkey(3) for details. =item $tdb->nextkey ($lastkey) Return the next key in the database after $lastkey. Returns C on failure or if there are no more keys in the database. See tdb_nextkey(3) for details. =item $tdb->error Returns the current error state of the C<$tdb> object. See the list of error codes given in L. =item $tdb->errorstr Returns a printable string that describes the error state of the database. =item $tdb->reopen [CROAK] Closes and reopens the database. Required after a L, if both processes wish to use the database. B If C fails, then it is unsafe to call any further methods on C<$tdb>. Thus, the only way to find out I C failed is to use a logging function. =item TDB_FileX::reopen_all [CROAK] Closes and reopens all open databases. See Lreopen>. B If C fails, there is no indication of I C<$tdb> objects failed or why. If you have to survive failures, you may wish to do your own C loop instead. =item $tdb->traverse ($cb->($key, $data)) [CROAK] Call $cb for each entry in the database. The callback should return false to continue, or a true value to abort the traversal. The callback is called with the key and value as arguments and should return a false value if you wish to continue traversal, and a true value if the traversal should be aborted. C returns the number of elements traversed. If $cb is C, then this function simply counts the number of elements. =item $tdb->traverse_read ($cb->($key, $data)) [CROAK] Like C, but only acquires a read lock. =item $tdb->set_logging_function ($cb->($level, $msg)) Set the logging function to use when this database object encounters errors. $cb is called with the severity level (an integer) and the message (a string). =item $tdb->lockall [CROAK] Lock an entire database with an exclusive write lock, returning false on error. The purpose of this call is to avoid locking overhead for many operations, but the database has to be unlocked manually when done. =item $tdb->unlockall [CROAK] Unlock an entire database previously locked with Llockall>. =item $tdb->lockall_read [CROAK] Same as Llockall>, but uses a shared read lock instead of a writer lock. =item $tdb->unlockall_read [CROAK] Opposite of Llockall_read>. =item $tdb->lockall_mark [CROAK] =item $tdb->lockall_unmark [CROAK] Please tlel me exactly what these do. =item $tdb->lockall_nonblock [CROAK] =item $tdb->lockall_read_nonblock [CROAK] Please tell me what exactly these do. =item $tdb->transaction_start [CROAK] Starts a transaction - all operations will be queued, but not applied to the database, until the transaction is either committed Ltransaction_commit> or aborted/thrown away, with Ltransaction_cancel>. =item $tdb->transaction_start_nonblock [CROAK] Please tell me what this does. =item $tdb->transaction_commit [CROAK] Applies all changes in the transaction. =item $tdb->transaction_cancel [CROAK] Throws away all changes in the transaction. =item $tdb->transaction_prepare_commit [CROAK] Instead of calling Ltransaction_commit> you can do the commit in two phases by calling this method before commit, which does the expensive steps first. =item $bool = $tdb->transaction_active Returns true if a transaction is currently active. =item $tdb->enable_seqnum Enables sequence number generatiuon supporet for the database. =item $seq = $tdb->get_seqnum Returns the current sequence number. Internally, this is a 32 bit unsigned integer, but the API converts it into a native integer, so the same internal sequence number might be represented differently on different machines. =item $tdb->increment_seqnum_nonblock Increments the sequence number. Note that the sequence number is also incremented by TDB itself oon many operations. =item $size = $tdb->hash_size Returns the size of the hash table. The size cannot be changed other than by recreating the database. =item $octets = $tdb->map_size Returns the current mmap size for the database. =item $flags = $tdb->get_flags Returns the flags for the database (the same as the C in C). =item $tdb->add_flags ($flag) Tried to add flags to the database - yes, the parameter says C<$flag> (singular) but the documentation and the code say I (plural). =item $tdb->remove_flags ($flag) Attempts to remove flags from the database. =item $fileno = $tdb->fd Returns the file descriptor (not file handle) for the underlying database file. =item $path = $tdb->name Returns the path used to open the database. =item $tdb->wipe_all [CROAK] Efficientlly deletes all entries in the database. This does not shrink the file itself. =item $tdb->repack [CROAK] Tries to improve layout of the database by copying all items into a temporary in-memory database, wiping the database, and copying all items back. Yes, everything must fit into memory. =item $bool = $tdb->check ($cb->($key, $value)) Does extensive checks on the database, optionally (if not C) calling a check function for each pair, which must return true if the data is valid. Returns a boolean indicating whether the database was found healthy and all the calls to the callback returned true. =item $bool = $tdb->rescue ($cb->($key, $value)) Tries to recover some or all key-value pairs from a potentially damanged database file. For each recovered pair it calls the given callback. Returns a boolean indicating whether the database was found healthy and all the calls to the callback returned true. =item $bool = TDB_FileX::runtime_check_for_robust_mutexes Tests whether robust mutexes are available for locking. This involves forking the process, so it can be costly and problematic. This function needs to be called before using the C flag. But see the C parametrer to C for an alternative. =item $tdb->dump_all Dump the records and freelist to STDOUT in an almost human readable form. =item $tdb->printfreelist Dump the freelist to STDOUT. =back =head2 EXPORTS Nothing constants are exported by default. The tag C<:all> exports allpo of the constants. Individually or with the tag C<:flags>: DEFAULT CLEAR_IF_FIRST INTERNAL NOLOCK NOMMAP CONVERT BIGENDIAN NOSYNC SEQNUM VOLATILE ALLOW_NESTING DISALLOW_NESTING INCOMPATIBLE_HASH MUTEX_LOCKING Individually or with the tag C<:insert>: REPLACE INSERT MODIFY Individually or with the tag C<:error>: SUCCESS ERR_CORRUPT ERR_IO ERR_LOCK ERR_OOM ERR_EXISTS ERR_NOLOCK ERR_LOCK_TIMEOUT ERR_NOEXIST ERR_EINVAL ERR_RDONLY Individually or with the tag C<:debug>: DEBUG_FATAL DEBUG_ERROR DEBUG_WARNING DEBUG_TRACE =head1 UNICODE HANDLING TDB databases can only store octet strings. Unlike most other database interfaces, TDB_FileX will safely handle Perl strings by downgrading them. Perl will warn about strings that cnanot be downgraded. =head1 DISK USAGE TDB databses use 24 octets for every key-value pair, plus the octet size of the key and sata, e.g. the pair "key" => "value" takes up 24+3+5 octets on disk. The database header is 168 octets (if I haven't miscounted). Each hashtable entry is 4 octets, and one more than the hash size is allocated, so the hahs table size is (hash_size + 1) * 4. =head1 LIMITATIONS =head2 Database Size As far as I can see, TDB dastabases are limited to 4 GB. =head2 Hash Functions Hash functioons need to be set globally - they are limited to a maximum of 4, but this can be easily extended, but requires source code editing. This is due to a limitation of the TDB C API. =head2 No recoivery after failed C There is no way to survive an error during C. Unfortunately this is a limitation in the TDB C API. =head1 SEE ALSO tdb(3), L. =head1 AUTHOR Angus Lees, Egus@inodes.org> Currently maintained by Marc A. Lehmann http://home.schmorp.de/ =cut