Changeset 745 for trunk/server/lib/tdb


Ignore:
Timestamp:
Nov 27, 2012, 4:43:17 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: updated trunk to 3.6.0

Location:
trunk/server
Files:
15 deleted
27 edited
20 copied

Legend:

Unmodified
Added
Removed
  • trunk/server

  • trunk/server/lib/tdb/common/check.c

    r414 r745  
    2929{
    3030        struct tdb_header hdr;
    31 
    32         if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), DOCONV()) == -1)
     31        uint32_t h1, h2;
     32
     33        if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), 0) == -1)
    3334                return false;
    3435        if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0)
     
    3940                goto corrupt;
    4041
    41         if (hdr.rwlocks != 0)
     42        if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
     43                goto corrupt;
     44
     45        tdb_header_hash(tdb, &h1, &h2);
     46        if (hdr.magic1_hash && hdr.magic2_hash &&
     47            (hdr.magic1_hash != h1 || hdr.magic2_hash != h2))
    4248                goto corrupt;
    4349
     
    302308}
    303309
    304 int tdb_check(struct tdb_context *tdb,
     310/* Slow, but should be very rare. */
     311size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off)
     312{
     313        size_t len;
     314
     315        for (len = 0; off + len < tdb->map_size; len++) {
     316                char c;
     317                if (tdb->methods->tdb_read(tdb, off, &c, 1, 0))
     318                        return 0;
     319                if (c != 0 && c != 0x42)
     320                        break;
     321        }
     322        return len;
     323}
     324
     325_PUBLIC_ int tdb_check(struct tdb_context *tdb,
    305326              int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
    306327              void *private_data)
     
    311332        struct tdb_record rec;
    312333        bool found_recovery = false;
    313 
    314         if (tdb_lockall(tdb) == -1)
    315                 return -1;
     334        tdb_len_t dead;
     335        bool locked;
     336
     337        /* Read-only databases use no locking at all: it's best-effort.
     338         * We may have a write lock already, so skip that case too. */
     339        if (tdb->read_only || tdb->allrecord_lock.count != 0) {
     340                locked = false;
     341        } else {
     342                if (tdb_lockall_read(tdb) == -1)
     343                        return -1;
     344                locked = true;
     345        }
    316346
    317347        /* Make sure we know true size of the underlying file. */
     
    370400                                goto free;
    371401                        break;
     402                /* If we crash after ftruncate, we can get zeroes or fill. */
     403                case TDB_RECOVERY_INVALID_MAGIC:
     404                case 0x42424242:
     405                        if (recovery_start == off) {
     406                                found_recovery = true;
     407                                break;
     408                        }
     409                        dead = tdb_dead_space(tdb, off);
     410                        if (dead < sizeof(rec))
     411                                goto corrupt;
     412
     413                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
     414                                 "Dead space at %d-%d (of %u)\n",
     415                                 off, off + dead, tdb->map_size));
     416                        rec.rec_len = dead - sizeof(rec);
     417                        break;
    372418                case TDB_RECOVERY_MAGIC:
    373                 case 0: /* Used for invalid (or in-progress) recovery area. */
    374419                        if (recovery_start != off) {
    375420                                TDB_LOG((tdb, TDB_DEBUG_ERROR,
     
    380425                        found_recovery = true;
    381426                        break;
    382                 default:
     427                default: ;
     428                corrupt:
    383429                        tdb->ecode = TDB_ERR_CORRUPT;
    384430                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
     
    406452        if (recovery_start != 0 && !found_recovery) {
    407453                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    408                          "Expected %s recovery area, got %s\n",
    409                          recovery_start ? "a" : "no",
    410                          found_recovery ? "one" : "none"));
     454                         "Expected a recovery area at %u\n",
     455                         recovery_start));
    411456                goto free;
    412457        }
    413458
    414459        free(hashes);
    415         tdb_unlockall(tdb);
     460        if (locked) {
     461                tdb_unlockall_read(tdb);
     462        }
    416463        return 0;
    417464
     
    419466        free(hashes);
    420467unlock:
    421         tdb_unlockall(tdb);
     468        if (locked) {
     469                tdb_unlockall_read(tdb);
     470        }
    422471        return -1;
    423472}
  • trunk/server/lib/tdb/common/dump.c

    r414 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    8181}
    8282
    83 void tdb_dump_all(struct tdb_context *tdb)
     83_PUBLIC_ void tdb_dump_all(struct tdb_context *tdb)
    8484{
    8585        int i;
     
    9191}
    9292
    93 int tdb_printfreelist(struct tdb_context *tdb)
     93_PUBLIC_ int tdb_printfreelist(struct tdb_context *tdb)
    9494{
    9595        int ret;
  • trunk/server/lib/tdb/common/error.c

    r414 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    2828#include "tdb_private.h"
    2929
    30 enum TDB_ERROR tdb_error(struct tdb_context *tdb)
     30_PUBLIC_ enum TDB_ERROR tdb_error(struct tdb_context *tdb)
    3131{
    3232        return tdb->ecode;
     
    4747
    4848/* Error string for the last tdb error */
    49 const char *tdb_errorstr(struct tdb_context *tdb)
     49_PUBLIC_ const char *tdb_errorstr(struct tdb_context *tdb)
    5050{
    5151        uint32_t i;
  • trunk/server/lib/tdb/common/freelist.c

    r414 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    9999
    100100/* Add an element into the freelist. Merge adjacent records if
    101    neccessary. */
     101   necessary. */
    102102int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
    103103{
     
    144144                struct tdb_record l;
    145145                tdb_off_t leftsize;
    146                
     146
    147147                /* Read in tailer and jump back to header */
    148148                if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
     
    335335                        break;
    336336                }
    337                
     337
    338338                /* this multiplier means we only extremely rarely
    339339                   search more than 50 or so records. At 50 records we
     
    368368   return the size of the freelist - used to decide if we should repack
    369369*/
    370 int tdb_freelist_size(struct tdb_context *tdb)
     370_PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb)
    371371{
    372372        tdb_off_t ptr;
  • trunk/server/lib/tdb/common/freelistcheck.c

    r414 r745  
    4444}
    4545
    46 int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
     46_PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
    4747{
    4848        struct tdb_context *mem_tdb = NULL;
  • trunk/server/lib/tdb/common/io.c

    r599 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    9494        // the owner (us) is not allowed to write to the file (different from unix)
    9595        TDB_LOG((tdb, TDB_DEBUG_TRACE,"unlocking at %d len=%d before writing.\n", off, len));
    96         tdb_brlock( tdb, off, F_UNLCK, F_SETLK, 0, 1);
     96        tdb_brunlock( tdb, F_RDLCK, off, len);
    9797        // if a wider previous lock is in effect, we cannot write lock our segment
    9898        // (e.g. a lock_upgrade locks all the file), so we hope the previous lock
    9999        // is a write lock: do not wait for lock.
    100         tdb_brlock( tdb, off, F_WRLCK, F_SETLK, 0, len);
     100        tdb_brlock( tdb, F_WRLCK, off, len, F_SETLK);
    101101#endif
    102102
     
    126126                                 "write %d bytes at %d in two attempts\n",
    127127                                 len, off));
    128 
    129128#ifdef __OS2__ // remove our lock
    130                         tdb_brlock( tdb, off, F_UNLCK, F_SETLK, 0, len);
     129                        tdb_brunlock( tdb, F_WRLCK, off, len);
    131130#endif
    132131                        return -1;
    133132                }
    134133        }
    135 
    136134#ifdef __OS2__ // remove our lock
    137         tdb_brlock( tdb, off, F_UNLCK, F_SETLK, 0, len);
     135                        tdb_brunlock( tdb, F_WRLCK, off, len);
    138136#endif
    139 
    140137        return 0;
    141138}
     
    497494        tdb_oob,
    498495        tdb_expand_file,
    499         tdb_brlock
    500496};
    501497
  • trunk/server/lib/tdb/common/lock.c

    r647 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    2727
    2828#include "tdb_private.h"
    29 
    30 #define TDB_MARK_LOCK 0x80000000
    31 
    3229#ifdef __OS2__
    3330
    34 static char* lock_type( int lck)
    35 {
    36         static char buffer[16];
    37         switch(lck) {
    38         case F_GETLK: return "F_GETLK";
    39         case F_SETLK: return "F_SETLK";
    40         case F_SETLKW: return "F_SETLKW";
    41         default:
    42                 sprintf( buffer, "unknown %d", lck);
    43         }
    44         return buffer;
     31static char* lock_type( bool waitflag)
     32{
     33        if (waitflag)
     34                return "F_SETLKW";
     35        else
     36                return "F_SETLK";
    4537}
    4638
     
    5951
    6052static int _mutex_brlock(struct tdb_context *tdb, tdb_off_t offset,
    61                int rw_type, int lck_type, int probe, size_t len)
     53               int rw_type, bool waitflag, size_t len)
    6254{
    6355        HMTX    hSem;
     
    6658       
    6759        switch( offset) {
    68         case GLOBAL_LOCK:
     60        case OPEN_LOCK:
    6961                hSem = tdb->hGlobalLock;
    7062                break;
     
    8678        TDB_LOG((tdb, TDB_DEBUG_TRACE,"_mutex_brlock handle %d, offset %d\n", hSem, offset));
    8779
    88         if (lck_type == F_SETLKW)
     80        if (waitflag)
    8981                ulTimeout = SEM_INDEFINITE_WAIT;
    9082        else
     
    112104        errno = EINVAL;
    113105        TDB_LOG(( tdb, TDB_DEBUG_ERROR, "_mutex_brlock pid %X, failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d, rc=%d\n",
    114                  getpid(), tdb->fd, offset, rw_type, lck_type, (int)len, rc));
     106                 getpid(), tdb->fd, offset, rw_type, waitflag, (int)len, rc));
    115107        tdb->ecode = TDB_ERR_LOCK;
    116108        return -1;
     
    118110#endif
    119111
    120 void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr)
     112_PUBLIC_ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr)
    121113{
    122114        tdb->interrupt_sig_ptr = ptr;
    123115}
    124116
    125 /* a byte range locking function - return 0 on success
    126    this functions locks/unlocks 1 byte at the specified offset.
    127 
    128    On error, errno is also set so that errors are passed back properly
    129    through tdb_open().
    130 
    131    note that a len of zero means lock to end of file
    132 */
    133 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,
    134                int rw_type, int lck_type, int probe, size_t len)
    135 {
    136 
     117static int fcntl_lock(struct tdb_context *tdb,
     118                      int rw, tdb_off_t off, size_t len, bool waitflag)
     119{
    137120#ifdef __OS2__
    138121        APIRET      rc;
    139         ULONG       fAccess = 0;
    140         int         fLock = 0;
     122        ULONG       fAccess = 0; // default exclusiv
     123        int         fLock = 1;   // default lock
    141124        off_t       cbFile;
    142125        off_t       offStart;
    143126        off_t       cbRange;
    144 
    145         TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_brlock pid %X, fd %d, lck_type %s, rw_type %s, offset %d, len %d\n",
    146                 getpid(), tdb->fd, lock_type(lck_type), read_type(rw_type), offset, len));
    147 
    148         if (tdb->flags & TDB_NOLOCK) {
    149                 return 0;
    150         }
    151 
    152         if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) {
    153                 tdb->ecode = TDB_ERR_RDONLY;
    154                 return -1;
    155         }
     127        FILELOCK    lockArea = {0}, unlockArea = {0};
     128
     129        TDB_LOG((tdb, TDB_DEBUG_TRACE, "fcntl_lock in pid %X, fd %d, lck_type %s, rw_type %s, offset %d, len %d\n",
     130                getpid(), tdb->fd, lock_type(waitflag), read_type(rw), off, len));
    156131       
    157         switch( offset) {
    158         case GLOBAL_LOCK:
     132        switch(off) {
     133        case OPEN_LOCK:
    159134        case ACTIVE_LOCK:
    160135        case TRANSACTION_LOCK:
    161                 return _mutex_brlock( tdb, offset, rw_type,  lck_type,  probe, len);
     136                return _mutex_brlock(tdb, off, rw, waitflag, len);
    162137        }
    163138
    164139        /* flags and order */
    165         fAccess = 0; /* exclusive */
    166         switch (rw_type)
     140        switch (rw)
    167141        {
    168142                case F_UNLCK:
    169143                        fLock = 0;
     144                        unlockArea.lOffset = off;
     145                        unlockArea.lRange  = len ? len : tdb->header.hash_size *4; //was LONG_MAX
    170146                        break;
    171147                case F_RDLCK:
     148                        lockArea.lOffset = off;
     149                        lockArea.lRange  = len ? len : LONG_MAX;
    172150                        fAccess = 1; /* read-only */
     151                        break;
    173152                case F_WRLCK:
    174                         fLock = 1;
     153                        lockArea.lOffset = off;
     154                        lockArea.lRange  = len ? len : LONG_MAX;
    175155                        break;
    176156                default:
     
    178158        }
    179159               
    180         FILELOCK   aflock[2];
    181         bzero(&aflock[(fLock + 1) & 1], sizeof(aflock[0]));
    182         aflock[fLock].lOffset = offset;
    183         aflock[fLock].lRange  = len ? len : LONG_MAX;
    184         rc = DosSetFileLocks(tdb->fd, &aflock[0], &aflock[1], SEM_IMMEDIATE_RETURN, fAccess);
    185 
    186         if (rc != NO_ERROR && lck_type == F_SETLKW) {
     160        rc = DosSetFileLocks(tdb->fd, &unlockArea, &lockArea, SEM_IMMEDIATE_RETURN, fAccess);
     161
     162        if (rc != NO_ERROR && waitflag) {
    187163                int     count = 20;
    188164                do {
    189                         rc = DosSetFileLocks(tdb->fd, &aflock[0], &aflock[1], 100, fAccess);
     165                        rc = DosSetFileLocks(tdb->fd, &unlockArea, &lockArea, 100, fAccess);
    190166                        count--;
    191167                } while( count>0 && rc !=NO_ERROR);
    192168
    193169        }
     170
     171        TDB_LOG(( tdb, TDB_DEBUG_TRACE, "fcntl_lock out pid %X, fd %d, lck_type %s, rw_type %s, offset %d, len %d, rc=%d\n",
     172                getpid(), tdb->fd, lock_type(waitflag), read_type(rw), off, len, rc));
     173
    194174        if (rc != NO_ERROR) {
    195175                errno  = EINVAL;
    196                 /* Generic lock error. errno set by fcntl.
    197                  * EAGAIN is an expected return from non-blocking
    198                  * locks. */
    199                 if (!probe && lck_type != F_SETLK) {
    200                         /* Ensure error code is set for log fun to examine. */
    201                         tdb->ecode = TDB_ERR_LOCK;
    202                         TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",
    203                                  tdb->fd, offset, rw_type, lck_type, (int)len));
     176                return -1;
     177        }
     178
     179#else
     180        struct flock fl;
     181
     182        fl.l_type = rw;
     183        fl.l_whence = SEEK_SET;
     184        fl.l_start = off;
     185        fl.l_len = len;
     186        fl.l_pid = 0;
     187
     188        if (waitflag)
     189                return fcntl(tdb->fd, F_SETLKW, &fl);
     190        else
     191                return fcntl(tdb->fd, F_SETLK, &fl);
     192#endif
     193}
     194
     195static int fcntl_unlock(struct tdb_context *tdb, int rw, tdb_off_t off, size_t len)
     196{
     197        struct flock fl;
     198#if 0 /* Check they matched up locks and unlocks correctly. */
     199        char line[80];
     200        FILE *locks;
     201        bool found = false;
     202
     203        locks = fopen("/proc/locks", "r");
     204
     205        while (fgets(line, 80, locks)) {
     206                char *p;
     207                int type, start, l;
     208
     209                /* eg. 1: FLOCK  ADVISORY  WRITE 2440 08:01:2180826 0 EOF */
     210                p = strchr(line, ':') + 1;
     211                if (strncmp(p, " POSIX  ADVISORY  ", strlen(" POSIX  ADVISORY  ")))
     212                        continue;
     213                p += strlen(" FLOCK  ADVISORY  ");
     214                if (strncmp(p, "READ  ", strlen("READ  ")) == 0)
     215                        type = F_RDLCK;
     216                else if (strncmp(p, "WRITE ", strlen("WRITE ")) == 0)
     217                        type = F_WRLCK;
     218                else
     219                        abort();
     220                p += 6;
     221                if (atoi(p) != getpid())
     222                        continue;
     223                p = strchr(strchr(p, ' ') + 1, ' ') + 1;
     224                start = atoi(p);
     225                p = strchr(p, ' ') + 1;
     226                if (strncmp(p, "EOF", 3) == 0)
     227                        l = 0;
     228                else
     229                        l = atoi(p) - start + 1;
     230
     231                if (off == start) {
     232                        if (len != l) {
     233                                fprintf(stderr, "Len %u should be %u: %s",
     234                                        (int)len, l, line);
     235                                abort();
     236                        }
     237                        if (type != rw) {
     238                                fprintf(stderr, "Type %s wrong: %s",
     239                                        rw == F_RDLCK ? "READ" : "WRITE", line);
     240                                abort();
     241                        }
     242                        found = true;
     243                        break;
    204244                }
    205 
    206                 TDB_LOG(( tdb, TDB_DEBUG_TRACE, "tdb_brlock pid %X, failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",
    207                          getpid(), tdb->fd, offset, rw_type, lck_type, (int)len));
    208                 tdb->ecode = TDB_ERR_LOCK;
    209                 return -1;
    210         }
    211 
    212         TDB_LOG(( tdb, TDB_DEBUG_TRACE, "tdb_brlock pid %X, fd %d, lck_type %s, rw_type %s, offset %d, len %d DONE\n",
    213                 getpid(), tdb->fd, lock_type(lck_type), read_type(rw_type), offset, len));
    214 
     245        }
     246
     247        if (!found) {
     248                fprintf(stderr, "Unlock on %u@%u not found!\n",
     249                        (int)off, (int)len);
     250                abort();
     251        }
     252
     253        fclose(locks);
     254#endif
     255
     256        fl.l_type = F_UNLCK;
     257        fl.l_whence = SEEK_SET;
     258        fl.l_start = off;
     259        fl.l_len = len;
     260        fl.l_pid = 0;
     261#ifdef __OS2__
     262        return fcntl_lock(tdb, F_UNLCK, off, len, 1);
    215263#else
    216 
    217         struct flock fl;
     264        return fcntl(tdb->fd, F_SETLKW, &fl);
     265#endif
     266}
     267
     268/* list -1 is the alloc list, otherwise a hash chain. */
     269static tdb_off_t lock_offset(int list)
     270{
     271        return FREELIST_TOP + 4*list;
     272}
     273
     274/* a byte range locking function - return 0 on success
     275   this functions locks/unlocks 1 byte at the specified offset.
     276
     277   On error, errno is also set so that errors are passed back properly
     278   through tdb_open().
     279
     280   note that a len of zero means lock to end of file
     281*/
     282int tdb_brlock(struct tdb_context *tdb,
     283               int rw_type, tdb_off_t offset, size_t len,
     284               enum tdb_lock_flags flags)
     285{
    218286        int ret;
    219287
    220288        if (tdb->flags & TDB_NOLOCK) {
     289                return 0;
     290        }
     291
     292        if (flags & TDB_LOCK_MARK_ONLY) {
    221293                return 0;
    222294        }
     
    227299        }
    228300
    229         fl.l_type = rw_type;
    230         fl.l_whence = SEEK_SET;
    231         fl.l_start = offset;
    232         fl.l_len = len;
    233         fl.l_pid = 0;
    234 
    235301        do {
    236                 ret = fcntl(tdb->fd,lck_type,&fl);
    237 
     302                ret = fcntl_lock(tdb, rw_type, offset, len,
     303                                 flags & TDB_LOCK_WAIT);
    238304                /* Check for a sigalarm break. */
    239305                if (ret == -1 && errno == EINTR &&
     
    249315                 * EAGAIN is an expected return from non-blocking
    250316                 * locks. */
    251                 if (!probe && lck_type != F_SETLK) {
    252                         TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",
    253                                  tdb->fd, offset, rw_type, lck_type, (int)len));
     317                if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) {
     318                        TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d\n",
     319                                 tdb->fd, offset, rw_type, flags, (int)len));
    254320                }
    255321                return -1;
    256322        }
    257323        return 0;
    258 #endif
    259 }
    260 
     324}
     325
     326int tdb_brunlock(struct tdb_context *tdb,
     327                 int rw_type, tdb_off_t offset, size_t len)
     328{
     329        int ret;
     330
     331        if (tdb->flags & TDB_NOLOCK) {
     332                return 0;
     333        }
     334
     335        do {
     336                ret = fcntl_unlock(tdb, rw_type, offset, len);
     337        } while (ret == -1 && errno == EINTR);
     338
     339        if (ret == -1) {
     340                TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d\n",
     341                         tdb->fd, offset, rw_type, (int)len));
     342        }
     343        return ret;
     344}
    261345
    262346/*
     
    266350  made. For those OSes we may loop for a while. 
    267351*/
    268 int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)
     352int tdb_allrecord_upgrade(struct tdb_context *tdb)
    269353{
    270354        int count = 1000;
     355
     356        if (tdb->allrecord_lock.count != 1) {
     357                TDB_LOG((tdb, TDB_DEBUG_ERROR,
     358                         "tdb_allrecord_upgrade failed: count %u too high\n",
     359                         tdb->allrecord_lock.count));
     360                return -1;
     361        }
     362
     363        if (tdb->allrecord_lock.off != 1) {
     364                TDB_LOG((tdb, TDB_DEBUG_ERROR,
     365                         "tdb_allrecord_upgrade failed: already upgraded?\n"));
     366                return -1;
     367        }
     368
    271369        while (count--) {
    272370                struct timeval tv;
    273 
    274371#ifdef __OS2__
    275372                // YD we cannot upgrade without an unlock first...
    276                 tdb_brlock(tdb, offset, F_UNLCK, F_SETLKW, 1, len);
     373                tdb_brlock(tdb, F_UNLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT|TDB_LOCK_PROBE);
    277374#endif
    278 
    279                 if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) {
     375                if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
     376                               TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) {
     377                        tdb->allrecord_lock.ltype = F_WRLCK;
     378                        tdb->allrecord_lock.off = 0;
    280379                        return 0;
    281380                }
     
    288387                select(0, NULL, NULL, NULL, &tv);
    289388        }
    290         TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock_upgrade failed at offset %d\n", offset));
     389        TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n"));
    291390        return -1;
    292391}
    293392
    294 
    295 /* lock a list in the database. list -1 is the alloc list */
    296 static int _tdb_lock(struct tdb_context *tdb, int list, int ltype, int op)
     393static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb,
     394                                           tdb_off_t offset)
     395{
     396        unsigned int i;
     397
     398        for (i=0; i<tdb->num_lockrecs; i++) {
     399                if (tdb->lockrecs[i].off == offset) {
     400                        return &tdb->lockrecs[i];
     401                }
     402        }
     403        return NULL;
     404}
     405
     406/* lock an offset in the database. */
     407int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
     408                  enum tdb_lock_flags flags)
    297409{
    298410        struct tdb_lock_type *new_lck;
    299         int i;
    300         bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
    301 
    302         ltype &= ~TDB_MARK_LOCK;
    303 
    304         /* a global lock allows us to avoid per chain locks */
    305         if (tdb->global_lock.count &&
    306             (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
    307                 return 0;
    308         }
    309 
    310         if (tdb->global_lock.count) {
     411
     412        if (offset >= lock_offset(tdb->header.hash_size)) {
    311413                tdb->ecode = TDB_ERR_LOCK;
    312                 return -1;
    313         }
    314 
    315         if (list < -1 || list >= (int)tdb->header.hash_size) {
    316                 tdb->ecode = TDB_ERR_LOCK;
    317                 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n",
    318                            list, ltype));
     414                TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n",
     415                         offset, ltype));
    319416                return -1;
    320417        }
     
    322419                return 0;
    323420
    324         for (i=0; i<tdb->num_lockrecs; i++) {
    325                 if (tdb->lockrecs[i].list == list) {
    326                         if (tdb->lockrecs[i].count == 0) {
    327                                 /*
    328                                  * Can't happen, see tdb_unlock(). It should
    329                                  * be an assert.
    330                                  */
    331                                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: "
    332                                          "lck->count == 0 for list %d", list));
    333                         }
    334                         /*
    335                          * Just increment the in-memory struct, posix locks
    336                          * don't stack.
    337                          */
    338                         tdb->lockrecs[i].count++;
    339                         return 0;
    340                 }
     421        new_lck = find_nestlock(tdb, offset);
     422        if (new_lck) {
     423                /*
     424                 * Just increment the in-memory struct, posix locks
     425                 * don't stack.
     426                 */
     427                new_lck->count++;
     428                return 0;
    341429        }
    342430
     
    352440        /* Since fcntl locks don't nest, we do a lock for the first one,
    353441           and simply bump the count for future ones */
    354         if (!mark_lock &&
    355             tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list, ltype, op,
    356                                      0, 1)) {
    357                 return -1;
    358         }
    359 
    360         tdb->num_locks++;
    361 
    362         tdb->lockrecs[tdb->num_lockrecs].list = list;
     442        if (tdb_brlock(tdb, ltype, offset, 1, flags)) {
     443                return -1;
     444        }
     445
     446        tdb->lockrecs[tdb->num_lockrecs].off = offset;
    363447        tdb->lockrecs[tdb->num_lockrecs].count = 1;
    364448        tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
    365         tdb->num_lockrecs += 1;
     449        tdb->num_lockrecs++;
    366450
    367451        return 0;
     452}
     453
     454static int tdb_lock_and_recover(struct tdb_context *tdb)
     455{
     456        int ret;
     457
     458        /* We need to match locking order in transaction commit. */
     459        if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT)) {
     460                return -1;
     461        }
     462
     463        if (tdb_brlock(tdb, F_WRLCK, OPEN_LOCK, 1, TDB_LOCK_WAIT)) {
     464                tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
     465                return -1;
     466        }
     467
     468        ret = tdb_transaction_recover(tdb);
     469
     470        tdb_brunlock(tdb, F_WRLCK, OPEN_LOCK, 1);
     471        tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
     472
     473        return ret;
     474}
     475
     476static bool have_data_locks(const struct tdb_context *tdb)
     477{
     478        unsigned int i;
     479
     480        for (i = 0; i < tdb->num_lockrecs; i++) {
     481                if (tdb->lockrecs[i].off >= lock_offset(-1))
     482                        return true;
     483        }
     484        return false;
     485}
     486
     487static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype,
     488                         enum tdb_lock_flags waitflag)
     489{
     490        int ret;
     491        bool check = false;
     492
     493        /* a allrecord lock allows us to avoid per chain locks */
     494        if (tdb->allrecord_lock.count &&
     495            (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
     496                return 0;
     497        }
     498
     499        if (tdb->allrecord_lock.count) {
     500                tdb->ecode = TDB_ERR_LOCK;
     501                ret = -1;
     502        } else {
     503                /* Only check when we grab first data lock. */
     504                check = !have_data_locks(tdb);
     505                ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag);
     506
     507                if (ret == 0 && check && tdb_needs_recovery(tdb)) {
     508                        tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
     509
     510                        if (tdb_lock_and_recover(tdb) == -1) {
     511                                return -1;
     512                        }
     513                        return tdb_lock_list(tdb, list, ltype, waitflag);
     514                }
     515        }
     516        return ret;
    368517}
    369518
     
    372521{
    373522        int ret;
    374         ret = _tdb_lock(tdb, list, ltype, F_SETLKW);
     523
     524        ret = tdb_lock_list(tdb, list, ltype, TDB_LOCK_WAIT);
    375525        if (ret) {
    376526                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
     
    383533int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype)
    384534{
    385         return _tdb_lock(tdb, list, ltype, F_SETLK);
    386 }
    387 
    388 
    389 /* unlock the database: returns void because it's too late for errors. */
    390         /* changed to return int it may be interesting to know there
    391            has been an error  --simo */
    392 int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
     535        return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT);
     536}
     537
     538
     539int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
     540                    bool mark_lock)
    393541{
    394542        int ret = -1;
    395         int i;
    396         struct tdb_lock_type *lck = NULL;
    397         bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
    398 
    399         ltype &= ~TDB_MARK_LOCK;
    400 
    401         /* a global lock allows us to avoid per chain locks */
    402         if (tdb->global_lock.count &&
    403             (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) {
    404                 return 0;
    405         }
    406 
    407         if (tdb->global_lock.count) {
    408                 tdb->ecode = TDB_ERR_LOCK;
    409                 return -1;
    410         }
     543        struct tdb_lock_type *lck;
    411544
    412545        if (tdb->flags & TDB_NOLOCK)
     
    414547
    415548        /* Sanity checks */
    416         if (list < -1 || list >= (int)tdb->header.hash_size) {
    417                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));
     549        if (offset >= lock_offset(tdb->header.hash_size)) {
     550                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->header.hash_size));
    418551                return ret;
    419552        }
    420553
    421         for (i=0; i<tdb->num_lockrecs; i++) {
    422                 if (tdb->lockrecs[i].list == list) {
    423                         lck = &tdb->lockrecs[i];
    424                         break;
    425                 }
    426         }
    427 
     554        lck = find_nestlock(tdb, offset);
    428555        if ((lck == NULL) || (lck->count == 0)) {
    429556                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
     
    446573                ret = 0;
    447574        } else {
    448                 ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK,
    449                                                F_SETLKW, 0, 1);
    450         }
    451         tdb->num_locks--;
     575                ret = tdb_brunlock(tdb, ltype, offset, 1);
     576        }
    452577
    453578        /*
     
    455580         * last array element.
    456581         */
    457 
    458         if (tdb->num_lockrecs > 1) {
    459                 *lck = tdb->lockrecs[tdb->num_lockrecs-1];
    460         }
    461         tdb->num_lockrecs -= 1;
     582        *lck = tdb->lockrecs[--tdb->num_lockrecs];
    462583
    463584        /*
     
    475596}
    476597
     598int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
     599{
     600        /* a global lock allows us to avoid per chain locks */
     601        if (tdb->allrecord_lock.count &&
     602            (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
     603                return 0;
     604        }
     605
     606        if (tdb->allrecord_lock.count) {
     607                tdb->ecode = TDB_ERR_LOCK;
     608                return -1;
     609        }
     610
     611        return tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
     612}
     613
    477614/*
    478615  get the transaction lock
    479616 */
    480 int tdb_transaction_lock(struct tdb_context *tdb, int ltype)
    481 {
    482         if (tdb->global_lock.count) {
    483                 return 0;
    484         }
    485         if (tdb->transaction_lock_count > 0) {
    486                 tdb->transaction_lock_count++;
    487                 return 0;
    488         }
    489 
    490         if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype,
    491                                      F_SETLKW, 0, 1) == -1) {
    492                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n"));
    493                 tdb->ecode = TDB_ERR_LOCK;
    494                 return -1;
    495         }
    496         tdb->transaction_lock_count++;
    497         return 0;
     617int tdb_transaction_lock(struct tdb_context *tdb, int ltype,
     618                         enum tdb_lock_flags lockflags)
     619{
     620        return tdb_nest_lock(tdb, TRANSACTION_LOCK, ltype, lockflags);
    498621}
    499622
     
    501624  release the transaction lock
    502625 */
    503 int tdb_transaction_unlock(struct tdb_context *tdb)
    504 {
    505         int ret;
    506         if (tdb->global_lock.count) {
    507                 return 0;
    508         }
    509         if (tdb->transaction_lock_count > 1) {
    510                 tdb->transaction_lock_count--;
    511                 return 0;
    512         }
    513         ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1);
    514         if (ret == 0) {
    515                 tdb->transaction_lock_count = 0;
    516         }
    517         return ret;
    518 }
    519 
    520 
    521 
    522 
    523 /* lock/unlock entire database */
    524 static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op)
    525 {
    526         bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
    527 
    528         ltype &= ~TDB_MARK_LOCK;
    529 
     626int tdb_transaction_unlock(struct tdb_context *tdb, int ltype)
     627{
     628        return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false);
     629}
     630
     631/* Returns 0 if all done, -1 if error, 1 if ok. */
     632static int tdb_allrecord_check(struct tdb_context *tdb, int ltype,
     633                               enum tdb_lock_flags flags, bool upgradable)
     634{
    530635        /* There are no locks on read-only dbs */
    531636        if (tdb->read_only || tdb->traverse_read) {
     
    534639        }
    535640
    536         if (tdb->global_lock.count && tdb->global_lock.ltype == ltype) {
    537                 tdb->global_lock.count++;
    538                 return 0;
    539         }
    540 
    541         if (tdb->global_lock.count) {
     641        if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) {
     642                tdb->allrecord_lock.count++;
     643                return 0;
     644        }
     645
     646        if (tdb->allrecord_lock.count) {
    542647                /* a global lock of a different type exists */
    543648                tdb->ecode = TDB_ERR_LOCK;
    544649                return -1;
    545650        }
    546        
    547         if (tdb->num_locks != 0) {
     651
     652        if (tdb_have_extra_locks(tdb)) {
    548653                /* can't combine global and chain locks */
    549654                tdb->ecode = TDB_ERR_LOCK;
     
    551656        }
    552657
    553         if (!mark_lock &&
    554             tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op,
    555                                      0, 4*tdb->header.hash_size)) {
    556                 if (op == F_SETLKW) {
    557                         TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno)));
     658        if (upgradable && ltype != F_RDLCK) {
     659                /* tdb error: you can't upgrade a write lock! */
     660                tdb->ecode = TDB_ERR_LOCK;
     661                return -1;
     662        }
     663        return 1;
     664}
     665
     666/* We only need to lock individual bytes, but Linux merges consecutive locks
     667 * so we lock in contiguous ranges. */
     668static int tdb_chainlock_gradual(struct tdb_context *tdb,
     669                                 int ltype, enum tdb_lock_flags flags,
     670                                 size_t off, size_t len)
     671{
     672        int ret;
     673        enum tdb_lock_flags nb_flags = (flags & ~TDB_LOCK_WAIT);
     674
     675        if (len <= 4) {
     676                /* Single record.  Just do blocking lock. */
     677                return tdb_brlock(tdb, ltype, off, len, flags);
     678        }
     679
     680        /* First we try non-blocking. */
     681        ret = tdb_brlock(tdb, ltype, off, len, nb_flags);
     682        if (ret == 0) {
     683                return 0;
     684        }
     685
     686        /* Try locking first half, then second. */
     687        ret = tdb_chainlock_gradual(tdb, ltype, flags, off, len / 2);
     688        if (ret == -1)
     689                return -1;
     690
     691        ret = tdb_chainlock_gradual(tdb, ltype, flags,
     692                                    off + len / 2, len - len / 2);
     693        if (ret == -1) {
     694                tdb_brunlock(tdb, ltype, off, len / 2);
     695                return -1;
     696        }
     697        return 0;
     698}
     699
     700/* lock/unlock entire database.  It can only be upgradable if you have some
     701 * other way of guaranteeing exclusivity (ie. transaction write lock).
     702 * We do the locking gradually to avoid being starved by smaller locks. */
     703int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
     704                       enum tdb_lock_flags flags, bool upgradable)
     705{
     706        switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) {
     707        case -1:
     708                return -1;
     709        case 0:
     710                return 0;
     711        }
     712
     713        /* We cover two kinds of locks:
     714         * 1) Normal chain locks.  Taken for almost all operations.
     715         * 3) Individual records locks.  Taken after normal or free
     716         *    chain locks.
     717         *
     718         * It is (1) which cause the starvation problem, so we're only
     719         * gradual for that. */
     720        if (tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP,
     721                                  tdb->header.hash_size * 4) == -1) {
     722                return -1;
     723        }
     724
     725        /* Grab individual record locks. */
     726        if (tdb_brlock(tdb, ltype, lock_offset(tdb->header.hash_size), 0,
     727                       flags) == -1) {
     728                tdb_brunlock(tdb, ltype, FREELIST_TOP,
     729                             tdb->header.hash_size * 4);
     730                return -1;
     731        }
     732
     733        tdb->allrecord_lock.count = 1;
     734        /* If it's upgradable, it's actually exclusive so we can treat
     735         * it as a write lock. */
     736        tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype;
     737        tdb->allrecord_lock.off = upgradable;
     738
     739        if (tdb_needs_recovery(tdb)) {
     740                bool mark = flags & TDB_LOCK_MARK_ONLY;
     741                tdb_allrecord_unlock(tdb, ltype, mark);
     742                if (mark) {
     743                        tdb->ecode = TDB_ERR_LOCK;
     744                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
     745                                 "tdb_lockall_mark cannot do recovery\n"));
     746                        return -1;
    558747                }
    559                 return -1;
    560         }
    561 
    562         tdb->global_lock.count = 1;
    563         tdb->global_lock.ltype = ltype;
     748                if (tdb_lock_and_recover(tdb) == -1) {
     749                        return -1;
     750                }
     751                return tdb_allrecord_lock(tdb, ltype, flags, upgradable);
     752        }
    564753
    565754        return 0;
     
    569758
    570759/* unlock entire db */
    571 static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
    572 {
    573         bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK);
    574 
    575         ltype &= ~TDB_MARK_LOCK;
    576 
     760int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock)
     761{
    577762        /* There are no locks on read-only dbs */
    578763        if (tdb->read_only || tdb->traverse_read) {
     
    581766        }
    582767
    583         if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) {
     768        if (tdb->allrecord_lock.count == 0) {
    584769                tdb->ecode = TDB_ERR_LOCK;
    585770                return -1;
    586771        }
    587772
    588         if (tdb->global_lock.count > 1) {
    589                 tdb->global_lock.count--;
    590                 return 0;
    591         }
    592 
    593         if (!mark_lock &&
    594             tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW,
    595                                      0, 4*tdb->header.hash_size)) {
     773        /* Upgradable locks are marked as write locks. */
     774        if (tdb->allrecord_lock.ltype != ltype
     775            && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) {
     776                tdb->ecode = TDB_ERR_LOCK;
     777                return -1;
     778        }
     779
     780        if (tdb->allrecord_lock.count > 1) {
     781                tdb->allrecord_lock.count--;
     782                return 0;
     783        }
     784
     785        if (!mark_lock && tdb_brunlock(tdb, ltype, FREELIST_TOP, 0)) {
    596786                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
    597787                return -1;
    598788        }
    599789
    600         tdb->global_lock.count = 0;
    601         tdb->global_lock.ltype = 0;
     790        tdb->allrecord_lock.count = 0;
     791        tdb->allrecord_lock.ltype = 0;
    602792
    603793        return 0;
     
    605795
    606796/* lock entire database with write lock */
    607 int tdb_lockall(struct tdb_context *tdb)
     797_PUBLIC_ int tdb_lockall(struct tdb_context *tdb)
    608798{
    609799        tdb_trace(tdb, "tdb_lockall");
    610         return _tdb_lockall(tdb, F_WRLCK, F_SETLKW);
     800        return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
    611801}
    612802
    613803/* lock entire database with write lock - mark only */
    614 int tdb_lockall_mark(struct tdb_context *tdb)
     804_PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb)
    615805{
    616806        tdb_trace(tdb, "tdb_lockall_mark");
    617         return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW);
     807        return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false);
    618808}
    619809
    620810/* unlock entire database with write lock - unmark only */
    621 int tdb_lockall_unmark(struct tdb_context *tdb)
     811_PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb)
    622812{
    623813        tdb_trace(tdb, "tdb_lockall_unmark");
    624         return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK);
     814        return tdb_allrecord_unlock(tdb, F_WRLCK, true);
    625815}
    626816
    627817/* lock entire database with write lock - nonblocking varient */
    628 int tdb_lockall_nonblock(struct tdb_context *tdb)
    629 {
    630         int ret = _tdb_lockall(tdb, F_WRLCK, F_SETLK);
     818_PUBLIC_ int tdb_lockall_nonblock(struct tdb_context *tdb)
     819{
     820        int ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false);
    631821        tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret);
    632822        return ret;
     
    634824
    635825/* unlock entire database with write lock */
    636 int tdb_unlockall(struct tdb_context *tdb)
     826_PUBLIC_ int tdb_unlockall(struct tdb_context *tdb)
    637827{
    638828        tdb_trace(tdb, "tdb_unlockall");
    639         return _tdb_unlockall(tdb, F_WRLCK);
     829        return tdb_allrecord_unlock(tdb, F_WRLCK, false);
    640830}
    641831
    642832/* lock entire database with read lock */
    643 int tdb_lockall_read(struct tdb_context *tdb)
     833_PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb)
    644834{
    645835        tdb_trace(tdb, "tdb_lockall_read");
    646         return _tdb_lockall(tdb, F_RDLCK, F_SETLKW);
     836        return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
    647837}
    648838
    649839/* lock entire database with read lock - nonblock varient */
    650 int tdb_lockall_read_nonblock(struct tdb_context *tdb)
    651 {
    652         int ret = _tdb_lockall(tdb, F_RDLCK, F_SETLK);
     840_PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb)
     841{
     842        int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false);
    653843        tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret);
    654844        return ret;
     
    656846
    657847/* unlock entire database with read lock */
    658 int tdb_unlockall_read(struct tdb_context *tdb)
     848_PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb)
    659849{
    660850        tdb_trace(tdb, "tdb_unlockall_read");
    661         return _tdb_unlockall(tdb, F_RDLCK);
     851        return tdb_allrecord_unlock(tdb, F_RDLCK, false);
    662852}
    663853
    664854/* lock/unlock one hash chain. This is meant to be used to reduce
    665855   contention - it cannot guarantee how many records will be locked */
    666 int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
     856_PUBLIC_ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
    667857{
    668858        int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
     
    674864   to reduce contention - it cannot guarantee how many records will be
    675865   locked */
    676 int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
     866_PUBLIC_ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
    677867{
    678868        int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
     
    682872
    683873/* mark a chain as locked without actually locking it. Warning! use with great caution! */
    684 int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key)
    685 {
    686         int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK);
     874_PUBLIC_ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key)
     875{
     876        int ret = tdb_nest_lock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
     877                                F_WRLCK, TDB_LOCK_MARK_ONLY);
    687878        tdb_trace_1rec(tdb, "tdb_chainlock_mark", key);
    688879        return ret;
     
    690881
    691882/* unmark a chain as locked without actually locking it. Warning! use with great caution! */
    692 int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)
     883_PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)
    693884{
    694885        tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key);
    695         return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK);
    696 }
    697 
    698 int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
     886        return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
     887                               F_WRLCK, true);
     888}
     889
     890_PUBLIC_ int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
    699891{
    700892        tdb_trace_1rec(tdb, "tdb_chainunlock", key);
     
    702894}
    703895
    704 int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
     896_PUBLIC_ int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
    705897{
    706898        int ret;
     
    710902}
    711903
    712 int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
     904_PUBLIC_ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
    713905{
    714906        tdb_trace_1rec(tdb, "tdb_chainunlock_read", key);
     
    716908}
    717909
    718 
    719 
    720910/* record lock stops delete underneath */
    721911int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
    722912{
    723         if (tdb->global_lock.count) {
    724                 return 0;
    725         }
    726         return off ? tdb->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0;
     913        if (tdb->allrecord_lock.count) {
     914                return 0;
     915        }
     916        return off ? tdb_brlock(tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT) : 0;
    727917}
    728918
     
    738928                if (i->off == off)
    739929                        return -1;
    740         return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1);
    741 }
    742 
    743 /*
    744   Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
    745   an error to fail to get the lock here.
    746 */
     930        if (tdb->allrecord_lock.count) {
     931                if (tdb->allrecord_lock.ltype == F_WRLCK) {
     932                        return 0;
     933                }
     934                return -1;
     935        }
     936        return tdb_brlock(tdb, F_WRLCK, off, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
     937}
     938
    747939int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off)
    748940{
    749         return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1);
     941        if (tdb->allrecord_lock.count) {
     942                return 0;
     943        }
     944        return tdb_brunlock(tdb, F_WRLCK, off, 1);
    750945}
    751946
     
    756951        uint32_t count = 0;
    757952
    758         if (tdb->global_lock.count) {
     953        if (tdb->allrecord_lock.count) {
    759954                return 0;
    760955        }
     
    765960                if (i->off == off)
    766961                        count++;
    767         return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0);
    768 }
     962        return (count == 1 ? tdb_brunlock(tdb, F_RDLCK, off, 1) : 0);
     963}
     964
     965bool tdb_have_extra_locks(struct tdb_context *tdb)
     966{
     967        unsigned int extra = tdb->num_lockrecs;
     968
     969        /* A transaction holds the lock for all records. */
     970        if (!tdb->transaction && tdb->allrecord_lock.count) {
     971                return true;
     972        }
     973
     974        /* We always hold the active lock if CLEAR_IF_FIRST. */
     975        if (find_nestlock(tdb, ACTIVE_LOCK)) {
     976                extra--;
     977        }
     978
     979        /* In a transaction, we expect to hold the transaction lock */
     980        if (tdb->transaction && find_nestlock(tdb, TRANSACTION_LOCK)) {
     981                extra--;
     982        }
     983
     984        return extra;
     985}
     986
     987/* The transaction code uses this to remove all locks. */
     988void tdb_release_transaction_locks(struct tdb_context *tdb)
     989{
     990        unsigned int i, active = 0;
     991
     992        if (tdb->allrecord_lock.count != 0) {
     993                tdb_brunlock(tdb, tdb->allrecord_lock.ltype, FREELIST_TOP, 0);
     994                tdb->allrecord_lock.count = 0;
     995        }
     996
     997        for (i=0;i<tdb->num_lockrecs;i++) {
     998                struct tdb_lock_type *lck = &tdb->lockrecs[i];
     999
     1000                /* Don't release the active lock!  Copy it to first entry. */
     1001                if (lck->off == ACTIVE_LOCK) {
     1002                        tdb->lockrecs[active++] = *lck;
     1003                } else {
     1004                        tdb_brunlock(tdb, lck->ltype, lck->off, 1);
     1005                }
     1006        }
     1007        tdb->num_lockrecs = active;
     1008        if (tdb->num_lockrecs == 0) {
     1009                SAFE_FREE(tdb->lockrecs);
     1010        }
     1011}
  • trunk/server/lib/tdb/common/open.c

    r456 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    3636static struct tdb_context *tdbs = NULL;
    3737
    38 
    39 /* This is based on the hash algorithm from gdbm */
    40 static unsigned int default_tdb_hash(TDB_DATA *key)
    41 {
    42         uint32_t value; /* Used to compute the hash value.  */
    43         uint32_t   i;   /* Used to cycle through random values. */
    44 
    45         /* Set the initial value from the key size. */
    46         for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
    47                 value = (value + (key->dptr[i] << (i*5 % 24)));
    48 
    49         return (1103515243 * value + 12345); 
    50 }
    51 
     38/* We use two hashes to double-check they're using the right hash function. */
     39void tdb_header_hash(struct tdb_context *tdb,
     40                     uint32_t *magic1_hash, uint32_t *magic2_hash)
     41{
     42        TDB_DATA hash_key;
     43        uint32_t tdb_magic = TDB_MAGIC;
     44
     45        hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD);
     46        hash_key.dsize = sizeof(TDB_MAGIC_FOOD);
     47        *magic1_hash = tdb->hash_fn(&hash_key);
     48
     49        hash_key.dptr = (unsigned char *)CONVERT(tdb_magic);
     50        hash_key.dsize = sizeof(tdb_magic);
     51        *magic2_hash = tdb->hash_fn(&hash_key);
     52
     53        /* Make sure at least one hash is non-zero! */
     54        if (*magic1_hash == 0 && *magic2_hash == 0)
     55                *magic1_hash = 1;
     56}
    5257
    5358/* initialise a new database with a specified hash size */
     
    5762        size_t size;
    5863        int ret = -1;
    59         ssize_t written;
    6064
    6165        /* We make it up in memory, then write it out if not internal */
     
    6973        newdb->version = TDB_VERSION;
    7074        newdb->hash_size = hash_size;
     75
     76        tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash);
     77
     78        /* Make sure older tdbs (which don't check the magic hash fields)
     79         * will refuse to open this TDB. */
     80        if (tdb->flags & TDB_INCOMPATIBLE_HASH)
     81                newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC;
     82
    7183        if (tdb->flags & TDB_INTERNAL) {
    7284                tdb->map_size = size;
     
    89101        memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
    90102        /* we still have "ret == -1" here */
    91         written = write(tdb->fd, newdb, size);
    92         if (written == size) {
     103        if (tdb_write_all(tdb->fd, newdb, size))
    93104                ret = 0;
    94         } else if (written != -1) {
    95                 /* call write once again, this usually should return -1 and
    96                  * set errno appropriately */
    97                 size -= written;
    98                 written = write(tdb->fd, newdb+written, size);
    99                 if (written == size) {
    100                 ret = 0;
    101                 } else if (written >= 0) {
    102                         /* a second incomplete write - we give up.
    103                          * guessing the errno... */
    104                         errno = ENOSPC;
    105                 }
    106         }
    107105
    108106  fail:
     
    117115{
    118116        struct tdb_context *i;
    119        
     117
    120118        for (i = tdbs; i; i = i->next) {
    121119                if (i->device == device && i->inode == ino) {
     
    137135
    138136   @param name may be NULL for internal databases. */
    139 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
     137_PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
    140138                      int open_flags, mode_t mode)
    141139{
     
    149147}
    150148
    151 
    152 struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
     149static bool check_header_hash(struct tdb_context *tdb,
     150                              bool default_hash, uint32_t *m1, uint32_t *m2)
     151{
     152        tdb_header_hash(tdb, m1, m2);
     153        if (tdb->header.magic1_hash == *m1 &&
     154            tdb->header.magic2_hash == *m2) {
     155                return true;
     156        }
     157
     158        /* If they explicitly set a hash, always respect it. */
     159        if (!default_hash)
     160                return false;
     161
     162        /* Otherwise, try the other inbuilt hash. */
     163        if (tdb->hash_fn == tdb_old_hash)
     164                tdb->hash_fn = tdb_jenkins_hash;
     165        else
     166                tdb->hash_fn = tdb_old_hash;
     167        return check_header_hash(tdb, false, m1, m2);
     168}
     169
     170_PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
    153171                                int open_flags, mode_t mode,
    154172                                const struct tdb_logging_context *log_ctx,
     
    161179        uint32_t vertest;
    162180        unsigned v;
     181        const char *hash_alg;
     182        uint32_t magic1, magic2;
    163183
    164184        if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
     
    182202                tdb->log.log_private = NULL;
    183203        }
    184         tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
     204
     205        if (name == NULL && (tdb_flags & TDB_INTERNAL)) {
     206                name = "__TDB_INTERNAL__";
     207        }
     208
     209        if (name == NULL) {
     210                tdb->name = discard_const_p(char, "__NULL__");
     211                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n"));
     212                tdb->name = NULL;
     213                errno = EINVAL;
     214                goto fail;
     215        }
     216
     217        /* now make a copy of the name, as the caller memory might went away */
     218        if (!(tdb->name = (char *)strdup(name))) {
     219                /*
     220                 * set the name as the given string, so that tdb_name() will
     221                 * work in case of an error.
     222                 */
     223                tdb->name = discard_const_p(char, name);
     224                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n",
     225                         name));
     226                tdb->name = NULL;
     227                errno = ENOMEM;
     228                goto fail;
     229        }
     230
     231        if (hash_fn) {
     232                tdb->hash_fn = hash_fn;
     233                hash_alg = "the user defined";
     234        } else {
     235                /* This controls what we use when creating a tdb. */
     236                if (tdb->flags & TDB_INCOMPATIBLE_HASH) {
     237                        tdb->hash_fn = tdb_jenkins_hash;
     238                } else {
     239                        tdb->hash_fn = tdb_old_hash;
     240                }
     241                hash_alg = "either default";
     242        }
    185243
    186244#ifdef __OS2__
     
    189247        }
    190248#endif
    191 
    192249        /* cache the page size */
    193250        tdb->page_size = getpagesize();
     
    204261                goto fail;
    205262        }
    206        
     263
    207264        if (hash_size == 0)
    208265                hash_size = DEFAULT_HASH_SIZE;
     
    223280        }
    224281
     282        if (getenv("TDB_NO_FSYNC")) {
     283                tdb->flags |= TDB_NOSYNC;
     284        }
     285
    225286        /*
    226287         * TDB_ALLOW_NESTING is the default behavior.
     
    253314
    254315        /* ensure there is only one process initialising at once */
    255         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
    256                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
     316        if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
     317                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n",
    257318                         name, strerror(errno)));
    258319                goto fail;      /* errno set by tdb_brlock */
     
    261322        /* we need to zero database if we are the only one with it open */
    262323        if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
    263             (!tdb->read_only)
    264324#ifndef __OS2__
    265             && (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))
    266 #endif
    267             ) {
     325            (!tdb->read_only) &&
     326            (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
     327#else
     328            (!tdb->read_only) ) {
     329#endif
    268330                open_flags |= O_CREAT;
    269331                if (ftruncate(tdb->fd, 0) == -1) {
     
    304366                goto fail;
    305367
    306         if (tdb->header.rwlocks != 0) {
     368        if (tdb->header.rwlocks != 0 &&
     369            tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
    307370                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
     371                goto fail;
     372        }
     373
     374        if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) {
     375                /* older TDB without magic hash references */
     376                tdb->hash_fn = tdb_old_hash;
     377        } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
     378                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
     379                         "%s was not created with %s hash function we are using\n"
     380                         "magic1_hash[0x%08X %s 0x%08X] "
     381                         "magic2_hash[0x%08X %s 0x%08X]\n",
     382                         name, hash_alg,
     383                         tdb->header.magic1_hash,
     384                         (tdb->header.magic1_hash == magic1) ? "==" : "!=",
     385                         magic1,
     386                         tdb->header.magic2_hash,
     387                         (tdb->header.magic2_hash == magic2) ? "==" : "!=",
     388                         magic2));
     389                errno = EINVAL;
    308390                goto fail;
    309391        }
     
    318400        }
    319401
    320         if (!(tdb->name = (char *)strdup(name))) {
    321                 errno = ENOMEM;
    322                 goto fail;
    323         }
    324 
    325402        tdb->map_size = st.st_size;
    326403        tdb->device = st.st_dev;
     
    329406        if (locked) {
    330407#ifndef __OS2__
    331                 if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
     408                if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
    332409                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
    333                                  "failed to take ACTIVE_LOCK on %s: %s\n",
     410                                 "failed to release ACTIVE_LOCK on %s: %s\n",
    334411                                 name, strerror(errno)));
    335412                        goto fail;
    336413                }
    337 
    338414#endif
    339415        }
     
    346422        if (tdb_flags & TDB_CLEAR_IF_FIRST) {
    347423                /* leave this lock in place to indicate it's in use */
    348                 if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)
     424                if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
    349425                        goto fail;
     426                }
    350427        }
    351428#endif
     
    358435#ifdef __OS2__
    359436        // YD internal databases do not get global lock!
    360         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
     437        if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1)
    361438                goto fail;
    362439#endif
     
    381458        /* Internal (memory-only) databases skip all the code above to
    382459         * do with disk files, and resume here by releasing their
    383          * global lock and hooking into the active list. */
     460         * open lock and hooking into the active list. */
    384461#ifndef __OS2__
    385         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
    386                 goto fail;
     462        if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) {
     463                goto fail;
     464        }
    387465#endif
    388466        tdb->next = tdbs;
    389                 tdbs = tdb;
     467        tdbs = tdb;
    390468        return tdb;
    391469
     
    405483                        tdb_munmap(tdb);
    406484        }
    407         SAFE_FREE(tdb->name);
     485        if (tdb->fd != -1)
     486                if (close(tdb->fd) != 0)
     487                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
    408488#ifdef __OS2__
    409489        DosCloseMutexSem( tdb->hGlobalLock);
     
    414494        tdb->hTransactionLock = 0;
    415495#endif
    416         if (tdb->fd != -1)
    417                 if (close(tdb->fd) != 0)
    418                         TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
     496        SAFE_FREE(tdb->lockrecs);
     497        SAFE_FREE(tdb->name);
    419498        SAFE_FREE(tdb);
    420499        errno = save_errno;
     
    427506 */
    428507
    429 void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
     508_PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
    430509{
    431510        tdb->max_dead_records = max_dead;
     
    437516 * @returns -1 for error; 0 for success.
    438517 **/
    439 int tdb_close(struct tdb_context *tdb)
     518_PUBLIC_ int tdb_close(struct tdb_context *tdb)
    440519{
    441520        struct tdb_context **i;
    442521        int ret = 0;
    443522
     523        if (tdb->transaction) {
     524                tdb_transaction_cancel(tdb);
     525        }
    444526        tdb_trace(tdb, "tdb_close");
    445         if (tdb->transaction) {
    446                 _tdb_transaction_cancel(tdb);
    447         }
    448527
    449528        if (tdb->map_ptr) {
     
    457536        // YD internal databases do not have a global lock
    458537        if (!(tdb->flags & TDB_INTERNAL))
    459                 tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLK, 0, 1);
     538        tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false);
    460539#endif
    461540        if (tdb->fd != -1) {
     
    491570
    492571/* register a loging function */
    493 void tdb_set_logging_function(struct tdb_context *tdb,
    494                               const struct tdb_logging_context *log_ctx)
     572_PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb,
     573                                       const struct tdb_logging_context *log_ctx)
    495574{
    496575        tdb->log = *log_ctx;
    497576}
    498577
    499 void *tdb_get_logging_private(struct tdb_context *tdb)
     578_PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb)
    500579{
    501580        return tdb->log.log_private;
     
    526605#endif
    527606
    528         if (tdb->num_locks != 0 || tdb->global_lock.count) {
     607        if (tdb_have_extra_locks(tdb)) {
    529608                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
    530609                goto fail;
     
    561640#endif /* fake pread or pwrite */
    562641
    563         if (active_lock &&
    564             (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) {
     642        /* We may still think we hold the active lock. */
     643        tdb->num_lockrecs = 0;
     644        SAFE_FREE(tdb->lockrecs);
     645
     646        if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
    565647                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
    566648                goto fail;
     
    576658/* reopen a tdb - this can be used after a fork to ensure that we have an independent
    577659   seek pointer from our parent and to re-establish locks */
    578 int tdb_reopen(struct tdb_context *tdb)
     660_PUBLIC_ int tdb_reopen(struct tdb_context *tdb)
    579661{
    580662        return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST);
     
    582664
    583665/* reopen all tdb's */
    584 int tdb_reopen_all(int parent_longlived)
     666_PUBLIC_ int tdb_reopen_all(int parent_longlived)
    585667{
    586668        struct tdb_context *tdb;
     
    623705                // extract path info
    624706                _splitpath( name, drive, dir, fname, ext);
    625                 sprintf( szSem, "\\SEM32\\TDB_GL_%s%s%s%i", dir, fname, ext, global_Sem32Add);
     707                sprintf( szSem, "\\SEM32\\TDB_OL_%s%s%s%i", dir, fname, ext, global_Sem32Add);
    626708                rc = DosCreateMutexSem( szSem, &tdb->hGlobalLock, 0, FALSE);
    627709                if (rc == ERROR_DUPLICATE_NAME)
     
    632714                        return -1;
    633715                }
    634                 TDB_LOG((tdb, TDB_DEBUG_TRACE,"%s pid %d global handle %d\n", caller, getpid(), tdb->hGlobalLock));
     716                TDB_LOG((tdb, TDB_DEBUG_TRACE,"%s pid %d open handle %d\n", caller, getpid(), tdb->hGlobalLock));
    635717
    636718                sprintf( szSem, "\\SEM32\\TDB_AL_%s%s%s%i", dir, fname, ext, global_Sem32Add);
     
    659741}
    660742#endif
    661                
  • trunk/server/lib/tdb/common/tdb.c

    r648 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    2828#include "tdb_private.h"
    2929
    30 TDB_DATA tdb_null;
     30_PUBLIC_ TDB_DATA tdb_null;
    3131
    3232/*
     
    3434  the TDB_SEQNUM flag
    3535*/
    36 void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
     36_PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
    3737{
    3838        tdb_off_t seqnum=0;
    39        
     39
    4040        if (!(tdb->flags & TDB_SEQNUM)) {
    4141                return;
     
    6060        }
    6161
    62         if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) {
     62        if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK,
     63                          TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
    6364                return;
    6465        }
     
    6667        tdb_increment_seqnum_nonblock(tdb);
    6768
    68         tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);
     69        tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false);
    6970}
    7071
     
    8081{
    8182        tdb_off_t rec_ptr;
    82        
     83
    8384        /* read in the hash top */
    8485        if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     
    154155                }
    155156        }
    156          
    157157
    158158        /* must be long enough key, data and tailer */
     
    171171                return tdb_rec_write(tdb, rec_ptr, &rec);
    172172        }
    173  
     173
    174174        return 0;
    175175}
     
    200200}
    201201
    202 TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
     202_PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
    203203{
    204204        TDB_DATA ret = _tdb_fetch(tdb, key);
     
    213213 * should be fast and should not block on other syscalls.
    214214 *
    215  * DONT CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
     215 * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
    216216 *
    217217 * For mmapped tdb's that do not have a transaction open it points the parsing
     
    222222 * This is interesting for all readers of potentially large data structures in
    223223 * the tdb records, ldb indexes being one example.
     224 *
     225 * Return -1 if the record was not found.
    224226 */
    225227
    226 int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
     228_PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
    227229                     int (*parser)(TDB_DATA key, TDB_DATA data,
    228230                                   void *private_data),
     
    238240
    239241        if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
     242                /* record not found */
    240243                tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
    241244                tdb->ecode = TDB_ERR_NOEXIST;
    242                 return 0;
     245                return -1;
    243246        }
    244247        tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
     
    261264{
    262265        struct tdb_record rec;
    263        
     266
    264267        if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
    265268                return 0;
     
    268271}
    269272
    270 int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
     273_PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
    271274{
    272275        uint32_t hash = tdb->hash_fn(&key);
     
    319322        tdb_off_t rec_ptr;
    320323        struct tdb_record rec;
    321        
     324
    322325        /* read in the hash top */
    323326        if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     
    348351                return -1;
    349352        }
    350        
     353
    351354        /* read in the hash top */
    352355        if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     
    427430}
    428431
    429 int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
     432_PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
    430433{
    431434        uint32_t hash = tdb->hash_fn(&key);
     
    444447{
    445448        tdb_off_t rec_ptr;
    446        
     449
    447450        /* read in the hash top */
    448451        if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     
    597600   return 0 on success, -1 on failure
    598601*/
    599 int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
     602_PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
    600603{
    601604        uint32_t hash;
     
    620623
    621624/* Append to an entry. Create if not exist. */
    622 int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
     625_PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
    623626{
    624627        uint32_t hash;
     
    659662        ret = _tdb_store(tdb, key, dbuf, 0, hash);
    660663        tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
    661        
     664
    662665failed:
    663666        tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     
    671674  useful for external logging functions
    672675*/
    673 const char *tdb_name(struct tdb_context *tdb)
     676_PUBLIC_ const char *tdb_name(struct tdb_context *tdb)
    674677{
    675678        return tdb->name;
     
    681684  of the fd
    682685*/
    683 int tdb_fd(struct tdb_context *tdb)
     686_PUBLIC_ int tdb_fd(struct tdb_context *tdb)
    684687{
    685688        return tdb->fd;
     
    690693  useful for external tdb routines that wish to log tdb errors
    691694*/
    692 tdb_log_func tdb_log_fn(struct tdb_context *tdb)
     695_PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb)
    693696{
    694697        return tdb->log.log_fn;
     
    706709  test of a possible tdb change.
    707710*/
    708 int tdb_get_seqnum(struct tdb_context *tdb)
     711_PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb)
    709712{
    710713        tdb_off_t seqnum=0;
     
    714717}
    715718
    716 int tdb_hash_size(struct tdb_context *tdb)
     719_PUBLIC_ int tdb_hash_size(struct tdb_context *tdb)
    717720{
    718721        return tdb->header.hash_size;
    719722}
    720723
    721 size_t tdb_map_size(struct tdb_context *tdb)
     724_PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb)
    722725{
    723726        return tdb->map_size;
    724727}
    725728
    726 int tdb_get_flags(struct tdb_context *tdb)
     729_PUBLIC_ int tdb_get_flags(struct tdb_context *tdb)
    727730{
    728731        return tdb->flags;
    729732}
    730733
    731 void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
     734_PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
    732735{
    733736        if ((flags & TDB_ALLOW_NESTING) &&
     
    749752}
    750753
    751 void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
     754_PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
    752755{
    753756        if ((flags & TDB_ALLOW_NESTING) &&
     
    773776  enable sequence number handling on an open tdb
    774777*/
    775 void tdb_enable_seqnum(struct tdb_context *tdb)
     778_PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb)
    776779{
    777780        tdb->flags |= TDB_SEQNUM;
     
    805808/*
    806809  wipe the entire database, deleting all records. This can be done
    807   very fast by using a global lock. The entire data portion of the
     810  very fast by using a allrecord lock. The entire data portion of the
    808811  file becomes a single entry in the freelist.
    809812
    810813  This code carefully steps around the recovery area, leaving it alone
    811814 */
    812 int tdb_wipe_all(struct tdb_context *tdb)
     815_PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb)
    813816{
    814817        int i;
     
    917920  repack a tdb
    918921 */
    919 int tdb_repack(struct tdb_context *tdb)
     922_PUBLIC_ int tdb_repack(struct tdb_context *tdb)
    920923{
    921924        struct tdb_context *tmp_db;
     
    987990}
    988991
     992/* Even on files, we can get partial writes due to signals. */
     993bool tdb_write_all(int fd, const void *buf, size_t count)
     994{
     995        while (count) {
     996                ssize_t ret;
     997                ret = write(fd, buf, count);
     998                if (ret < 0)
     999                        return false;
     1000                buf = (const char *)buf + ret;
     1001                count -= ret;
     1002        }
     1003        return true;
     1004}
     1005
    9891006#ifdef TDB_TRACE
    9901007static void tdb_trace_write(struct tdb_context *tdb, const char *str)
    9911008{
    992         if (write(tdb->tracefd, str, strlen(str)) != strlen(str)) {
     1009        if (!tdb_write_alltdb->tracefd, str, strlen(str)) {
    9931010                close(tdb->tracefd);
    9941011                tdb->tracefd = -1;
  • trunk/server/lib/tdb/common/tdb_private.h

    r657 r745  
    55
    66   Copyright (C) Andrew Tridgell              2005
    7    
     7
    88     ** NOTE! The following LGPL license applies to the tdb
    99     ** library. This does NOT imply that all of Samba is released
    1010     ** under the LGPL
    11    
     11
    1212   This library is free software; you can redistribute it and/or
    1313   modify it under the terms of the GNU Lesser General Public
     
    2323   License along with this library; if not, see <http://www.gnu.org/licenses/>.
    2424*/
    25 
    2625#ifdef __OS2__
    2726#define INCL_ERRORS
     
    5655#define TDB_DEAD_MAGIC (0xFEE1DEAD)
    5756#define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
     57#define TDB_RECOVERY_INVALID_MAGIC (0x0)
     58#define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U)
    5859#define TDB_ALIGNMENT 4
    5960#define DEFAULT_HASH_SIZE 131
     
    108109
    109110/* lock offsets */
    110 #define GLOBAL_LOCK      0
     111#define OPEN_LOCK        0
    111112#define ACTIVE_LOCK      4
    112113#define TRANSACTION_LOCK 8
     
    153154        tdb_off_t recovery_start; /* offset of transaction recovery region */
    154155        tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
    155         tdb_off_t reserved[29];
     156        uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */
     157        uint32_t magic2_hash; /* hash of TDB_MAGIC. */
     158        tdb_off_t reserved[27];
    156159};
    157160
    158161struct tdb_lock_type {
    159         int list;
     162        uint32_t off;
    160163        uint32_t count;
    161164        uint32_t ltype;
     
    169172};
    170173
     174enum tdb_lock_flags {
     175        /* WAIT == F_SETLKW, NOWAIT == F_SETLK */
     176        TDB_LOCK_NOWAIT = 0,
     177        TDB_LOCK_WAIT = 1,
     178        /* If set, don't log an error on failure. */
     179        TDB_LOCK_PROBE = 2,
     180        /* If set, don't actually lock at all. */
     181        TDB_LOCK_MARK_ONLY = 4,
     182};
    171183
    172184struct tdb_methods {
     
    176188        int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
    177189        int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
    178         int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_t);
    179190};
    180191
     
    187198        int traverse_read; /* read-only traversal */
    188199        int traverse_write; /* read-write traversal */
    189         struct tdb_lock_type global_lock;
     200        struct tdb_lock_type allrecord_lock; /* .offset == upgradable */
    190201        int num_lockrecs;
    191202        struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
     
    200211        unsigned int (*hash_fn)(TDB_DATA *key);
    201212        int open_flags; /* flags used in the open - needed by reopen */
    202         unsigned int num_locks; /* number of chain locks held */
    203213        const struct tdb_methods *methods;
    204214        struct tdb_transaction *transaction;
    205215        int page_size;
    206216        int max_dead_records;
    207         int transaction_lock_count;
    208217#ifdef TDB_TRACE
    209218        int tracefd;
     
    225234int tdb_lock(struct tdb_context *tdb, int list, int ltype);
    226235int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
     236int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
     237                  enum tdb_lock_flags flags);
     238int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
     239                    bool mark_lock);
    227240int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
    228 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len);
    229 int tdb_transaction_lock(struct tdb_context *tdb, int ltype);
    230 int tdb_transaction_unlock(struct tdb_context *tdb);
    231 int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len);
     241int tdb_brlock(struct tdb_context *tdb,
     242               int rw_type, tdb_off_t offset, size_t len,
     243               enum tdb_lock_flags flags);
     244int tdb_brunlock(struct tdb_context *tdb,
     245                 int rw_type, tdb_off_t offset, size_t len);
     246bool tdb_have_extra_locks(struct tdb_context *tdb);
     247void tdb_release_transaction_locks(struct tdb_context *tdb);
     248int tdb_transaction_lock(struct tdb_context *tdb, int ltype,
     249                         enum tdb_lock_flags lockflags);
     250int tdb_transaction_unlock(struct tdb_context *tdb, int ltype);
     251int tdb_recovery_area(struct tdb_context *tdb,
     252                      const struct tdb_methods *methods,
     253                      tdb_off_t *recovery_offset,
     254                      struct tdb_record *rec);
     255int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
     256                       enum tdb_lock_flags flags, bool upgradable);
     257int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock);
     258int tdb_allrecord_upgrade(struct tdb_context *tdb);
    232259int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off);
    233260int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off);
     
    241268int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off);
    242269int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off);
    243 int _tdb_transaction_cancel(struct tdb_context *tdb);
     270bool tdb_needs_recovery(struct tdb_context *tdb);
    244271int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
    245272int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
     
    257284int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
    258285                      struct tdb_record *rec);
    259 
    260 
     286bool tdb_write_all(int fd, const void *buf, size_t count);
     287int tdb_transaction_recover(struct tdb_context *tdb);
     288void tdb_header_hash(struct tdb_context *tdb,
     289                     uint32_t *magic1_hash, uint32_t *magic2_hash);
     290unsigned int tdb_old_hash(TDB_DATA *key);
     291size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off);
  • trunk/server/lib/tdb/common/transaction.c

    r657 r745  
    99     ** library. This does NOT imply that all of Samba is released
    1010     ** under the LGPL
    11    
     11
    1212   This library is free software; you can redistribute it and/or
    1313   modify it under the terms of the GNU Lesser General Public
     
    6060    existing transaction record. If the inner transaction is cancelled
    6161    then a subsequent commit will fail
    62  
     62
    6363  - keep a mirrored copy of the tdb hash chain heads to allow for the
    6464    fast hash heads scan on traverse, updating the mirrored copy in
     
    7777
    7878  - check for a valid recovery record on open of the tdb, while the
    79     global lock is held. Automatically recover from the transaction
     79    open lock is held. Automatically recover from the transaction
    8080    recovery area if needed, then continue with the open as
    8181    usual. This allows for smooth crash recovery with no administrator
     
    136136        tdb_off_t magic_offset;
    137137
    138         /* set when the GLOBAL_LOCK has been taken */
    139         bool global_lock_taken;
    140 
    141138        /* old file size before transaction */
    142139        tdb_len_t old_map_size;
    143140
    144         /* we should re-pack on commit */
    145         bool need_repack;
     141        /* did we expand in this transaction */
     142        bool expanded;
    146143};
    147144
     
    189186                }
    190187        }
    191        
     188
    192189        /* now copy it out of this block */
    193190        memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len);
     
    296293                }
    297294        }
    298        
     295
    299296        /* overwrite part of an existing block */
    300297        if (buf == NULL) {
     
    407404        }
    408405
    409         tdb->transaction->need_repack = true;
    410 
    411         return 0;
    412 }
    413 
    414 /*
    415   brlock during a transaction - ignore them
    416 */
    417 static int transaction_brlock(struct tdb_context *tdb, tdb_off_t offset,
    418                               int rw_type, int lck_type, int probe, size_t len)
    419 {
     406        tdb->transaction->expanded = true;
     407
    420408        return 0;
    421409}
     
    427415        transaction_oob,
    428416        transaction_expand_file,
    429         transaction_brlock
    430417};
    431418
     
    435422  transaction is allowed to be pending per tdb_context
    436423*/
    437 int tdb_transaction_start(struct tdb_context *tdb)
     424static int _tdb_transaction_start(struct tdb_context *tdb,
     425                                  enum tdb_lock_flags lockflags)
    438426{
    439427        /* some sanity checks */
     
    456444        }
    457445
    458         if (tdb->num_locks != 0 || tdb->global_lock.count) {
     446        if (tdb_have_extra_locks(tdb)) {
    459447                /* the caller must not have any locks when starting a
    460448                   transaction as otherwise we'll be screwed by lack
     
    487475           discussed with Volker, there are a number of ways we could
    488476           make this async, which we will probably do in the future */
    489         if (tdb_transaction_lock(tdb, F_WRLCK) == -1) {
     477        if (tdb_transaction_lock(tdb, F_WRLCK, lockflags) == -1) {
    490478                SAFE_FREE(tdb->transaction->blocks);
    491479                SAFE_FREE(tdb->transaction);
    492                 return -1;
    493         }
    494        
     480                if ((lockflags & TDB_LOCK_WAIT) == 0) {
     481                        tdb->ecode = TDB_ERR_NOLOCK;
     482                }
     483                return -1;
     484        }
     485
    495486        /* get a read lock from the freelist to the end of file. This
    496487           is upgraded to a write lock during the commit */
    497488#ifndef __OS2__ // YD the transation lock is an exclusive lock for us, it is enough.
    498         if (tdb_brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {
     489        if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, true) == -1) {
    499490                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n"));
    500                 tdb->ecode = TDB_ERR_LOCK;
    501                 goto fail;
     491                goto fail_allrecord_lock;
    502492        }
    503493#endif
     
    531521        tdb_trace(tdb, "tdb_transaction_start");
    532522        return 0;
    533        
     523
    534524fail:
    535525#ifndef __OS2__ // YD the transation lock is an exclusive lock for us, it is enough.
    536         tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
     526        tdb_allrecord_unlock(tdb, F_RDLCK, false);
    537527#endif
    538         tdb_transaction_unlock(tdb);
     528fail_allrecord_lock:
     529        tdb_transaction_unlock(tdb, F_WRLCK);
    539530        SAFE_FREE(tdb->transaction->blocks);
    540531        SAFE_FREE(tdb->transaction->hash_heads);
     
    543534}
    544535
     536_PUBLIC_ int tdb_transaction_start(struct tdb_context *tdb)
     537{
     538        return _tdb_transaction_start(tdb, TDB_LOCK_WAIT);
     539}
     540
     541_PUBLIC_ int tdb_transaction_start_nonblock(struct tdb_context *tdb)
     542{
     543        return _tdb_transaction_start(tdb, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
     544}
    545545
    546546/*
     
    553553        }
    554554
     555#ifdef HAVE_FDATASYNC
     556        if (fdatasync(tdb->fd) != 0) {
     557#else
    555558        if (fsync(tdb->fd) != 0) {
     559#endif
    556560                tdb->ecode = TDB_ERR_IO;
    557561                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
     
    574578
    575579
    576 int _tdb_transaction_cancel(struct tdb_context *tdb)
     580static int _tdb_transaction_cancel(struct tdb_context *tdb)
    577581{       
    578582        int i, ret = 0;
     
    601605        if (tdb->transaction->magic_offset) {
    602606                const struct tdb_methods *methods = tdb->transaction->io_methods;
    603                 uint32_t zero = 0;
     607                const uint32_t invalid = TDB_RECOVERY_INVALID_MAGIC;
    604608
    605609                /* remove the recovery marker */
    606                 if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &zero, 4) == -1 ||
     610                if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &invalid, 4) == -1 ||
    607611                transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) {
    608612                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n"));
     
    611615        }
    612616
    613         if (tdb->transaction->global_lock_taken) {
    614                 tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
    615                 tdb->transaction->global_lock_taken = false;
    616         }
    617 
    618         /* remove any global lock created during the transaction */
    619         if (tdb->global_lock.count != 0) {
    620                 tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size);
    621                 tdb->global_lock.count = 0;
    622         }
    623 
    624         /* remove any locks created during the transaction */
    625         if (tdb->num_locks != 0) {
    626                 for (i=0;i<tdb->num_lockrecs;i++) {
    627                         tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list,
    628                                    F_UNLCK,F_SETLKW, 0, 1);
    629                 }
    630                 tdb->num_locks = 0;
    631                 tdb->num_lockrecs = 0;
    632                 SAFE_FREE(tdb->lockrecs);
    633         }
     617        /* This also removes the OPEN_LOCK, if we have it. */
     618        tdb_release_transaction_locks(tdb);
    634619
    635620        /* restore the normal io methods */
    636621        tdb->methods = tdb->transaction->io_methods;
    637622
    638 #ifndef __OS2__ // YD the transation lock is an exclusive lock for us, it is enough
    639         tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);
    640 #endif
    641         tdb_transaction_unlock(tdb);
    642623        SAFE_FREE(tdb->transaction->hash_heads);
    643624        SAFE_FREE(tdb->transaction);
    644        
     625
    645626        return ret;
    646627}
     
    649630  cancel the current transaction
    650631*/
    651 int tdb_transaction_cancel(struct tdb_context *tdb)
     632_PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb)
    652633{
    653634        tdb_trace(tdb, "tdb_transaction_cancel");
     
    682663}
    683664
     665int tdb_recovery_area(struct tdb_context *tdb,
     666                      const struct tdb_methods *methods,
     667                      tdb_off_t *recovery_offset,
     668                      struct tdb_record *rec)
     669{
     670        if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, recovery_offset) == -1) {
     671                return -1;
     672        }
     673
     674        if (*recovery_offset == 0) {
     675                rec->rec_len = 0;
     676                return 0;
     677        }
     678
     679        if (methods->tdb_read(tdb, *recovery_offset, rec, sizeof(*rec),
     680                              DOCONV()) == -1) {
     681                return -1;
     682        }
     683
     684        /* ignore invalid recovery regions: can happen in crash */
     685        if (rec->magic != TDB_RECOVERY_MAGIC &&
     686            rec->magic != TDB_RECOVERY_INVALID_MAGIC) {
     687                *recovery_offset = 0;
     688                rec->rec_len = 0;
     689        }
     690        return 0;
     691}
     692
    684693/*
    685694  allocate the recovery area, or use an existing recovery area if it is
     
    695704        tdb_off_t recovery_head;
    696705
    697         if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
     706        if (tdb_recovery_area(tdb, methods, &recovery_head, &rec) == -1) {
    698707                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n"));
    699                 return -1;
    700         }
    701 
    702         rec.rec_len = 0;
    703 
    704         if (recovery_head != 0 &&
    705             methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
    706                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));
    707708                return -1;
    708709        }
     
    800801        memset(rec, 0, sizeof(*rec));
    801802
    802         rec->magic    = 0;
     803        rec->magic    = TDB_RECOVERY_INVALID_MAGIC;
    803804        rec->data_len = recovery_size;
    804805        rec->rec_len  = recovery_max_size;
    805806        rec->key_len  = old_map_size;
    806         CONVERT(rec);
     807        CONVERT(*rec);
    807808
    808809        /* build the recovery data into a single blob to allow us to do a single
     
    822823                        length = tdb->transaction->last_block_size;
    823824                }
    824                
     825
    825826                if (offset >= old_map_size) {
    826827                        continue;
     
    851852        tailer = sizeof(*rec) + recovery_max_size;
    852853        memcpy(p, &tailer, 4);
    853         CONVERT(p);
     854        if (DOCONV()) {
     855                tdb_convert(p, 4);
     856        }
    854857
    855858        /* write the recovery data to the recovery area */
     
    935938
    936939        methods = tdb->transaction->io_methods;
    937        
     940
    938941        /* if there are any locks pending then the caller has not
    939942           nested their locks properly, so fail the transaction */
    940         if (tdb->num_locks || tdb->global_lock.count) {
     943        if (tdb_have_extra_locks(tdb)) {
    941944                tdb->ecode = TDB_ERR_LOCK;
    942945                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n"));
     
    947950        /* upgrade the main transaction lock region to a write lock */
    948951#ifndef __OS2__ // YD the global lock is an exclusive lock for us, it is enough
    949         if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {
     952        if (tdb_allrecord_upgrade(tdb) == -1) {
    950953                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n"));
    951                 tdb->ecode = TDB_ERR_LOCK;
    952954                _tdb_transaction_cancel(tdb);
    953955                return -1;
     
    955957#endif
    956958
    957         /* get the global lock - this prevents new users attaching to the database
     959        /* get the open lock - this prevents new users attaching to the database
    958960           during the commit */
    959         if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
    960                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n"));
    961                 tdb->ecode = TDB_ERR_LOCK;
     961        if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
     962                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get open lock\n"));
    962963                _tdb_transaction_cancel(tdb);
    963964                return -1;
    964965        }
    965 
    966         tdb->transaction->global_lock_taken = true;
    967966
    968967        if (!(tdb->flags & TDB_NOSYNC)) {
     
    991990        }
    992991
    993         /* Keep the global lock until the actual commit */
     992        /* Keep the open lock until the actual commit */
    994993
    995994        return 0;
     
    999998   prepare to commit the current transaction
    1000999*/
    1001 int tdb_transaction_prepare_commit(struct tdb_context *tdb)
    1002 {       
     1000_PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb)
     1001{
    10031002        tdb_trace(tdb, "tdb_transaction_prepare_commit");
    10041003        return _tdb_transaction_prepare_commit(tdb);
    10051004}
    10061005
     1006/* A repack is worthwhile if the largest is less than half total free. */
     1007static bool repack_worthwhile(struct tdb_context *tdb)
     1008{
     1009        tdb_off_t ptr;
     1010        struct tdb_record rec;
     1011        tdb_len_t total = 0, largest = 0;
     1012
     1013        if (tdb_ofs_read(tdb, FREELIST_TOP, &ptr) == -1) {
     1014                return false;
     1015        }
     1016
     1017        while (ptr != 0 && tdb_rec_free_read(tdb, ptr, &rec) == 0) {
     1018                total += rec.rec_len;
     1019                if (rec.rec_len > largest) {
     1020                        largest = rec.rec_len;
     1021                }
     1022                ptr = rec.next;
     1023        }
     1024
     1025        return total > largest * 2;
     1026}
     1027
    10071028/*
    10081029  commit the current transaction
    10091030*/
    1010 int tdb_transaction_commit(struct tdb_context *tdb)
    1011 {       
     1031_PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb)
     1032{
    10121033        const struct tdb_methods *methods;
    10131034        int i;
    1014         bool need_repack;
     1035        bool need_repack = false;
    10151036
    10161037        if (tdb->transaction == NULL) {
     
    10201041
    10211042        tdb_trace(tdb, "tdb_transaction_commit");
     1043
    10221044        if (tdb->transaction->transaction_error) {
    10231045                tdb->ecode = TDB_ERR_IO;
     
    10261048                return -1;
    10271049        }
     1050
    10281051
    10291052        if (tdb->transaction->nesting != 0) {
     
    10601083                        length = tdb->transaction->last_block_size;
    10611084                }
     1085
    10621086                if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) {
    10631087                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n"));
    1064                        
     1088
    10651089                        /* we've overwritten part of the data and
    10661090                           possibly expanded the file, so we need to
     
    10761100                SAFE_FREE(tdb->transaction->blocks[i]);
    10771101        }
     1102
     1103        /* Do this before we drop lock or blocks. */
     1104        if (tdb->transaction->expanded) {
     1105                need_repack = repack_worthwhile(tdb);
     1106        }
    10781107
    10791108        SAFE_FREE(tdb->transaction->blocks);
     
    11001129#endif
    11011130
    1102         need_repack = tdb->transaction->need_repack;
    1103 
    11041131        /* use a transaction cancel to free memory and remove the
    11051132           transaction locks */
     
    11161143/*
    11171144  recover from an aborted transaction. Must be called with exclusive
    1118   database write access already established (including the global
     1145  database write access already established (including the open
    11191146  lock to prevent new processes attaching)
    11201147*/
     
    12171244                return -1;                     
    12181245        }
    1219        
    1220         /* reduce the file size to the old size */
    1221         tdb_munmap(tdb);
    1222         if (ftruncate(tdb->fd, recovery_eof) != 0) {
    1223                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n"));
    1224                 tdb->ecode = TDB_ERR_IO;
    1225                 return -1;                     
    1226         }
    1227         tdb->map_size = recovery_eof;
    1228         tdb_mmap(tdb);
    12291246
    12301247        if (transaction_sync(tdb, 0, recovery_eof) == -1) {
     
    12401257        return 0;
    12411258}
     1259
     1260/* Any I/O failures we say "needs recovery". */
     1261bool tdb_needs_recovery(struct tdb_context *tdb)
     1262{
     1263        tdb_off_t recovery_head;
     1264        struct tdb_record rec;
     1265
     1266        /* find the recovery area */
     1267        if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
     1268                return true;
     1269        }
     1270
     1271        if (recovery_head == 0) {
     1272                /* we have never allocated a recovery record */
     1273                return false;
     1274        }
     1275
     1276        /* read the recovery record */
     1277        if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
     1278                                   sizeof(rec), DOCONV()) == -1) {
     1279                return true;
     1280        }
     1281
     1282        return (rec.magic == TDB_RECOVERY_MAGIC);
     1283}
  • trunk/server/lib/tdb/common/traverse.c

    r647 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    4545                           hashes are used. In that case we spend most of our
    4646                           time in tdb_brlock(), locking empty hash chains.
    47                            
     47
    4848                           To avoid this, we do an unlocked pre-check to see
    4949                           if the hash chain is empty before starting to look
     
    5353                           lock, so instead we get the lock and re-fetch the
    5454                           value below.
    55                            
     55
    5656                           Notice that not doing this optimisation on the
    5757                           first hash chain is critical. We must guarantee
     
    6363                           could miss them anyway without this trick, so the
    6464                           semantics don't change.
    65                            
     65
    6666                           With a non-indexed ldb search this trick gains us a
    6767                           factor of around 80 in speed on a linux 2.6.x
     
    213213  a write style traverse - temporarily marks the db read only
    214214*/
    215 int tdb_traverse_read(struct tdb_context *tdb,
     215_PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb,
    216216                      tdb_traverse_func fn, void *private_data)
    217217{
    218 
    219218        struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK };
    220219        int ret;
     
    222221        /* we need to get a read lock on the transaction lock here to
    223222           cope with the lock ordering semantics of solaris10 */
    224         if (tdb_transaction_lock(tdb, F_RDLCK)) {
     223        if (tdb_transaction_lock(tdb, F_RDLCK, TDB_LOCK_WAIT)) {
    225224                return -1;
    226225        }
     
    231230        tdb->traverse_read--;
    232231
    233         tdb_transaction_unlock(tdb);
     232        tdb_transaction_unlock(tdb, F_RDLCK);
    234233
    235234        return ret;
     
    243242  alignment restrictions malloc gives you.
    244243*/
    245 int tdb_traverse(struct tdb_context *tdb,
     244_PUBLIC_ int tdb_traverse(struct tdb_context *tdb,
    246245                 tdb_traverse_func fn, void *private_data)
    247246{
     
    253252        }
    254253
    255         if (tdb_transaction_lock(tdb, F_WRLCK)) {
     254        if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) {
    256255                return -1;
    257256        }
     
    262261        tdb->traverse_write--;
    263262
    264         tdb_transaction_unlock(tdb);
     263        tdb_transaction_unlock(tdb, F_WRLCK);
    265264
    266265        return ret;
     
    269268
    270269/* find the first entry in the database and return its key */
    271 TDB_DATA tdb_firstkey(struct tdb_context *tdb)
     270_PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb)
    272271{
    273272        TDB_DATA key;
     
    300299
    301300/* find the next entry in the database, returning its key */
    302 TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
     301_PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
    303302{
    304303        uint32_t oldhash;
  • trunk/server/lib/tdb/docs/README

    r414 r745  
    106106
    107107----------------------------------------------------------------------
     108int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
     109                     int (*parser)(TDB_DATA key, TDB_DATA data,
     110                                   void *private_data),
     111                     void *private_data);
     112
     113   Hand a record to a parser function without allocating it.
     114
     115   This function is meant as a fast tdb_fetch alternative for large records
     116   that are frequently read. The "key" and "data" arguments point directly
     117   into the tdb shared memory, they are not aligned at any boundary.
     118
     119   WARNING: The parser is called while tdb holds a lock on the record. DO NOT
     120   call other tdb routines from within the parser. Also, for good performance
     121   you should make the parser fast to allow parallel operations.
     122
     123   tdb_parse_record returns -1 if the record was not found.  If the record was
     124   found, the return value of "parser" is passed up to the caller.
     125
     126----------------------------------------------------------------------
    108127int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
    109128
  • trunk/server/lib/tdb/include/tdb.h

    r414 r745  
    3131#endif
    3232
    33 #include "signal.h"
    34 
    35 /* flags to tdb_store() */
    36 #define TDB_REPLACE 1           /* Unused */
    37 #define TDB_INSERT 2            /* Don't overwrite an existing entry */
    38 #define TDB_MODIFY 3            /* Don't create an existing entry    */
    39 
    40 /* flags for tdb_open() */
    41 #define TDB_DEFAULT 0 /* just a readability place holder */
    42 #define TDB_CLEAR_IF_FIRST 1
    43 #define TDB_INTERNAL 2 /* don't store on disk */
    44 #define TDB_NOLOCK   4 /* don't do any locking */
    45 #define TDB_NOMMAP   8 /* don't use mmap */
    46 #define TDB_CONVERT 16 /* convert endian (internal use) */
    47 #define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
    48 #define TDB_NOSYNC   64 /* don't use synchronous transactions */
    49 #define TDB_SEQNUM   128 /* maintain a sequence number */
    50 #define TDB_VOLATILE   256 /* Activate the per-hashchain freelist, default 5 */
    51 #define TDB_ALLOW_NESTING 512 /* Allow transactions to nest */
    52 #define TDB_DISALLOW_NESTING 1024 /* Disallow transactions to nest */
    53 
    54 /* error codes */
     33#include <signal.h>
     34
     35/**
     36 * @defgroup tdb The tdb API
     37 *
     38 * tdb is a Trivial database. In concept, it is very much like GDBM, and BSD's
     39 * DB except that it allows multiple simultaneous writers and uses locking
     40 * internally to keep writers from trampling on each other. tdb is also
     41 * extremely small.
     42 *
     43 * @section tdb_interface Interface
     44 *
     45 * The interface is very similar to gdbm except for the following:
     46 *
     47 * <ul>
     48 * <li>different open interface. The tdb_open call is more similar to a
     49 * traditional open()</li>
     50 * <li>no tdbm_reorganise() function</li>
     51 * <li>no tdbm_sync() function. No operations are cached in the library
     52 *     anyway</li>
     53 * <li>added a tdb_traverse() function for traversing the whole database</li>
     54 * <li>added transactions support</li>
     55 * </ul>
     56 *
     57 * A general rule for using tdb is that the caller frees any returned TDB_DATA
     58 * structures. Just call free(p.dptr) to free a TDB_DATA return value called p.
     59 * This is the same as gdbm.
     60 *
     61 * @{
     62 */
     63
     64/** Flags to tdb_store() */
     65#define TDB_REPLACE 1           /** Unused */
     66#define TDB_INSERT 2            /** Don't overwrite an existing entry */
     67#define TDB_MODIFY 3            /** Don't create an existing entry    */
     68
     69/** Flags for tdb_open() */
     70#define TDB_DEFAULT 0 /** just a readability place holder */
     71#define TDB_CLEAR_IF_FIRST 1 /** If this is the first open, wipe the db */
     72#define TDB_INTERNAL 2 /** Don't store on disk */
     73#define TDB_NOLOCK   4 /** Don't do any locking */
     74#define TDB_NOMMAP   8 /** Don't use mmap */
     75#define TDB_CONVERT 16 /** Convert endian (internal use) */
     76#define TDB_BIGENDIAN 32 /** Header is big-endian (internal use) */
     77#define TDB_NOSYNC   64 /** Don't use synchronous transactions */
     78#define TDB_SEQNUM   128 /** Maintain a sequence number */
     79#define TDB_VOLATILE   256 /** Activate the per-hashchain freelist, default 5 */
     80#define TDB_ALLOW_NESTING 512 /** Allow transactions to nest */
     81#define TDB_DISALLOW_NESTING 1024 /** Disallow transactions to nest */
     82#define TDB_INCOMPATIBLE_HASH 2048 /** Better hashing: can't be opened by tdb < 1.2.6. */
     83
     84/** The tdb error codes */
    5585enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
    5686                TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
     
    5888                TDB_ERR_NESTING};
    5989
    60 /* debugging uses one of the following levels */
     90/** Debugging uses one of the following levels */
    6191enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR,
    6292                      TDB_DEBUG_WARNING, TDB_DEBUG_TRACE};
    6393
     94/** The tdb data structure */
    6495typedef struct TDB_DATA {
    6596        unsigned char *dptr;
     
    79110#endif
    80111
    81 /* this is the context structure that is returned from a db open */
     112/** This is the context structure that is returned from a db open. */
    82113typedef struct tdb_context TDB_CONTEXT;
    83114
     
    91122};
    92123
     124/**
     125 * @brief Open the database and creating it if necessary.
     126 *
     127 * @param[in]  name     The name of the db to open.
     128 *
     129 * @param[in]  hash_size The hash size is advisory, use zero for a default
     130 *                       value.
     131 *
     132 * @param[in]  tdb_flags The flags to use to open the db:\n\n
     133 *                         TDB_CLEAR_IF_FIRST - Clear database if we are the
     134 *                                              only one with it open\n
     135 *                         TDB_INTERNAL - Don't use a file, instaed store the
     136 *                                        data in memory. The filename is
     137 *                                        ignored in this case.\n
     138 *                         TDB_NOLOCK - Don't do any locking\n
     139 *                         TDB_NOMMAP - Don't use mmap\n
     140 *                         TDB_NOSYNC - Don't synchronise transactions to disk\n
     141 *                         TDB_SEQNUM - Maintain a sequence number\n
     142 *                         TDB_VOLATILE - activate the per-hashchain freelist,
     143 *                                        default 5.\n
     144 *                         TDB_ALLOW_NESTING - Allow transactions to nest.\n
     145 *                         TDB_DISALLOW_NESTING - Disallow transactions to nest.\n
     146 *
     147 * @param[in]  open_flags Flags for the open(2) function.
     148 *
     149 * @param[in]  mode     The mode for the open(2) function.
     150 *
     151 * @return              A tdb context structure, NULL on error.
     152 */
    93153struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
    94154                      int open_flags, mode_t mode);
     155
     156/**
     157 * @brief Open the database and creating it if necessary.
     158 *
     159 * This is like tdb_open(), but allows you to pass an initial logging and
     160 * hash function. Be careful when passing a hash function - all users of the
     161 * database must use the same hash function or you will get data corruption.
     162 *
     163 * @param[in]  name     The name of the db to open.
     164 *
     165 * @param[in]  hash_size The hash size is advisory, use zero for a default
     166 *                       value.
     167 *
     168 * @param[in]  tdb_flags The flags to use to open the db:\n\n
     169 *                         TDB_CLEAR_IF_FIRST - Clear database if we are the
     170 *                                              only one with it open\n
     171 *                         TDB_INTERNAL - Don't use a file, instaed store the
     172 *                                        data in memory. The filename is
     173 *                                        ignored in this case.\n
     174 *                         TDB_NOLOCK - Don't do any locking\n
     175 *                         TDB_NOMMAP - Don't use mmap\n
     176 *                         TDB_NOSYNC - Don't synchronise transactions to disk\n
     177 *                         TDB_SEQNUM - Maintain a sequence number\n
     178 *                         TDB_VOLATILE - activate the per-hashchain freelist,
     179 *                                        default 5.\n
     180 *                         TDB_ALLOW_NESTING - Allow transactions to nest.\n
     181 *                         TDB_DISALLOW_NESTING - Disallow transactions to nest.\n
     182 *
     183 * @param[in]  open_flags Flags for the open(2) function.
     184 *
     185 * @param[in]  mode     The mode for the open(2) function.
     186 *
     187 * @param[in]  log_ctx  The logging function to use.
     188 *
     189 * @param[in]  hash_fn  The hash function you want to use.
     190 *
     191 * @return              A tdb context structure, NULL on error.
     192 *
     193 * @see tdb_open()
     194 */
    95195struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
    96196                         int open_flags, mode_t mode,
    97197                         const struct tdb_logging_context *log_ctx,
    98198                         tdb_hash_func hash_fn);
     199
     200/**
     201 * @brief Set the maximum number of dead records per hash chain.
     202 *
     203 * @param[in]  tdb      The database handle to set the maximum.
     204 *
     205 * @param[in]  max_dead The maximum number of dead records per hash chain.
     206 */
    99207void tdb_set_max_dead(struct tdb_context *tdb, int max_dead);
    100208
     209/**
     210 * @brief Reopen a tdb.
     211 *
     212 * This can be used after a fork to ensure that we have an independent seek
     213 * pointer from our parent and to re-establish locks.
     214 *
     215 * @param[in]  tdb      The database to reopen.
     216 *
     217 * @return              0 on success, -1 on error.
     218 */
    101219int tdb_reopen(struct tdb_context *tdb);
     220
     221/**
     222 * @brief Reopen all tdb's
     223 *
     224 * If the parent is longlived (ie. a parent daemon architecture), we know it
     225 * will keep it's active lock on a tdb opened with CLEAR_IF_FIRST. Thus for
     226 * child processes we don't have to add an active lock. This is essential to
     227 * improve performance on systems that keep POSIX locks as a non-scalable data
     228 * structure in the kernel.
     229 *
     230 * @param[in]  parent_longlived Wether the parent is longlived or not.
     231 *
     232 * @return              0 on success, -1 on error.
     233 */
    102234int tdb_reopen_all(int parent_longlived);
     235
     236/**
     237 * @brief Set a different tdb logging function.
     238 *
     239 * @param[in]  tdb      The tdb to set the logging function.
     240 *
     241 * @param[in]  log_ctx  The logging function to set.
     242 */
    103243void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx);
     244
     245/**
     246 * @brief Get the tdb last error code.
     247 *
     248 * @param[in]  tdb      The tdb to get the error code from.
     249 *
     250 * @return              A TDB_ERROR code.
     251 *
     252 * @see TDB_ERROR
     253 */
    104254enum TDB_ERROR tdb_error(struct tdb_context *tdb);
     255
     256/**
     257 * @brief Get a error string for the last tdb error
     258 *
     259 * @param[in]  tdb      The tdb to get the error code from.
     260 *
     261 * @return              An error string.
     262 */
    105263const char *tdb_errorstr(struct tdb_context *tdb);
     264
     265/**
     266 * @brief Fetch an entry in the database given a key.
     267 *
     268 * The caller must free the resulting data.
     269 *
     270 * @param[in]  tdb      The tdb to fetch the key.
     271 *
     272 * @param[in]  key      The key to fetch.
     273 *
     274 * @return              The key entry found in the database, NULL on error with
     275 *                      TDB_ERROR set.
     276 *
     277 * @see tdb_error()
     278 * @see tdb_errorstr()
     279 */
    106280TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
     281
     282/**
     283 * @brief Hand a record to a parser function without allocating it.
     284 *
     285 * This function is meant as a fast tdb_fetch alternative for large records
     286 * that are frequently read. The "key" and "data" arguments point directly
     287 * into the tdb shared memory, they are not aligned at any boundary.
     288 *
     289 * @warning The parser is called while tdb holds a lock on the record. DO NOT
     290 * call other tdb routines from within the parser. Also, for good performance
     291 * you should make the parser fast to allow parallel operations.
     292 *
     293 * @param[in]  tdb      The tdb to parse the record.
     294 *
     295 * @param[in]  key      The key to parse.
     296 *
     297 * @param[in]  parser   The parser to use to parse the data.
     298 *
     299 * @param[in]  private_data A private data pointer which is passed to the parser
     300 *                          function.
     301 *
     302 * @return              -1 if the record was not found. If the record was found,
     303 *                      the return value of "parser" is passed up to the caller.
     304 */
    107305int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
    108                      int (*parser)(TDB_DATA key, TDB_DATA data,
    109                                    void *private_data),
    110                      void *private_data);
     306                              int (*parser)(TDB_DATA key, TDB_DATA data,
     307                                            void *private_data),
     308                              void *private_data);
     309
     310/**
     311 * @brief Delete an entry in the database given a key.
     312 *
     313 * @param[in]  tdb      The tdb to delete the key.
     314 *
     315 * @param[in]  key      The key to delete.
     316 *
     317 * @return              0 on success, -1 if the key doesn't exist.
     318 */
    111319int tdb_delete(struct tdb_context *tdb, TDB_DATA key);
     320
     321/**
     322 * @brief Store an element in the database.
     323 *
     324 * This replaces any existing element with the same key.
     325 *
     326 * @param[in]  tdb      The tdb to store the entry.
     327 *
     328 * @param[in]  key      The key to use to store the entry.
     329 *
     330 * @param[in]  dbuf     The data to store under the key.
     331 *
     332 * @param[in]  flag     The flags to store the key:\n\n
     333 *                      TDB_INSERT: Don't overwrite an existing entry.\n
     334 *                      TDB_MODIFY: Don't create a new entry\n
     335 *
     336 * @return              0 on success, -1 on error with error code set.
     337 *
     338 * @see tdb_error()
     339 * @see tdb_errorstr()
     340 */
    112341int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
     342
     343/**
     344 * @brief Append data to an entry.
     345 *
     346 * If the entry doesn't exist, it will create a new one.
     347 *
     348 * @param[in]  tdb      The database to use.
     349 *
     350 * @param[in]  key      The key to append the data.
     351 *
     352 * @param[in]  new_dbuf The data to append to the key.
     353 *
     354 * @return              0 on success, -1 on error with error code set.
     355 *
     356 * @see tdb_error()
     357 * @see tdb_errorstr()
     358 */
    113359int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf);
     360
     361/**
     362 * @brief Close a database.
     363 *
     364 * @param[in]  tdb      The database to close.
     365 *
     366 * @return              0 for success, -1 on error.
     367 */
    114368int tdb_close(struct tdb_context *tdb);
     369
     370/**
     371 * @brief Find the first entry in the database and return its key.
     372 *
     373 * The caller must free the returned data.
     374 *
     375 * @param[in]  tdb      The database to use.
     376 *
     377 * @return              The first entry of the database, an empty TDB_DATA entry
     378 *                      if the database is empty.
     379 */
    115380TDB_DATA tdb_firstkey(struct tdb_context *tdb);
     381
     382/**
     383 * @brief Find the next entry in the database, returning its key.
     384 *
     385 * The caller must free the returned data.
     386 *
     387 * @param[in]  tdb      The database to use.
     388 *
     389 * @param[in]  key      The key from which you want the next key.
     390 *
     391 * @return              The next entry of the current key, an empty TDB_DATA
     392 *                      entry if there is no entry.
     393 */
    116394TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key);
    117 int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *);
    118 int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *);
     395
     396/**
     397 * @brief Traverse the entire database.
     398 *
     399 * While travering the function fn(tdb, key, data, state) is called on each
     400 * element. If fn is NULL then it is not called. A non-zero return value from
     401 * fn() indicates that the traversal should stop. Traversal callbacks may not
     402 * start transactions.
     403 *
     404 * @warning The data buffer given to the callback fn does NOT meet the alignment
     405 * restrictions malloc gives you.
     406 *
     407 * @param[in]  tdb      The database to traverse.
     408 *
     409 * @param[in]  fn       The function to call on each entry.
     410 *
     411 * @param[in]  private_data The private data which should be passed to the
     412 *                          traversing function.
     413 *
     414 * @return              The record count traversed, -1 on error.
     415 */
     416int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *private_data);
     417
     418/**
     419 * @brief Traverse the entire database.
     420 *
     421 * While traversing the database the function fn(tdb, key, data, state) is
     422 * called on each element, but marking the database read only during the
     423 * traversal, so any write operations will fail. This allows tdb to use read
     424 * locks, which increases the parallelism possible during the traversal.
     425 *
     426 * @param[in]  tdb      The database to traverse.
     427 *
     428 * @param[in]  fn       The function to call on each entry.
     429 *
     430 * @param[in]  private_data The private data which should be passed to the
     431 *                          traversing function.
     432 *
     433 * @return              The record count traversed, -1 on error.
     434 */
     435int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *private_data);
     436
     437/**
     438 * @brief Check if an entry in the database exists.
     439 *
     440 * @note 1 is returned if the key is found and 0 is returned if not found this
     441 * doesn't match the conventions in the rest of this module, but is compatible
     442 * with gdbm.
     443 *
     444 * @param[in]  tdb      The database to check if the entry exists.
     445 *
     446 * @param[in]  key      The key to check if the entry exists.
     447 *
     448 * @return              1 if the key is found, 0 if not.
     449 */
    119450int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
     451
     452/**
     453 * @brief Lock entire database with a write lock.
     454 *
     455 * @param[in]  tdb      The database to lock.
     456 *
     457 * @return              0 on success, -1 on error with error code set.
     458 *
     459 * @see tdb_error()
     460 * @see tdb_errorstr()
     461 */
    120462int tdb_lockall(struct tdb_context *tdb);
     463
     464/**
     465 * @brief Lock entire database with a write lock.
     466 *
     467 * This is the non-blocking call.
     468 *
     469 * @param[in]  tdb      The database to lock.
     470 *
     471 * @return              0 on success, -1 on error with error code set.
     472 *
     473 * @see tdb_lockall()
     474 * @see tdb_error()
     475 * @see tdb_errorstr()
     476 */
    121477int tdb_lockall_nonblock(struct tdb_context *tdb);
     478
     479/**
     480 * @brief Unlock entire database with write lock.
     481 *
     482 * @param[in]  tdb      The database to unlock.
     483 *
     484 * @return              0 on success, -1 on error with error code set.
     485 *
     486 * @see tdb_lockall()
     487 * @see tdb_error()
     488 * @see tdb_errorstr()
     489 */
    122490int tdb_unlockall(struct tdb_context *tdb);
     491
     492/**
     493 * @brief Lock entire database with a read lock.
     494 *
     495 * @param[in]  tdb      The database to lock.
     496 *
     497 * @return              0 on success, -1 on error with error code set.
     498 *
     499 * @see tdb_error()
     500 * @see tdb_errorstr()
     501 */
    123502int tdb_lockall_read(struct tdb_context *tdb);
     503
     504/**
     505 * @brief Lock entire database with a read lock.
     506 *
     507 * This is the non-blocking call.
     508 *
     509 * @param[in]  tdb      The database to lock.
     510 *
     511 * @return              0 on success, -1 on error with error code set.
     512 *
     513 * @see tdb_lockall_read()
     514 * @see tdb_error()
     515 * @see tdb_errorstr()
     516 */
    124517int tdb_lockall_read_nonblock(struct tdb_context *tdb);
     518
     519/**
     520 * @brief Unlock entire database with read lock.
     521 *
     522 * @param[in]  tdb      The database to unlock.
     523 *
     524 * @return              0 on success, -1 on error with error code set.
     525 *
     526 * @see tdb_lockall_read()
     527 * @see tdb_error()
     528 * @see tdb_errorstr()
     529 */
    125530int tdb_unlockall_read(struct tdb_context *tdb);
     531
     532/**
     533 * @brief Lock entire database with write lock - mark only.
     534 *
     535 * @todo Add more details.
     536 *
     537 * @param[in]  tdb      The database to mark.
     538 *
     539 * @return              0 on success, -1 on error with error code set.
     540 *
     541 * @see tdb_error()
     542 * @see tdb_errorstr()
     543 */
    126544int tdb_lockall_mark(struct tdb_context *tdb);
     545
     546/**
     547 * @brief Lock entire database with write lock - unmark only.
     548 *
     549 * @todo Add more details.
     550 *
     551 * @param[in]  tdb      The database to mark.
     552 *
     553 * @return              0 on success, -1 on error with error code set.
     554 *
     555 * @see tdb_error()
     556 * @see tdb_errorstr()
     557 */
    127558int tdb_lockall_unmark(struct tdb_context *tdb);
     559
     560/**
     561 * @brief Get the name of the current tdb file.
     562 *
     563 * This is useful for external logging functions.
     564 *
     565 * @param[in]  tdb      The database to get the name from.
     566 *
     567 * @return              The name of the database.
     568 */
    128569const char *tdb_name(struct tdb_context *tdb);
     570
     571/**
     572 * @brief Get the underlying file descriptor being used by tdb.
     573 *
     574 * This is useful for external routines that want to check the device/inode
     575 * of the fd.
     576 *
     577 * @param[in]  tdb      The database to get the fd from.
     578 *
     579 * @return              The file descriptor or -1.
     580 */
    129581int tdb_fd(struct tdb_context *tdb);
     582
     583/**
     584 * @brief Get the current logging function.
     585 *
     586 * This is useful for external tdb routines that wish to log tdb errors.
     587 *
     588 * @param[in]  tdb      The database to get the logging function from.
     589 *
     590 * @return              The logging function of the database.
     591 *
     592 * @see tdb_get_logging_private()
     593 */
    130594tdb_log_func tdb_log_fn(struct tdb_context *tdb);
     595
     596/**
     597 * @brief Get the private data of the logging function.
     598 *
     599 * @param[in]  tdb      The database to get the data from.
     600 *
     601 * @return              The private data pointer of the logging function.
     602 *
     603 * @see tdb_log_fn()
     604 */
    131605void *tdb_get_logging_private(struct tdb_context *tdb);
     606
     607/**
     608 * @brief Start a transaction.
     609 *
     610 * All operations after the transaction start can either be committed with
     611 * tdb_transaction_commit() or cancelled with tdb_transaction_cancel().
     612 *
     613 * If you call tdb_transaction_start() again on the same tdb context while a
     614 * transaction is in progress, then the same transaction buffer is re-used. The
     615 * number of tdb_transaction_{commit,cancel} operations must match the number
     616 * of successful tdb_transaction_start() calls.
     617 *
     618 * Note that transactions are by default disk synchronous, and use a recover
     619 * area in the database to automatically recover the database on the next open
     620 * if the system crashes during a transaction. You can disable the synchronous
     621 * transaction recovery setup using the TDB_NOSYNC flag, which will greatly
     622 * speed up operations at the risk of corrupting your database if the system
     623 * crashes.
     624 *
     625 * Operations made within a transaction are not visible to other users of the
     626 * database until a successful commit.
     627 *
     628 * @param[in]  tdb      The database to start the transaction.
     629 *
     630 * @return              0 on success, -1 on error with error code set.
     631 *
     632 * @see tdb_error()
     633 * @see tdb_errorstr()
     634 */
    132635int tdb_transaction_start(struct tdb_context *tdb);
     636
     637/**
     638 * @brief Start a transaction, non-blocking.
     639 *
     640 * @param[in]  tdb      The database to start the transaction.
     641 *
     642 * @return              0 on success, -1 on error with error code set.
     643 *
     644 * @see tdb_error()
     645 * @see tdb_errorstr()
     646 * @see tdb_transaction_start()
     647 */
     648int tdb_transaction_start_nonblock(struct tdb_context *tdb);
     649
     650/**
     651 * @brief Prepare to commit a current transaction, for two-phase commits.
     652 *
     653 * Once prepared for commit, the only allowed calls are tdb_transaction_commit()
     654 * or tdb_transaction_cancel(). Preparing allocates disk space for the pending
     655 * updates, so a subsequent commit should succeed (barring any hardware
     656 * failures).
     657 *
     658 * @param[in]  tdb      The database to prepare the commit.
     659 *
     660 * @return              0 on success, -1 on error with error code set.
     661 *
     662 * @see tdb_error()
     663 * @see tdb_errorstr()
     664 */
    133665int tdb_transaction_prepare_commit(struct tdb_context *tdb);
     666
     667/**
     668 * @brief Commit a current transaction.
     669 *
     670 * This updates the database and releases the current transaction locks.
     671 *
     672 * @param[in]  tdb      The database to commit the transaction.
     673 *
     674 * @return              0 on success, -1 on error with error code set.
     675 *
     676 * @see tdb_error()
     677 * @see tdb_errorstr()
     678 */
    134679int tdb_transaction_commit(struct tdb_context *tdb);
     680
     681/**
     682 * @brief Cancel a current transaction.
     683 *
     684 * This discards all write and lock operations that have been made since the
     685 * transaction started.
     686 *
     687 * @param[in]  tdb      The tdb to cancel the transaction on.
     688 *
     689 * @return              0 on success, -1 on error with error code set.
     690 *
     691 * @see tdb_error()
     692 * @see tdb_errorstr()
     693 */
    135694int tdb_transaction_cancel(struct tdb_context *tdb);
    136 int tdb_transaction_recover(struct tdb_context *tdb);
     695
     696/**
     697 * @brief Get the tdb sequence number.
     698 *
     699 * Only makes sense if the writers opened with TDB_SEQNUM set. Note that this
     700 * sequence number will wrap quite quickly, so it should only be used for a
     701 * 'has something changed' test, not for code that relies on the count of the
     702 * number of changes made. If you want a counter then use a tdb record.
     703 *
     704 * The aim of this sequence number is to allow for a very lightweight test of a
     705 * possible tdb change.
     706 *
     707 * @param[in]  tdb      The database to get the sequence number from.
     708 *
     709 * @return              The sequence number or 0.
     710 *
     711 * @see tdb_open()
     712 * @see tdb_enable_seqnum()
     713 */
    137714int tdb_get_seqnum(struct tdb_context *tdb);
     715
     716/**
     717 * @brief Get the hash size.
     718 *
     719 * @param[in]  tdb      The database to get the hash size from.
     720 *
     721 * @return              The hash size.
     722 */
    138723int tdb_hash_size(struct tdb_context *tdb);
     724
     725/**
     726 * @brief Get the map size.
     727 *
     728 * @param[in]  tdb     The database to get the map size from.
     729 *
     730 * @return             The map size.
     731 */
    139732size_t tdb_map_size(struct tdb_context *tdb);
     733
     734/**
     735 * @brief Get the tdb flags set during open.
     736 *
     737 * @param[in]  tdb      The database to get the flags form.
     738 *
     739 * @return              The flags set to on the database.
     740 */
    140741int tdb_get_flags(struct tdb_context *tdb);
     742
     743/**
     744 * @brief Add flags to the database.
     745 *
     746 * @param[in]  tdb      The database to add the flags.
     747 *
     748 * @param[in]  flag     The tdb flags to add.
     749 */
    141750void tdb_add_flags(struct tdb_context *tdb, unsigned flag);
     751
     752/**
     753 * @brief Remove flags from the database.
     754 *
     755 * @param[in]  tdb      The database to remove the flags.
     756 *
     757 * @param[in]  flag     The tdb flags to remove.
     758 */
    142759void tdb_remove_flags(struct tdb_context *tdb, unsigned flag);
     760
     761/**
     762 * @brief Enable sequence number handling on an open tdb.
     763 *
     764 * @param[in]  tdb      The database to enable sequence number handling.
     765 *
     766 * @see tdb_get_seqnum()
     767 */
    143768void tdb_enable_seqnum(struct tdb_context *tdb);
     769
     770/**
     771 * @brief Increment the tdb sequence number.
     772 *
     773 * This only works if the tdb has been opened using the TDB_SEQNUM flag or
     774 * enabled useing tdb_enable_seqnum().
     775 *
     776 * @param[in]  tdb      The database to increment the sequence number.
     777 *
     778 * @see tdb_enable_seqnum()
     779 * @see tdb_get_seqnum()
     780 */
    144781void tdb_increment_seqnum_nonblock(struct tdb_context *tdb);
     782
     783/**
     784 * @brief Create a hash of the key.
     785 *
     786 * @param[in]  key      The key to hash
     787 *
     788 * @return              The hash.
     789 */
     790unsigned int tdb_jenkins_hash(TDB_DATA *key);
     791
     792/**
     793 * @brief Check the consistency of the database.
     794 *
     795 * This check the consistency of the database calling back the check function
     796 * (if non-NULL) on each record.  If some consistency check fails, or the
     797 * supplied check function returns -1, tdb_check returns -1, otherwise 0.
     798 *
     799 * @note The logging function (if set) will be called with additional
     800 * information on the corruption found.
     801 *
     802 * @param[in]  tdb      The database to check.
     803 *
     804 * @param[in]  check    The check function to use.
     805 *
     806 * @param[in]  private_data the private data to pass to the check function.
     807 *
     808 * @return              0 on success, -1 on error with error code set.
     809 *
     810 * @see tdb_error()
     811 * @see tdb_errorstr()
     812 */
    145813int tdb_check(struct tdb_context *tdb,
    146814              int (*check) (TDB_DATA key, TDB_DATA data, void *private_data),
    147815              void *private_data);
     816
     817/* @} ******************************************************************/
    148818
    149819/* Low level locking functions: use with care */
     
    167837int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries);
    168838int tdb_freelist_size(struct tdb_context *tdb);
     839char *tdb_summary(struct tdb_context *tdb);
    169840
    170841extern TDB_DATA tdb_null;
  • trunk/server/lib/tdb/libtdb.m4

    r414 r745  
    1414fi
    1515TDB_OBJ="common/tdb.o common/dump.o common/transaction.o common/error.o common/traverse.o"
    16 TDB_OBJ="$TDB_OBJ common/freelist.o common/freelistcheck.o common/io.o common/lock.o common/open.o common/check.o"
     16TDB_OBJ="$TDB_OBJ common/freelist.o common/freelistcheck.o common/io.o common/lock.o common/open.o common/check.o common/hash.o common/summary.o"
    1717AC_SUBST(TDB_OBJ)
    1818AC_SUBST(LIBREPLACEOBJ)
     
    2020TDB_LIBS=""
    2121AC_SUBST(TDB_LIBS)
     22
     23TDB_DEPS=""
     24if test x$libreplace_cv_HAVE_FDATASYNC_IN_LIBRT = xyes ; then
     25        TDB_DEPS="$TDB_DEPS -lrt"
     26fi
     27AC_SUBST(TDB_DEPS)
    2228
    2329TDB_CFLAGS="-I$tdbdir/include"
  • trunk/server/lib/tdb/manpages/tdbbackup.8.xml

    r414 r745  
    11<?xml version="1.0" encoding="iso-8859-1"?>
    2 <!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
     2<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33<refentry id="tdbbackup.8">
    44
     
    88        <refmiscinfo class="source">Samba</refmiscinfo>
    99        <refmiscinfo class="manual">System Administration tools</refmiscinfo>
    10         <refmiscinfo class="version">3.5</refmiscinfo>
     10        <refmiscinfo class="version">3.6</refmiscinfo>
    1111</refmeta>
    1212
  • trunk/server/lib/tdb/manpages/tdbdump.8.xml

    r414 r745  
    11<?xml version="1.0" encoding="iso-8859-1"?>
    2 <!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
     2<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33<refentry id="tdbdump.8">
    44
     
    88        <refmiscinfo class="source">Samba</refmiscinfo>
    99        <refmiscinfo class="manual">System Administration tools</refmiscinfo>
    10         <refmiscinfo class="version">3.5</refmiscinfo>
     10        <refmiscinfo class="version">3.6</refmiscinfo>
    1111</refmeta>
    1212
  • trunk/server/lib/tdb/manpages/tdbtool.8.xml

    r414 r745  
    11<?xml version="1.0" encoding="iso-8859-1"?>
    2 <!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
     2<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33<refentry id="tdbtool.8">
    44
     
    88        <refmiscinfo class="source">Samba</refmiscinfo>
    99        <refmiscinfo class="manual">System Administration tools</refmiscinfo>
    10         <refmiscinfo class="version">3.5</refmiscinfo>
     10        <refmiscinfo class="version">3.6</refmiscinfo>
    1111</refmeta>
    1212
  • trunk/server/lib/tdb/pytdb.c

    r414 r745  
    1010     ** library. This does NOT imply that all of Samba is released
    1111     ** under the LGPL
    12    
     12
    1313   This library is free software; you can redistribute it and/or
    1414   modify it under the terms of the GNU Lesser General Public
     
    2525*/
    2626
     27#include <Python.h>
    2728#include "replace.h"
    2829#include "system/filesys.h"
    2930
    30 #include <Python.h>
    3131#ifndef Py_RETURN_NONE
    3232#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
     
    4242} PyTdbObject;
    4343
    44 PyAPI_DATA(PyTypeObject) PyTdb;
     44staticforward PyTypeObject PyTdb;
    4545
    4646static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
     
    7878static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    7979{
    80         char *name;
     80        char *name = NULL;
    8181        int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600;
    8282        TDB_CONTEXT *ctx;
     
    8484        const char *kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
    8585
    86         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
    87                 return NULL;
     86        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
     87                return NULL;
     88
     89        if (name == NULL) {
     90                tdb_flags |= TDB_INTERNAL;
     91        }
    8892
    8993        ctx = tdb_open(name, hash_size, tdb_flags, flags, mode);
     
    9498
    9599        ret = PyObject_New(PyTdbObject, &PyTdb);
     100        if (!ret) {
     101                tdb_close(ctx);
     102                return NULL;
     103        }
     104
    96105        ret->ctx = ctx;
    97106        ret->closed = false;
     
    113122}
    114123
    115 static PyObject *obj_transaction_recover(PyTdbObject *self)
    116 {
    117         int ret = tdb_transaction_recover(self->ctx);
     124static PyObject *obj_transaction_prepare_commit(PyTdbObject *self)
     125{
     126        int ret = tdb_transaction_prepare_commit(self->ctx);
    118127        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    119128        Py_RETURN_NONE;
     
    267276}
    268277
     278static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args)
     279{
     280        unsigned flags;
     281
     282        if (!PyArg_ParseTuple(args, "I", &flags))
     283                return NULL;
     284
     285        tdb_add_flags(self->ctx, flags);
     286        Py_RETURN_NONE;
     287}
     288
     289static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args)
     290{
     291        unsigned flags;
     292
     293        if (!PyArg_ParseTuple(args, "I", &flags))
     294                return NULL;
     295
     296        tdb_remove_flags(self->ctx, flags);
     297        Py_RETURN_NONE;
     298}
    269299
    270300typedef struct {
     
    306336
    307337        ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
     338        if (!ret)
     339                return NULL;
    308340        ret->current = tdb_firstkey(self->ctx);
    309341        ret->iteratee = self;
     
    316348        int ret = tdb_wipe_all(self->ctx);
    317349        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     350        Py_RETURN_NONE;
     351}
     352
     353static PyObject *obj_repack(PyTdbObject *self)
     354{
     355        int ret = tdb_repack(self->ctx);
     356        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     357        Py_RETURN_NONE;
     358}
     359
     360static PyObject *obj_enable_seqnum(PyTdbObject *self)
     361{
     362        tdb_enable_seqnum(self->ctx);
     363        Py_RETURN_NONE;
     364}
     365
     366static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self)
     367{
     368        tdb_increment_seqnum_nonblock(self->ctx);
    318369        Py_RETURN_NONE;
    319370}
     
    326377                "S.transaction_commit() -> None\n"
    327378                "Commit the currently active transaction." },
    328         { "transaction_recover", (PyCFunction)obj_transaction_recover, METH_NOARGS,
    329                 "S.transaction_recover() -> None\n"
    330                 "Recover the currently active transaction." },
     379        { "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS,
     380                "S.transaction_prepare_commit() -> None\n"
     381                "Prepare to commit the currently active transaction" },
    331382        { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS,
    332383                "S.transaction_start() -> None\n"
     
    352403        { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None"
    353404                "Store data." },
     405        { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
     406        { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
    354407        { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
    355408        { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
    356409                "Wipe the entire database." },
     410        { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
     411                "Repack the entire database." },
     412        { "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS,
     413                "S.enable_seqnum() -> None" },
     414        { "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS,
     415                "S.increment_seqnum_nonblock() -> None" },
    357416        { NULL }
    358417};
     
    376435}
    377436
     437static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
     438{
     439        return PyInt_FromLong(tdb_freelist_size(self->ctx));
     440}
     441
    378442static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
    379443{
     
    385449        return PyString_FromString(tdb_name(self->ctx));
    386450}
     451
     452static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
     453{
     454        return PyInt_FromLong(tdb_get_seqnum(self->ctx));
     455}
     456
    387457
    388458static PyGetSetDef tdb_object_getsetters[] = {
    389459        { (char *)"hash_size", (getter)obj_get_hash_size, NULL, NULL },
    390460        { (char *)"map_size", (getter)obj_get_map_size, NULL, NULL },
     461        { (char *)"freelist_size", (getter)obj_get_freelist_size, NULL, NULL },
    391462        { (char *)"flags", (getter)obj_get_flags, NULL, NULL },
    392463        { (char *)"max_dead", NULL, (setter)obj_set_max_dead, NULL },
    393464        { (char *)"filename", (getter)obj_get_filename, NULL, (char *)"The filename of this TDB file."},
     465        { (char *)"seqnum", (getter)obj_get_seqnum, NULL, NULL },
    394466        { NULL }
    395467};
     
    397469static PyObject *tdb_object_repr(PyTdbObject *self)
    398470{
    399         return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
     471        if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
     472                return PyString_FromString("Tdb(<internal>)");
     473        } else {
     474                return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
     475        }
    400476}
    401477
     
    404480        if (!self->closed)
    405481                tdb_close(self->ctx);
    406         PyObject_Del(self);
     482        self->ob_type->tp_free(self);
    407483}
    408484
     
    463539        .mp_ass_subscript = (objobjargproc)obj_setitem,
    464540};
    465 PyTypeObject PyTdb = {
     541static PyTypeObject PyTdb = {
    466542        .tp_name = "Tdb",
    467543        .tp_basicsize = sizeof(PyTdbObject),
     
    483559};
    484560
     561void inittdb(void);
    485562void inittdb(void)
    486563{
     
    508585        PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT));
    509586        PyModule_AddObject(m, "BIGENDIAN", PyInt_FromLong(TDB_BIGENDIAN));
     587        PyModule_AddObject(m, "NOSYNC", PyInt_FromLong(TDB_NOSYNC));
     588        PyModule_AddObject(m, "SEQNUM", PyInt_FromLong(TDB_SEQNUM));
     589        PyModule_AddObject(m, "VOLATILE", PyInt_FromLong(TDB_VOLATILE));
     590        PyModule_AddObject(m, "ALLOW_NESTING", PyInt_FromLong(TDB_ALLOW_NESTING));
     591        PyModule_AddObject(m, "DISALLOW_NESTING", PyInt_FromLong(TDB_DISALLOW_NESTING));
     592        PyModule_AddObject(m, "INCOMPATIBLE_HASH", PyInt_FromLong(TDB_INCOMPATIBLE_HASH));
     593
    510594        PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText"));
     595
     596        PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION));
    511597
    512598        Py_INCREF(&PyTdb);
  • trunk/server/lib/tdb/python/tdbdump.py

    r414 r745  
    1 #!/usr/bin/python
     1#!/usr/bin/env python
    22# Trivial reimplementation of tdbdump in Python
    33
  • trunk/server/lib/tdb/python/tests/simple.py

    r414 r745  
    1 #!/usr/bin/python
     1#!/usr/bin/env python
    22# Some simple tests for the Python bindings for TDB
    33# Note that this tests the interface of the Python bindings
     
    1313
    1414class OpenTdbTests(TestCase):
     15
    1516    def test_nonexistant_read(self):
    16         self.assertRaises(IOError, tdb.Tdb, "/some/nonexistant/file", 0, tdb.DEFAULT, os.O_RDWR)
     17        self.assertRaises(IOError, tdb.Tdb, "/some/nonexistant/file", 0,
     18                tdb.DEFAULT, os.O_RDWR)
    1719
    1820class CloseTdbTests(TestCase):
     21
    1922    def test_double_close(self):
    20         self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, os.O_CREAT|os.O_RDWR)
     23        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
     24                os.O_CREAT|os.O_RDWR)
    2125        self.assertNotEqual(None, self.tdb)
    2226
     
    2630
    2731
     32class InternalTdbTests(TestCase):
     33
     34    def test_repr(self):
     35        self.tdb = tdb.Tdb()
     36
     37        # repr used to crash on internal db
     38        self.assertEquals(repr(self.tdb), "Tdb(<internal>)")
     39
     40
    2841class SimpleTdbTests(TestCase):
     42
    2943    def setUp(self):
    3044        super(SimpleTdbTests, self).setUp()
    31         self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, os.O_CREAT|os.O_RDWR)
     45        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
     46                os.O_CREAT|os.O_RDWR)
    3247        self.assertNotEqual(None, self.tdb)
    3348
     
    8297        self.tdb.map_size
    8398
     99    def test_freelist_size(self):
     100        self.tdb.freelist_size
     101
    84102    def test_name(self):
    85103        self.tdb.filename
     
    104122        self.assertEquals("1", self.tdb["bloe"])
    105123
    106     def test_iterator(self):
     124    def test_transaction_prepare_commit(self):
    107125        self.tdb["bloe"] = "2"
    108         self.tdb["bla"] = "hoi"
    109         i = iter(self.tdb)
    110         self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()]))
     126        self.tdb.transaction_start()
     127        self.tdb["bloe"] = "1"
     128        self.tdb.transaction_prepare_commit()
     129        self.tdb.transaction_commit()
     130        self.assertEquals("1", self.tdb["bloe"])
    111131
    112132    def test_iterkeys(self):
     
    123143        self.assertEquals(0, len(list(self.tdb)))
    124144
     145    def test_repack(self):
     146        self.tdb["foo"] = "abc"
     147        self.tdb["bar"] = "def"
     148        del self.tdb["foo"]
     149        self.tdb.repack()
     150
     151    def test_seqnum(self):
     152        self.tdb.enable_seqnum()
     153        seq1 = self.tdb.seqnum
     154        self.tdb.increment_seqnum_nonblock()
     155        seq2 = self.tdb.seqnum
     156        self.assertEquals(seq2-seq1, 1)
     157
    125158    def test_len(self):
    126159        self.assertEquals(0, len(list(self.tdb)))
     
    128161        self.assertEquals(1, len(list(self.tdb)))
    129162
     163    def test_add_flags(self):
     164        self.tdb.add_flags(tdb.NOMMAP)
     165        self.tdb.remove_flags(tdb.NOMMAP)
     166
     167
     168class VersionTests(TestCase):
     169
     170    def test_present(self):
     171        self.assertTrue(isinstance(tdb.__version__, str))
     172
    130173
    131174if __name__ == '__main__':
  • trunk/server/lib/tdb/tdb.pc.in

    r414 r745  
    77Description: A trivial database
    88Version: @PACKAGE_VERSION@
    9 Libs: -L${libdir} -ltdb
     9Libs: @LIB_RPATH@ -L${libdir} -ltdb
    1010Cflags: -I${includedir}
    1111URL: http://tdb.samba.org/
  • trunk/server/lib/tdb/tools/tdbbackup.c

    r414 r745  
    153153        }
    154154
    155         if (tdb_transaction_start(tdb_new) != 0) {
    156                 printf("Failed to start transaction on new tdb\n");
     155        /* lock the backup tdb so that nobody else can change it */
     156        if (tdb_lockall(tdb_new) != 0) {
     157                printf("Failed to lock backup tdb\n");
    157158                tdb_close(tdb);
    158159                tdb_close(tdb_new);
     
    178179        tdb_close(tdb);
    179180
    180         if (tdb_transaction_commit(tdb_new) != 0) {
    181                 fprintf(stderr, "Failed to commit new tdb\n");
    182                 tdb_close(tdb_new);
    183                 unlink(tmp_name);
    184                 free(tmp_name);         
    185                 return 1;
     181        /* copy done, unlock the backup tdb */
     182        tdb_unlockall(tdb_new);
     183
     184#ifdef HAVE_FDATASYNC
     185        if (fdatasync(tdb_fd(tdb_new)) != 0) {
     186#else
     187        if (fsync(tdb_fd(tdb_new)) != 0) {
     188#endif
     189                /* not fatal */
     190                fprintf(stderr, "failed to fsync backup file\n");
    186191        }
    187192
  • trunk/server/lib/tdb/tools/tdbtest.c

    r414 r745  
    216216}
    217217
     218static char *test_path(const char *filename)
     219{
     220        const char *prefix = getenv("TEST_DATA_PREFIX");
     221
     222        if (prefix) {
     223                char *path = NULL;
     224                int ret;
     225
     226                ret = asprintf(&path, "%s/%s", prefix, filename);
     227                if (ret == -1) {
     228                        return NULL;
     229                }
     230                return path;
     231        }
     232
     233        return strdup(filename);
     234}
     235
    218236 int main(int argc, const char *argv[])
    219237{
     
    221239        int loops = 10000;
    222240        int num_entries;
    223         char test_gdbm[] = "test.gdbm";
    224 
    225         unlink("test.gdbm");
    226 
    227         db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST,
     241        char test_gdbm[1] = "test.gdbm";
     242        char *test_tdb;
     243
     244        test_gdbm[0] = test_path("test.gdbm");
     245        test_tdb = test_path("test.tdb");
     246
     247        unlink(test_gdbm[0]);
     248
     249        db = tdb_open(test_tdb, 0, TDB_CLEAR_IF_FIRST,
    228250                      O_RDWR | O_CREAT | O_TRUNC, 0600);
    229251        gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST,
     
    262284        gdbm_close(gdbm);
    263285
     286        free(test_gdbm[0]);
     287        free(test_tdb);
     288
    264289        return 0;
    265290}
  • trunk/server/lib/tdb/tools/tdbtool.c

    r456 r745  
    418418static void info_tdb(void)
    419419{
    420         int count;
    421         total_bytes = 0;
    422         if ((count = tdb_traverse(tdb, traverse_fn, NULL)) == -1)
     420        char *summary = tdb_summary(tdb);
     421
     422        if (!summary) {
    423423                printf("Error = %s\n", tdb_errorstr(tdb));
    424         else
    425                 printf("%d records totalling %d bytes\n", count, total_bytes);
     424        } else {
     425                printf("%s", summary);
     426                free(summary);
     427        }
    426428}
    427429
     
    574576    if (cmdname) {
    575577#endif
    576 
    577578        if (cmdname && strlen(cmdname) == 0) {
    578579                mycmd = CMD_NEXT;
  • trunk/server/lib/tdb/tools/tdbtorture.c

    r414 r745  
    3131static int error_count;
    3232static int always_transaction = 0;
     33static int hash_size = 2;
     34static int loopnum;
     35static int count_pipe;
     36static struct tdb_logging_context log_ctx;
    3337
    3438#ifdef PRINTF_ATTRIBUTE
     
    4953        fflush(stdout);
    5054#if 0
    51         {
     55        if (level != TDB_DEBUG_TRACE) {
    5256                char *ptr;
     57                signal(SIGUSR1, SIG_IGN);
    5358                asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
    5459                system(ptr);
     
    212217static void usage(void)
    213218{
    214         printf("Usage: tdbtorture [-t] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
     219        printf("Usage: tdbtorture [-t] [-k] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
    215220        exit(0);
    216221}
    217222
    218  int main(int argc, char * const *argv)
    219 {
    220         int i, seed = -1;
    221         int num_procs = 3;
    222         int num_loops = 5000;
    223         int hash_size = 2;
    224         int c;
    225         extern char *optarg;
    226         pid_t *pids;
    227 
    228         struct tdb_logging_context log_ctx;
    229         log_ctx.log_fn = tdb_log;
    230 
    231         while ((c = getopt(argc, argv, "n:l:s:H:th")) != -1) {
    232                 switch (c) {
    233                 case 'n':
    234                         num_procs = strtol(optarg, NULL, 0);
    235                         break;
    236                 case 'l':
    237                         num_loops = strtol(optarg, NULL, 0);
    238                         break;
    239                 case 'H':
    240                         hash_size = strtol(optarg, NULL, 0);
    241                         break;
    242                 case 's':
    243                         seed = strtol(optarg, NULL, 0);
    244                         break;
    245                 case 't':
    246                         always_transaction = 1;
    247                         break;
    248                 default:
    249                         usage();
    250                 }
    251         }
    252 
    253         unlink("torture.tdb");
    254 
    255         pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
    256         pids[0] = getpid();
    257 
    258         for (i=0;i<num_procs-1;i++) {
    259                 if ((pids[i+1]=fork()) == 0) break;
    260         }
    261 
    262         db = tdb_open_ex("torture.tdb", hash_size, TDB_CLEAR_IF_FIRST,
     223static void send_count_and_suicide(int sig)
     224{
     225        /* This ensures our successor can continue where we left off. */
     226        write(count_pipe, &loopnum, sizeof(loopnum));
     227        /* This gives a unique signature. */
     228        kill(getpid(), SIGUSR2);
     229}
     230
     231static int run_child(const char *filename, int i, int seed, unsigned num_loops, unsigned start)
     232{
     233        db = tdb_open_ex(filename, hash_size, TDB_DEFAULT,
    263234                         O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
    264235        if (!db) {
     
    266237        }
    267238
    268         if (seed == -1) {
    269                 seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
    270         }
    271 
    272         if (i == 0) {
    273                 printf("testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
    274                        num_procs, num_loops, hash_size, seed, always_transaction ? " (all within transactions)" : "");
    275         }
    276 
    277239        srand(seed + i);
    278240        srandom(seed + i);
    279241
    280         for (i=0;i<num_loops && error_count == 0;i++) {
     242        /* Set global, then we're ready to handle being killed. */
     243        loopnum = start;
     244        signal(SIGUSR1, send_count_and_suicide);
     245
     246        for (;loopnum<num_loops && error_count == 0;loopnum++) {
    281247                addrec_db();
    282248        }
     
    302268        tdb_close(db);
    303269
    304         if (getpid() != pids[0]) {
    305                 return error_count;
    306         }
    307 
    308         for (i=1;i<num_procs;i++) {
     270        return (error_count < 100 ? error_count : 100);
     271}
     272
     273static char *test_path(const char *filename)
     274{
     275        const char *prefix = getenv("TEST_DATA_PREFIX");
     276
     277        if (prefix) {
     278                char *path = NULL;
     279                int ret;
     280
     281                ret = asprintf(&path, "%s/%s", prefix, filename);
     282                if (ret == -1) {
     283                        return NULL;
     284                }
     285                return path;
     286        }
     287
     288        return strdup(filename);
     289}
     290
     291int main(int argc, char * const *argv)
     292{
     293        int i, seed = -1;
     294        int num_loops = 5000;
     295        int num_procs = 3;
     296        int c, pfds[2];
     297        extern char *optarg;
     298        pid_t *pids;
     299        int kill_random = 0;
     300        int *done;
     301        char *test_tdb;
     302
     303        log_ctx.log_fn = tdb_log;
     304
     305        while ((c = getopt(argc, argv, "n:l:s:H:thk")) != -1) {
     306                switch (c) {
     307                case 'n':
     308                        num_procs = strtol(optarg, NULL, 0);
     309                        break;
     310                case 'l':
     311                        num_loops = strtol(optarg, NULL, 0);
     312                        break;
     313                case 'H':
     314                        hash_size = strtol(optarg, NULL, 0);
     315                        break;
     316                case 's':
     317                        seed = strtol(optarg, NULL, 0);
     318                        break;
     319                case 't':
     320                        always_transaction = 1;
     321                        break;
     322                case 'k':
     323                        kill_random = 1;
     324                        break;
     325                default:
     326                        usage();
     327                }
     328        }
     329
     330        test_tdb = test_path("torture.tdb");
     331
     332        unlink(test_tdb);
     333
     334        if (seed == -1) {
     335                seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
     336        }
     337
     338        if (num_procs == 1 && !kill_random) {
     339                /* Don't fork for this case, makes debugging easier. */
     340                error_count = run_child(test_tdb, 0, seed, num_loops, 0);
     341                goto done;
     342        }
     343
     344        pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
     345        done = (int *)calloc(sizeof(int), num_procs);
     346
     347        if (pipe(pfds) != 0) {
     348                perror("Creating pipe");
     349                exit(1);
     350        }
     351        count_pipe = pfds[1];
     352
     353        for (i=0;i<num_procs;i++) {
     354                if ((pids[i]=fork()) == 0) {
     355                        close(pfds[0]);
     356                        if (i == 0) {
     357                                printf("Testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
     358                                       num_procs, num_loops, hash_size, seed, always_transaction ? " (all within transactions)" : "");
     359                        }
     360                        exit(run_child(test_tdb, i, seed, num_loops, 0));
     361                }
     362        }
     363
     364        while (num_procs) {
    309365                int status, j;
    310366                pid_t pid;
     367
    311368                if (error_count != 0) {
    312369                        /* try and stop the test on any failure */
    313                         for (j=1;j<num_procs;j++) {
     370                        for (j=0;j<num_procs;j++) {
    314371                                if (pids[j] != 0) {
    315372                                        kill(pids[j], SIGTERM);
     
    317374                        }
    318375                }
    319                 pid = waitpid(-1, &status, 0);
     376
     377                pid = waitpid(-1, &status, kill_random ? WNOHANG : 0);
     378                if (pid == 0) {
     379                        struct timeval tv;
     380
     381                        /* Sleep for 1/10 second. */
     382                        tv.tv_sec = 0;
     383                        tv.tv_usec = 100000;
     384                        select(0, NULL, NULL, NULL, &tv);
     385
     386                        /* Kill someone. */
     387                        kill(pids[random() % num_procs], SIGUSR1);
     388                        continue;
     389                }
     390
    320391                if (pid == -1) {
    321392                        perror("failed to wait for child\n");
    322393                        exit(1);
    323394                }
    324                 for (j=1;j<num_procs;j++) {
     395
     396                for (j=0;j<num_procs;j++) {
    325397                        if (pids[j] == pid) break;
    326398                }
     
    329401                        exit(1);
    330402                }
    331                 if (WEXITSTATUS(status) != 0) {
    332                         printf("child %d exited with status %d\n",
    333                                (int)pid, WEXITSTATUS(status));
     403                if (WIFSIGNALED(status)) {
     404                        if (WTERMSIG(status) == SIGUSR2
     405                            || WTERMSIG(status) == SIGUSR1) {
     406                                /* SIGUSR2 means they wrote to pipe. */
     407                                if (WTERMSIG(status) == SIGUSR2) {
     408                                        read(pfds[0], &done[j],
     409                                             sizeof(done[j]));
     410                                }
     411                                pids[j] = fork();
     412                                if (pids[j] == 0)
     413                                        exit(run_child(test_tdb, j, seed,
     414                                                       num_loops, done[j]));
     415                                printf("Restarting child %i for %u-%u\n",
     416                                       j, done[j], num_loops);
     417                                continue;
     418                        }
     419                        printf("child %d exited with signal %d\n",
     420                               (int)pid, WTERMSIG(status));
    334421                        error_count++;
    335                 }
    336                 pids[j] = 0;
     422                } else {
     423                        if (WEXITSTATUS(status) != 0) {
     424                                printf("child %d exited with status %d\n",
     425                                       (int)pid, WEXITSTATUS(status));
     426                                error_count++;
     427                        }
     428                }
     429                memmove(&pids[j], &pids[j+1],
     430                        (num_procs - j - 1)*sizeof(pids[0]));
     431                num_procs--;
    337432        }
    338433
    339434        free(pids);
    340435
     436done:
    341437        if (error_count == 0) {
     438                db = tdb_open_ex(test_tdb, hash_size, TDB_DEFAULT,
     439                                 O_RDWR, 0, &log_ctx, NULL);
     440                if (!db) {
     441                        fatal("db open failed");
     442                }
     443                if (tdb_check(db, NULL, NULL) == -1) {
     444                        printf("db check failed");
     445                        exit(1);
     446                }
     447                tdb_close(db);
    342448                printf("OK\n");
    343449        }
    344450
     451        free(test_tdb);
    345452        return error_count;
    346453}
Note: See TracChangeset for help on using the changeset viewer.