r19426: merge nearly all the differences between Samba3 tdb and Samba4
authorAndrew Tridgell <tridge@samba.org>
Fri, 20 Oct 2006 09:55:47 +0000 (09:55 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:15:35 +0000 (12:15 -0500)
tdb. This includes:

 - the new tdb_lockall and tdb_lockall_read code, which will be needed
   for the ldb speedups

 - the tdb logging changes. This is an intermediate step to keep the
   differences between the two branches small. The plan is still to
   move to a tdb_init()/tdb_set_logging_function()/tdb_attach() style
   of open which will make things much cleaner.

 - the updated test suites and standalone tdb build code

 - use libreplace headers

There are still some small differences I haven't merged. I'll discuss
those on the list.
(This used to be commit 48903c75edfaf75dbd3e9d052e615552cdff39b4)

17 files changed:
source3/tdb/Makefile.in
source3/tdb/aclocal.m4
source3/tdb/autogen.sh
source3/tdb/common/freelist.c
source3/tdb/common/io.c
source3/tdb/common/lock.c
source3/tdb/common/open.c
source3/tdb/common/tdb.c
source3/tdb/common/tdb_private.h
source3/tdb/common/tdbutil.c
source3/tdb/common/transaction.c
source3/tdb/common/traverse.c
source3/tdb/config.mk
source3/tdb/include/tdb.h
source3/tdb/include/tdbutil.h
source3/tdb/tools/tdbtest.c
source3/tdb/tools/tdbtorture.c

index 1c23aaeea7fdd4f3ee6680eb6055472cdc8eb004..e158752d4319326fb3e7f9326611f2e9df83aeb4 100644 (file)
@@ -1,54 +1,81 @@
+#!gmake
 #
 # Makefile for tdb directory
 #
 
-CFLAGS = -Iinclude @CFLAGS@
 CC = @CC@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
 bindir = @bindir@
 includedir = @includedir@
 libdir = @libdir@
+VPATH = @srcdir@:@libreplacedir@
+srcdir = @srcdir@
+builddir = @builddir@
+CFLAGS = -I$(srcdir)/include -Iinclude -I@libreplacedir@ @CFLAGS@
+
+.PHONY: test
 
 PROGS = bin/tdbtool bin/tdbtorture
-TDB_OBJ = common/tdb.o common/dump.o common/io.o common/lock.o \
-       common/open.o common/traverse.o common/freelist.o common/error.o \
-       common/transaction.o
+TDB_OBJ = @TDBOBJ@ @LIBREPLACEOBJ@
+
+DIRS = bin common tools
 
-all: $(PROGS)
+all: showflags dirs $(PROGS)
+
+showflags:
+       @echo 'tdb will be compiled with flags:'
+       @echo '  CFLAGS = $(CFLAGS)'
+       @echo '  LIBS = $(LIBS)'
 
 .c.o:
        @echo Compiling $*.c
+       @mkdir -p `dirname $@`
        @$(CC) $(CFLAGS) -c $< -o $@
 
+dirs:
+       @mkdir -p $(DIRS)
+
 install: all
        mkdir -p $(bindir)
        mkdir -p $(includedir)
        mkdir -p $(libdir) 
        mkdir -p $(libdir)/pkgconfig
        cp $(PROGS) $(bindir)
-       cp include/tdb.h $(includedir)
+       cp $(srcdir)/include/tdb.h $(includedir)
        cp tdb.pc $(libdir)/pkgconfig
 
-bin/tdbtest: tools/tdbtest.o $(TDB_OBJ)
-       $(CC) $(CFLAGS) -o bin/tdbtest tools/tdbtest.o $(TDB_OBJ) -lgdbm
+libtdb.a: $(TDB_OBJ)
+       ar -rv libtdb.a $(TDB_OBJ)
+
+bin/tdbtest: tools/tdbtest.o libtdb.a
+       $(CC) $(CFLAGS) -o bin/tdbtest tools/tdbtest.o -L. -ltdb -lgdbm
+
+bin/tdbtool: tools/tdbtool.o libtdb.a
+       $(CC) $(CFLAGS) -o bin/tdbtool tools/tdbtool.o -L. -ltdb
+
+bin/tdbtorture: tools/tdbtorture.o libtdb.a
+       $(CC) $(CFLAGS) -o bin/tdbtorture tools/tdbtorture.o -L. -ltdb
 
-bin/tdbtool: tools/tdbtool.o $(TDB_OBJ)
-       $(CC) $(CFLAGS) -o bin/tdbtool tools/tdbtool.o $(TDB_OBJ)
+bin/tdbdump: tools/tdbdump.o libtdb.a
+       $(CC) $(CFLAGS) -o bin/tdbdump tools/tdbdump.o -L. -ltdb
 
-bin/tdbtorture: tools/tdbtorture.o $(TDB_OBJ)
-       $(CC) $(CFLAGS) -o bin/tdbtorture tools/tdbtorture.o $(TDB_OBJ)
+bin/tdbbackup: tools/tdbbackup.o libtdb.a
+       $(CC) $(CFLAGS) -o bin/tdbbackup tools/tdbbackup.o -L. -ltdb
 
-bin/tdbdump: tools/tdbdump.o $(TDB_OBJ)
-       $(CC) $(CFLAGS) -o bin/tdbdump tools/tdbdump.o $(TDB_OBJ)
+test: bin/tdbtorture
+       bin/tdbtorture
 
-bin/tdbbackup: tools/tdbbackup.o $(TDB_OBJ)
-       $(CC) $(CFLAGS) -o bin/tdbbackup tools/tdbbackup.o $(TDB_OBJ)
+installcheck: test install
 
 clean:
-       rm -f $(PROGS) common/*.o tools/*.o *~ *.bak */*~ */*.bak *% core test.db test.tdb test.gdbm
+       rm -f $(PROGS) *.o *.a common/*.o tools/*.o tdb.pc
+       rm -f test.db test.tdb torture.tdb test.gdbm
 
-installcheck: install
-       $(bindir)/tdbtorture
+distclean: clean
+       rm -f *~ */*~
+       rm -f config.log config.status include/config.h config.cache
+       rm -f Makefile
 
-test: installcheck
+realdistclean: distclean
+       rm -f configure include/config.h.in
index cdc2a2fa5210c9d8eafbb558b947917579f27d83..5605e476bab4eeef40cc586a3fecb1a5c174a5a6 100644 (file)
@@ -1,12 +1 @@
-dnl see if a declaration exists for a function or variable
-dnl defines HAVE_function_DECL if it exists
-dnl AC_HAVE_DECL(var, includes)
-AC_DEFUN(AC_HAVE_DECL,
-[
- AC_CACHE_CHECK([for $1 declaration],ac_cv_have_$1_decl,[
-    AC_TRY_COMPILE([$2],[int i = (int)$1],
-        ac_cv_have_$1_decl=yes,ac_cv_have_$1_decl=no)])
- if test x"$ac_cv_have_$1_decl" = x"yes"; then
-    AC_DEFINE([HAVE_]translit([$1], [a-z], [A-Z])[_DECL],1,[Whether $1() is available])
- fi
-])
+m4_include(libreplace.m4)
index 89053ad9f8ad58cdcaa80e0c3ce327bf7438896e..bf84eeee19a9116f3dc79177449a91321b3e8c31 100755 (executable)
@@ -1,7 +1,13 @@
 #!/bin/sh
 
-autoheader || exit 1
-autoconf || exit 1
+rm -rf autom4te.cache
+rm -f configure config.h.in
+
+IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
+autoconf $IPATHS || exit 1
+autoheader $IPATHS || exit 1
+
+rm -rf autom4te.cache
 
 echo "Now run ./configure and then make."
 exit 0
index 3483751164768243f308813f761ab5816a98a088..9d1ae59801d42ee37b02f331a19309c49e94ca36 100644 (file)
@@ -37,7 +37,7 @@ static int rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_str
        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 0x%x at offset=%d - fixing\n", 
+               TDB_LOG((tdb, TDB_DEBUG_WARNING, "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)
@@ -47,7 +47,7 @@ static int rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_str
        if (rec->magic != TDB_FREE_MAGIC) {
                /* Ensure ecode is set for log fn. */
                tdb->ecode = TDB_ERR_CORRUPT;
-               TDB_LOG((tdb, 0,"rec_free_read bad magic 0x%x at offset=%d\n", 
+               TDB_LOG((tdb, TDB_DEBUG_WARNING, "rec_free_read bad magic 0x%x at offset=%d\n", 
                           rec->magic, off));
                return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
        }
@@ -73,7 +73,7 @@ static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_
                /* Follow chain (next offset is at start of record) */
                last_ptr = i;
        }
-       TDB_LOG((tdb, 0,"remove_from_freelist: not on list at off=%d\n", off));
+       TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off));
        return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
 }
 
@@ -102,7 +102,7 @@ int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
 
        /* set an initial tailer, so if we fail we don't leave a bogus record */
        if (update_tailer(tdb, offset, rec) != 0) {
-               TDB_LOG((tdb, 0, "tdb_free: upfate_tailer failed!\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n"));
                goto fail;
        }
 
@@ -112,14 +112,14 @@ int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec)
                struct list_struct r;
 
                if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_free: right read failed at %u\n", right));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right read failed at %u\n", right));
                        goto left;
                }
 
                /* If it's free, expand to include it. */
                if (r.magic == TDB_FREE_MAGIC) {
                        if (remove_from_freelist(tdb, right, r.next) == -1) {
-                               TDB_LOG((tdb, 0, "tdb_free: right free failed at %u\n", right));
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right free failed at %u\n", right));
                                goto left;
                        }
                        rec->rec_len += sizeof(r) + r.rec_len;
@@ -135,7 +135,7 @@ left:
                
                /* Read in tailer and jump back to header */
                if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_free: left offset read failed at %u\n", left));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left));
                        goto update;
                }
 
