- added tdb_flags option to tdb_open()
authorAndrew Tridgell <tridge@samba.org>
Sun, 2 Jan 2000 23:00:27 +0000 (23:00 +0000)
committerAndrew Tridgell <tridge@samba.org>
Sun, 2 Jan 2000 23:00:27 +0000 (23:00 +0000)
- 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

12 files changed:
source/include/proto.h
source/locking/locking.c
source/nmbd/nmbd_namelistdb.c
source/nmbd/nmbd_winsserver.c
source/smbd/connection.c
source/tdb/tdb.c
source/tdb/tdb.h
source/tdb/tdbtest.c
source/tdb/tdbtool.c
source/tdb/tdbtorture.c
source/utils/status.c
source/web/statuspage.c

index c45da94f461275affe4b5b5a712ba903429ec146..251f051452934d691afa2e5e32d30597078d0369 100644 (file)
@@ -2428,7 +2428,6 @@ void conn_free(connection_struct *conn);
 /*The following definitions come from  smbd/connection.c  */
 
 BOOL yield_connection(connection_struct *conn,char *name,int max_connections);
-int delete_dead(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf);
 BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear);
 
 /*The following definitions come from  smbd/dfree.c  */
@@ -2856,7 +2855,8 @@ TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
 TDB_DATA tdb_nextkey(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);
+TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
+                     int open_flags, mode_t mode);
 int tdb_close(TDB_CONTEXT *tdb);
 int tdb_writelock(TDB_CONTEXT *tdb);
 int tdb_writeunlock(TDB_CONTEXT *tdb);
index 156ff016ea610d923cc87e00f849efd27d96132f..dafd324edc2ad6ed787e7f3966370926666dd4c2 100644 (file)
@@ -159,7 +159,7 @@ BOOL locking_init(int read_only)
        if (tdb) return True;
 
        tdb = tdb_open(lock_path("locking.tdb"), 
-                      0,
+                      0, TDB_CLEAR_IF_FIRST, 
                       read_only?O_RDONLY:O_RDWR|O_CREAT,
                       0644);
 
index dbb8be1f2d5a4475e81bb27cde417d582581b721..e2433f42d3d1eccd028beeff93c1ccd8c2f15ebf 100644 (file)
@@ -602,21 +602,15 @@ static void dump_subnet_namelist( struct subnet_record *subrec, FILE *fp)
 
 void dump_all_namelists(void)
 {
-  pstring fname;
   FILE *fp; 
   struct subnet_record *subrec;
 
-  pstrcpy(fname,lp_lockdir());
-  trim_string(fname,NULL,"/");
-  pstrcat(fname,"/"); 
-  pstrcat(fname,"namelist.debug");
-
-  fp = sys_fopen(fname,"w");
+  fp = sys_fopen(lock_path("namelist.debug"),"w");
      
   if (!fp)
   { 
     DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
-              fname,strerror(errno)));
+              "namelist.debug",strerror(errno)));
     return;
   }
       
index 45e93351674289924ea277c96f72dda5b0c83e9c..d1a100aaea22afb9562c9ee7d747f9e55a160312 100644 (file)
@@ -172,7 +172,6 @@ Load or create the WINS database.
 
 BOOL initialise_wins(void)
 {
-  pstring fname;
   time_t time_now = time(NULL);
   FILE *fp;
   pstring line;
@@ -182,15 +181,10 @@ BOOL initialise_wins(void)
 
   add_samba_names_to_subnet(wins_server_subnet);
 
-  pstrcpy(fname,lp_lockdir());
-  trim_string(fname,NULL,"/");
-  pstrcat(fname,"/");
-  pstrcat(fname,WINS_LIST);
-
-  if((fp = sys_fopen(fname,"r")) == NULL)
+  if((fp = sys_fopen(lock_path(WINS_LIST),"r")) == NULL)
   {
     DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
-           fname, strerror(errno) ));
+           WINS_LIST, strerror(errno) ));
     return True;
   }
 
index 5b5ab005c8099f02afbe25f9a702b7e3db73a749..13c051a5a3643ae0fe3e0d023f41ba927adbd5f5 100644 (file)
@@ -23,6 +23,7 @@
 
 
 extern fstring remote_machine;
+static TDB_CONTEXT *tdb;
 
 extern int DEBUGLEVEL;
 
@@ -33,9 +34,7 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
 {
        struct connections_key key;
        TDB_DATA kbuf;
-       TDB_CONTEXT *tdb;
 
-       tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDWR | O_CREAT, 0644);
        if (!tdb) return False;
 
        DEBUG(3,("Yielding connection to %s\n",name));
