mirror of
https://github.com/samba-team/samba.git
synced 2025-02-08 05:57:51 +03:00
r19426: merge nearly all the differences between Samba3 tdb and Samba4
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)
This commit is contained in:
parent
3da4607374
commit
7d52581978
@ -1,54 +1,81 @@
|
|||||||
|
#!gmake
|
||||||
#
|
#
|
||||||
# Makefile for tdb directory
|
# Makefile for tdb directory
|
||||||
#
|
#
|
||||||
|
|
||||||
CFLAGS = -Iinclude @CFLAGS@
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
exec_prefix = @exec_prefix@
|
exec_prefix = @exec_prefix@
|
||||||
bindir = @bindir@
|
bindir = @bindir@
|
||||||
includedir = @includedir@
|
includedir = @includedir@
|
||||||
libdir = @libdir@
|
libdir = @libdir@
|
||||||
|
VPATH = @srcdir@:@libreplacedir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
builddir = @builddir@
|
||||||
|
CFLAGS = -I$(srcdir)/include -Iinclude -I@libreplacedir@ @CFLAGS@
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
|
||||||
PROGS = bin/tdbtool bin/tdbtorture
|
PROGS = bin/tdbtool bin/tdbtorture
|
||||||
TDB_OBJ = common/tdb.o common/dump.o common/io.o common/lock.o \
|
TDB_OBJ = @TDBOBJ@ @LIBREPLACEOBJ@
|
||||||
common/open.o common/traverse.o common/freelist.o common/error.o \
|
|
||||||
common/transaction.o
|
|
||||||
|
|
||||||
all: $(PROGS)
|
DIRS = bin common tools
|
||||||
|
|
||||||
|
all: showflags dirs $(PROGS)
|
||||||
|
|
||||||
|
showflags:
|
||||||
|
@echo 'tdb will be compiled with flags:'
|
||||||
|
@echo ' CFLAGS = $(CFLAGS)'
|
||||||
|
@echo ' LIBS = $(LIBS)'
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@echo Compiling $*.c
|
@echo Compiling $*.c
|
||||||
|
@mkdir -p `dirname $@`
|
||||||
@$(CC) $(CFLAGS) -c $< -o $@
|
@$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
dirs:
|
||||||
|
@mkdir -p $(DIRS)
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
mkdir -p $(bindir)
|
mkdir -p $(bindir)
|
||||||
mkdir -p $(includedir)
|
mkdir -p $(includedir)
|
||||||
mkdir -p $(libdir)
|
mkdir -p $(libdir)
|
||||||
mkdir -p $(libdir)/pkgconfig
|
mkdir -p $(libdir)/pkgconfig
|
||||||
cp $(PROGS) $(bindir)
|
cp $(PROGS) $(bindir)
|
||||||
cp include/tdb.h $(includedir)
|
cp $(srcdir)/include/tdb.h $(includedir)
|
||||||
cp tdb.pc $(libdir)/pkgconfig
|
cp tdb.pc $(libdir)/pkgconfig
|
||||||
|
|
||||||
bin/tdbtest: tools/tdbtest.o $(TDB_OBJ)
|
libtdb.a: $(TDB_OBJ)
|
||||||
$(CC) $(CFLAGS) -o bin/tdbtest tools/tdbtest.o $(TDB_OBJ) -lgdbm
|
ar -rv libtdb.a $(TDB_OBJ)
|
||||||
|
|
||||||
bin/tdbtool: tools/tdbtool.o $(TDB_OBJ)
|
bin/tdbtest: tools/tdbtest.o libtdb.a
|
||||||
$(CC) $(CFLAGS) -o bin/tdbtool tools/tdbtool.o $(TDB_OBJ)
|
$(CC) $(CFLAGS) -o bin/tdbtest tools/tdbtest.o -L. -ltdb -lgdbm
|
||||||
|
|
||||||
bin/tdbtorture: tools/tdbtorture.o $(TDB_OBJ)
|
bin/tdbtool: tools/tdbtool.o libtdb.a
|
||||||
$(CC) $(CFLAGS) -o bin/tdbtorture tools/tdbtorture.o $(TDB_OBJ)
|
$(CC) $(CFLAGS) -o bin/tdbtool tools/tdbtool.o -L. -ltdb
|
||||||
|
|
||||||
bin/tdbdump: tools/tdbdump.o $(TDB_OBJ)
|
bin/tdbtorture: tools/tdbtorture.o libtdb.a
|
||||||
$(CC) $(CFLAGS) -o bin/tdbdump tools/tdbdump.o $(TDB_OBJ)
|
$(CC) $(CFLAGS) -o bin/tdbtorture tools/tdbtorture.o -L. -ltdb
|
||||||
|
|
||||||
bin/tdbbackup: tools/tdbbackup.o $(TDB_OBJ)
|
bin/tdbdump: tools/tdbdump.o libtdb.a
|
||||||
$(CC) $(CFLAGS) -o bin/tdbbackup tools/tdbbackup.o $(TDB_OBJ)
|
$(CC) $(CFLAGS) -o bin/tdbdump tools/tdbdump.o -L. -ltdb
|
||||||
|
|
||||||
|
bin/tdbbackup: tools/tdbbackup.o libtdb.a
|
||||||
|
$(CC) $(CFLAGS) -o bin/tdbbackup tools/tdbbackup.o -L. -ltdb
|
||||||
|
|
||||||
|
test: bin/tdbtorture
|
||||||
|
bin/tdbtorture
|
||||||
|
|
||||||
|
installcheck: test install
|
||||||
|
|
||||||
clean:
|
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
|
distclean: clean
|
||||||
$(bindir)/tdbtorture
|
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
|
||||||
|
13
source3/tdb/aclocal.m4
vendored
13
source3/tdb/aclocal.m4
vendored
@ -1,12 +1 @@
|
|||||||
dnl see if a declaration exists for a function or variable
|
m4_include(libreplace.m4)
|
||||||
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
|
|
||||||
])
|
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
autoheader || exit 1
|
rm -rf autom4te.cache
|
||||||
autoconf || exit 1
|
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."
|
echo "Now run ./configure and then make."
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -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) {
|
if (rec->magic == TDB_MAGIC) {
|
||||||
/* this happens when a app is showdown while deleting a record - we should
|
/* this happens when a app is showdown while deleting a record - we should
|
||||||
not completely fail when this happens */
|
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, off));
|
||||||
rec->magic = TDB_FREE_MAGIC;
|
rec->magic = TDB_FREE_MAGIC;
|
||||||
if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
|
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) {
|
if (rec->magic != TDB_FREE_MAGIC) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_CORRUPT;
|
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));
|
rec->magic, off));
|
||||||
return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
|
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) */
|
/* Follow chain (next offset is at start of record) */
|
||||||
last_ptr = i;
|
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);
|
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 */
|
/* set an initial tailer, so if we fail we don't leave a bogus record */
|
||||||
if (update_tailer(tdb, offset, rec) != 0) {
|
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;
|
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;
|
struct list_struct r;
|
||||||
|
|
||||||
if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
|
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;
|
goto left;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If it's free, expand to include it. */
|
/* If it's free, expand to include it. */
|
||||||
if (r.magic == TDB_FREE_MAGIC) {
|
if (r.magic == TDB_FREE_MAGIC) {
|
||||||
if (remove_from_freelist(tdb, right, r.next) == -1) {
|
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;
|
goto left;
|
||||||
}
|
}
|
||||||
rec->rec_len += sizeof(r) + r.rec_len;
|
rec->rec_len += sizeof(r) + r.rec_len;
|
||||||
@ -135,7 +135,7 @@ left:
|
|||||||
|
|
||||||
/* Read in tailer and jump back to header */
|
/* Read in tailer and jump back to header */
|
||||||
if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
|
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;
|
goto update;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,14 +148,14 @@ left:
|
|||||||
|
|
||||||
/* Now read in record */
|
/* Now read in record */
|
||||||
if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
|
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;
|
goto update;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If it's free, expand to include it. */
|
/* If it's free, expand to include it. */
|
||||||
if (l.magic == TDB_FREE_MAGIC) {
|
if (l.magic == TDB_FREE_MAGIC) {
|
||||||
if (remove_from_freelist(tdb, left, l.next) == -1) {
|
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;
|
goto update;
|
||||||
} else {
|
} else {
|
||||||
offset = left;
|
offset = left;
|
||||||
@ -166,7 +166,7 @@ left:
|
|||||||
|
|
||||||
update:
|
update:
|
||||||
if (update_tailer(tdb, offset, rec) == -1) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ update:
|
|||||||
if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
|
if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
|
||||||
tdb_rec_write(tdb, offset, rec) == -1 ||
|
tdb_rec_write(tdb, offset, rec) == -1 ||
|
||||||
tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,28 +29,6 @@
|
|||||||
|
|
||||||
#include "tdb_private.h"
|
#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
|
/* 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
|
see if the database has been expanded by someone else and expand
|
||||||
if necessary
|
if necessary
|
||||||
@ -65,7 +43,7 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
|
|||||||
if (!probe) {
|
if (!probe) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_IO;
|
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));
|
(int)len, (int)tdb->map_size));
|
||||||
}
|
}
|
||||||
return TDB_ERRCODE(TDB_ERR_IO, -1);
|
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) {
|
if (!probe) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_IO;
|
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));
|
(int)len, (int)st.st_size));
|
||||||
}
|
}
|
||||||
return TDB_ERRCODE(TDB_ERR_IO, -1);
|
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) {
|
} else if (pwrite(tdb->fd, buf, len, off) != (ssize_t)len) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_IO;
|
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)));
|
off, len, strerror(errno)));
|
||||||
return TDB_ERRCODE(TDB_ERR_IO, -1);
|
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) {
|
if (ret != (ssize_t)len) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_IO;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
TDB_LOG((tdb, 0,"tdb_read failed at %d len=%d ret=%d (%s) map_size=%d\n",
|
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d len=%d ret=%d (%s) map_size=%d\n",
|
||||||
off, len, (int)ret, strerror(errno), (int)tdb->map_size));
|
off, len, ret, strerror(errno), (int)tdb->map_size));
|
||||||
return TDB_ERRCODE(TDB_ERR_IO, -1);
|
return TDB_ERRCODE(TDB_ERR_IO, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,7 +195,7 @@ void tdb_mmap(struct tdb_context *tdb)
|
|||||||
|
|
||||||
if (tdb->map_ptr == MAP_FAILED) {
|
if (tdb->map_ptr == MAP_FAILED) {
|
||||||
tdb->map_ptr = NULL;
|
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)));
|
tdb->map_size, strerror(errno)));
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
if (ftruncate(tdb->fd, size+addition) == -1) {
|
||||||
char b = 0;
|
char b = 0;
|
||||||
if (pwrite(tdb->fd, &b, 1, (size+addition) - 1) != 1) {
|
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)));
|
size+addition, strerror(errno)));
|
||||||
return -1;
|
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 n = addition>sizeof(buf)?sizeof(buf):addition;
|
||||||
int ret = pwrite(tdb->fd, buf, n, size);
|
int ret = pwrite(tdb->fd, buf, n, size);
|
||||||
if (ret != n) {
|
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)));
|
n, strerror(errno)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -275,7 +253,7 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
|
|||||||
tdb_off_t offset;
|
tdb_off_t offset;
|
||||||
|
|
||||||
if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
|
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;
|
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))) {
|
if (!(buf = (char *)malloc(len))) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_OOM;
|
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)));
|
len, strerror(errno)));
|
||||||
return TDB_ERRCODE(TDB_ERR_OOM, buf);
|
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)) {
|
if (TDB_BAD_MAGIC(rec)) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_CORRUPT;
|
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_ERRCODE(TDB_ERR_CORRUPT, -1);
|
||||||
}
|
}
|
||||||
return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
|
return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
note that a len of zero means lock to end of file
|
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 tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,
|
||||||
int rw_type, int lck_type, int probe, size_t len)
|
int rw_type, int lck_type, int probe, size_t len)
|
||||||
{
|
{
|
||||||
struct flock fl;
|
struct flock fl;
|
||||||
@ -68,7 +68,7 @@ int tdb_brlock_len(struct tdb_context *tdb, tdb_off_t offset,
|
|||||||
if (!probe && lck_type != F_SETLK) {
|
if (!probe && lck_type != F_SETLK) {
|
||||||
/* Ensure error code is set for log fun to examine. */
|
/* Ensure error code is set for log fun to examine. */
|
||||||
tdb->ecode = TDB_ERR_LOCK;
|
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));
|
tdb->fd, offset, rw_type, lck_type, (int)len));
|
||||||
}
|
}
|
||||||
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
|
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;
|
int count = 1000;
|
||||||
while (count--) {
|
while (count--) {
|
||||||
struct timeval tv;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
if (errno != EDEADLK) {
|
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;
|
tv.tv_usec = 1;
|
||||||
select(0, NULL, NULL, NULL, &tv);
|
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;
|
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 */
|
/* lock a list in the database. list -1 is the alloc list */
|
||||||
int tdb_lock(struct tdb_context *tdb, int list, int ltype)
|
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) {
|
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));
|
list, ltype));
|
||||||
return -1;
|
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,
|
/* Since fcntl locks don't nest, we do a lock for the first one,
|
||||||
and simply bump the count for future ones */
|
and simply bump the count for future ones */
|
||||||
if (tdb->locked[list+1].count == 0) {
|
if (tdb->locked[list+1].count == 0) {
|
||||||
if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0)) {
|
if (tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list,ltype,F_SETLKW, 0, 1)) {
|
||||||
TDB_LOG((tdb, 0,"tdb_lock failed on list %d ltype=%d (%s)\n",
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d ltype=%d (%s)\n",
|
||||||
list, ltype, strerror(errno)));
|
list, ltype, strerror(errno)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -148,23 +147,33 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
|
|||||||
{
|
{
|
||||||
int ret = -1;
|
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)
|
if (tdb->flags & TDB_NOLOCK)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if (list < -1 || list >= (int)tdb->header.hash_size) {
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdb->locked[list+1].count==0) {
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdb->locked[list+1].count == 1) {
|
if (tdb->locked[list+1].count == 1) {
|
||||||
/* Down to last nested lock: unlock underneath */
|
/* 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--;
|
tdb->num_locks--;
|
||||||
} else {
|
} else {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -172,40 +181,97 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
|
|||||||
tdb->locked[list+1].count--;
|
tdb->locked[list+1].count--;
|
||||||
|
|
||||||
if (ret)
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* lock/unlock entire database */
|
/* 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 */
|
/* There are no locks on read-only dbs */
|
||||||
if (tdb->read_only || tdb->traverse_read)
|
if (tdb->read_only || tdb->traverse_read)
|
||||||
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
|
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 (tdb->global_lock.count && tdb->global_lock.ltype == ltype) {
|
||||||
if (i < tdb->header.hash_size) {
|
tdb->global_lock.count++;
|
||||||
u32 j;
|
return 0;
|
||||||
|
|
||||||
for ( j = 0; j < i; j++)
|
|
||||||
tdb_unlock(tdb, j, F_WRLCK);
|
|
||||||
return TDB_ERRCODE(TDB_ERR_NOLOCK, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
void tdb_unlockall(struct tdb_context *tdb)
|
|
||||||
|
/* unlock entire db */
|
||||||
|
static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
|
||||||
{
|
{
|
||||||
u32 i;
|
/* There are no locks on read-only dbs */
|
||||||
for (i=0; i < tdb->header.hash_size; i++)
|
if (tdb->read_only || tdb->traverse_read) {
|
||||||
tdb_unlock(tdb, i, F_WRLCK);
|
return TDB_ERRCODE(TDB_ERR_LOCK, -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
return _tdb_unlockall(tdb, F_RDLCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lock/unlock one hash chain. This is meant to be used to reduce
|
/* 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 */
|
/* record lock stops delete underneath */
|
||||||
int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
|
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)
|
for (i = &tdb->travlocks; i; i = i->next)
|
||||||
if (i->off == off)
|
if (i->off == off)
|
||||||
return -1;
|
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)
|
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 */
|
/* 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)
|
for (i = &tdb->travlocks; i; i = i->next)
|
||||||
if (i->off == off)
|
if (i->off == off)
|
||||||
count++;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -123,14 +123,15 @@ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* a default logging function */
|
/* 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,
|
struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
||||||
int open_flags, mode_t mode,
|
int open_flags, mode_t mode,
|
||||||
tdb_log_func log_fn,
|
const struct tdb_logging_context *log_ctx,
|
||||||
tdb_hash_func hash_fn)
|
tdb_hash_func hash_fn)
|
||||||
{
|
{
|
||||||
struct tdb_context *tdb;
|
struct tdb_context *tdb;
|
||||||
@ -150,7 +151,12 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
|||||||
tdb->map_ptr = NULL;
|
tdb->map_ptr = NULL;
|
||||||
tdb->flags = tdb_flags;
|
tdb->flags = tdb_flags;
|
||||||
tdb->open_flags = open_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;
|
tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
|
||||||
|
|
||||||
/* cache the page size */
|
/* 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) {
|
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));
|
name));
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto fail;
|
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_NOLOCK | TDB_NOMMAP);
|
||||||
tdb->flags &= ~TDB_CLEAR_IF_FIRST;
|
tdb->flags &= ~TDB_CLEAR_IF_FIRST;
|
||||||
if (tdb_new_database(tdb, hash_size) != 0) {
|
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 fail;
|
||||||
}
|
}
|
||||||
goto internal;
|
goto internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tdb->fd = open(name, open_flags, mode)) == -1) {
|
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)));
|
name, strerror(errno)));
|
||||||
goto fail; /* errno set by open(2) */
|
goto fail; /* errno set by open(2) */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure there is only one process initialising at once */
|
/* ensure there is only one process initialising at once */
|
||||||
if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
|
if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_open_ex: failed to get global lock on %s: %s\n",
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
|
||||||
name, strerror(errno)));
|
name, strerror(errno)));
|
||||||
goto fail; /* errno set by tdb_brlock */
|
goto fail; /* errno set by tdb_brlock */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we need to zero database if we are the only one with it open */
|
/* we need to zero database if we are the only one with it open */
|
||||||
if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
|
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;
|
open_flags |= O_CREAT;
|
||||||
if (ftruncate(tdb->fd, 0) == -1) {
|
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",
|
"failed to truncate %s: %s\n",
|
||||||
name, strerror(errno)));
|
name, strerror(errno)));
|
||||||
goto fail; /* errno set by ftruncate */
|
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;
|
goto fail;
|
||||||
|
|
||||||
if (tdb->header.rwlocks != 0) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is it already in the open list? If so, fail. */
|
/* Is it already in the open list? If so, fail. */
|
||||||
if (tdb_already_open(st.st_dev, st.st_ino)) {
|
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",
|
"%s (%d,%d) is already open in this process\n",
|
||||||
name, (int)st.st_dev, (int)st.st_ino));
|
name, (int)st.st_dev, (int)st.st_ino));
|
||||||
errno = EBUSY;
|
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,
|
tdb->locked = (struct tdb_lock_type *)calloc(tdb->header.hash_size+1,
|
||||||
sizeof(tdb->locked[0]));
|
sizeof(tdb->locked[0]));
|
||||||
if (!tdb->locked) {
|
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",
|
"failed to allocate lock structure for %s\n",
|
||||||
name));
|
name));
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
@ -268,8 +274,8 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
|||||||
}
|
}
|
||||||
tdb_mmap(tdb);
|
tdb_mmap(tdb);
|
||||||
if (locked) {
|
if (locked) {
|
||||||
if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) {
|
if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_open_ex: "
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
|
||||||
"failed to take ACTIVE_LOCK on %s: %s\n",
|
"failed to take ACTIVE_LOCK on %s: %s\n",
|
||||||
name, strerror(errno)));
|
name, strerror(errno)));
|
||||||
goto fail;
|
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) {
|
if (tdb_flags & TDB_CLEAR_IF_FIRST) {
|
||||||
/* leave this lock in place to indicate it's in use */
|
/* 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;
|
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
|
/* Internal (memory-only) databases skip all the code above to
|
||||||
* do with disk files, and resume here by releasing their
|
* do with disk files, and resume here by releasing their
|
||||||
* global lock and hooking into the active list. */
|
* 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;
|
goto fail;
|
||||||
tdb->next = tdbs;
|
tdb->next = tdbs;
|
||||||
tdbs = tdb;
|
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);
|
SAFE_FREE(tdb->name);
|
||||||
if (tdb->fd != -1)
|
if (tdb->fd != -1)
|
||||||
if (close(tdb->fd) != 0)
|
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->locked);
|
||||||
SAFE_FREE(tdb);
|
SAFE_FREE(tdb);
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
@ -365,11 +371,16 @@ int tdb_close(struct tdb_context *tdb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* register a loging function */
|
/* 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
|
/* 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 */
|
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. */
|
return 0; /* Nothing to do. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdb->num_locks != 0) {
|
if (tdb->num_locks != 0 || tdb->global_lock.count) {
|
||||||
TDB_LOG((tdb, 0, "tdb_reopen: reopen not allowed with locks held\n"));
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdb->transaction != 0) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdb_munmap(tdb) != 0) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (close(tdb->fd) != 0)
|
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);
|
tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
|
||||||
if (tdb->fd == -1) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
if ((tdb->flags & TDB_CLEAR_IF_FIRST) &&
|
if ((tdb->flags & TDB_CLEAR_IF_FIRST) &&
|
||||||
(tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)) {
|
(tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) {
|
||||||
TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n"));
|
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (fstat(tdb->fd, &st) != 0) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
tdb_mmap(tdb);
|
tdb_mmap(tdb);
|
||||||
|
@ -42,7 +42,7 @@ static void tdb_increment_seqnum(struct tdb_context *tdb)
|
|||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ static void tdb_increment_seqnum(struct tdb_context *tdb)
|
|||||||
seqnum++;
|
seqnum++;
|
||||||
tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &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)
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +403,7 @@ int tdb_fd(struct tdb_context *tdb)
|
|||||||
*/
|
*/
|
||||||
tdb_log_func tdb_log_fn(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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -24,42 +24,13 @@
|
|||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SAMBA_BUILD_
|
#include "replace.h"
|
||||||
#include <stdlib.h>
|
#include "system/filesys.h"
|
||||||
#include <stdio.h>
|
#include "system/time.h"
|
||||||
#ifdef HAVE_STDINT_H
|
#include "system/shmem.h"
|
||||||
#include <stdint.h>
|
#include "system/select.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 "tdb.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
|
#ifndef u32
|
||||||
#define u32 unsigned
|
#define u32 unsigned
|
||||||
#endif
|
#endif
|
||||||
@ -100,21 +71,13 @@ typedef u32 tdb_off_t;
|
|||||||
/* NB assumes there is a local variable called "tdb" that is the
|
/* NB assumes there is a local variable called "tdb" that is the
|
||||||
* current context, also takes doubly-parenthesized print-style
|
* current context, also takes doubly-parenthesized print-style
|
||||||
* argument. */
|
* argument. */
|
||||||
#define TDB_LOG(x) tdb->log_fn x
|
#define TDB_LOG(x) tdb->log.log_fn x
|
||||||
|
|
||||||
/* lock offsets */
|
/* lock offsets */
|
||||||
#define GLOBAL_LOCK 0
|
#define GLOBAL_LOCK 0
|
||||||
#define ACTIVE_LOCK 4
|
#define ACTIVE_LOCK 4
|
||||||
#define TRANSACTION_LOCK 8
|
#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 */
|
/* free memory if the pointer is valid and zero the pointer */
|
||||||
#ifndef SAFE_FREE
|
#ifndef SAFE_FREE
|
||||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
|
#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 *);
|
void (*next_hash_chain)(struct tdb_context *, u32 *);
|
||||||
int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
|
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_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 {
|
struct tdb_context {
|
||||||
@ -188,6 +151,7 @@ struct tdb_context {
|
|||||||
tdb_len_t map_size; /* how much space has been mapped */
|
tdb_len_t map_size; /* how much space has been mapped */
|
||||||
int read_only; /* opened read-only */
|
int read_only; /* opened read-only */
|
||||||
int traverse_read; /* read-only traversal */
|
int traverse_read; /* read-only traversal */
|
||||||
|
struct tdb_lock_type global_lock;
|
||||||
struct tdb_lock_type *locked; /* array of chain locks */
|
struct tdb_lock_type *locked; /* array of chain locks */
|
||||||
enum TDB_ERROR ecode; /* error code for last tdb error */
|
enum TDB_ERROR ecode; /* error code for last tdb error */
|
||||||
struct tdb_header header; /* a cached copy of the header */
|
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 */
|
struct tdb_context *next; /* all tdbs to avoid multiple opens */
|
||||||
dev_t device; /* uniquely identifies this tdb */
|
dev_t device; /* uniquely identifies this tdb */
|
||||||
ino_t inode; /* 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);
|
unsigned int (*hash_fn)(TDB_DATA *key);
|
||||||
int open_flags; /* flags used in the open - needed by reopen */
|
int open_flags; /* flags used in the open - needed by reopen */
|
||||||
unsigned int num_locks; /* number of chain locks held */
|
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);
|
void tdb_mmap(struct tdb_context *tdb);
|
||||||
int tdb_lock(struct tdb_context *tdb, int list, int ltype);
|
int tdb_lock(struct tdb_context *tdb, int list, int ltype);
|
||||||
int tdb_unlock(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_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_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_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);
|
int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
|
||||||
|
@ -19,8 +19,11 @@
|
|||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tdb_private.h"
|
#include "includes.h"
|
||||||
#include <fnmatch.h>
|
#undef malloc
|
||||||
|
#undef realloc
|
||||||
|
#undef calloc
|
||||||
|
#undef strdup
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
Allow a caller to set a "alarm" flag that tdb can check to abort
|
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);
|
CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
|
||||||
if (gotalarm) {
|
if (gotalarm) {
|
||||||
DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
|
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
|
/* TODO: If we time out waiting for a lock, it might
|
||||||
* be nice to use F_GETLK to get the pid of the
|
* be nice to use F_GETLK to get the pid of the
|
||||||
* process currently holding the lock and print that
|
* 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().
|
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;
|
va_list ap;
|
||||||
char *ptr = NULL;
|
char *ptr = NULL;
|
||||||
@ -669,7 +672,7 @@ static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
|
|||||||
if (!ptr || !*ptr)
|
if (!ptr || !*ptr)
|
||||||
return;
|
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);
|
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)
|
int open_flags, mode_t mode)
|
||||||
{
|
{
|
||||||
TDB_CONTEXT *tdb;
|
TDB_CONTEXT *tdb;
|
||||||
|
struct tdb_logging_context log_ctx;
|
||||||
|
|
||||||
if (!lp_use_mmap())
|
if (!lp_use_mmap())
|
||||||
tdb_flags |= TDB_NOMMAP;
|
tdb_flags |= TDB_NOMMAP;
|
||||||
|
|
||||||
|
log_ctx.log_fn = tdb_log;
|
||||||
|
log_ctx.log_private = NULL;
|
||||||
|
|
||||||
tdb = tdb_open_ex(name, hash_size, tdb_flags,
|
tdb = tdb_open_ex(name, hash_size, tdb_flags,
|
||||||
open_flags, mode, tdb_log, NULL);
|
open_flags, mode, &log_ctx, NULL);
|
||||||
if (!tdb)
|
if (!tdb)
|
||||||
return NULL;
|
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
|
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.
|
that dies within writing does not leave a corrupt tdb behind.
|
||||||
|
@ -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);
|
return tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv);
|
||||||
|
|
||||||
fail:
|
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->ecode = TDB_ERR_IO;
|
||||||
tdb->transaction->transaction_error = 1;
|
tdb->transaction->transaction_error = 1;
|
||||||
return -1;
|
return -1;
|
||||||
@ -308,7 +308,7 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
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->ecode = TDB_ERR_IO;
|
||||||
tdb->transaction->transaction_error = 1;
|
tdb->transaction->transaction_error = 1;
|
||||||
return -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
|
brlock during a transaction - ignore them
|
||||||
*/
|
*/
|
||||||
int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -382,7 +382,7 @@ int tdb_transaction_start(struct tdb_context *tdb)
|
|||||||
{
|
{
|
||||||
/* some sanity checks */
|
/* some sanity checks */
|
||||||
if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) {
|
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;
|
tdb->ecode = TDB_ERR_EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -390,16 +390,16 @@ int tdb_transaction_start(struct tdb_context *tdb)
|
|||||||
/* cope with nested tdb_transaction_start() calls */
|
/* cope with nested tdb_transaction_start() calls */
|
||||||
if (tdb->transaction != NULL) {
|
if (tdb->transaction != NULL) {
|
||||||
tdb->transaction->nesting++;
|
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));
|
tdb->transaction->nesting));
|
||||||
return 0;
|
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
|
/* the caller must not have any locks when starting a
|
||||||
transaction as otherwise we'll be screwed by lack
|
transaction as otherwise we'll be screwed by lack
|
||||||
of nested locks in posix */
|
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;
|
tdb->ecode = TDB_ERR_LOCK;
|
||||||
return -1;
|
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
|
/* you cannot use transactions inside a traverse (although you can use
|
||||||
traverse inside a transaction) as otherwise you can end up with
|
traverse inside a transaction) as otherwise you can end up with
|
||||||
deadlock */
|
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;
|
tdb->ecode = TDB_ERR_LOCK;
|
||||||
return -1;
|
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
|
/* get the transaction write lock. This is a blocking lock. As
|
||||||
discussed with Volker, there are a number of ways we could
|
discussed with Volker, there are a number of ways we could
|
||||||
make this async, which we will probably do in the future */
|
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) {
|
if (tdb_brlock(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_transaction_start: failed to get transaction lock\n"));
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get transaction lock\n"));
|
||||||
tdb->ecode = TDB_ERR_LOCK;
|
tdb->ecode = TDB_ERR_LOCK;
|
||||||
SAFE_FREE(tdb->transaction);
|
SAFE_FREE(tdb->transaction);
|
||||||
return -1;
|
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
|
/* get a read lock from the freelist to the end of file. This
|
||||||
is upgraded to a write lock during the commit */
|
is upgraded to a write lock during the commit */
|
||||||
if (tdb_brlock_len(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {
|
if (tdb_brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_transaction_start: failed to get hash locks\n"));
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n"));
|
||||||
tdb->ecode = TDB_ERR_LOCK;
|
tdb->ecode = TDB_ERR_LOCK;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup a copy of the hash table heads so the hash scan in
|
/* setup a copy of the hash table heads so the hash scan in
|
||||||
traverse can be fast */
|
traverse can be fast */
|
||||||
tdb->transaction->hash_heads = (unsigned int *)
|
tdb->transaction->hash_heads = (u32 *)
|
||||||
calloc(tdb->header.hash_size+1, sizeof(tdb_off_t));
|
calloc(tdb->header.hash_size+1, sizeof(u32));
|
||||||
if (tdb->transaction->hash_heads == NULL) {
|
if (tdb->transaction->hash_heads == NULL) {
|
||||||
tdb->ecode = TDB_ERR_OOM;
|
tdb->ecode = TDB_ERR_OOM;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
|
if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
|
||||||
TDB_HASHTABLE_SIZE(tdb), 0) != 0) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -467,7 +467,7 @@ int tdb_transaction_start(struct tdb_context *tdb)
|
|||||||
transaction linked list due to hash table updates */
|
transaction linked list due to hash table updates */
|
||||||
if (transaction_write(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
|
if (transaction_write(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
|
||||||
TDB_HASHTABLE_SIZE(tdb)) != 0) {
|
TDB_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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -475,8 +475,8 @@ int tdb_transaction_start(struct tdb_context *tdb)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
tdb_brlock_len(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
|
tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
|
||||||
tdb_brlock_len(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
||||||
SAFE_FREE(tdb->transaction->hash_heads);
|
SAFE_FREE(tdb->transaction->hash_heads);
|
||||||
SAFE_FREE(tdb->transaction);
|
SAFE_FREE(tdb->transaction);
|
||||||
return -1;
|
return -1;
|
||||||
@ -489,7 +489,7 @@ fail:
|
|||||||
int tdb_transaction_cancel(struct tdb_context *tdb)
|
int tdb_transaction_cancel(struct tdb_context *tdb)
|
||||||
{
|
{
|
||||||
if (tdb->transaction == NULL) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,12 +509,18 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
|
|||||||
free(el);
|
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 */
|
/* remove any locks created during the transaction */
|
||||||
if (tdb->num_locks != 0) {
|
if (tdb->num_locks != 0) {
|
||||||
int h;
|
int h;
|
||||||
for (h=0;h<tdb->header.hash_size+1;h++) {
|
for (h=0;h<tdb->header.hash_size+1;h++) {
|
||||||
if (tdb->locked[h].count != 0) {
|
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;
|
tdb->locked[h].count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -524,8 +530,8 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
|
|||||||
/* restore the normal io methods */
|
/* restore the normal io methods */
|
||||||
tdb->methods = tdb->transaction->io_methods;
|
tdb->methods = tdb->transaction->io_methods;
|
||||||
|
|
||||||
tdb_brlock_len(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
|
tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
|
||||||
tdb_brlock_len(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
||||||
SAFE_FREE(tdb->transaction->hash_heads);
|
SAFE_FREE(tdb->transaction->hash_heads);
|
||||||
SAFE_FREE(tdb->transaction);
|
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) {
|
if (fsync(tdb->fd) != 0) {
|
||||||
tdb->ecode = TDB_ERR_IO;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef MS_SYNC
|
#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,
|
if (msync(moffset + (char *)tdb->map_ptr,
|
||||||
length + (offset - moffset), MS_SYNC) != 0) {
|
length + (offset - moffset), MS_SYNC) != 0) {
|
||||||
tdb->ecode = TDB_ERR_IO;
|
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)));
|
strerror(errno)));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -591,7 +597,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
|
|||||||
tdb_off_t recovery_head;
|
tdb_off_t recovery_head;
|
||||||
|
|
||||||
if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,7 +605,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
|
|||||||
|
|
||||||
if (recovery_head != 0 &&
|
if (recovery_head != 0 &&
|
||||||
methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +625,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
|
|||||||
the transaction) */
|
the transaction) */
|
||||||
if (recovery_head != 0) {
|
if (recovery_head != 0) {
|
||||||
if (tdb_free(tdb, recovery_head, &rec) == -1) {
|
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;
|
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,
|
if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
|
||||||
(tdb->map_size - tdb->transaction->old_map_size) +
|
(tdb->map_size - tdb->transaction->old_map_size) +
|
||||||
sizeof(rec) + *recovery_max_size) == -1) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +657,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
|
|||||||
CONVERT(recovery_head);
|
CONVERT(recovery_head);
|
||||||
if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD,
|
if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD,
|
||||||
&recovery_head, sizeof(tdb_off_t)) == -1) {
|
&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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -705,7 +711,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (el->offset + el->length > tdb->transaction->old_map_size) {
|
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);
|
free(data);
|
||||||
tdb->ecode = TDB_ERR_CORRUPT;
|
tdb->ecode = TDB_ERR_CORRUPT;
|
||||||
return -1;
|
return -1;
|
||||||
@ -733,7 +739,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
|
|||||||
|
|
||||||
/* write the recovery data to the recovery area */
|
/* write the recovery data to the recovery area */
|
||||||
if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
|
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);
|
free(data);
|
||||||
tdb->ecode = TDB_ERR_IO;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
@ -755,7 +761,7 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
|
|||||||
*magic_offset = recovery_offset + offsetof(struct list_struct, magic);
|
*magic_offset = recovery_offset + offsetof(struct list_struct, magic);
|
||||||
|
|
||||||
if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -778,14 +784,14 @@ int tdb_transaction_commit(struct tdb_context *tdb)
|
|||||||
u32 zero = 0;
|
u32 zero = 0;
|
||||||
|
|
||||||
if (tdb->transaction == NULL) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdb->transaction->transaction_error) {
|
if (tdb->transaction->transaction_error) {
|
||||||
tdb->ecode = TDB_ERR_IO;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
tdb_transaction_cancel(tdb);
|
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;
|
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
|
/* if there are any locks pending then the caller has not
|
||||||
nested their locks properly, so fail the transaction */
|
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->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);
|
tdb_transaction_cancel(tdb);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* upgrade the main transaction lock region to a write lock */
|
/* upgrade the main transaction lock region to a write lock */
|
||||||
if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {
|
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->ecode = TDB_ERR_LOCK;
|
||||||
tdb_transaction_cancel(tdb);
|
tdb_transaction_cancel(tdb);
|
||||||
return -1;
|
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
|
/* get the global lock - this prevents new users attaching to the database
|
||||||
during the commit */
|
during the commit */
|
||||||
if (tdb_brlock_len(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
|
if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_transaction_commit: failed to get global lock\n"));
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: failed to get global lock\n"));
|
||||||
tdb->ecode = TDB_ERR_LOCK;
|
tdb->ecode = TDB_ERR_LOCK;
|
||||||
tdb_transaction_cancel(tdb);
|
tdb_transaction_cancel(tdb);
|
||||||
return -1;
|
return -1;
|
||||||
@ -831,8 +837,8 @@ int tdb_transaction_commit(struct tdb_context *tdb)
|
|||||||
if (!(tdb->flags & TDB_NOSYNC)) {
|
if (!(tdb->flags & TDB_NOSYNC)) {
|
||||||
/* write the recovery data to the end of the file */
|
/* write the recovery data to the end of the file */
|
||||||
if (transaction_setup_recovery(tdb, &magic_offset) == -1) {
|
if (transaction_setup_recovery(tdb, &magic_offset) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_transaction_commit: failed to setup recovery data\n"));
|
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to setup recovery data\n"));
|
||||||
tdb_brlock_len(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
||||||
tdb_transaction_cancel(tdb);
|
tdb_transaction_cancel(tdb);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -844,8 +850,8 @@ int tdb_transaction_commit(struct tdb_context *tdb)
|
|||||||
tdb->map_size -
|
tdb->map_size -
|
||||||
tdb->transaction->old_map_size) == -1) {
|
tdb->transaction->old_map_size) == -1) {
|
||||||
tdb->ecode = TDB_ERR_IO;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
TDB_LOG((tdb, 0, "tdb_transaction_commit: expansion failed\n"));
|
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: expansion failed\n"));
|
||||||
tdb_brlock_len(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
|
||||||
tdb_transaction_cancel(tdb);
|
tdb_transaction_cancel(tdb);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -858,7 +864,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
|
|||||||
struct tdb_transaction_el *el = tdb->transaction->elements;
|
struct tdb_transaction_el *el = tdb->transaction->elements;
|
||||||
|
|
||||||
if (methods->tdb_write(tdb, el->offset, el->data, el->length) == -1) {
|
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
|
/* we've overwritten part of the data and
|
||||||
possibly expanded the file, so we need to
|
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_recover(tdb);
|
||||||
|
|
||||||
tdb_transaction_cancel(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;
|
return -1;
|
||||||
}
|
}
|
||||||
tdb->transaction->elements = el->next;
|
tdb->transaction->elements = el->next;
|
||||||
@ -885,7 +891,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
|
|||||||
|
|
||||||
/* remove the recovery marker */
|
/* remove the recovery marker */
|
||||||
if (methods->tdb_write(tdb, magic_offset, &zero, 4) == -1) {
|
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;
|
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
|
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 */
|
/* find the recovery area */
|
||||||
if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -946,7 +952,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
/* read the recovery record */
|
/* read the recovery record */
|
||||||
if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
|
if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
|
||||||
sizeof(rec), DOCONV()) == -1) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -957,7 +963,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tdb->read_only) {
|
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;
|
tdb->ecode = TDB_ERR_CORRUPT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -966,7 +972,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
|
|
||||||
data = (unsigned char *)malloc(rec.data_len);
|
data = (unsigned char *)malloc(rec.data_len);
|
||||||
if (data == NULL) {
|
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;
|
tdb->ecode = TDB_ERR_OOM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -974,7 +980,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
/* read the full recovery data */
|
/* read the full recovery data */
|
||||||
if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
|
if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
|
||||||
rec.data_len, 0) == -1) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
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) {
|
if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) {
|
||||||
free(data);
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1001,7 +1007,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
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 the recovery area is after the recovered eof then remove it */
|
||||||
if (recovery_eof <= recovery_head) {
|
if (recovery_eof <= recovery_head) {
|
||||||
if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1018,7 +1024,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
/* remove the recovery magic */
|
/* remove the recovery magic */
|
||||||
if (tdb_ofs_write(tdb, recovery_head + offsetof(struct list_struct, magic),
|
if (tdb_ofs_write(tdb, recovery_head + offsetof(struct list_struct, magic),
|
||||||
&zero) == -1) {
|
&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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1026,7 +1032,7 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
/* reduce the file size to the old size */
|
/* reduce the file size to the old size */
|
||||||
tdb_munmap(tdb);
|
tdb_munmap(tdb);
|
||||||
if (ftruncate(tdb->fd, recovery_eof) != 0) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1034,12 +1040,12 @@ int tdb_transaction_recover(struct tdb_context *tdb)
|
|||||||
tdb_mmap(tdb);
|
tdb_mmap(tdb);
|
||||||
|
|
||||||
if (transaction_sync(tdb, 0, recovery_eof) == -1) {
|
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;
|
tdb->ecode = TDB_ERR_IO;
|
||||||
return -1;
|
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));
|
recovery_eof));
|
||||||
|
|
||||||
/* all done */
|
/* all done */
|
||||||
|
@ -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>. */
|
/* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi@exanet.com>. */
|
||||||
if (tlock->off == rec->next) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ static int tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tloc
|
|||||||
fail:
|
fail:
|
||||||
tlock->off = 0;
|
tlock->off = 0;
|
||||||
if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 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;
|
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)
|
if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (tdb_unlock_record(tdb, tl->off) != 0)
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
key.dsize = rec.key_len;
|
key.dsize = rec.key_len;
|
||||||
@ -180,7 +180,7 @@ static int tdb_traverse_internal(struct tdb_context *tdb,
|
|||||||
/* They want us to terminate traversal */
|
/* They want us to terminate traversal */
|
||||||
ret = count;
|
ret = count;
|
||||||
if (tdb_unlock_record(tdb, tl->off) != 0) {
|
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;
|
ret = -1;
|
||||||
}
|
}
|
||||||
SAFE_FREE(key.dptr);
|
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
|
/* we need to get a read lock on the transaction lock here to
|
||||||
cope with the lock ordering semantics of solaris10 */
|
cope with the lock ordering semantics of solaris10 */
|
||||||
if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_RDLCK, F_SETLKW, 0) == -1) {
|
if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_traverse_read: failed to get transaction lock\n"));
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_traverse_read: failed to get transaction lock\n"));
|
||||||
tdb->ecode = TDB_ERR_LOCK;
|
tdb->ecode = TDB_ERR_LOCK;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ int tdb_traverse_read(struct tdb_context *tdb,
|
|||||||
ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
|
ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
|
||||||
tdb->traverse_read--;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -237,15 +237,15 @@ int tdb_traverse(struct tdb_context *tdb,
|
|||||||
return tdb_traverse_read(tdb, fn, private_data);
|
return tdb_traverse_read(tdb, fn, private_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
|
if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
|
||||||
TDB_LOG((tdb, 0, "tdb_traverse: failed to get transaction lock\n"));
|
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_traverse: failed to get transaction lock\n"));
|
||||||
tdb->ecode = TDB_ERR_LOCK;
|
tdb->ecode = TDB_ERR_LOCK;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
|
|||||||
key.dsize = rec.key_len;
|
key.dsize = rec.key_len;
|
||||||
key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
|
key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
|
||||||
if (tdb_unlock(tdb, BUCKET(tdb->travlocks.hash), F_WRLCK) != 0)
|
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;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
|
|||||||
return tdb_null;
|
return tdb_null;
|
||||||
tdb->travlocks.hash = BUCKET(rec.full_hash);
|
tdb->travlocks.hash = BUCKET(rec.full_hash);
|
||||||
if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
|
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;
|
return tdb_null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,11 +325,11 @@ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
|
|||||||
key.dsize);
|
key.dsize);
|
||||||
/* Unlock the chain of this new record */
|
/* Unlock the chain of this new record */
|
||||||
if (tdb_unlock(tdb, tdb->travlocks.hash, F_WRLCK) != 0)
|
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 */
|
/* Unlock the chain of old record */
|
||||||
if (tdb_unlock(tdb, BUCKET(oldhash), F_WRLCK) != 0)
|
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;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@ OBJ_FILES = \
|
|||||||
common/tdb.o common/dump.o common/io.o common/lock.o \
|
common/tdb.o common/dump.o common/io.o common/lock.o \
|
||||||
common/open.o common/traverse.o common/freelist.o \
|
common/open.o common/traverse.o common/freelist.o \
|
||||||
common/error.o common/transaction.o common/tdbutil.o
|
common/error.o common/transaction.o common/tdbutil.o
|
||||||
PUBLIC_DEPENDENCIES = \
|
CFLAGS = -Ilib/tdb/include
|
||||||
LIBREPLACE
|
|
||||||
PUBLIC_HEADERS = include/tdb.h
|
PUBLIC_HEADERS = include/tdb.h
|
||||||
#
|
#
|
||||||
# End SUBSYSTEM ldb
|
# End SUBSYSTEM ldb
|
||||||
|
@ -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_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
|
||||||
TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY};
|
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 {
|
typedef struct TDB_DATA {
|
||||||
char *dptr;
|
char *dptr;
|
||||||
size_t dsize;
|
size_t dsize;
|
||||||
@ -76,19 +80,24 @@ typedef struct TDB_DATA {
|
|||||||
typedef struct tdb_context TDB_CONTEXT;
|
typedef struct tdb_context TDB_CONTEXT;
|
||||||
|
|
||||||
typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *);
|
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);
|
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,
|
struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
|
||||||
int open_flags, mode_t mode);
|
int open_flags, mode_t mode);
|
||||||
struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
|
||||||
int open_flags, mode_t mode,
|
int open_flags, mode_t mode,
|
||||||
tdb_log_func log_fn,
|
const struct tdb_logging_context *log_ctx,
|
||||||
tdb_hash_func hash_fn);
|
tdb_hash_func hash_fn);
|
||||||
|
|
||||||
int tdb_reopen(struct tdb_context *tdb);
|
int tdb_reopen(struct tdb_context *tdb);
|
||||||
int tdb_reopen_all(int parent_longlived);
|
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);
|
enum TDB_ERROR tdb_error(struct tdb_context *tdb);
|
||||||
const char *tdb_errorstr(struct tdb_context *tdb);
|
const char *tdb_errorstr(struct tdb_context *tdb);
|
||||||
TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
|
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_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *);
|
||||||
int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
|
int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
|
||||||
int tdb_lockall(struct tdb_context *tdb);
|
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);
|
const char *tdb_name(struct tdb_context *tdb);
|
||||||
int tdb_fd(struct tdb_context *tdb);
|
int tdb_fd(struct tdb_context *tdb);
|
||||||
tdb_log_func tdb_log_fn(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_start(struct tdb_context *tdb);
|
||||||
int tdb_transaction_commit(struct tdb_context *tdb);
|
int tdb_transaction_commit(struct tdb_context *tdb);
|
||||||
int tdb_transaction_cancel(struct tdb_context *tdb);
|
int tdb_transaction_cancel(struct tdb_context *tdb);
|
||||||
int tdb_transaction_recover(struct tdb_context *tdb);
|
int tdb_transaction_recover(struct tdb_context *tdb);
|
||||||
int tdb_get_seqnum(struct tdb_context *tdb);
|
int tdb_get_seqnum(struct tdb_context *tdb);
|
||||||
int tdb_hash_size(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 */
|
/* Low level locking functions: use with care */
|
||||||
int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key);
|
int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key);
|
||||||
|
@ -67,7 +67,5 @@ int tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr,
|
|||||||
uint32 *oldval, uint32 change_val);
|
uint32 *oldval, uint32 change_val);
|
||||||
int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key,
|
int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key,
|
||||||
unsigned int timeout);
|
unsigned int timeout);
|
||||||
int tdb_get_flags(struct tdb_context *tdb);
|
|
||||||
size_t tdb_map_size(struct tdb_context *tdb);
|
|
||||||
|
|
||||||
#endif /* __TDBUTIL_H__ */
|
#endif /* __TDBUTIL_H__ */
|
||||||
|
@ -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 */
|
/* 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 DELETE_PROB 7
|
||||||
#define STORE_PROB 5
|
#define STORE_PROB 5
|
||||||
|
|
||||||
static TDB_CONTEXT *db;
|
static struct tdb_context *db;
|
||||||
static GDBM_FILE gdbm;
|
static GDBM_FILE gdbm;
|
||||||
|
|
||||||
struct timeval tp1,tp2;
|
struct timeval tp1,tp2;
|
||||||
|
|
||||||
static void start_timer(void)
|
static void _start_timer(void)
|
||||||
{
|
{
|
||||||
gettimeofday(&tp1,NULL);
|
gettimeofday(&tp1,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double end_timer(void)
|
static double _end_timer(void)
|
||||||
{
|
{
|
||||||
gettimeofday(&tp2,NULL);
|
gettimeofday(&tp2,NULL);
|
||||||
return((tp2.tv_sec - tp1.tv_sec) +
|
return((tp2.tv_sec - tp1.tv_sec) +
|
||||||
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
|
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fatal(char *why)
|
static void fatal(const char *why)
|
||||||
{
|
{
|
||||||
perror(why);
|
perror(why);
|
||||||
exit(1);
|
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;
|
va_list ap;
|
||||||
|
|
||||||
@ -179,7 +174,7 @@ static void addrec_gdbm(void)
|
|||||||
free(d);
|
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
|
#if 0
|
||||||
printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
|
printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
|
||||||
@ -192,14 +187,15 @@ static void merge_test(void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char keys[5][2];
|
char keys[5][2];
|
||||||
|
char tdata[] = "test";
|
||||||
TDB_DATA key, data;
|
TDB_DATA key, data;
|
||||||
|
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
sprintf(keys[i], "%d", i);
|
snprintf(keys[i],2, "%d", i);
|
||||||
key.dptr = keys[i];
|
key.dptr = keys[i];
|
||||||
key.dsize = 2;
|
key.dsize = 2;
|
||||||
|
|
||||||
data.dptr = "test";
|
data.dptr = tdata;
|
||||||
data.dsize = 4;
|
data.dsize = 4;
|
||||||
|
|
||||||
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
||||||
@ -219,16 +215,17 @@ static void merge_test(void)
|
|||||||
tdb_delete(db, key);
|
tdb_delete(db, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
int i, seed=0;
|
int i, seed=0;
|
||||||
int loops = 10000;
|
int loops = 10000;
|
||||||
|
char test_gdbm[] = "test.gdbm";
|
||||||
|
|
||||||
unlink("test.gdbm");
|
unlink("test.gdbm");
|
||||||
|
|
||||||
db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST,
|
db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST,
|
||||||
O_RDWR | O_CREAT | O_TRUNC, 0600);
|
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);
|
0600, NULL);
|
||||||
|
|
||||||
if (!db || !gdbm) {
|
if (!db || !gdbm) {
|
||||||
@ -239,17 +236,17 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
srand(seed);
|
srand(seed);
|
||||||
start_timer();
|
_start_timer();
|
||||||
for (i=0;i<loops;i++) addrec_gdbm();
|
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
|
#endif
|
||||||
|
|
||||||
merge_test();
|
merge_test();
|
||||||
|
|
||||||
srand(seed);
|
srand(seed);
|
||||||
start_timer();
|
_start_timer();
|
||||||
for (i=0;i<loops;i++) addrec_db();
|
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();
|
compare_db();
|
||||||
|
|
||||||
|
@ -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
|
/* this tests tdb by doing lots of ops from several simultaneous
|
||||||
writers - that stresses the locking code. Build with TDB_DEBUG=1
|
writers - that stresses the locking code.
|
||||||
for best effect */
|
*/
|
||||||
|
|
||||||
|
#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 REOPEN_PROB 30
|
||||||
#define DELETE_PROB 8
|
#define DELETE_PROB 8
|
||||||
#define STORE_PROB 4
|
#define STORE_PROB 4
|
||||||
#define APPEND_PROB 6
|
#define APPEND_PROB 6
|
||||||
#define LOCKSTORE_PROB 0
|
#define TRANSACTION_PROB 10
|
||||||
|
#define LOCKSTORE_PROB 5
|
||||||
#define TRAVERSE_PROB 20
|
#define TRAVERSE_PROB 20
|
||||||
|
#define TRAVERSE_READ_PROB 20
|
||||||
#define CULL_PROB 100
|
#define CULL_PROB 100
|
||||||
#define KEYLEN 3
|
#define KEYLEN 3
|
||||||
#define DATALEN 100
|
#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;
|
va_list ap;
|
||||||
|
|
||||||
|
error_count++;
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
vfprintf(stdout, format, ap);
|
vfprintf(stdout, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@ -50,10 +52,10 @@ static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fatal(char *why)
|
static void fatal(const char *why)
|
||||||
{
|
{
|
||||||
perror(why);
|
perror(why);
|
||||||
exit(1);
|
error_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *randbuf(int len)
|
static char *randbuf(int len)
|
||||||
@ -69,41 +71,62 @@ static char *randbuf(int len)
|
|||||||
return buf;
|
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)
|
void *state)
|
||||||
{
|
{
|
||||||
|
#if CULL_PROB
|
||||||
if (random() % CULL_PROB == 0) {
|
if (random() % CULL_PROB == 0) {
|
||||||
tdb_delete(tdb, key);
|
tdb_delete(tdb, key);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addrec_db(void)
|
static void addrec_db(void)
|
||||||
{
|
{
|
||||||
int klen, dlen, slen;
|
int klen, dlen;
|
||||||
char *k, *d, *s;
|
char *k, *d;
|
||||||
TDB_DATA key, data, lockkey;
|
TDB_DATA key, data;
|
||||||
|
|
||||||
klen = 1 + (rand() % KEYLEN);
|
klen = 1 + (rand() % KEYLEN);
|
||||||
dlen = 1 + (rand() % DATALEN);
|
dlen = 1 + (rand() % DATALEN);
|
||||||
slen = 1 + (rand() % LOCKLEN);
|
|
||||||
|
|
||||||
k = randbuf(klen);
|
k = randbuf(klen);
|
||||||
d = randbuf(dlen);
|
d = randbuf(dlen);
|
||||||
s = randbuf(slen);
|
|
||||||
|
|
||||||
key.dptr = k;
|
key.dptr = (unsigned char *)k;
|
||||||
key.dsize = klen+1;
|
key.dsize = klen+1;
|
||||||
|
|
||||||
data.dptr = d;
|
data.dptr = (unsigned char *)d;
|
||||||
data.dsize = dlen+1;
|
data.dsize = dlen+1;
|
||||||
|
|
||||||
lockkey.dptr = s;
|
#if TRANSACTION_PROB
|
||||||
lockkey.dsize = slen+1;
|
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 REOPEN_PROB
|
||||||
if (random() % REOPEN_PROB == 0) {
|
if (in_transaction == 0 && random() % REOPEN_PROB == 0) {
|
||||||
tdb_reopen_all(1);
|
tdb_reopen_all(0);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -135,13 +158,13 @@ static void addrec_db(void)
|
|||||||
|
|
||||||
#if LOCKSTORE_PROB
|
#if LOCKSTORE_PROB
|
||||||
if (random() % LOCKSTORE_PROB == 0) {
|
if (random() % LOCKSTORE_PROB == 0) {
|
||||||
tdb_chainlock(db, lockkey);
|
tdb_chainlock(db, key);
|
||||||
data = tdb_fetch(db, key);
|
data = tdb_fetch(db, key);
|
||||||
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
||||||
fatal("tdb_store failed");
|
fatal("tdb_store failed");
|
||||||
}
|
}
|
||||||
if (data.dptr) free(data.dptr);
|
if (data.dptr) free(data.dptr);
|
||||||
tdb_chainunlock(db, lockkey);
|
tdb_chainunlock(db, key);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -153,75 +176,143 @@ static void addrec_db(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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);
|
data = tdb_fetch(db, key);
|
||||||
if (data.dptr) free(data.dptr);
|
if (data.dptr) free(data.dptr);
|
||||||
|
|
||||||
next:
|
next:
|
||||||
free(k);
|
free(k);
|
||||||
free(d);
|
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)
|
void *state)
|
||||||
{
|
{
|
||||||
tdb_delete(tdb, key);
|
tdb_delete(tdb, key);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NPROC
|
static void usage(void)
|
||||||
#define NPROC 6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NLOOPS
|
|
||||||
#define NLOOPS 200000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
{
|
||||||
int i, seed=0;
|
printf("Usage: tdbtorture [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
|
||||||
int loops = NLOOPS;
|
exit(0);
|
||||||
pid_t pids[NPROC];
|
}
|
||||||
|
|
||||||
db = tdb_open("torture.tdb", 0, TDB_CLEAR_IF_FIRST,
|
int main(int argc, char * const *argv)
|
||||||
O_RDWR | O_CREAT, 0600);
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
|
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) {
|
if (!db) {
|
||||||
fatal("db open failed");
|
fatal("db open failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0;i<NPROC;i++) {
|
if (seed == -1) {
|
||||||
pids[i] = fork();
|
seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
|
||||||
if (pids[i] == 0) {
|
}
|
||||||
tdb_reopen_all(1);
|
|
||||||
|
|
||||||
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());
|
srand(seed + i);
|
||||||
srandom(seed + getpid() + time(NULL));
|
srandom(seed + i);
|
||||||
for (i=0;i<loops;i++) addrec_db();
|
|
||||||
|
|
||||||
tdb_traverse(db, NULL, NULL);
|
for (i=0;i<num_loops && error_count == 0;i++) {
|
||||||
|
addrec_db();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error_count == 0) {
|
||||||
|
tdb_traverse_read(db, NULL, NULL);
|
||||||
tdb_traverse(db, traverse_fn, NULL);
|
tdb_traverse(db, traverse_fn, NULL);
|
||||||
tdb_traverse(db, traverse_fn, NULL);
|
tdb_traverse(db, traverse_fn, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
tdb_close(db);
|
tdb_close(db);
|
||||||
exit(0);
|
|
||||||
}
|
if (getpid() != pids[0]) {
|
||||||
|
return error_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0;i<NPROC;i++) {
|
for (i=1;i<num_procs;i++) {
|
||||||
int status;
|
int status, j;
|
||||||
if (waitpid(pids[i], &status, 0) != pids[i]) {
|
pid_t pid;
|
||||||
printf("failed to wait for %d\n",
|
if (error_count != 0) {
|
||||||
(int)pids[i]);
|
/* 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);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (WEXITSTATUS(status) != 0) {
|
if (WEXITSTATUS(status) != 0) {
|
||||||
printf("child %d exited with status %d\n",
|
printf("child %d exited with status %d\n",
|
||||||
(int)pids[i], WEXITSTATUS(status));
|
(int)pid, WEXITSTATUS(status));
|
||||||
exit(1);
|
error_count++;
|
||||||
}
|
}
|
||||||
|
pids[j] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error_count == 0) {
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
return error_count;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user