@@ -148,14 +148,14 @@ left:
 
                /* Now read in record */
                if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
                        goto update;
                }
 
                /* If it's free, expand to include it. */
                if (l.magic == TDB_FREE_MAGIC) {
                        if (remove_from_freelist(tdb, left, l.next) == -1) {
-                               TDB_LOG((tdb, 0, "tdb_free: left free failed at %u\n", left));
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left free failed at %u\n", left));
                                goto update;
                        } else {
                                offset = left;
@@ -166,7 +166,7 @@ left:
 
 update:
        if (update_tailer(tdb, offset, rec) == -1) {
-               TDB_LOG((tdb, 0, "tdb_free: update_tailer failed at %u\n", offset));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
                goto fail;
        }
 
@@ -176,7 +176,7 @@ update:
        if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
            tdb_rec_write(tdb, offset, rec) == -1 ||
            tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
-               TDB_LOG((tdb, 0, "tdb_free record write failed at offset=%d\n", offset));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset));
                goto fail;
        }
 
index 5d7edfefffadece2976564d4883ee9c7209d4d4b..9a6084888d05a6dce3ea1abc2b6707a9b25522a2 100644 (file)
 
 #include "tdb_private.h"
 
-#ifndef HAVE_PREAD
- static ssize_t pread(int fd, void *buf, size_t count, off_t offset)
-{
-       if (lseek(fd, offset, SEEK_SET) != offset) {
-               errno = EIO;
-               return -1;
-       }
-       return read(fd, buf, count);
-}
-#endif
-
-#ifndef HAVE_PWRITE
- static ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
-{
-       if (lseek(fd, offset, SEEK_SET) != offset) {
-               errno = EIO;
-               return -1;
-       }
-       return write(fd, buf, count);
-}
-#endif
-
 /* 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 
@@ -65,7 +43,7 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
                if (!probe) {
                        /* Ensure ecode is set for log fn. */
                        tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, 0,"tdb_oob len %d beyond internal malloc size %d\n",
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond internal malloc size %d\n",
                                 (int)len, (int)tdb->map_size));
                }
                return TDB_ERRCODE(TDB_ERR_IO, -1);
@@ -79,7 +57,7 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
                if (!probe) {
                        /* Ensure ecode is set for log fn. */
                        tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, 0,"tdb_oob len %d beyond eof at %d\n",
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond eof at %d\n",
                                 (int)len, (int)st.st_size));
                }
                return TDB_ERRCODE(TDB_ERR_IO, -1);
@@ -114,7 +92,7 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
        } else if (pwrite(tdb->fd, buf, len, off) != (ssize_t)len) {
                /* Ensure ecode is set for log fn. */
                tdb->ecode = TDB_ERR_IO;
-               TDB_LOG((tdb, 0,"tdb_write failed at %d len=%d (%s)\n",
+               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d len=%d (%s)\n",
                           off, len, strerror(errno)));
                return TDB_ERRCODE(TDB_ERR_IO, -1);
        }
@@ -146,8 +124,8 @@ static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
                if (ret != (ssize_t)len) {
                        /* Ensure ecode is set for log fn. */
                        tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, 0,"tdb_read failed at %d len=%d ret=%d (%s) map_size=%d\n",
-                                off, len, (int)ret, strerror(errno), (int)tdb->map_size));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d len=%d ret=%d (%s) map_size=%d\n",
+                                off, len, ret, strerror(errno), (int)tdb->map_size));
                        return TDB_ERRCODE(TDB_ERR_IO, -1);
                }
        }
