Rev: 23590
Last Changed Date: 2007-06-22 13:36:10 -0400 (Fri, 22 Jun 2007)
*/
- /*
+ /*
trivial database library - standalone version
Copyright (C) Andrew Tridgell 1999-2005
Copyright (C) Jeremy Allison 2000-2006
Copyright (C) Paul `Rusty' Russell 2000
-
+
** NOTE! The following LGPL license applies to the tdb
** library. This does NOT imply that all of Samba is released
** under the LGPL
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
#define HAVE_UTIME_H
#define HAVE_UTIME
#endif
-#define _XOPEN_SOURCE 500
+#define _XOPEN_SOURCE 600
+#include "config.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "tdb.h"
+static TDB_DATA tdb_null;
+
#ifndef u32
#define u32 unsigned
#endif
this functions locks/unlocks 1 byte at the specified offset.
On error, errno is also set so that errors are passed back properly
- through tdb_open().
+ through tdb_open().
note that a len of zero means lock to end of file
*/
-int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,
+int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,
int rw_type, int lck_type, int probe, size_t len)
{
struct flock fl;
if (!probe && lck_type != F_SETLK) {
/* Ensure error code is set for log fun to examine. */
tdb->ecode = TDB_ERR_LOCK;
- TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",
+ TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",
tdb->fd, offset, rw_type, lck_type, (int)len));
}
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
upgrade a read lock to a write lock. This needs to be handled in a
special way as some OSes (such as solaris) have too conservative
deadlock detection and claim a deadlock when progress can be
- made. For those OSes we may loop for a while.
+ made. For those OSes we may loop for a while.
*/
int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
{
ltype &= ~TDB_MARK_LOCK;
/* a global lock allows us to avoid per chain locks */
- if (tdb->global_lock.count &&
+ if (tdb->global_lock.count &&
(ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
return 0;
}
}
if (list < -1 || list >= (int)tdb->header.hash_size) {
- TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n",
+ TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n",
list, ltype));
return -1;
}
ltype &= ~TDB_MARK_LOCK;
/* a global lock allows us to avoid per chain locks */
- if (tdb->global_lock.count &&
+ if (tdb->global_lock.count &&
(ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
return 0;
}
}
if (ret)
- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));
+ TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));
return ret;
}
if (tdb->have_transaction_lock || tdb->global_lock.count) {
return 0;
}
- if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype,
+ if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype,
F_SETLKW, 0, 1) == -1) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n"));
tdb->ecode = TDB_ERR_LOCK;
/* a global lock of a different type exists */
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
}
-
+
if (tdb->num_locks != 0) {
/* can't combine global and chain locks */
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
}
if (!mark_lock &&
- tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW,
+ tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW,
0, 4*tdb->header.hash_size)) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
return -1;
/* check for an out of bounds access - if it is out of bounds then
see if the database has been expanded by someone else and expand
- if necessary
+ if necessary
note that "len" is the minimum length needed for the db
*/
static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
}
/* write a lump of data at a specified offset */
-static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
+static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
const void *buf, tdb_len_t len)
{
if (len == 0) {
/* read a lump of data at a specified offset, maybe convert */
-static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
+static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
tdb_len_t len, int cv)
{
if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) {
/*
do an unlocked scan of the hash table heads to find the next non-zero head. The value
will then be confirmed with the lock held
-*/
+*/
static void tdb_next_hash_chain(struct tdb_context *tdb, u32 *chain)
{
u32 h = *chain;
#ifdef HAVE_MMAP
if (!(tdb->flags & TDB_NOMMAP)) {
- tdb->map_ptr = mmap(NULL, tdb->map_size,
- PROT_READ|(tdb->read_only? 0:PROT_WRITE),
+ tdb->map_ptr = mmap(NULL, tdb->map_size,
+ PROT_READ|(tdb->read_only? 0:PROT_WRITE),
MAP_SHARED|MAP_FILE, tdb->fd, 0);
/*
if (tdb->map_ptr == MAP_FAILED) {
tdb->map_ptr = NULL;
- TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n",
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n",
tdb->map_size, strerror(errno)));
}
} else {
if (ftruncate(tdb->fd, size+addition) == -1) {
char b = 0;
if (pwrite(tdb->fd, &b, 1, (size+addition) - 1) != 1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n",
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n",
size+addition, strerror(errno)));
return -1;
}
int n = addition>sizeof(buf)?sizeof(buf):addition;
int ret = pwrite(tdb->fd, buf, n, size);
if (ret != n) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of %d failed (%s)\n",
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of %d failed (%s)\n",
n, strerror(errno)));
return -1;
}
- allow for nested calls to tdb_transaction_start(), re-using the
existing transaction record. If the inner transaction is cancelled
then a subsequent commit will fail
-
+
- keep a mirrored copy of the tdb hash chain heads to allow for the
fast hash heads scan on traverse, updating the mirrored copy in
the transaction version of tdb_write
read while in a transaction. We need to check first if the data is in our list
of transaction elements, then if not do a real read
*/
-static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
+static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
tdb_len_t len, int cv)
{
struct tdb_transaction_el *el;
len -= partial;
off += partial;
buf = (void *)(partial + (char *)buf);
-
+
if (len != 0 && transaction_read(tdb, off, buf, len, cv) != 0) {
goto fail;
}
/*
write while in a transaction
*/
-static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
+static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
const void *buf, tdb_len_t len)
{
struct tdb_transaction_el *el, *best_el=NULL;
if (len == 0) {
return 0;
}
-
+
/* if the write is to a hash head, then update the transaction
hash heads */
if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
len -= partial;
off += partial;
buf = (const void *)(partial + (const char *)buf);
-
+
if (len != 0 && transaction_write(tdb, off, buf, len) != 0) {
goto fail;
}
}
/* see if we can append the new entry to an existing entry */
- if (best_el && best_el->offset + best_el->length == off &&
+ if (best_el && best_el->offset + best_el->length == off &&
(off+len < tdb->transaction->old_map_size ||
off > tdb->transaction->old_map_size)) {
unsigned char *data = best_el->data;
el = (struct tdb_transaction_el *)malloc(sizeof(*el));
if (el == NULL) {
tdb->ecode = TDB_ERR_OOM;
- tdb->transaction->transaction_error = 1;
+ tdb->transaction->transaction_error = 1;
return -1;
}
el->next = NULL;
if (el->data == NULL) {
free(el);
tdb->ecode = TDB_ERR_OOM;
- tdb->transaction->transaction_error = 1;
+ tdb->transaction->transaction_error = 1;
return -1;
}
if (buf) {
/*
transaction version of tdb_expand().
*/
-static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
+static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
tdb_off_t addition)
{
/* add a write to the transaction elements, so subsequent
/*
brlock during a transaction - ignore them
*/
-static int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset,
+static int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset,
int rw_type, int lck_type, int probe, size_t len)
{
return 0;
/* cope with nested tdb_transaction_start() calls */
if (tdb->transaction != NULL) {
tdb->transaction->nesting++;
- TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n",
+ TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n",
tdb->transaction->nesting));
return 0;
}
SAFE_FREE(tdb->transaction);
return -1;
}
-
+
/* get a read lock from the freelist to the end of file. This
is upgraded to a write lock during the commit */
if (tdb_brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {
/* by calling this transaction write here, we ensure that we don't grow the
transaction linked list due to hash table updates */
- if (transaction_write(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
+ if (transaction_write(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
TDB_HASHTABLE_SIZE(tdb)) != 0) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to prime hash table\n"));
tdb->ecode = TDB_ERR_IO;
}
return 0;
-
+
fail:
tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
tdb_transaction_unlock(tdb);
cancel the current transaction
*/
int tdb_transaction_cancel(struct tdb_context *tdb)
-{
+{
if (tdb->transaction == NULL) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
return -1;
tdb->transaction->transaction_error = 1;
tdb->transaction->nesting--;
return 0;
- }
+ }
tdb->map_size = tdb->transaction->old_map_size;
tdb_transaction_unlock(tdb);
SAFE_FREE(tdb->transaction->hash_heads);
SAFE_FREE(tdb->transaction);
-
+
return 0;
}
sync to disk
*/
static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
-{
+{
if (fsync(tdb->fd) != 0) {
tdb->ecode = TDB_ERR_IO;
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
#ifdef MS_SYNC
if (tdb->map_ptr) {
tdb_off_t moffset = offset & ~(tdb->page_size-1);
- if (msync(moffset + (char *)tdb->map_ptr,
+ if (msync(moffset + (char *)tdb->map_ptr,
length + (offset - moffset), MS_SYNC) != 0) {
tdb->ecode = TDB_ERR_IO;
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
allocate the recovery area, or use an existing recovery area if it is
large enough
*/
-static int tdb_recovery_allocate(struct tdb_context *tdb,
+static int tdb_recovery_allocate(struct tdb_context *tdb,
tdb_len_t *recovery_size,
tdb_off_t *recovery_offset,
tdb_len_t *recovery_max_size)
rec.rec_len = 0;
- if (recovery_head != 0 &&
+ if (recovery_head != 0 &&
methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));
return -1;
*recovery_offset = tdb->map_size;
recovery_head = *recovery_offset;
- if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
+ if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
(tdb->map_size - tdb->transaction->old_map_size) +
sizeof(rec) + *recovery_max_size) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
/* write the recovery header offset and sync - we can sync without a race here
as the magic ptr in the recovery record has not been set */
CONVERT(recovery_head);
- if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD,
+ if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD,
&recovery_head, sizeof(tdb_off_t)) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
return -1;
/*
setup the recovery data that will be used on a crash during commit
*/
-static int transaction_setup_recovery(struct tdb_context *tdb,
+static int transaction_setup_recovery(struct tdb_context *tdb,
tdb_off_t *magic_offset)
{
struct tdb_transaction_el *el;
/*
check that the recovery area has enough space
*/
- if (tdb_recovery_allocate(tdb, &recovery_size,
+ if (tdb_recovery_allocate(tdb, &recovery_size,
&recovery_offset, &recovery_max_size) == -1) {
return -1;
}
commit the current transaction
*/
int tdb_transaction_commit(struct tdb_context *tdb)
-{
+{
const struct tdb_methods *methods;
tdb_off_t magic_offset = 0;
u32 zero = 0;
if (tdb->transaction->nesting != 0) {
tdb->transaction->nesting--;
return 0;
- }
+ }
/* check for a null transaction */
if (tdb->transaction->elements == NULL) {
}
methods = tdb->transaction->io_methods;
-
+
/* if there are any locks pending then the caller has not
nested their locks properly, so fail the transaction */
if (tdb->num_locks || tdb->global_lock.count) {
/* expand the file to the new size if needed */
if (tdb->map_size != tdb->transaction->old_map_size) {
- if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
- tdb->map_size -
+ if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
+ tdb->map_size -
tdb->transaction->old_map_size) == -1) {
tdb->ecode = TDB_ERR_IO;
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: expansion failed\n"));
if (methods->tdb_write(tdb, el->offset, el->data, el->length) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n"));
-
+
/* we've overwritten part of the data and
possibly expanded the file, so we need to
run the crash recovery code */
tdb->methods = methods;
- tdb_transaction_recover(tdb);
+ tdb_transaction_recover(tdb);
tdb_transaction_cancel(tdb);
tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
return -1;
}
tdb->transaction->elements = el->next;
- free(el->data);
+ free(el->data);
free(el);
- }
+ }
if (!(tdb->flags & TDB_NOSYNC)) {
/* ensure the new data is on disk */
}
/* read the recovery record */
- if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
+ if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
sizeof(rec), DOCONV()) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));
tdb->ecode = TDB_ERR_IO;
return -1;
}
data = (unsigned char *)malloc(rec.data_len);
if (data == NULL) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));
tdb->ecode = TDB_ERR_OOM;
return -1;
}
/* read the full recovery data */
if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
rec.data_len, 0) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));
+ TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));
tdb->ecode = TDB_ERR_IO;
return -1;
}
if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n"));
tdb->ecode = TDB_ERR_IO;
- return -1;
+ return -1;
}
}
/* remove the recovery magic */
- if (tdb_ofs_write(tdb, recovery_head + offsetof(struct list_struct, magic),
+ if (tdb_ofs_write(tdb, recovery_head + offsetof(struct list_struct, magic),
&zero) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
tdb->ecode = TDB_ERR_IO;
- return -1;
+ return -1;
}
-
+
/* reduce the file size to the old size */
tdb_munmap(tdb);
if (ftruncate(tdb->fd, recovery_eof) != 0) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n"));
tdb->ecode = TDB_ERR_IO;
- return -1;
+ return -1;
}
tdb->map_size = recovery_eof;
tdb_mmap(tdb);
return -1;
}
- TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n",
+ TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n",
recovery_eof));
/* all done */
if (rec->magic == TDB_MAGIC) {
/* this happens when a app is showdown while deleting a record - we should
not completely fail when this happens */
- TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n",
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n",
rec->magic, off));
rec->magic = TDB_FREE_MAGIC;
if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
if (rec->magic != TDB_FREE_MAGIC) {
/* Ensure ecode is set for log fn. */
tdb->ecode = TDB_ERR_CORRUPT;
- TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n",
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n",
rec->magic, off));
return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
}
if (left > TDB_DATA_START(tdb->header.hash_size)) {
struct list_struct l;
tdb_off_t leftsize;
-
+
/* Read in tailer and jump back to header */
if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left));
}
-/*
+/*
the core of tdb_allocate - called when we have decided which
free list entry to use
*/
if (rec->rec_len > length + MIN_REC_SIZE) {
/* Length of left piece */
length = TDB_ALIGN(length, TDB_ALIGNMENT);
-
+
/* Right piece to go on free list */
newrec.rec_len = rec->rec_len - (sizeof(*rec) + length);
newrec_ptr = rec_ptr + sizeof(*rec) + length;
-
+
/* And left record is shortened */
rec->rec_len = length;
} else {
newrec_ptr = 0;
}
-
+
/* Remove allocated record from the free list */
if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
return 0;
}
-
+
/* Update header: do this before we drop alloc
lock, otherwise tdb_free() might try to
merge with us, thinking we're free.
if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
return 0;
}
-
+
/* Did we create new block? */
if (newrec_ptr) {
/* Update allocated record tailer (we
if (update_tailer(tdb, rec_ptr, rec) == -1) {
return 0;
}
-
+
/* Free new record */
if (tdb_free(tdb, newrec_ptr, &newrec) == -1) {
return 0;
}
}
-
+
/* all done - return the new record offset */
return rec_ptr;
}
bestfit.last_ptr = 0;
bestfit.rec_len = 0;
- /*
+ /*
this is a best fit allocation strategy. Originally we used
a first fit strategy, but it suffered from massive fragmentation
issues when faced with a slowly increasing record size.
common for the use of tdb with ldb, where large
hashes are used. In that case we spend most of our
time in tdb_brlock(), locking empty hash chains.
-
+
To avoid this, we do an unlocked pre-check to see
if the hash chain is empty before starting to look
inside it. If it is empty then we can avoid that
the value we get back, as we read it without a
lock, so instead we get the lock and re-fetch the
value below.
-
+
Notice that not doing this optimisation on the
first hash chain is critical. We must guarantee
that we have done at least one fcntl lock at the
could possibly miss those with this trick, but we
could miss them anyway without this trick, so the
semantics don't change.
-
+
With a non-indexed ldb search this trick gains us a
factor of around 80 in speed on a linux 2.6.x
system (testing using ldbtest).
/* Try to clean dead ones from old traverses */
current = tlock->off;
tlock->off = rec->next;
- if (!(tdb->read_only || tdb->traverse_read) &&
+ if (!(tdb->read_only || tdb->traverse_read) &&
tdb_do_delete(tdb, current, rec) != 0)
goto fail;
}
if fn is NULL then it is not called
a non-zero return value from fn() indicates that the traversal should stop
*/
-static int tdb_traverse_internal(struct tdb_context *tdb,
+static int tdb_traverse_internal(struct tdb_context *tdb,
tdb_traverse_func fn, void *private_data,
struct tdb_traverse_lock *tl)
{
while ((ret = tdb_next_lock(tdb, tl, &rec)) > 0) {
count++;
/* now read the full record */
- key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec),
+ key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec),
rec.key_len + rec.data_len);
if (!key.dptr) {
ret = -1;
/*
a write style traverse - temporarily marks the db read only
*/
-int tdb_traverse_read(struct tdb_context *tdb,
+int tdb_traverse_read(struct tdb_context *tdb,
tdb_traverse_func fn, void *private_data)
{
struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK };
a write style traverse - needs to get the transaction lock to
prevent deadlocks
*/
-int tdb_traverse(struct tdb_context *tdb,
+int tdb_traverse(struct tdb_context *tdb,
tdb_traverse_func fn, void *private_data)
{
struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
if (tdb->read_only || tdb->traverse_read) {
return tdb_traverse_read(tdb, fn, private_data);
}
-
+
if (tdb_transaction_lock(tdb, F_WRLCK)) {
return -1;
}
struct list_struct rec;
tdb_off_t tailer_ofs, tailer;
- if (tdb->methods->tdb_read(tdb, offset, (char *)&rec,
+ if (tdb->methods->tdb_read(tdb, offset, (char *)&rec,
sizeof(rec), DOCONV()) == -1) {
printf("ERROR: failed to read record at %u\n", offset);
return 0;
printf("freelist top=[0x%08x]\n", rec_ptr );
while (rec_ptr) {
- if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec,
+ if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec,
sizeof(rec), DOCONV()) == -1) {
tdb_unlock(tdb, -1, F_WRLCK);
return -1;
return -1;
}
- printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n",
+ printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n",
rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len);
total_free += rec.rec_len;
/* move to the next record */
rec_ptr = rec.next;
}
- printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,
+ printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,
(int)total_free);
return tdb_unlock(tdb, -1, F_WRLCK);
/* file: tdb.c */
-TDB_DATA tdb_null;
-
/*
non-blocking increment of the tdb sequence number if the tdb has been opened using
the TDB_SEQNUM flag
void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
{
tdb_off_t seqnum=0;
-
+
if (!(tdb->flags & TDB_SEQNUM)) {
return;
}
struct list_struct *r)
{
tdb_off_t rec_ptr;
-
+
/* read in the hash top */
if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
return 0;
rec.data_len = dbuf.dsize;
return tdb_rec_write(tdb, rec_ptr, &rec);
}
-
+
return 0;
}
return ret;
}
-/* check if an entry in the database exists
+/* check if an entry in the database exists
note that 1 is returned if the key is found and 0 is returned if not found
this doesn't match the conventions in the rest of this module, but is
static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash)
{
struct list_struct rec;
-
+
if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
return 0;
tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
int res = 0;
tdb_off_t rec_ptr;
struct list_struct rec;
-
+
/* read in the hash top */
if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
return 0;
if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
return -1;
}
-
+
/* read in the hash top */
if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
goto fail;
struct list_struct *r, tdb_len_t length)
{
tdb_off_t rec_ptr;
-
+
/* read in the hash top */
if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
return 0;
}
/* store an element in the database, replacing any existing element
- with the same key
+ with the same key
return 0 on success, -1 on failure
*/
tdb_increment_seqnum(tdb);
}
- SAFE_FREE(p);
+ SAFE_FREE(p);
tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
return ret;
}
dbuf.dsize += new_dbuf.dsize;
ret = tdb_store(tdb, key, dbuf, 0);
-
+
failed:
tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
SAFE_FREE(dbuf.dptr);
for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
value = (value + (key->dptr[i] << (i*5 % 24)));
- return (1103515243 * value + 12345);
+ return (1103515243 * value + 12345);
}
ino_t ino)
{
struct tdb_context *i;
-
+
for (i = tdbs; i; i = i->next) {
if (i->device == device && i->inode == ino) {
return 1;
return 0;
}
-/* open the database, creating it if necessary
+/* open the database, creating it if necessary
The open_flags and mode are passed straight to the open call on the
database file. A flags value of O_WRONLY is invalid. The hash size
is advisory, use zero for a default value.
- Return is NULL on error, in which case errno is also set. Don't
+ Return is NULL on error, in which case errno is also set. Don't
try to call tdb_error or tdb_errname, just do strerror(errno).
@param name may be NULL for internal databases. */
errno = EINVAL;
goto fail;
}
-
+
if (hash_size == 0)
hash_size = DEFAULT_HASH_SIZE;
if ((open_flags & O_ACCMODE) == O_RDONLY) {
if (!tdb)
return NULL;
-
+
if (tdb->map_ptr) {
if (tdb->flags & TDB_INTERNAL)
SAFE_FREE(tdb->map_ptr);
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
goto fail;
}
- if ((tdb->flags & TDB_CLEAR_IF_FIRST) &&
+ if ((tdb->flags & TDB_CLEAR_IF_FIRST) &&
(tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
goto fail;