From 9a781a8c6de9513ba5f4cafef41379fae96807c1 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 2 Jan 2000 23:00:27 +0000 Subject: - added tdb_flags option to tdb_open() - added TDB_CLEAR_IF_FIRST flag to clear the database if this is the first attached process. Useful for non-persistent databases like our locking area (this will also make upgrades to new database layouts easier) - use lock_path() in a couple of places - leave connections database open while smbd running - cleaned up some tdb code a little, using macros for constants (This used to be commit 00e9da3ca577527db392aced62f02c69cfee8f4f) --- source3/tdb/tdb.c | 53 ++++++++++++++++++++++++++++++++++++------------ source3/tdb/tdb.h | 7 ++++++- source3/tdb/tdbtest.c | 5 +++-- source3/tdb/tdbtool.c | 5 +++-- source3/tdb/tdbtorture.c | 5 ++--- 5 files changed, 54 insertions(+), 21 deletions(-) (limited to 'source3/tdb') diff --git a/source3/tdb/tdb.c b/source3/tdb/tdb.c index 7b8f8db4c0..731d1fdbc8 100644 --- a/source3/tdb/tdb.c +++ b/source3/tdb/tdb.c @@ -44,6 +44,14 @@ #define TDB_LEN_MULTIPLIER 10 #define FREELIST_TOP (sizeof(struct tdb_header)) +#define LOCK_SET 1 +#define LOCK_CLEAR 0 + +/* lock offsets */ +#define GLOBAL_LOCK 0 +#define ACTIVE_LOCK 4 +#define LIST_LOCK_BASE 1024 + #define BUCKET(hash) ((hash) % tdb->header.hash_size) /* the body of the database is made of one list_struct for the free space @@ -85,7 +93,8 @@ static char *memdup(char *d, int size) /* a byte range locking function - return 0 on success this functions locks/unlocks 1 byte at the specified offset */ -static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, int set) +static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, + int set, int rw_type, int lck_type) { #if NOLOCK return 0; @@ -94,13 +103,13 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, int set) if (tdb->read_only) return -1; - fl.l_type = set?F_WRLCK:F_UNLCK; + fl.l_type = set==LOCK_SET?rw_type:F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = offset; fl.l_len = 1; fl.l_pid = 0; - if (fcntl(tdb->fd, F_SETLKW, &fl) != 0) { + if (fcntl(tdb->fd, lck_type, &fl) != 0 && lck_type == F_SETLKW) { #if TDB_DEBUG printf("lock %d failed at %d (%s)\n", set, offset, strerror(errno)); @@ -121,7 +130,8 @@ static int tdb_lock(TDB_CONTEXT *tdb, int list) return -1; } if (tdb->locked[list+1] == 0) { - if (tdb_brlock(tdb, 4*(list+1), 1) != 0) { + if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_SET, + F_WRLCK, F_SETLKW) != 0) { return -1; } } @@ -146,7 +156,8 @@ static int tdb_unlock(TDB_CONTEXT *tdb, int list) return -1; } if (tdb->locked[list+1] == 1) { - if (tdb_brlock(tdb, 4*(list+1), 0) != 0) { + if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_CLEAR, + F_WRLCK, F_SETLKW) != 0) { return -1; } } @@ -264,6 +275,8 @@ static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len) buf = (char *)malloc(len); + if (!buf) return NULL; + if (tdb_read(tdb, offset, buf, len) == -1) { free(buf); return NULL; @@ -1091,7 +1104,8 @@ int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) return is NULL on error */ -TDB_CONTEXT *tdb_open(char *name, int hash_size, int flags, mode_t mode) +TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode) { TDB_CONTEXT tdb, *ret; struct stat st; @@ -1100,21 +1114,36 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int flags, mode_t mode) tdb.name = NULL; tdb.map_ptr = NULL; - if ((flags & O_ACCMODE) == O_WRONLY) goto fail; + if ((open_flags & O_ACCMODE) == O_WRONLY) goto fail; if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE; memset(&tdb, 0, sizeof(tdb)); - tdb.fd = open(name, flags, mode); + tdb.read_only = ((open_flags & O_ACCMODE) == O_RDONLY); + + tdb.fd = open(name, open_flags, mode); if (tdb.fd == -1) goto fail; - tdb_brlock(&tdb, 0, 1); + /* ensure there is only one process initialising at once */ + tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_SET, F_WRLCK, F_SETLKW); + + if (tdb_flags & TDB_CLEAR_IF_FIRST) { + /* we need to zero the database if we are the only + one with it open */ + if (tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_WRLCK, F_SETLK) == 0) { + ftruncate(tdb.fd, 0); + tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLK); + } + } + + /* leave this lock in place */ + tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_RDLCK, F_SETLKW); if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header) || tdb.header.version != TDB_VERSION) { /* its not a valid database - possibly initialise it */ - if (!(flags & O_CREAT)) { + if (!(open_flags & O_CREAT)) { goto fail; } if (tdb_new_database(&tdb, hash_size) == -1) goto fail; @@ -1131,7 +1160,6 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int flags, mode_t mode) sizeof(tdb.locked[0])); if (!tdb.locked) goto fail; tdb.map_size = st.st_size; - tdb.read_only = ((flags & O_ACCMODE) == O_RDONLY); #if HAVE_MMAP tdb.map_ptr = (void *)mmap(NULL, st.st_size, tdb.read_only? PROT_READ : PROT_READ|PROT_WRITE, @@ -1148,11 +1176,10 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int flags, mode_t mode) hash_size, tdb.map_size); #endif - tdb_brlock(&tdb, 0, 0); + tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLKW); return ret; fail: - tdb_brlock(&tdb, 0, 0); if (tdb.name) free(tdb.name); if (tdb.fd != -1) close(tdb.fd); if (tdb.map_ptr) munmap(tdb.map_ptr, tdb.map_size); diff --git a/source3/tdb/tdb.h b/source3/tdb/tdb.h index 527e65740a..9cb8f71a90 100644 --- a/source3/tdb/tdb.h +++ b/source3/tdb/tdb.h @@ -44,16 +44,21 @@ typedef struct { struct tdb_header header; /* a cached copy of the header */ } TDB_CONTEXT; +/* flags to tdb_store() */ #define TDB_REPLACE 1 #define TDB_INSERT 2 +/* flags for tdb_open() */ +#define TDB_CLEAR_IF_FIRST 1 + #if STANDALONE +TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode); int tdb_writelock(TDB_CONTEXT *tdb); int tdb_writeunlock(TDB_CONTEXT *tdb); TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key); int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key); int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag); -TDB_CONTEXT *tdb_open(char *name, int hash_size, int flags, mode_t mode); int tdb_close(TDB_CONTEXT *tdb); TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb); TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key); diff --git a/source3/tdb/tdbtest.c b/source3/tdb/tdbtest.c index 8089e7be7d..581d8192d9 100644 --- a/source3/tdb/tdbtest.c +++ b/source3/tdb/tdbtest.c @@ -180,11 +180,12 @@ static int traverse_fn(TDB_CONTEXT *db, TDB_DATA key, TDB_DATA dbuf) int main(int argc, char *argv[]) { int i, seed=0; - int loops = 50000; + int loops = 10000; unlink("test.gdbm"); - db = tdb_open("test.db", 0, O_RDWR | O_CREAT | O_TRUNC, 0600); + db = tdb_open("test.db", 0, TDB_CLEAR_IF_FIRST, + O_RDWR | O_CREAT | O_TRUNC, 0600); gdbm = gdbm_open("test.gdbm", 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, 0600, NULL); diff --git a/source3/tdb/tdbtool.c b/source3/tdb/tdbtool.c index 5eb410d418..428bae84c2 100644 --- a/source3/tdb/tdbtool.c +++ b/source3/tdb/tdbtool.c @@ -41,7 +41,8 @@ static void create_tdb(void) return; } if (tdb) tdb_close(tdb); - tdb = tdb_open(tok, 0, O_RDWR | O_CREAT | O_TRUNC, 0600); + tdb = tdb_open(tok, 0, TDB_CLEAR_IF_FIRST, + O_RDWR | O_CREAT | O_TRUNC, 0600); } static void open_tdb(void) @@ -52,7 +53,7 @@ static void open_tdb(void) return; } if (tdb) tdb_close(tdb); - tdb = tdb_open(tok, 0, O_RDWR, 0600); + tdb = tdb_open(tok, 0, 0, O_RDWR, 0600); } static void insert_tdb(void) diff --git a/source3/tdb/tdbtorture.c b/source3/tdb/tdbtorture.c index 1aac6d4a01..3eb462d79e 100644 --- a/source3/tdb/tdbtorture.c +++ b/source3/tdb/tdbtorture.c @@ -93,13 +93,12 @@ int main(int argc, char *argv[]) int i, seed=0; int loops = NLOOPS; - unlink("test.tdb"); - for (i=0;i