@@ -217,7 +195,7 @@ void tdb_mmap(struct tdb_context *tdb)
 
                if (tdb->map_ptr == MAP_FAILED) {
                        tdb->map_ptr = NULL;
-                       TDB_LOG((tdb, 2, "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 {
@@ -242,7 +220,7 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
        if (ftruncate(tdb->fd, size+addition) == -1) {
                char b = 0;
                if (pwrite(tdb->fd,  &b, 1, (size+addition) - 1) != 1) {
-                       TDB_LOG((tdb, 0, "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;
                }
@@ -256,7 +234,7 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
                int n = addition>sizeof(buf)?sizeof(buf):addition;
                int ret = pwrite(tdb->fd, buf, n, size);
                if (ret != n) {
-                       TDB_LOG((tdb, 0, "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;
                }
@@ -275,7 +253,7 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
        tdb_off_t offset;
 
        if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
-               TDB_LOG((tdb, 0, "lock failed in tdb_expand\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
                return -1;
        }
 
@@ -364,7 +342,7 @@ char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
        if (!(buf = (char *)malloc(len))) {
                /* Ensure ecode is set for log fn. */
                tdb->ecode = TDB_ERR_OOM;
-               TDB_LOG((tdb, 0,"tdb_alloc_read malloc failed len=%d (%s)\n",
+               TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n",
                           len, strerror(errno)));
                return TDB_ERRCODE(TDB_ERR_OOM, buf);
        }
@@ -383,7 +361,7 @@ int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *
        if (TDB_BAD_MAGIC(rec)) {
                /* Ensure ecode is set for log fn. */
                tdb->ecode = TDB_ERR_CORRUPT;
-               TDB_LOG((tdb, 0,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
                return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
        }
        return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
index a96d77a229a02afd60a2c7c65ba526223b083994..a5bff2d0b31ba102993386164d999958fe15e644 100644 (file)
@@ -36,8 +36,8 @@
 
    note that a len of zero means lock to end of file
 */
-int tdb_brlock_len(struct tdb_context *tdb, tdb_off_t offset, 
-                  int rw_type, int lck_type, int probe, size_t len)
+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;
        int ret;
@@ -68,7 +68,7 @@ int tdb_brlock_len(struct tdb_context *tdb, tdb_off_t offset,
                if (!probe && lck_type != F_SETLK) {
                        /* Ensure error code is set for log fun to examine. */
                        tdb->ecode = TDB_ERR_LOCK;
-                       TDB_LOG((tdb, 5,"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);
@@ -88,7 +88,7 @@ int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
        int count = 1000;
        while (count--) {
                struct timeval tv;
-               if (tdb_brlock_len(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) {
+               if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) {
                        return 0;
                }
                if (errno != EDEADLK) {
@@ -99,27 +99,26 @@ int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
                tv.tv_usec = 1;
                select(0, NULL, NULL, NULL, &tv);
        }
-       TDB_LOG((tdb, 5,"tdb_brlock_upgrade failed at offset %d\n", offset));
+       TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock_upgrade failed at offset %d\n", offset));
        return -1;
 }
 
 
-/* a byte range locking function - return 0 on success
-   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(). */
-int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, 
-              int rw_type, int lck_type, int probe)
-{
-       return tdb_brlock_len(tdb, offset, rw_type, lck_type, probe, 1);
-}
-
 /* lock a list in the database. list -1 is the alloc list */
 int tdb_lock(struct tdb_context *tdb, int list, int ltype)
 {
+       /* a global lock allows us to avoid per chain locks */
+       if (tdb->global_lock.count && 
+           (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
+               return 0;
+       }
+
+       if (tdb->global_lock.count) {
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       }
+
        if (list < -1 || list >= (int)tdb->header.hash_size) {
-               TDB_LOG((tdb, 0,"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;
        }
@@ -129,8 +128,8 @@ int tdb_lock(struct tdb_context *tdb, int list, int ltype)
        /* Since fcntl locks don't nest, we do a lock for the first one,
           and simply bump the count for future ones */
        if (tdb->locked[list+1].count == 0) {
-               if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0)) {
-                       TDB_LOG((tdb, 0,"tdb_lock failed on list %d ltype=%d (%s)\n", 
+               if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0, 1)) {
+                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d ltype=%d (%s)\n", 
                                 list, ltype, strerror(errno)));
                        return -1;
                }
@@ -148,23 +147,33 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
 {
        int ret = -1;
 
+       /* a global lock allows us to avoid per chain locks */
+       if (tdb->global_lock.count && 
+           (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
+               return 0;
+       }
+
+       if (tdb->global_lock.count) {
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       }
+
        if (tdb->flags & TDB_NOLOCK)
                return 0;
 
        /* Sanity checks */
        if (list < -1 || list >= (int)tdb->header.hash_size) {
-               TDB_LOG((tdb, 0, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
                return ret;
        }
 
        if (tdb->locked[list+1].count==0) {
-               TDB_LOG((tdb, 0, "tdb_unlock: count is 0\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
                return ret;
        }
 
        if (tdb->locked[list+1].count == 1) {
                /* Down to last nested lock: unlock underneath */
-               ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0);
+               ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, F_SETLKW, 0, 1);
                tdb->num_locks--;
        } else {
                ret = 0;
@@ -172,40 +181,97 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
        tdb->locked[list+1].count--;
 
        if (ret)
-               TDB_LOG((tdb, 0,"tdb_unlock: An error occurred unlocking!\n")); 
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n")); 
        return ret;
 }
 
 
 
 /* lock/unlock entire database */
-int tdb_lockall(struct tdb_context *tdb)
+static int _tdb_lockall(struct tdb_context *tdb, int ltype)
 {
-       u32 i;
-
        /* There are no locks on read-only dbs */
        if (tdb->read_only || tdb->traverse_read)
                return TDB_ERRCODE(TDB_ERR_LOCK, -1);
-       for (i = 0; i < tdb->header.hash_size; i++) 
-               if (tdb_lock(tdb, i, F_WRLCK))
-                       break;
 
-       /* If error, release locks we have... */
-       if (i < tdb->header.hash_size) {
-               u32 j;
+       if (tdb->global_lock.count && tdb->global_lock.ltype == ltype) {
+               tdb->global_lock.count++;
+               return 0;
+       }
+
+       if (tdb->global_lock.count) {
+               /* 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 (tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, F_SETLKW, 
+                                    0, 4*tdb->header.hash_size)) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno)));
+               return -1;
+       }
+
+       tdb->global_lock.count = 1;
+       tdb->global_lock.ltype = ltype;
+
+       return 0;
+}
+
+/* unlock entire db */
+static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
+{
+       /* There are no locks on read-only dbs */
+       if (tdb->read_only || tdb->traverse_read) {
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       }
 
-               for ( j = 0; j < i; j++)
-                       tdb_unlock(tdb, j, F_WRLCK);
-               return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
+       if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) {
+               return TDB_ERRCODE(TDB_ERR_LOCK, -1);
+       }
+
+       if (tdb->global_lock.count > 1) {
+               tdb->global_lock.count--;
+               return 0;
        }
 
+       if (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;
+       }
+
+       tdb->global_lock.count = 0;
+       tdb->global_lock.ltype = 0;
+
        return 0;
 }
-void tdb_unlockall(struct tdb_context *tdb)
+
+/* lock entire database with write lock */
+int tdb_lockall(struct tdb_context *tdb)
+{
+       return _tdb_lockall(tdb, F_WRLCK);
+}
+
+/* unlock entire database with write lock */
+int tdb_unlockall(struct tdb_context *tdb)
+{
+       return _tdb_unlockall(tdb, F_WRLCK);
+}
+
+/* lock entire database with read lock */
+int tdb_lockall_read(struct tdb_context *tdb)
+{
+       return _tdb_lockall(tdb, F_RDLCK);
+}
+
+/* unlock entire database with read lock */
+int tdb_unlockall_read(struct tdb_context *tdb)
 {
-       u32 i;
-       for (i=0; i < tdb->header.hash_size; i++)
-               tdb_unlock(tdb, i, F_WRLCK);
+       return _tdb_unlockall(tdb, F_RDLCK);
 }
 
 /* lock/unlock one hash chain. This is meant to be used to reduce
@@ -235,7 +301,7 @@ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
 /* record lock stops delete underneath */
 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
 {
-       return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0) : 0;
+       return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0;
 }
 
 /*
@@ -249,7 +315,7 @@ int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off)
        for (i = &tdb->travlocks; i; i = i->next)
                if (i->off == off)
                        return -1;
-       return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1);
+       return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1);
 }
 
 /*
@@ -258,7 +324,7 @@ int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off)
 */
 int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off)
 {
-       return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0);
+       return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1);
 }
 
 /* fcntl locks don't stack: avoid unlocking someone else's */
@@ -272,5 +338,5 @@ int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off)
        for (i = &tdb->travlocks; i; i = i->next)
                if (i->off == off)
                        count++;
-       return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0) : 0);
+       return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0);
 }
index b53b4c9f5ca678f35f389341dbd86fcd172e0ef1..e1f21aa8560b3e02bfadc2e0a61914de30f5f7da 100644 (file)
@@ -123,15 +123,16 @@ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
 }
 
 /* a default logging function */
-static void null_log_fn(struct tdb_context *tdb, int level, const char *fmt, ...)
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
 {
 }
 
 
 struct 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_hash_func hash_fn)
+                               int open_flags, mode_t mode,
+                               const struct tdb_logging_context *log_ctx,
+                               tdb_hash_func hash_fn)
 {
        struct tdb_context *tdb;
        struct stat st;
@@ -150,7 +151,12 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        tdb->map_ptr = NULL;
        tdb->flags = tdb_flags;
        tdb->open_flags = open_flags;
-       tdb->log_fn = log_fn?log_fn:null_log_fn;
+       if (log_ctx) {
+               tdb->log = *log_ctx;
+       } else {
+               tdb->log.log_fn = null_log_fn;
+               tdb->log.log_private = NULL;
+       }
        tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
 
        /* cache the page size */
@@ -160,7 +166,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        }
 
        if ((open_flags & O_ACCMODE) == O_WRONLY) {
-               TDB_LOG((tdb, 0, "tdb_open_ex: can't open tdb %s write-only\n",
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
                         name));
                errno = EINVAL;
                goto fail;
@@ -180,31 +186,31 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
                tdb->flags &= ~TDB_CLEAR_IF_FIRST;
                if (tdb_new_database(tdb, hash_size) != 0) {
-                       TDB_LOG((tdb, 0, "tdb_open_ex: tdb_new_database failed!"));
+                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
                        goto fail;
                }
                goto internal;
        }
 
        if ((tdb->fd = open(name, open_flags, mode)) == -1) {
-               TDB_LOG((tdb, 5, "tdb_open_ex: could not open file %s: %s\n",
+               TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n",
                         name, strerror(errno)));
                goto fail;      /* errno set by open(2) */
        }
 
        /* ensure there is only one process initialising at once */
-       if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
-               TDB_LOG((tdb, 0, "tdb_open_ex: failed to get global lock on %s: %s\n",
+       if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
                         name, strerror(errno)));
                goto fail;      /* errno set by tdb_brlock */
        }
 
        /* we need to zero database if we are the only one with it open */
        if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
-           (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))) {
+           (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) {
                open_flags |= O_CREAT;
                if (ftruncate(tdb->fd, 0) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_open_ex: "
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
                                 "failed to truncate %s: %s\n",
                                 name, strerror(errno)));
                        goto fail; /* errno set by ftruncate */
@@ -236,13 +242,13 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                goto fail;
 
        if (tdb->header.rwlocks != 0) {
-               TDB_LOG((tdb, 5, "tdb_open_ex: spinlocks no longer supported\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
                goto fail;
        }
 
        /* Is it already in the open list?  If so, fail. */
        if (tdb_already_open(st.st_dev, st.st_ino)) {
-               TDB_LOG((tdb, 2, "tdb_open_ex: "
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
                         "%s (%d,%d) is already open in this process\n",
                         name, (int)st.st_dev, (int)st.st_ino));
                errno = EBUSY;
@@ -260,7 +266,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        tdb->locked = (struct tdb_lock_type *)calloc(tdb->header.hash_size+1,
                                                     sizeof(tdb->locked[0]));
        if (!tdb->locked) {
-               TDB_LOG((tdb, 2, "tdb_open_ex: "
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
                         "failed to allocate lock structure for %s\n",
                         name));
                errno = ENOMEM;
@@ -268,8 +274,8 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        }
        tdb_mmap(tdb);
        if (locked) {
-               if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_open_ex: "
+               if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
                                 "failed to take ACTIVE_LOCK on %s: %s\n",
                                 name, strerror(errno)));
                        goto fail;
@@ -283,7 +289,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
 
        if (tdb_flags & TDB_CLEAR_IF_FIRST) {
                /* leave this lock in place to indicate it's in use */
-               if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)
+               if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)
                        goto fail;
        }
 
@@ -296,7 +302,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        /* Internal (memory-only) databases skip all the code above to
         * do with disk files, and resume here by releasing their
         * global lock and hooking into the active list. */
-       if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0) == -1)
+       if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
                goto fail;
        tdb->next = tdbs;
        tdbs = tdb;
@@ -317,7 +323,7 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        SAFE_FREE(tdb->name);
        if (tdb->fd != -1)
                if (close(tdb->fd) != 0)
-                       TDB_LOG((tdb, 5, "tdb_open_ex: failed to close tdb->fd on error!\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
        SAFE_FREE(tdb->locked);
        SAFE_FREE(tdb);
        errno = save_errno;
@@ -365,11 +371,16 @@ int tdb_close(struct tdb_context *tdb)
 }
 
 /* register a loging function */
-void tdb_logging_function(struct tdb_context *tdb, void (*fn)(struct tdb_context *, int , const char *, ...))
+void tdb_set_logging_function(struct tdb_context *tdb,
+                              const struct tdb_logging_context *log)
 {
-       tdb->log_fn = fn?fn:null_log_fn;
+        tdb->log = *log;
 }
 
+void *tdb_get_logging_private(struct tdb_context *tdb)
+{
+       return tdb->log.log_private;
+}
 
 /* reopen a tdb - this can be used after a fork to ensure that we have an independent
    seek pointer from our parent and to re-establish locks */
@@ -381,38 +392,38 @@ int tdb_reopen(struct tdb_context *tdb)
                return 0; /* Nothing to do. */
        }
 
-       if (tdb->num_locks != 0) {
-               TDB_LOG((tdb, 0, "tdb_reopen: reopen not allowed with locks held\n"));
+       if (tdb->num_locks != 0 || tdb->global_lock.count) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
                goto fail;
        }
 
        if (tdb->transaction != 0) {
-               TDB_LOG((tdb, 0, "tdb_reopen: reopen not allowed inside a transaction\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n"));
                goto fail;
        }
 
        if (tdb_munmap(tdb) != 0) {
-               TDB_LOG((tdb, 0, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
                goto fail;
        }
        if (close(tdb->fd) != 0)
-               TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
        tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
        if (tdb->fd == -1) {
-               TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno)));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
                goto fail;
        }
        if ((tdb->flags & TDB_CLEAR_IF_FIRST) && 
-           (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)) {
-               TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n"));
+           (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;
        }
        if (fstat(tdb->fd, &st) != 0) {
-               TDB_LOG((tdb, 0, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
                goto fail;
        }
        if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
-               TDB_LOG((tdb, 0, "tdb_reopen: file dev/inode has changed!\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n"));
                goto fail;
        }
        tdb_mmap(tdb);
index 524d404a5065e94a85a5652922384d8c110f123d..addb5b43782249a573a7a6b2dbcf5d1331e86f71 100644 (file)
@@ -42,7 +42,7 @@ static void tdb_increment_seqnum(struct tdb_context *tdb)
                return;
        }
 
-       if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1) != 0) {
+       if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) {
                return;
        }
 
@@ -53,7 +53,7 @@ static void tdb_increment_seqnum(struct tdb_context *tdb)
        seqnum++;
        tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
 
-       tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1);
+       tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);
 }
 
 
@@ -236,7 +236,7 @@ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash)
        }
 
        if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
