#include "spinlock.h"
#else
#include "includes.h"
+
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef malloc
+#undef malloc
+#endif
+
+#ifdef realloc
+#undef realloc
+#endif
+
+#ifdef calloc
+#undef calloc
+#endif
+
+#ifdef strdup
+#undef strdup
+#endif
+
+#ifdef strndup
+#undef strndup
+#endif
+
+#endif
+
#endif
#define TDB_MAGIC_FOOD "TDB file\n"
if (tdb->locked[list+1].count == 0) {
if (!tdb->read_only && tdb->header.rwlocks) {
if (tdb_spinlock(tdb, list, ltype)) {
- TDB_LOG((tdb, 0, "tdb_lock spinlock failed on list ltype=%d\n",
+ TDB_LOG((tdb, 0, "tdb_lock spinlock failed on list %d ltype=%d\n",
list, ltype));
return -1;
}
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, 0,"rec_free_read non-free magic at offset=%d - fixing\n",
+ TDB_LOG((tdb, 0,"rec_free_read non-free magic 0x%x at offset=%d - fixing\n",
rec->magic, off));
rec->magic = TDB_FREE_MAGIC;
if (tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
}
-/* If they do lockkeys, check that this hash is one they locked */
-static int tdb_keylocked(TDB_CONTEXT *tdb, u32 hash)
-{
- u32 i;
- if (!tdb->lockedkeys)
- return 1;
- for (i = 0; i < tdb->lockedkeys[0]; i++)
- if (tdb->lockedkeys[i+1] == hash)
- return 1;
- return TDB_ERRCODE(TDB_ERR_NOLOCK, 0);
-}
-
/* As tdb_find, but if you succeed, keep the lock */
static tdb_off tdb_find_lock_hash(TDB_CONTEXT *tdb, TDB_DATA key, u32 hash, int locktype,
struct list_struct *rec)
{
u32 rec_ptr;
- if (!tdb_keylocked(tdb, hash))
- return 0;
if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
return 0;
if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
{
int want_next = (tlock->off != 0);
- /* No traversal allows if you've called tdb_lockkeys() */
- if (tdb->lockedkeys)
- return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
-
/* Lock each chain from the start one. */
for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
if (tdb_lock(tdb, tlock->hash, F_WRLCK) == -1)
/* find which hash bucket it is in */
hash = tdb->hash_fn(&key);
- if (!tdb_keylocked(tdb, hash))
- return -1;
if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
return -1;
/* find which hash bucket it is in */
hash = tdb->hash_fn(&key);
- if (!tdb_keylocked(tdb, hash))
- return -1;
if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
return -1;
return (1103515243 * value + 12345);
}
-void tdb_set_hash_function(TDB_CONTEXT *tdb, tdb_hash_func fn)
-{
- tdb->hash_fn = fn;
-}
-
/* open the database, creating it if necessary
The open_flags and mode are passed straight to the open call on the
TDB_CONTEXT *tdb_open(const char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode)
{
- return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL);
+ return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
}
TDB_CONTEXT *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
int open_flags, mode_t mode,
- tdb_log_func log_fn)
+ tdb_log_func log_fn,
+ tdb_hash_func hash_fn)
{
TDB_CONTEXT *tdb;
struct stat st;
tdb->fd = -1;
tdb->name = NULL;
tdb->map_ptr = NULL;
- tdb->lockedkeys = NULL;
tdb->flags = tdb_flags;
tdb->open_flags = open_flags;
tdb->log_fn = log_fn;
- tdb->hash_fn = default_tdb_hash;
+ tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
if ((open_flags & O_ACCMODE) == O_WRONLY) {
TDB_LOG((tdb, 0, "tdb_open_ex: can't open tdb %s write-only\n",
if (tdb_already_open(st.st_dev, st.st_ino)) {
TDB_LOG((tdb, 2, "tdb_open_ex: "
"%s (%d,%d) is already open in this process\n",
- name, st.st_dev, st.st_ino));
+ name, (int)st.st_dev, (int)st.st_ino));
errno = EBUSY;
goto fail;
}
if (tdb->fd != -1)
ret = close(tdb->fd);
SAFE_FREE(tdb->locked);
- SAFE_FREE(tdb->lockedkeys);
/* Remove from contexts list */
for (i = &tdbs; *i; i = &(*i)->next) {
/* There are no locks on read-only dbs */
if (tdb->read_only)
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
- if (tdb->lockedkeys)
- return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
for (i = 0; i < tdb->header.hash_size; i++)
if (tdb_lock(tdb, i, F_WRLCK))
break;
tdb_unlock(tdb, i, F_WRLCK);
}
-int tdb_lockkeys(TDB_CONTEXT *tdb, u32 number, TDB_DATA keys[])
-{
- u32 i, j, hash;
-
- /* Can't lock more keys if already locked */
- if (tdb->lockedkeys)
- return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
- if (!(tdb->lockedkeys = malloc(sizeof(u32) * (number+1))))
- return TDB_ERRCODE(TDB_ERR_OOM, -1);
- /* First number in array is # keys */
- tdb->lockedkeys[0] = number;
-
- /* Insertion sort by bucket */
- for (i = 0; i < number; i++) {
- hash = tdb->hash_fn(&keys[i]);
- for (j = 0; j < i && BUCKET(tdb->lockedkeys[j+1]) < BUCKET(hash); j++);
- memmove(&tdb->lockedkeys[j+2], &tdb->lockedkeys[j+1], sizeof(u32) * (i-j));
- tdb->lockedkeys[j+1] = hash;
- }
- /* Finally, lock in order */
- for (i = 0; i < number; i++)
- if (tdb_lock(tdb, i, F_WRLCK))
- break;
-
- /* If error, release locks we have... */
- if (i < number) {
- for ( j = 0; j < i; j++)
- tdb_unlock(tdb, j, F_WRLCK);
- SAFE_FREE(tdb->lockedkeys);
- return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
- }
- return 0;
-}
-
-/* Unlock the keys previously locked by tdb_lockkeys() */
-void tdb_unlockkeys(TDB_CONTEXT *tdb)
-{
- u32 i;
- if (!tdb->lockedkeys)
- return;
- for (i = 0; i < tdb->lockedkeys[0]; i++)
- tdb_unlock(tdb, tdb->lockedkeys[i+1], F_WRLCK);
- SAFE_FREE(tdb->lockedkeys);
-}
-
/* lock/unlock one hash chain. This is meant to be used to reduce
contention - it cannot guarantee how many records will be locked */
int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key)