@@ -49,23 +48,10 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
        kbuf.dsize = sizeof(key);
 
        tdb_delete(tdb, kbuf);
-       tdb_close(tdb);
        return(True);
 }
 
 
-/****************************************************************************
-claim an entry in the connections database
-****************************************************************************/
-int delete_dead(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
-{
-       struct connections_key key;
-       memcpy(&key, kbuf.dptr, sizeof(key));
-       if (!process_exists(key.pid)) tdb_delete(tdb, kbuf);
-       return 0;
-}
-
-
 /****************************************************************************
 claim an entry in the connections database
 ****************************************************************************/
@@ -74,13 +60,15 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
        struct connections_key key;
        struct connections_data crec;
        TDB_DATA kbuf, dbuf;
-       TDB_CONTEXT *tdb;
        extern int Client;
 
        if (max_connections <= 0)
                return(True);
-       
-       tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDWR | O_CREAT, 0644);
+
+       if (!tdb) {
+               tdb = tdb_open(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST, 
+                              O_RDWR | O_CREAT, 0644);
+       }
        if (!tdb) return False;
 
        DEBUG(5,("claiming %s %d\n",name,max_connections));
@@ -93,10 +81,6 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
        kbuf.dptr = (char *)&key;
        kbuf.dsize = sizeof(key);
 
-       if (Clear) {
-               tdb_traverse(tdb, delete_dead);
-       }
-
        /* fill in the crec */
        ZERO_STRUCT(crec);
        crec.magic = 0x280267;
index 7b8f8db4c0825a9d577bd42a69b1270cfece1733..731d1fdbc8a6d727c98514bfeec6857ce35f9000 100644 (file)
 #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);
index 527e65740a66ee5b6f0b74c9ba7d3a6f8d8261a2..9cb8f71a902f196f5fd625d759cf5d0c2edcfb47 100644 (file)
@@ -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);
index 8089e7be7d5a845a379aa6453e455a224b6e7a31..581d8192d9016e0471cc13046c6507ba036e827b 100644 (file)
@@ -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);
 
index 5eb410d418c0f36dfaa2d18f0997604882f9a20a..428bae84c2fa5d764de3c63ad08cd2d7d0a26ace 100644 (file)
@@ -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)
index 1aac6d4a011fb41d5dccab24f62a2798e0df70bc..3eb462d79eb3ec468367571b2cd5c1f6f5220d04 100644 (file)
@@ -93,13 +93,12 @@ int main(int argc, char *argv[])
        int i, seed=0;
        int loops = NLOOPS;
 
-       unlink("test.tdb");
-
        for (i=0;i<NPROC-1;i++) {
                if (fork() == 0) break;
        }
 
-       db = tdb_open("test.tdb", 0, O_RDWR | O_CREAT, 0600);
+       db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST, 
+                     O_RDWR | O_CREAT, 0600);
        if (!db) {
                fatal("db open failed");
        }
index 51118914922038ed131f1a32e02587f93288f559..3082402d8b572495c7ad6b7602c7d9f1ca2fb1fb 100644 (file)
@@ -261,11 +261,11 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
                case 's':
                        pstrcpy(servicesf, optarg);
                        break;
-               case 'u':                                       /* added by OH */
-                       Ucrit_addUsername(optarg);                    /* added by OH */
+               case 'u':                                      
+                       Ucrit_addUsername(optarg);             
                        break;
                default:
-                       fprintf(stderr, "Usage: %s [-P] [-d] [-L] [-p] [-S] [-s configfile] [-u username]\n", *argv); /* changed by OH */
+                       fprintf(stderr, "Usage: %s [-P] [-d] [-L] [-p] [-S] [-s configfile] [-u username]\n", *argv);
                        return (-1);
                }
        }
@@ -283,7 +283,7 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
                return profile_dump();
        }
        
-       tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDONLY, 0);
+       tdb = tdb_open(lock_path("connections.tdb"), 0, 0, O_RDONLY, 0);
        if (!tdb) {
                printf("connections.tdb not initialised\n");
                if (!lp_status(-1))
index e3e10f09d5d5ae08dc9e00a4abab9ed3a6c32771..eaf3fdb86489ad582ddb3ba4d469cb2fe8bd3204 100644 (file)
@@ -172,7 +172,7 @@ void status_page(void)
                refresh_interval = atoi(v);
        }
 
-       tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDONLY, 0);
+       tdb = tdb_open(lock_path("connections.tdb"), 0, 0, O_RDONLY, 0);
        if (tdb) tdb_traverse(tdb, traverse_fn1);
 
        printf("<H2>Server Status</H2>\n");