-               TDB_LOG((tdb, 0, "tdb_delete: WARNING tdb_unlock failed!\n"));
+               TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
        return ret;
 }
 
@@ -403,7 +403,7 @@ int tdb_fd(struct tdb_context *tdb)
 */
 tdb_log_func tdb_log_fn(struct tdb_context *tdb)
 {
-       return tdb->log_fn;
+       return tdb->log.log_fn;
 }
 
 
@@ -429,3 +429,14 @@ int tdb_hash_size(struct tdb_context *tdb)
 {
        return tdb->header.hash_size;
 }
+
+size_t tdb_map_size(struct tdb_context *tdb)
+{
+       return tdb->map_size;
+}
+
+int tdb_get_flags(struct tdb_context *tdb)
+{
+       return tdb->flags;
+}
+
index d4f94048a4551bf4d06f3cc52952536ec051fe32..cd573654340e5b38472b2d46e9b39f0d512a2e02 100644 (file)
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#ifndef _SAMBA_BUILD_
-#include <stdlib.h>
-#include <stdio.h>
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "system/shmem.h"
+#include "system/select.h"
 #include "tdb.h"
 
-#ifndef HAVE_PREAD_DECL
-ssize_t pread(int fd, void *buf, size_t count, off_t offset);
-#endif
-#ifndef HAVE_PWRITE_DECL
-ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
-#endif
-
-#else
-#include "includes.h"
-#undef malloc
-#undef realloc
-#undef calloc
-#undef strdup
-#endif
-
 #ifndef u32
 #define u32 unsigned
 #endif
@@ -100,21 +71,13 @@ typedef u32 tdb_off_t;
 /* NB assumes there is a local variable called "tdb" that is the
  * current context, also takes doubly-parenthesized print-style
  * argument. */
-#define TDB_LOG(x) tdb->log_fn x
+#define TDB_LOG(x) tdb->log.log_fn x
 
 /* lock offsets */
 #define GLOBAL_LOCK      0
 #define ACTIVE_LOCK      4
 #define TRANSACTION_LOCK 8
 
-#ifndef MAP_FILE
-#define MAP_FILE 0
-#endif
-
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *)-1)
-#endif
-
 /* free memory if the pointer is valid and zero the pointer */
 #ifndef SAFE_FREE
 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
@@ -178,7 +141,7 @@ struct tdb_methods {
        void (*next_hash_chain)(struct tdb_context *, u32 *);
        int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
        int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
-       int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int);
+       int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_t);
 };
 
 struct tdb_context {
@@ -188,6 +151,7 @@ struct tdb_context {
        tdb_len_t map_size; /* how much space has been mapped */
        int read_only; /* opened read-only */
        int traverse_read; /* read-only traversal */
+       struct tdb_lock_type global_lock;
        struct tdb_lock_type *locked; /* array of chain locks */
        enum TDB_ERROR ecode; /* error code for last tdb error */
        struct tdb_header header; /* a cached copy of the header */
@@ -196,7 +160,7 @@ struct tdb_context {
        struct tdb_context *next; /* all tdbs to avoid multiple opens */
        dev_t device;   /* uniquely identifies this tdb */
        ino_t inode;    /* uniquely identifies this tdb */
-       void (*log_fn)(struct tdb_context *tdb, int level, const char *, ...) PRINTF_ATTRIBUTE(3,4); /* logging function */
+       struct tdb_logging_context log;
        unsigned int (*hash_fn)(TDB_DATA *key);
        int open_flags; /* flags used in the open - needed by reopen */
        unsigned int num_locks; /* number of chain locks held */
@@ -213,10 +177,8 @@ int tdb_munmap(struct tdb_context *tdb);
 void tdb_mmap(struct tdb_context *tdb);
 int tdb_lock(struct tdb_context *tdb, int list, int ltype);
 int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
-int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe);
+int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len);
 int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len);
-int tdb_brlock_len(struct tdb_context *tdb, tdb_off_t offset, 
-                  int rw_type, int lck_type, int probe, size_t len);
 int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off);
 int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off);
 int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
index 45e18913241bbefd7b1eb638849605e64750f3e9..3e18c09fbf321bd772b78a7fcc93050612d7e312 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "tdb_private.h"
-#include <fnmatch.h>
+#include "includes.h"
+#undef malloc
+#undef realloc
+#undef calloc
+#undef strdup
 
 /***************************************************************
  Allow a caller to set a "alarm" flag that tdb can check to abort
@@ -91,7 +94,7 @@ static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key,
                CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
                if (gotalarm) {
                        DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
-                               timeout, key.dptr, tdb->name ));
+                               timeout, key.dptr, tdb_name(tdb)));
                        /* TODO: If we time out waiting for a lock, it might
                         * be nice to use F_GETLK to get the pid of the
                         * process currently holding the lock and print that
@@ -657,7 +660,7 @@ int tdb_unpack(char *buf, int bufsize, const char *fmt, ...)
  Log tdb messages via DEBUG().
 ****************************************************************************/
 
-static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
+static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
 {
        va_list ap;
        char *ptr = NULL;
@@ -669,7 +672,7 @@ static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
        if (!ptr || !*ptr)
                return;
 
-       DEBUG(level, ("tdb(%s): %s", tdb->name ? tdb->name : "unnamed", ptr));
+       DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
        SAFE_FREE(ptr);
 }
 
@@ -682,12 +685,16 @@ TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
                          int open_flags, mode_t mode)
 {
        TDB_CONTEXT *tdb;
+       struct tdb_logging_context log_ctx;
 
        if (!lp_use_mmap())
                tdb_flags |= TDB_NOMMAP;
 
+       log_ctx.log_fn = tdb_log;
+       log_ctx.log_private = NULL;
+
        tdb = tdb_open_ex(name, hash_size, tdb_flags, 
-                                   open_flags, mode, tdb_log, NULL);
+                         open_flags, mode, &log_ctx, NULL);
        if (!tdb)
                return NULL;
 
@@ -773,16 +780,6 @@ void tdb_search_list_free(TDB_LIST_NODE* node)
        };
 }
 
-size_t tdb_map_size(struct tdb_context *tdb)
-{
-       return tdb->map_size;
-}
-
-int tdb_get_flags(struct tdb_context *tdb)
-{
-       return tdb->flags;
-}
-
 /****************************************************************************
  tdb_store, wrapped in a transaction. This way we make sure that a process
  that dies within writing does not leave a corrupt tdb behind.
index 8e21e3ad87fcdc5c0c6c7b014cf3949bc425a838..a7ce5e3f618934e730a0e8a4d3852001877e14f7 100644 (file)
@@ -183,7 +183,7 @@ static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
        return tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv);
 
 fail:
-       TDB_LOG((tdb, 0, "transaction_read: failed at off=%d len=%d\n", off, len));
+       TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len));
        tdb->ecode = TDB_ERR_IO;
        tdb->transaction->transaction_error = 1;
        return -1;
@@ -308,7 +308,7 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
        return 0;
 
 fail:
-       TDB_LOG((tdb, 0, "transaction_write: failed at off=%d len=%d\n", off, len));
+       TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n", off, len));
        tdb->ecode = TDB_ERR_IO;
        tdb->transaction->transaction_error = 1;
        return -1;
@@ -359,7 +359,7 @@ static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
   brlock during a transaction - ignore them
 */
 int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset, 
-                      int rw_type, int lck_type, int probe)
+                      int rw_type, int lck_type, int probe, size_t len)
 {
        return 0;
 }
@@ -382,7 +382,7 @@ int tdb_transaction_start(struct tdb_context *tdb)
 {
        /* some sanity checks */
        if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) {
-               TDB_LOG((tdb, 0, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n"));
                tdb->ecode = TDB_ERR_EINVAL;
                return -1;
        }
@@ -390,16 +390,16 @@ int tdb_transaction_start(struct tdb_context *tdb)
        /* cope with nested tdb_transaction_start() calls */
        if (tdb->transaction != NULL) {
                tdb->transaction->nesting++;
-               TDB_LOG((tdb, 0, "tdb_transaction_start: nesting %d\n", 
+               TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", 
                         tdb->transaction->nesting));
                return 0;
        }
 
-       if (tdb->num_locks != 0) {
+       if (tdb->num_locks != 0 || tdb->global_lock.count) {
                /* the caller must not have any locks when starting a
                   transaction as otherwise we'll be screwed by lack
                   of nested locks in posix */
-               TDB_LOG((tdb, 0, "tdb_transaction_start: cannot start a transaction with locks held\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n"));
                tdb->ecode = TDB_ERR_LOCK;
                return -1;
        }
@@ -408,7 +408,7 @@ int tdb_transaction_start(struct tdb_context *tdb)
                /* you cannot use transactions inside a traverse (although you can use
                   traverse inside a transaction) as otherwise you can end up with
                   deadlock */
-               TDB_LOG((tdb, 0, "tdb_transaction_start: cannot start a transaction within a traverse\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction within a traverse\n"));
                tdb->ecode = TDB_ERR_LOCK;
                return -1;
        }
@@ -423,8 +423,8 @@ int tdb_transaction_start(struct tdb_context *tdb)
        /* get the transaction write lock. This is a blocking lock. As
           discussed with Volker, there are a number of ways we could
           make this async, which we will probably do in the future */
-       if (tdb_brlock_len(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_start: failed to get transaction lock\n"));
+       if (tdb_brlock(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get transaction lock\n"));
                tdb->ecode = TDB_ERR_LOCK;
                SAFE_FREE(tdb->transaction);
                return -1;
@@ -432,23 +432,23 @@ int tdb_transaction_start(struct tdb_context *tdb)
        
        /* 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_len(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_start: failed to get hash locks\n"));
+       if (tdb_brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n"));
                tdb->ecode = TDB_ERR_LOCK;
                goto fail;
        }
 
        /* setup a copy of the hash table heads so the hash scan in
           traverse can be fast */
-       tdb->transaction->hash_heads = (unsigned int *)
-               calloc(tdb->header.hash_size+1, sizeof(tdb_off_t));
+       tdb->transaction->hash_heads = (u32 *)
+               calloc(tdb->header.hash_size+1, sizeof(u32));
        if (tdb->transaction->hash_heads == NULL) {
                tdb->ecode = TDB_ERR_OOM;
                goto fail;
        }
        if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
                                   TDB_HASHTABLE_SIZE(tdb), 0) != 0) {
-               TDB_LOG((tdb, 0, "tdb_transaction_start: failed to read hash heads\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to read hash heads\n"));
                tdb->ecode = TDB_ERR_IO;
                goto fail;
        }
@@ -467,7 +467,7 @@ int tdb_transaction_start(struct tdb_context *tdb)
           transaction linked list due to hash table updates */
        if (transaction_write(tdb, FREELIST_TOP, tdb->transaction->hash_heads, 
                              TDB_HASHTABLE_SIZE(tdb)) != 0) {
-               TDB_LOG((tdb, 0, "tdb_transaction_start: failed to prime hash table\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to prime hash table\n"));
                tdb->ecode = TDB_ERR_IO;
                goto fail;
        }
@@ -475,8 +475,8 @@ int tdb_transaction_start(struct tdb_context *tdb)
        return 0;
        
 fail:
-       tdb_brlock_len(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
-       tdb_brlock_len(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+       tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
+       tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
        SAFE_FREE(tdb->transaction->hash_heads);
        SAFE_FREE(tdb->transaction);
        return -1;
@@ -489,7 +489,7 @@ fail:
 int tdb_transaction_cancel(struct tdb_context *tdb)
 {      
        if (tdb->transaction == NULL) {
-               TDB_LOG((tdb, 0, "tdb_transaction_cancel: no transaction\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
                return -1;
        }
 
@@ -509,12 +509,18 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
                free(el);
        }
 
+       /* remove any global lock created during the transaction */
+       if (tdb->global_lock.count != 0) {
+               tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size);
+               tdb->global_lock.count = 0;
+       }
+
        /* remove any locks created during the transaction */
        if (tdb->num_locks != 0) {
                int h;
                for (h=0;h<tdb->header.hash_size+1;h++) {
                        if (tdb->locked[h].count != 0) {
-                               tdb_brlock_len(tdb,FREELIST_TOP+4*h,F_UNLCK,F_SETLKW, 0, 1);
+                               tdb_brlock(tdb,FREELIST_TOP+4*h,F_UNLCK,F_SETLKW, 0, 1);
                                tdb->locked[h].count = 0;
                        }
                }
@@ -524,8 +530,8 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
        /* restore the normal io methods */
        tdb->methods = tdb->transaction->io_methods;
 
-       tdb_brlock_len(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
-       tdb_brlock_len(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+       tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
+       tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
        SAFE_FREE(tdb->transaction->hash_heads);
        SAFE_FREE(tdb->transaction);
        
@@ -539,7 +545,7 @@ static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t
 {      
        if (fsync(tdb->fd) != 0) {
                tdb->ecode = TDB_ERR_IO;
-               TDB_LOG((tdb, 0, "tdb_transaction: fsync failed\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
                return -1;
        }
 #ifdef MS_SYNC
@@ -548,7 +554,7 @@ static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t
                if (msync(moffset + (char *)tdb->map_ptr, 
                          length + (offset - moffset), MS_SYNC) != 0) {
                        tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, 0, "tdb_transaction: msync failed - %s\n",
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
                                 strerror(errno)));
                        return -1;
                }
@@ -591,7 +597,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
        tdb_off_t recovery_head;
 
        if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
-               TDB_LOG((tdb, 0, "tdb_recovery_allocate: failed to read recovery head\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n"));
                return -1;
        }
 
@@ -599,7 +605,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
 
        if (recovery_head != 0 && 
            methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
-               TDB_LOG((tdb, 0, "tdb_recovery_allocate: failed to read recovery record\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));
                return -1;
        }
 
@@ -619,7 +625,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
           the transaction) */
        if (recovery_head != 0) {
                if (tdb_free(tdb, recovery_head, &rec) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_recovery_allocate: failed to free previous recovery area\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to free previous recovery area\n"));
                        return -1;
                }
        }
@@ -635,7 +641,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
        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, 0, "tdb_recovery_allocate: failed to create recovery area\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
                return -1;
        }
 
@@ -651,7 +657,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
        CONVERT(recovery_head);
        if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD, 
                               &recovery_head, sizeof(tdb_off_t)) == -1) {
-               TDB_LOG((tdb, 0, "tdb_recovery_allocate: failed to write recovery head\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
                return -1;
        }
 
@@ -705,7 +711,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
                        continue;
                }
                if (el->offset + el->length > tdb->transaction->old_map_size) {
-                       TDB_LOG((tdb, 0, "tdb_transaction_commit: transaction data over new region boundary\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n"));
                        free(data);
                        tdb->ecode = TDB_ERR_CORRUPT;
                        return -1;
@@ -733,7 +739,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
 
        /* write the recovery data to the recovery area */
        if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_commit: failed to write recovery data\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery data\n"));
                free(data);
                tdb->ecode = TDB_ERR_IO;
                return -1;
@@ -755,7 +761,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
        *magic_offset = recovery_offset + offsetof(struct list_struct, magic);
 
        if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_commit: failed to write recovery magic\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n"));
                tdb->ecode = TDB_ERR_IO;
                return -1;
        }
@@ -778,14 +784,14 @@ int tdb_transaction_commit(struct tdb_context *tdb)
        u32 zero = 0;
 
        if (tdb->transaction == NULL) {
-               TDB_LOG((tdb, 0, "tdb_transaction_commit: no transaction\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
                return -1;
        }
 
        if (tdb->transaction->transaction_error) {
                tdb->ecode = TDB_ERR_IO;
                tdb_transaction_cancel(tdb);
-               TDB_LOG((tdb, 0, "tdb_transaction_commit: transaction error pending\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
                return -1;
        }
 
@@ -804,16 +810,16 @@ int tdb_transaction_commit(struct tdb_context *tdb)
        
        /* if there are any locks pending then the caller has not
           nested their locks properly, so fail the transaction */
-       if (tdb->num_locks) {
+       if (tdb->num_locks || tdb->global_lock.count) {
                tdb->ecode = TDB_ERR_LOCK;
-               TDB_LOG((tdb, 0, "tdb_transaction_commit: locks pending on commit\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: locks pending on commit\n"));
                tdb_transaction_cancel(tdb);
                return -1;
        }
 
        /* upgrade the main transaction lock region to a write lock */
        if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_start: failed to upgrade hash locks\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to upgrade hash locks\n"));
                tdb->ecode = TDB_ERR_LOCK;
                tdb_transaction_cancel(tdb);
                return -1;
@@ -821,8 +827,8 @@ int tdb_transaction_commit(struct tdb_context *tdb)
 
        /* get the global lock - this prevents new users attaching to the database
           during the commit */
-       if (tdb_brlock_len(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_commit: failed to get global lock\n"));
+       if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: failed to get global lock\n"));
                tdb->ecode = TDB_ERR_LOCK;
                tdb_transaction_cancel(tdb);
                return -1;
@@ -831,8 +837,8 @@ int tdb_transaction_commit(struct tdb_context *tdb)
        if (!(tdb->flags & TDB_NOSYNC)) {
                /* write the recovery data to the end of the file */
                if (transaction_setup_recovery(tdb, &magic_offset) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_transaction_commit: failed to setup recovery data\n"));
-                       tdb_brlock_len(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to setup recovery data\n"));
+                       tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
                        tdb_transaction_cancel(tdb);
                        return -1;
                }
@@ -844,8 +850,8 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                                             tdb->map_size - 
                                             tdb->transaction->old_map_size) == -1) {
                        tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, 0, "tdb_transaction_commit: expansion failed\n"));
-                       tdb_brlock_len(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: expansion failed\n"));
+                       tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
                        tdb_transaction_cancel(tdb);
                        return -1;
                }
@@ -858,7 +864,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                struct tdb_transaction_el *el = tdb->transaction->elements;
 
                if (methods->tdb_write(tdb, el->offset, el->data, el->length) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_transaction_commit: write failed during commit\n"));
+                       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
@@ -867,9 +873,9 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                        tdb_transaction_recover(tdb); 
 
                        tdb_transaction_cancel(tdb);
-                       tdb_brlock_len(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+                       tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
 
-                       TDB_LOG((tdb, 0, "tdb_transaction_commit: write failed\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n"));
                        return -1;
                }
                tdb->transaction->elements = el->next;
@@ -885,7 +891,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
 
                /* remove the recovery marker */
                if (methods->tdb_write(tdb, magic_offset, &zero, 4) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_transaction_commit: failed to remove recovery magic\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to remove recovery magic\n"));
                        return -1;
                }
 
@@ -895,7 +901,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                }
        }
 
-       tdb_brlock_len(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
+       tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
 
        /*
          TODO: maybe write to some dummy hdr field, or write to magic
@@ -933,7 +939,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
 
        /* find the recovery area */
        if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_recover: failed to read recovery head\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery head\n"));
                tdb->ecode = TDB_ERR_IO;
                return -1;
        }
@@ -946,7 +952,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        /* read the recovery record */
        if (tdb->methods->tdb_read(tdb, recovery_head, &rec, 
                                   sizeof(rec), DOCONV()) == -1) {
-               TDB_LOG((tdb, 0, "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;
        }
@@ -957,7 +963,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        }
 
        if (tdb->read_only) {
-               TDB_LOG((tdb, 0, "tdb_transaction_recover: attempt to recover read only database\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: attempt to recover read only database\n"));
                tdb->ecode = TDB_ERR_CORRUPT;
                return -1;
        }
@@ -966,7 +972,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
 
        data = (unsigned char *)malloc(rec.data_len);
        if (data == NULL) {
-               TDB_LOG((tdb, 0, "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;
        }
@@ -974,7 +980,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        /* read the full recovery data */
        if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
                                   rec.data_len, 0) == -1) {
-               TDB_LOG((tdb, 0, "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;
        }
@@ -991,7 +997,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
 
                if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) {
                        free(data);
-                       TDB_LOG((tdb, 0, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs));
                        tdb->ecode = TDB_ERR_IO;
                        return -1;
                }
@@ -1001,7 +1007,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        free(data);
 
        if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_recover: failed to sync recovery\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync recovery\n"));
                tdb->ecode = TDB_ERR_IO;
                return -1;
        }
@@ -1009,7 +1015,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        /* if the recovery area is after the recovered eof then remove it */
        if (recovery_eof <= recovery_head) {
                if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) {
-                       TDB_LOG((tdb, 0, "tdb_transaction_recover: failed to remove recovery head\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n"));
                        tdb->ecode = TDB_ERR_IO;
                        return -1;                      
                }
@@ -1018,7 +1024,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        /* remove the recovery magic */
        if (tdb_ofs_write(tdb, recovery_head + offsetof(struct list_struct, magic), 
                          &zero) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_recover: failed to remove recovery magic\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
                tdb->ecode = TDB_ERR_IO;
                return -1;                      
        }
@@ -1026,7 +1032,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        /* reduce the file size to the old size */
        tdb_munmap(tdb);
        if (ftruncate(tdb->fd, recovery_eof) != 0) {
-               TDB_LOG((tdb, 0, "tdb_transaction_recover: failed to reduce to recovery size\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n"));
                tdb->ecode = TDB_ERR_IO;
                return -1;                      
        }
@@ -1034,12 +1040,12 @@ int tdb_transaction_recover(struct tdb_context *tdb)
        tdb_mmap(tdb);
 
        if (transaction_sync(tdb, 0, recovery_eof) == -1) {
-               TDB_LOG((tdb, 0, "tdb_transaction_recover: failed to sync2 recovery\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync2 recovery\n"));
                tdb->ecode = TDB_ERR_IO;
                return -1;
        }
 
-       TDB_LOG((tdb, 0, "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 */
index 712504a764cfc5632c4db257f23a089c9efcdaeb..6d3b111479c069de630d594c40d61eff0cfdfc48 100644 (file)
@@ -100,7 +100,7 @@ static int tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tloc
 
                        /* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi@exanet.com>. */
                        if (tlock->off == rec->next) {
-                               TDB_LOG((tdb, 0, "tdb_next_lock: loop detected.\n"));
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n"));
                                goto fail;
                        }
 
@@ -127,7 +127,7 @@ static int tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tloc
  fail:
        tlock->off = 0;
        if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0)
-               TDB_LOG((tdb, 0, "tdb_next_lock: On error unlock failed!\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n"));
        return -1;
 }
 
@@ -163,7 +163,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
                        if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0)
                                goto out;
                        if (tdb_unlock_record(tdb, tl->off) != 0)
-                               TDB_LOG((tdb, 0, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
                        goto out;
                }
                key.dsize = rec.key_len;
@@ -180,7 +180,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
                        /* They want us to terminate traversal */
                        ret = count;
                        if (tdb_unlock_record(tdb, tl->off) != 0) {
-                               TDB_LOG((tdb, 0, "tdb_traverse: unlock_record failed!\n"));;
+                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));;
                                ret = -1;
                        }
                        SAFE_FREE(key.dptr);
@@ -208,8 +208,8 @@ int tdb_traverse_read(struct tdb_context *tdb,
        
        /* we need to get a read lock on the transaction lock here to
           cope with the lock ordering semantics of solaris10 */
-       if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_RDLCK, F_SETLKW, 0) == -1) {
-               TDB_LOG((tdb, 0, "tdb_traverse_read: failed to get transaction lock\n"));
+       if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_traverse_read: failed to get transaction lock\n"));
                tdb->ecode = TDB_ERR_LOCK;
                return -1;
        }
@@ -218,7 +218,7 @@ int tdb_traverse_read(struct tdb_context *tdb,
        ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
        tdb->traverse_read--;
 
-       tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0);
+       tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
 
        return ret;
 }
@@ -237,15 +237,15 @@ int tdb_traverse(struct tdb_context *tdb,
                return tdb_traverse_read(tdb, fn, private_data);
        }
        
-       if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
-               TDB_LOG((tdb, 0, "tdb_traverse: failed to get transaction lock\n"));
+       if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_traverse: failed to get transaction lock\n"));
                tdb->ecode = TDB_ERR_LOCK;
                return -1;
        }
 
        ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
 
-       tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0);
+       tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
 
        return ret;
 }
@@ -269,7 +269,7 @@ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
        key.dsize = rec.key_len;
        key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
        if (tdb_unlock(tdb, BUCKET(tdb->travlocks.hash), F_WRLCK) != 0)
-               TDB_LOG((tdb, 0, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
        return key;
 }
 
@@ -311,7 +311,7 @@ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
                        return tdb_null;
                tdb->travlocks.hash = BUCKET(rec.full_hash);
                if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
-                       TDB_LOG((tdb, 0, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
                        return tdb_null;
                }
        }
@@ -325,11 +325,11 @@ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
                                          key.dsize);
                /* Unlock the chain of this new record */
                if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
-                       TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
        }
        /* Unlock the chain of old record */
        if (tdb_unlock(tdb, BUCKET(oldhash), F_WRLCK) != 0)
-               TDB_LOG((tdb, 0, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
        return key;
 }
 
index b1e6e82d7469aad1ceefbd0931c4b3fe236a9bbd..c5d1a3399076d222c821d41e9a4573dc6780de80 100644 (file)
@@ -8,8 +8,7 @@ OBJ_FILES = \
        common/tdb.o common/dump.o common/io.o common/lock.o \
        common/open.o common/traverse.o common/freelist.o \
        common/error.o common/transaction.o common/tdbutil.o
-PUBLIC_DEPENDENCIES = \
-               LIBREPLACE
+CFLAGS = -Ilib/tdb/include
 PUBLIC_HEADERS = include/tdb.h
 #
 # End SUBSYSTEM ldb
index 82f8828c89d0405f310429e2fb22fcae37f2baf4..691c26af8182fffddb3d4db008ad4f4018b33af7 100644 (file)
@@ -55,6 +55,10 @@ enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
                TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
                TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY};
 
+/* debugging uses one of the following levels */
+enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR, 
+                     TDB_DEBUG_WARNING, TDB_DEBUG_TRACE};
+
 typedef struct TDB_DATA {
        char *dptr;
        size_t dsize;
@@ -76,19 +80,24 @@ typedef struct TDB_DATA {
 typedef struct tdb_context TDB_CONTEXT;
 
 typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *);
-typedef void (*tdb_log_func)(struct tdb_context *, int , const char *, ...);
+typedef void (*tdb_log_func)(struct tdb_context *, enum tdb_debug_level, const char *, ...) PRINTF_ATTRIBUTE(3, 4);
 typedef unsigned int (*tdb_hash_func)(TDB_DATA *key);
 
+struct tdb_logging_context {
+        tdb_log_func log_fn;
+        void *log_private;
+};
+
 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
                      int open_flags, mode_t mode);
 struct 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,
+                        const struct tdb_logging_context *log_ctx,
                         tdb_hash_func hash_fn);
 
 int tdb_reopen(struct tdb_context *tdb);
 int tdb_reopen_all(int parent_longlived);
-void tdb_logging_function(struct tdb_context *tdb, tdb_log_func);
+void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log);
 enum TDB_ERROR tdb_error(struct tdb_context *tdb);
 const char *tdb_errorstr(struct tdb_context *tdb);
 TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
@@ -102,16 +111,21 @@ int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *);
 int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *);
 int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
 int tdb_lockall(struct tdb_context *tdb);
-void tdb_unlockall(struct tdb_context *tdb);
+int tdb_unlockall(struct tdb_context *tdb);
+int tdb_lockall_read(struct tdb_context *tdb);
+int tdb_unlockall_read(struct tdb_context *tdb);
 const char *tdb_name(struct tdb_context *tdb);
 int tdb_fd(struct tdb_context *tdb);
 tdb_log_func tdb_log_fn(struct tdb_context *tdb);
+void *tdb_get_logging_private(struct tdb_context *tdb);
 int tdb_transaction_start(struct tdb_context *tdb);
 int tdb_transaction_commit(struct tdb_context *tdb);
 int tdb_transaction_cancel(struct tdb_context *tdb);
 int tdb_transaction_recover(struct tdb_context *tdb);
 int tdb_get_seqnum(struct tdb_context *tdb);
 int tdb_hash_size(struct tdb_context *tdb);
+size_t tdb_map_size(struct tdb_context *tdb);
+int tdb_get_flags(struct tdb_context *tdb);
 
 /* Low level locking functions: use with care */
 int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key);
index 72d1505f4e8c9efafbd1f010f16a7382cf083ca2..cb5d98fc5264e78552d33b49eaa040b4efaed1e7 100644 (file)
@@ -67,7 +67,5 @@ int tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr,
                              uint32 *oldval, uint32 change_val);
 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key,
                                unsigned int timeout);
-int tdb_get_flags(struct tdb_context *tdb);
-size_t tdb_map_size(struct tdb_context *tdb);
 
 #endif /* __TDBUTIL_H__ */
index 89295a3291f6a15d3c34be61f067fbc801dcb153..c7a09789fe0867cf913b1043aaea857c7883ac1d 100644 (file)
@@ -1,48 +1,43 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <signal.h>
-#include "tdb.h"
-#include <gdbm.h>
-
 /* a test program for tdb - the trivial database */
 
+#include "replace.h"
+#include "tdb.h"
+#include "system/filesys.h"
+#include "system/time.h"
+
+#include <gdbm.h>
 
 
 #define DELETE_PROB 7
 #define STORE_PROB 5
 
-static TDB_CONTEXT *db;
+static struct tdb_context *db;
 static GDBM_FILE gdbm;
 
 struct timeval tp1,tp2;
 
-static void start_timer(void)
+static void _start_timer(void)
 {
        gettimeofday(&tp1,NULL);
 }
 
-static double end_timer(void)
+static double _end_timer(void)
 {
        gettimeofday(&tp2,NULL);
        return((tp2.tv_sec - tp1.tv_sec) + 
               (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
 }
 
-static void fatal(char *why)
+static void fatal(const char *why)
 {
        perror(why);
        exit(1);
 }
 
-static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...)
 {
        va_list ap;
     
@@ -179,7 +174,7 @@ static void addrec_gdbm(void)
        free(d);
 }
 
-static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
 {
 #if 0
        printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
@@ -192,14 +187,15 @@ static void merge_test(void)
 {
        int i;
        char keys[5][2];
+       char tdata[] = "test";
        TDB_DATA key, data;
        
        for (i = 0; i < 5; i++) {
-               sprintf(keys[i], "%d", i);
+               snprintf(keys[i],2, "%d", i);
                key.dptr = keys[i];
                key.dsize = 2;
                
-               data.dptr = "test";
+               data.dptr = tdata;
                data.dsize = 4;
                
                if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
@@ -219,16 +215,17 @@ static void merge_test(void)
        tdb_delete(db, key);
 }
        
-int main(int argc, char *argv[])
+ int main(int argc, const char *argv[])
 {
        int i, seed=0;
        int loops = 10000;
+       char test_gdbm[] = "test.gdbm";
 
        unlink("test.gdbm");
 
        db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST, 
                      O_RDWR | O_CREAT | O_TRUNC, 0600);
-       gdbm = gdbm_open("test.gdbm", 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, 
+       gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, 
                         0600, NULL);
 
        if (!db || !gdbm) {
@@ -239,17 +236,17 @@ int main(int argc, char *argv[])
        
 #if 1
        srand(seed);
-       start_timer();
+       _start_timer();
        for (i=0;i<loops;i++) addrec_gdbm();
-       printf("gdbm got %.2f ops/sec\n", i/end_timer());
+       printf("gdbm got %.2f ops/sec\n", i/_end_timer());
 #endif
 
        merge_test();
 
        srand(seed);
-       start_timer();
+       _start_timer();
        for (i=0;i<loops;i++) addrec_db();
-       printf("tdb got %.2f ops/sec\n", i/end_timer());
+       printf("tdb got %.2f ops/sec\n", i/_end_timer());
 
        compare_db();
 
index 2d367b91e1f3012af64ce009376915dde2a3e42a..14a2b48cdc78d4bf5e4d215b1f2cd354e08312cc 100644 (file)
@@ -1,41 +1,43 @@
-#include <stdlib.h>
-#include <time.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include "tdb.h"
-
 /* this tests tdb by doing lots of ops from several simultaneous
-   writers - that stresses the locking code. Build with TDB_DEBUG=1
-   for best effect */
+   writers - that stresses the locking code. 
+*/
 
+#include "replace.h"
+#include "tdb.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
 
 
 #define REOPEN_PROB 30
 #define DELETE_PROB 8
 #define STORE_PROB 4
 #define APPEND_PROB 6
-#define LOCKSTORE_PROB 0
+#define TRANSACTION_PROB 10
+#define LOCKSTORE_PROB 5
 #define TRAVERSE_PROB 20
+#define TRAVERSE_READ_PROB 20
 #define CULL_PROB 100
 #define KEYLEN 3
 #define DATALEN 100
-#define LOCKLEN 20
 
-static TDB_CONTEXT *db;
+static struct tdb_context *db;
+static int in_transaction;
+static int error_count;
 
-static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
 {
        va_list ap;
     
+       error_count++;
+
        va_start(ap, format);
        vfprintf(stdout, format, ap);
        va_end(ap);
@@ -50,10 +52,10 @@ static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
 #endif 
 }
 
-static void fatal(char *why)
+static void fatal(const char *why)
 {
        perror(why);
-       exit(1);
+       error_count++;
 }
 
 static char *randbuf(int len)
@@ -69,41 +71,62 @@ static char *randbuf(int len)
        return buf;
 }
 
-static int cull_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf,
+static int cull_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
                         void *state)
 {
+#if CULL_PROB
        if (random() % CULL_PROB == 0) {
                tdb_delete(tdb, key);
        }
+#endif
        return 0;
 }
 
 static void addrec_db(void)
 {
-       int klen, dlen, slen;
-       char *k, *d, *s;
-       TDB_DATA key, data, lockkey;
+       int klen, dlen;
+       char *k, *d;
+       TDB_DATA key, data;
 
        klen = 1 + (rand() % KEYLEN);
        dlen = 1 + (rand() % DATALEN);
-       slen = 1 + (rand() % LOCKLEN);
 
        k = randbuf(klen);
        d = randbuf(dlen);
-       s = randbuf(slen);
 
-       key.dptr = k;
+       key.dptr = (unsigned char *)k;
        key.dsize = klen+1;
 
-       data.dptr = d;
+       data.dptr = (unsigned char *)d;
        data.dsize = dlen+1;
 
-       lockkey.dptr = s;
-       lockkey.dsize = slen+1;
+#if TRANSACTION_PROB
+       if (in_transaction == 0 && random() % TRANSACTION_PROB == 0) {
+               if (tdb_transaction_start(db) != 0) {
+                       fatal("tdb_transaction_start failed");
+               }
+               in_transaction++;
+               goto next;
+       }
+       if (in_transaction && random() % TRANSACTION_PROB == 0) {
+               if (tdb_transaction_commit(db) != 0) {
+                       fatal("tdb_transaction_commit failed");
+               }
+               in_transaction--;
+               goto next;
+       }
+       if (in_transaction && random() % TRANSACTION_PROB == 0) {
+               if (tdb_transaction_cancel(db) != 0) {
+                       fatal("tdb_transaction_cancel failed");
+               }
+               in_transaction--;
+               goto next;
+       }
+#endif
 
 #if REOPEN_PROB
-       if (random() % REOPEN_PROB == 0) {
-               tdb_reopen_all(1);
+       if (in_transaction == 0 && random() % REOPEN_PROB == 0) {
+               tdb_reopen_all(0);
                goto next;
        } 
 #endif
@@ -135,13 +158,13 @@ static void addrec_db(void)
 
 #if LOCKSTORE_PROB
        if (random() % LOCKSTORE_PROB == 0) {
-               tdb_chainlock(db, lockkey);
+               tdb_chainlock(db, key);
                data = tdb_fetch(db, key);
                if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
                        fatal("tdb_store failed");
                }
                if (data.dptr) free(data.dptr);
-               tdb_chainunlock(db, lockkey);
+               tdb_chainunlock(db, key);
                goto next;
        } 
 #endif
@@ -153,75 +176,143 @@ static void addrec_db(void)
        }
 #endif
 
+#if TRAVERSE_READ_PROB
+       if (random() % TRAVERSE_READ_PROB == 0) {
+               tdb_traverse_read(db, NULL, NULL);
+               goto next;
+       }
+#endif
+
        data = tdb_fetch(db, key);
        if (data.dptr) free(data.dptr);
 
 next:
        free(k);
        free(d);
-       free(s);
 }
 
-static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf,
+static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
                        void *state)
 {
        tdb_delete(tdb, key);
        return 0;
 }
 
-#ifndef NPROC
-#define NPROC 6
-#endif
-
-#ifndef NLOOPS
-#define NLOOPS 200000
-#endif
+static void usage(void)
+{
+       printf("Usage: tdbtorture [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
+       exit(0);
+}
 
-int main(int argc, char *argv[])
+ int main(int argc, char * const *argv)
 {
-       int i, seed=0;
-       int loops = NLOOPS;
-       pid_t pids[NPROC];
+       int i, seed = -1;
+       int num_procs = 3;
+       int num_loops = 5000;
+       int hash_size = 2;
+       int c;
+       extern char *optarg;
+       pid_t *pids;
+
+       struct tdb_logging_context log_ctx;
+       log_ctx.log_fn = tdb_log;
+
+       while ((c = getopt(argc, argv, "n:l:s:H:h")) != -1) {
+               switch (c) {
+               case 'n':
+                       num_procs = strtol(optarg, NULL, 0);
+                       break;
+               case 'l':
+                       num_loops = strtol(optarg, NULL, 0);
+                       break;
+               case 'H':
+                       hash_size = strtol(optarg, NULL, 0);
+                       break;
+               case 's':
+                       seed = strtol(optarg, NULL, 0);
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       unlink("torture.tdb");
+
+       pids = calloc(sizeof(pid_t), num_procs);
+       pids[0] = getpid();
 
-       db = tdb_open("torture.tdb", 0, TDB_CLEAR_IF_FIRST, 
-                     O_RDWR | O_CREAT, 0600);
+       for (i=0;i<num_procs-1;i++) {
+               if ((pids[i+1]=fork()) == 0) break;
+       }
+
+       db = tdb_open_ex("torture.tdb", hash_size, TDB_CLEAR_IF_FIRST, 
+                        O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
        if (!db) {
                fatal("db open failed");
        }
 
-       for (i=0;i<NPROC;i++) {
-               pids[i] = fork();
-               if (pids[i] == 0) {
-                       tdb_reopen_all(1);
+       if (seed == -1) {
+               seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
+       }
 
-                       tdb_logging_function(db, tdb_log);
+       if (i == 0) {
+               printf("testing with %d processes, %d loops, %d hash_size, seed=%d\n", 
+                      num_procs, num_loops, hash_size, seed);
+       }
 
-                       srand(seed + getpid());
-                       srandom(seed + getpid() + time(NULL));
-                       for (i=0;i<loops;i++) addrec_db();
+       srand(seed + i);
+       srandom(seed + i);
 
-                       tdb_traverse(db, NULL, NULL);
-                       tdb_traverse(db, traverse_fn, NULL);
-                       tdb_traverse(db, traverse_fn, NULL);
+       for (i=0;i<num_loops && error_count == 0;i++) {
+               addrec_db();
+       }
 
-                       tdb_close(db);
-                       exit(0);
-               }
+       if (error_count == 0) {
+               tdb_traverse_read(db, NULL, NULL);
+               tdb_traverse(db, traverse_fn, NULL);
+               tdb_traverse(db, traverse_fn, NULL);
        }
 
-       for (i=0;i<NPROC;i++) {
-               int status;
-               if (waitpid(pids[i], &status, 0) != pids[i]) {
-                       printf("failed to wait for %d\n",
-                              (int)pids[i]);
+       tdb_close(db);
+
+       if (getpid() != pids[0]) {
+               return error_count;
+       }
+
+       for (i=1;i<num_procs;i++) {
+               int status, j;
+               pid_t pid;
+               if (error_count != 0) {
+                       /* try and stop the test on any failure */
+                       for (j=1;j<num_procs;j++) {
+                               if (pids[j] != 0) {
+                                       kill(pids[j], SIGTERM);
+                               }
+                       }
+               }
+               pid = waitpid(-1, &status, 0);
+               if (pid == -1) {
+                       perror("failed to wait for child\n");
+                       exit(1);
+               }
+               for (j=1;j<num_procs;j++) {
+                       if (pids[j] == pid) break;
+               }
+               if (j == num_procs) {
+                       printf("unknown child %d exited!?\n", (int)pid);
                        exit(1);
                }
                if (WEXITSTATUS(status) != 0) {
                        printf("child %d exited with status %d\n",
-                              (int)pids[i], WEXITSTATUS(status));
-                       exit(1);
+                              (int)pid, WEXITSTATUS(status));
+                       error_count++;
                }
+               pids[j] = 0;
        }
-       printf("OK\n");
-       return 0;
+
+       if (error_count == 0) {
+               printf("OK\n");
+       }
+
+       return error_count;
 }