Changeset 740 for vendor/current/lib/tdb
- Timestamp:
- Nov 14, 2012, 12:59:34 PM (13 years ago)
- Location:
- vendor/current/lib/tdb
- Files:
-
- 20 added
- 15 deleted
- 26 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/lib/tdb/common/check.c
r414 r740 29 29 { 30 30 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) 33 34 return false; 34 35 if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) … … 39 40 goto corrupt; 40 41 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)) 42 48 goto corrupt; 43 49 … … 302 308 } 303 309 304 int tdb_check(struct tdb_context *tdb, 310 /* Slow, but should be very rare. */ 311 size_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, 305 326 int (*check)(TDB_DATA key, TDB_DATA data, void *private_data), 306 327 void *private_data) … … 311 332 struct tdb_record rec; 312 333 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 } 316 346 317 347 /* Make sure we know true size of the underlying file. */ … … 370 400 goto free; 371 401 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; 372 418 case TDB_RECOVERY_MAGIC: 373 case 0: /* Used for invalid (or in-progress) recovery area. */374 419 if (recovery_start != off) { 375 420 TDB_LOG((tdb, TDB_DEBUG_ERROR, … … 380 425 found_recovery = true; 381 426 break; 382 default: 427 default: ; 428 corrupt: 383 429 tdb->ecode = TDB_ERR_CORRUPT; 384 430 TDB_LOG((tdb, TDB_DEBUG_ERROR, … … 406 452 if (recovery_start != 0 && !found_recovery) { 407 453 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)); 411 456 goto free; 412 457 } 413 458 414 459 free(hashes); 415 tdb_unlockall(tdb); 460 if (locked) { 461 tdb_unlockall_read(tdb); 462 } 416 463 return 0; 417 464 … … 419 466 free(hashes); 420 467 unlock: 421 tdb_unlockall(tdb); 468 if (locked) { 469 tdb_unlockall_read(tdb); 470 } 422 471 return -1; 423 472 } -
vendor/current/lib/tdb/common/dump.c
r414 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 81 81 } 82 82 83 void tdb_dump_all(struct tdb_context *tdb)83 _PUBLIC_ void tdb_dump_all(struct tdb_context *tdb) 84 84 { 85 85 int i; … … 91 91 } 92 92 93 int tdb_printfreelist(struct tdb_context *tdb)93 _PUBLIC_ int tdb_printfreelist(struct tdb_context *tdb) 94 94 { 95 95 int ret; -
vendor/current/lib/tdb/common/error.c
r414 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 28 28 #include "tdb_private.h" 29 29 30 enum TDB_ERROR tdb_error(struct tdb_context *tdb)30 _PUBLIC_ enum TDB_ERROR tdb_error(struct tdb_context *tdb) 31 31 { 32 32 return tdb->ecode; … … 47 47 48 48 /* 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) 50 50 { 51 51 uint32_t i; -
vendor/current/lib/tdb/common/freelist.c
r414 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 99 99 100 100 /* Add an element into the freelist. Merge adjacent records if 101 nec cessary. */101 necessary. */ 102 102 int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) 103 103 { … … 144 144 struct tdb_record l; 145 145 tdb_off_t leftsize; 146 146 147 147 /* Read in tailer and jump back to header */ 148 148 if (tdb_ofs_read(tdb, left, &leftsize) == -1) { … … 335 335 break; 336 336 } 337 337 338 338 /* this multiplier means we only extremely rarely 339 339 search more than 50 or so records. At 50 records we … … 368 368 return the size of the freelist - used to decide if we should repack 369 369 */ 370 int tdb_freelist_size(struct tdb_context *tdb)370 _PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb) 371 371 { 372 372 tdb_off_t ptr; -
vendor/current/lib/tdb/common/freelistcheck.c
r414 r740 44 44 } 45 45 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) 47 47 { 48 48 struct tdb_context *mem_tdb = NULL; -
vendor/current/lib/tdb/common/io.c
r597 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 477 477 tdb_oob, 478 478 tdb_expand_file, 479 tdb_brlock480 479 }; 481 480 -
vendor/current/lib/tdb/common/lock.c
r414 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 28 28 #include "tdb_private.h" 29 29 30 #define TDB_MARK_LOCK 0x80000000 31 32 void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr) 30 _PUBLIC_ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr) 33 31 { 34 32 tdb->interrupt_sig_ptr = ptr; 33 } 34 35 static int fcntl_lock(struct tdb_context *tdb, 36 int rw, off_t off, off_t len, bool waitflag) 37 { 38 struct flock fl; 39 40 fl.l_type = rw; 41 fl.l_whence = SEEK_SET; 42 fl.l_start = off; 43 fl.l_len = len; 44 fl.l_pid = 0; 45 46 if (waitflag) 47 return fcntl(tdb->fd, F_SETLKW, &fl); 48 else 49 return fcntl(tdb->fd, F_SETLK, &fl); 50 } 51 52 static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len) 53 { 54 struct flock fl; 55 #if 0 /* Check they matched up locks and unlocks correctly. */ 56 char line[80]; 57 FILE *locks; 58 bool found = false; 59 60 locks = fopen("/proc/locks", "r"); 61 62 while (fgets(line, 80, locks)) { 63 char *p; 64 int type, start, l; 65 66 /* eg. 1: FLOCK ADVISORY WRITE 2440 08:01:2180826 0 EOF */ 67 p = strchr(line, ':') + 1; 68 if (strncmp(p, " POSIX ADVISORY ", strlen(" POSIX ADVISORY "))) 69 continue; 70 p += strlen(" FLOCK ADVISORY "); 71 if (strncmp(p, "READ ", strlen("READ ")) == 0) 72 type = F_RDLCK; 73 else if (strncmp(p, "WRITE ", strlen("WRITE ")) == 0) 74 type = F_WRLCK; 75 else 76 abort(); 77 p += 6; 78 if (atoi(p) != getpid()) 79 continue; 80 p = strchr(strchr(p, ' ') + 1, ' ') + 1; 81 start = atoi(p); 82 p = strchr(p, ' ') + 1; 83 if (strncmp(p, "EOF", 3) == 0) 84 l = 0; 85 else 86 l = atoi(p) - start + 1; 87 88 if (off == start) { 89 if (len != l) { 90 fprintf(stderr, "Len %u should be %u: %s", 91 (int)len, l, line); 92 abort(); 93 } 94 if (type != rw) { 95 fprintf(stderr, "Type %s wrong: %s", 96 rw == F_RDLCK ? "READ" : "WRITE", line); 97 abort(); 98 } 99 found = true; 100 break; 101 } 102 } 103 104 if (!found) { 105 fprintf(stderr, "Unlock on %u@%u not found!\n", 106 (int)off, (int)len); 107 abort(); 108 } 109 110 fclose(locks); 111 #endif 112 113 fl.l_type = F_UNLCK; 114 fl.l_whence = SEEK_SET; 115 fl.l_start = off; 116 fl.l_len = len; 117 fl.l_pid = 0; 118 119 return fcntl(tdb->fd, F_SETLKW, &fl); 120 } 121 122 /* list -1 is the alloc list, otherwise a hash chain. */ 123 static tdb_off_t lock_offset(int list) 124 { 125 return FREELIST_TOP + 4*list; 35 126 } 36 127 … … 43 134 note that a len of zero means lock to end of file 44 135 */ 45 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset,46 int rw_type, int lck_type, int probe, size_t len)47 { 48 struct flock fl; 136 int tdb_brlock(struct tdb_context *tdb, 137 int rw_type, tdb_off_t offset, size_t len, 138 enum tdb_lock_flags flags) 139 { 49 140 int ret; 50 141 51 142 if (tdb->flags & TDB_NOLOCK) { 143 return 0; 144 } 145 146 if (flags & TDB_LOCK_MARK_ONLY) { 52 147 return 0; 53 148 } … … 58 153 } 59 154 60 fl.l_type = rw_type;61 fl.l_whence = SEEK_SET;62 fl.l_start = offset;63 fl.l_len = len;64 fl.l_pid = 0;65 66 155 do { 67 ret = fcntl (tdb->fd,lck_type,&fl);68 156 ret = fcntl_lock(tdb, rw_type, offset, len, 157 flags & TDB_LOCK_WAIT); 69 158 /* Check for a sigalarm break. */ 70 159 if (ret == -1 && errno == EINTR && … … 80 169 * EAGAIN is an expected return from non-blocking 81 170 * locks. */ 82 if (! probe && lck_type != F_SETLK) {83 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n",84 tdb->fd, offset, rw_type, lck_type, (int)len));171 if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) { 172 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d\n", 173 tdb->fd, offset, rw_type, flags, (int)len)); 85 174 } 86 175 return -1; … … 89 178 } 90 179 180 int tdb_brunlock(struct tdb_context *tdb, 181 int rw_type, tdb_off_t offset, size_t len) 182 { 183 int ret; 184 185 if (tdb->flags & TDB_NOLOCK) { 186 return 0; 187 } 188 189 do { 190 ret = fcntl_unlock(tdb, rw_type, offset, len); 191 } while (ret == -1 && errno == EINTR); 192 193 if (ret == -1) { 194 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d\n", 195 tdb->fd, offset, rw_type, (int)len)); 196 } 197 return ret; 198 } 91 199 92 200 /* … … 96 204 made. For those OSes we may loop for a while. 97 205 */ 98 int tdb_ brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len)206 int tdb_allrecord_upgrade(struct tdb_context *tdb) 99 207 { 100 208 int count = 1000; 209 210 if (tdb->allrecord_lock.count != 1) { 211 TDB_LOG((tdb, TDB_DEBUG_ERROR, 212 "tdb_allrecord_upgrade failed: count %u too high\n", 213 tdb->allrecord_lock.count)); 214 return -1; 215 } 216 217 if (tdb->allrecord_lock.off != 1) { 218 TDB_LOG((tdb, TDB_DEBUG_ERROR, 219 "tdb_allrecord_upgrade failed: already upgraded?\n")); 220 return -1; 221 } 222 101 223 while (count--) { 102 224 struct timeval tv; 103 if (tdb_brlock(tdb, offset, F_WRLCK, F_SETLKW, 1, len) == 0) { 225 if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, 226 TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) { 227 tdb->allrecord_lock.ltype = F_WRLCK; 228 tdb->allrecord_lock.off = 0; 104 229 return 0; 105 230 } … … 112 237 select(0, NULL, NULL, NULL, &tv); 113 238 } 114 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_ brlock_upgrade failed at offset %d\n", offset));239 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n")); 115 240 return -1; 116 241 } 117 242 118 119 /* lock a list in the database. list -1 is the alloc list */ 120 static int _tdb_lock(struct tdb_context *tdb, int list, int ltype, int op) 243 static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb, 244 tdb_off_t offset) 245 { 246 unsigned int i; 247 248 for (i=0; i<tdb->num_lockrecs; i++) { 249 if (tdb->lockrecs[i].off == offset) { 250 return &tdb->lockrecs[i]; 251 } 252 } 253 return NULL; 254 } 255 256 /* lock an offset in the database. */ 257 int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype, 258 enum tdb_lock_flags flags) 121 259 { 122 260 struct tdb_lock_type *new_lck; 123 int i; 124 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 125 126 ltype &= ~TDB_MARK_LOCK; 127 128 /* a global lock allows us to avoid per chain locks */ 129 if (tdb->global_lock.count && 130 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { 131 return 0; 132 } 133 134 if (tdb->global_lock.count) { 135 tdb->ecode = TDB_ERR_LOCK; 136 return -1; 137 } 138 139 if (list < -1 || list >= (int)tdb->header.hash_size) { 140 tdb->ecode = TDB_ERR_LOCK; 141 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n", 142 list, ltype)); 261 262 if (offset >= lock_offset(tdb->header.hash_size)) { 263 tdb->ecode = TDB_ERR_LOCK; 264 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n", 265 offset, ltype)); 143 266 return -1; 144 267 } … … 146 269 return 0; 147 270 148 for (i=0; i<tdb->num_lockrecs; i++) { 149 if (tdb->lockrecs[i].list == list) { 150 if (tdb->lockrecs[i].count == 0) { 151 /* 152 * Can't happen, see tdb_unlock(). It should 153 * be an assert. 154 */ 155 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock: " 156 "lck->count == 0 for list %d", list)); 157 } 158 /* 159 * Just increment the in-memory struct, posix locks 160 * don't stack. 161 */ 162 tdb->lockrecs[i].count++; 163 return 0; 164 } 271 new_lck = find_nestlock(tdb, offset); 272 if (new_lck) { 273 /* 274 * Just increment the in-memory struct, posix locks 275 * don't stack. 276 */ 277 new_lck->count++; 278 return 0; 165 279 } 166 280 … … 176 290 /* Since fcntl locks don't nest, we do a lock for the first one, 177 291 and simply bump the count for future ones */ 178 if (!mark_lock && 179 tdb->methods->tdb_brlock(tdb,FREELIST_TOP+4*list, ltype, op, 180 0, 1)) { 181 return -1; 182 } 183 184 tdb->num_locks++; 185 186 tdb->lockrecs[tdb->num_lockrecs].list = list; 292 if (tdb_brlock(tdb, ltype, offset, 1, flags)) { 293 return -1; 294 } 295 296 tdb->lockrecs[tdb->num_lockrecs].off = offset; 187 297 tdb->lockrecs[tdb->num_lockrecs].count = 1; 188 298 tdb->lockrecs[tdb->num_lockrecs].ltype = ltype; 189 tdb->num_lockrecs += 1;299 tdb->num_lockrecs++; 190 300 191 301 return 0; 302 } 303 304 static int tdb_lock_and_recover(struct tdb_context *tdb) 305 { 306 int ret; 307 308 /* We need to match locking order in transaction commit. */ 309 if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT)) { 310 return -1; 311 } 312 313 if (tdb_brlock(tdb, F_WRLCK, OPEN_LOCK, 1, TDB_LOCK_WAIT)) { 314 tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0); 315 return -1; 316 } 317 318 ret = tdb_transaction_recover(tdb); 319 320 tdb_brunlock(tdb, F_WRLCK, OPEN_LOCK, 1); 321 tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0); 322 323 return ret; 324 } 325 326 static bool have_data_locks(const struct tdb_context *tdb) 327 { 328 unsigned int i; 329 330 for (i = 0; i < tdb->num_lockrecs; i++) { 331 if (tdb->lockrecs[i].off >= lock_offset(-1)) 332 return true; 333 } 334 return false; 335 } 336 337 static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype, 338 enum tdb_lock_flags waitflag) 339 { 340 int ret; 341 bool check = false; 342 343 /* a allrecord lock allows us to avoid per chain locks */ 344 if (tdb->allrecord_lock.count && 345 (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) { 346 return 0; 347 } 348 349 if (tdb->allrecord_lock.count) { 350 tdb->ecode = TDB_ERR_LOCK; 351 ret = -1; 352 } else { 353 /* Only check when we grab first data lock. */ 354 check = !have_data_locks(tdb); 355 ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag); 356 357 if (ret == 0 && check && tdb_needs_recovery(tdb)) { 358 tdb_nest_unlock(tdb, lock_offset(list), ltype, false); 359 360 if (tdb_lock_and_recover(tdb) == -1) { 361 return -1; 362 } 363 return tdb_lock_list(tdb, list, ltype, waitflag); 364 } 365 } 366 return ret; 192 367 } 193 368 … … 196 371 { 197 372 int ret; 198 ret = _tdb_lock(tdb, list, ltype, F_SETLKW); 373 374 ret = tdb_lock_list(tdb, list, ltype, TDB_LOCK_WAIT); 199 375 if (ret) { 200 376 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d " … … 207 383 int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype) 208 384 { 209 return _tdb_lock(tdb, list, ltype, F_SETLK); 210 } 211 212 213 /* unlock the database: returns void because it's too late for errors. */ 214 /* changed to return int it may be interesting to know there 215 has been an error --simo */ 216 int tdb_unlock(struct tdb_context *tdb, int list, int ltype) 385 return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT); 386 } 387 388 389 int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype, 390 bool mark_lock) 217 391 { 218 392 int ret = -1; 219 int i; 220 struct tdb_lock_type *lck = NULL; 221 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 222 223 ltype &= ~TDB_MARK_LOCK; 224 225 /* a global lock allows us to avoid per chain locks */ 226 if (tdb->global_lock.count && 227 (ltype == tdb->global_lock.ltype || ltype == F_RDLCK)) { 228 return 0; 229 } 230 231 if (tdb->global_lock.count) { 232 tdb->ecode = TDB_ERR_LOCK; 233 return -1; 234 } 393 struct tdb_lock_type *lck; 235 394 236 395 if (tdb->flags & TDB_NOLOCK) … … 238 397 239 398 /* Sanity checks */ 240 if ( list < -1 || list >= (int)tdb->header.hash_size) {241 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: list %d invalid (%d)\n", list, tdb->header.hash_size));399 if (offset >= lock_offset(tdb->header.hash_size)) { 400 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->header.hash_size)); 242 401 return ret; 243 402 } 244 403 245 for (i=0; i<tdb->num_lockrecs; i++) { 246 if (tdb->lockrecs[i].list == list) { 247 lck = &tdb->lockrecs[i]; 248 break; 249 } 250 } 251 404 lck = find_nestlock(tdb, offset); 252 405 if ((lck == NULL) || (lck->count == 0)) { 253 406 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n")); … … 270 423 ret = 0; 271 424 } else { 272 ret = tdb->methods->tdb_brlock(tdb, FREELIST_TOP+4*list, F_UNLCK, 273 F_SETLKW, 0, 1); 274 } 275 tdb->num_locks--; 425 ret = tdb_brunlock(tdb, ltype, offset, 1); 426 } 276 427 277 428 /* … … 279 430 * last array element. 280 431 */ 281 282 if (tdb->num_lockrecs > 1) { 283 *lck = tdb->lockrecs[tdb->num_lockrecs-1]; 284 } 285 tdb->num_lockrecs -= 1; 432 *lck = tdb->lockrecs[--tdb->num_lockrecs]; 286 433 287 434 /* … … 299 446 } 300 447 448 int tdb_unlock(struct tdb_context *tdb, int list, int ltype) 449 { 450 /* a global lock allows us to avoid per chain locks */ 451 if (tdb->allrecord_lock.count && 452 (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) { 453 return 0; 454 } 455 456 if (tdb->allrecord_lock.count) { 457 tdb->ecode = TDB_ERR_LOCK; 458 return -1; 459 } 460 461 return tdb_nest_unlock(tdb, lock_offset(list), ltype, false); 462 } 463 301 464 /* 302 465 get the transaction lock 303 466 */ 304 int tdb_transaction_lock(struct tdb_context *tdb, int ltype) 305 { 306 if (tdb->global_lock.count) { 307 return 0; 308 } 309 if (tdb->transaction_lock_count > 0) { 310 tdb->transaction_lock_count++; 311 return 0; 312 } 313 314 if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype, 315 F_SETLKW, 0, 1) == -1) { 316 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n")); 317 tdb->ecode = TDB_ERR_LOCK; 318 return -1; 319 } 320 tdb->transaction_lock_count++; 321 return 0; 467 int tdb_transaction_lock(struct tdb_context *tdb, int ltype, 468 enum tdb_lock_flags lockflags) 469 { 470 return tdb_nest_lock(tdb, TRANSACTION_LOCK, ltype, lockflags); 322 471 } 323 472 … … 325 474 release the transaction lock 326 475 */ 327 int tdb_transaction_unlock(struct tdb_context *tdb) 328 { 329 int ret; 330 if (tdb->global_lock.count) { 331 return 0; 332 } 333 if (tdb->transaction_lock_count > 1) { 334 tdb->transaction_lock_count--; 335 return 0; 336 } 337 ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); 338 if (ret == 0) { 339 tdb->transaction_lock_count = 0; 340 } 341 return ret; 342 } 343 344 345 346 347 /* lock/unlock entire database */ 348 static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op) 349 { 350 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 351 352 ltype &= ~TDB_MARK_LOCK; 353 476 int tdb_transaction_unlock(struct tdb_context *tdb, int ltype) 477 { 478 return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false); 479 } 480 481 /* Returns 0 if all done, -1 if error, 1 if ok. */ 482 static int tdb_allrecord_check(struct tdb_context *tdb, int ltype, 483 enum tdb_lock_flags flags, bool upgradable) 484 { 354 485 /* There are no locks on read-only dbs */ 355 486 if (tdb->read_only || tdb->traverse_read) { … … 358 489 } 359 490 360 if (tdb-> global_lock.count && tdb->global_lock.ltype == ltype) {361 tdb-> global_lock.count++;362 return 0; 363 } 364 365 if (tdb-> global_lock.count) {491 if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) { 492 tdb->allrecord_lock.count++; 493 return 0; 494 } 495 496 if (tdb->allrecord_lock.count) { 366 497 /* a global lock of a different type exists */ 367 498 tdb->ecode = TDB_ERR_LOCK; 368 499 return -1; 369 500 } 370 371 if (tdb ->num_locks != 0) {501 502 if (tdb_have_extra_locks(tdb)) { 372 503 /* can't combine global and chain locks */ 373 504 tdb->ecode = TDB_ERR_LOCK; … … 375 506 } 376 507 377 if (!mark_lock && 378 tdb->methods->tdb_brlock(tdb, FREELIST_TOP, ltype, op, 379 0, 4*tdb->header.hash_size)) { 380 if (op == F_SETLKW) { 381 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lockall failed (%s)\n", strerror(errno))); 382 } 383 return -1; 384 } 385 386 tdb->global_lock.count = 1; 387 tdb->global_lock.ltype = ltype; 388 508 if (upgradable && ltype != F_RDLCK) { 509 /* tdb error: you can't upgrade a write lock! */ 510 tdb->ecode = TDB_ERR_LOCK; 511 return -1; 512 } 513 return 1; 514 } 515 516 /* We only need to lock individual bytes, but Linux merges consecutive locks 517 * so we lock in contiguous ranges. */ 518 static int tdb_chainlock_gradual(struct tdb_context *tdb, 519 int ltype, enum tdb_lock_flags flags, 520 size_t off, size_t len) 521 { 522 int ret; 523 enum tdb_lock_flags nb_flags = (flags & ~TDB_LOCK_WAIT); 524 525 if (len <= 4) { 526 /* Single record. Just do blocking lock. */ 527 return tdb_brlock(tdb, ltype, off, len, flags); 528 } 529 530 /* First we try non-blocking. */ 531 ret = tdb_brlock(tdb, ltype, off, len, nb_flags); 532 if (ret == 0) { 533 return 0; 534 } 535 536 /* Try locking first half, then second. */ 537 ret = tdb_chainlock_gradual(tdb, ltype, flags, off, len / 2); 538 if (ret == -1) 539 return -1; 540 541 ret = tdb_chainlock_gradual(tdb, ltype, flags, 542 off + len / 2, len - len / 2); 543 if (ret == -1) { 544 tdb_brunlock(tdb, ltype, off, len / 2); 545 return -1; 546 } 389 547 return 0; 390 548 } 391 549 550 /* lock/unlock entire database. It can only be upgradable if you have some 551 * other way of guaranteeing exclusivity (ie. transaction write lock). 552 * We do the locking gradually to avoid being starved by smaller locks. */ 553 int tdb_allrecord_lock(struct tdb_context *tdb, int ltype, 554 enum tdb_lock_flags flags, bool upgradable) 555 { 556 switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) { 557 case -1: 558 return -1; 559 case 0: 560 return 0; 561 } 562 563 /* We cover two kinds of locks: 564 * 1) Normal chain locks. Taken for almost all operations. 565 * 3) Individual records locks. Taken after normal or free 566 * chain locks. 567 * 568 * It is (1) which cause the starvation problem, so we're only 569 * gradual for that. */ 570 if (tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP, 571 tdb->header.hash_size * 4) == -1) { 572 return -1; 573 } 574 575 /* Grab individual record locks. */ 576 if (tdb_brlock(tdb, ltype, lock_offset(tdb->header.hash_size), 0, 577 flags) == -1) { 578 tdb_brunlock(tdb, ltype, FREELIST_TOP, 579 tdb->header.hash_size * 4); 580 return -1; 581 } 582 583 tdb->allrecord_lock.count = 1; 584 /* If it's upgradable, it's actually exclusive so we can treat 585 * it as a write lock. */ 586 tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype; 587 tdb->allrecord_lock.off = upgradable; 588 589 if (tdb_needs_recovery(tdb)) { 590 bool mark = flags & TDB_LOCK_MARK_ONLY; 591 tdb_allrecord_unlock(tdb, ltype, mark); 592 if (mark) { 593 tdb->ecode = TDB_ERR_LOCK; 594 TDB_LOG((tdb, TDB_DEBUG_ERROR, 595 "tdb_lockall_mark cannot do recovery\n")); 596 return -1; 597 } 598 if (tdb_lock_and_recover(tdb) == -1) { 599 return -1; 600 } 601 return tdb_allrecord_lock(tdb, ltype, flags, upgradable); 602 } 603 604 return 0; 605 } 606 392 607 393 608 394 609 /* unlock entire db */ 395 static int _tdb_unlockall(struct tdb_context *tdb, int ltype) 396 { 397 bool mark_lock = ((ltype & TDB_MARK_LOCK) == TDB_MARK_LOCK); 398 399 ltype &= ~TDB_MARK_LOCK; 400 610 int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock) 611 { 401 612 /* There are no locks on read-only dbs */ 402 613 if (tdb->read_only || tdb->traverse_read) { … … 405 616 } 406 617 407 if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) { 408 tdb->ecode = TDB_ERR_LOCK; 409 return -1; 410 } 411 412 if (tdb->global_lock.count > 1) { 413 tdb->global_lock.count--; 414 return 0; 415 } 416 417 if (!mark_lock && 418 tdb->methods->tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 419 0, 4*tdb->header.hash_size)) { 618 if (tdb->allrecord_lock.count == 0) { 619 tdb->ecode = TDB_ERR_LOCK; 620 return -1; 621 } 622 623 /* Upgradable locks are marked as write locks. */ 624 if (tdb->allrecord_lock.ltype != ltype 625 && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) { 626 tdb->ecode = TDB_ERR_LOCK; 627 return -1; 628 } 629 630 if (tdb->allrecord_lock.count > 1) { 631 tdb->allrecord_lock.count--; 632 return 0; 633 } 634 635 if (!mark_lock && tdb_brunlock(tdb, ltype, FREELIST_TOP, 0)) { 420 636 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno))); 421 637 return -1; 422 638 } 423 639 424 tdb-> global_lock.count = 0;425 tdb-> global_lock.ltype = 0;640 tdb->allrecord_lock.count = 0; 641 tdb->allrecord_lock.ltype = 0; 426 642 427 643 return 0; … … 429 645 430 646 /* lock entire database with write lock */ 431 int tdb_lockall(struct tdb_context *tdb)647 _PUBLIC_ int tdb_lockall(struct tdb_context *tdb) 432 648 { 433 649 tdb_trace(tdb, "tdb_lockall"); 434 return _tdb_lockall(tdb, F_WRLCK, F_SETLKW);650 return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false); 435 651 } 436 652 437 653 /* lock entire database with write lock - mark only */ 438 int tdb_lockall_mark(struct tdb_context *tdb)654 _PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb) 439 655 { 440 656 tdb_trace(tdb, "tdb_lockall_mark"); 441 return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW);657 return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false); 442 658 } 443 659 444 660 /* unlock entire database with write lock - unmark only */ 445 int tdb_lockall_unmark(struct tdb_context *tdb)661 _PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb) 446 662 { 447 663 tdb_trace(tdb, "tdb_lockall_unmark"); 448 return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK);664 return tdb_allrecord_unlock(tdb, F_WRLCK, true); 449 665 } 450 666 451 667 /* lock entire database with write lock - nonblocking varient */ 452 int tdb_lockall_nonblock(struct tdb_context *tdb)453 { 454 int ret = _tdb_lockall(tdb, F_WRLCK, F_SETLK);668 _PUBLIC_ int tdb_lockall_nonblock(struct tdb_context *tdb) 669 { 670 int ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false); 455 671 tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret); 456 672 return ret; … … 458 674 459 675 /* unlock entire database with write lock */ 460 int tdb_unlockall(struct tdb_context *tdb)676 _PUBLIC_ int tdb_unlockall(struct tdb_context *tdb) 461 677 { 462 678 tdb_trace(tdb, "tdb_unlockall"); 463 return _tdb_unlockall(tdb, F_WRLCK);679 return tdb_allrecord_unlock(tdb, F_WRLCK, false); 464 680 } 465 681 466 682 /* lock entire database with read lock */ 467 int tdb_lockall_read(struct tdb_context *tdb)683 _PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb) 468 684 { 469 685 tdb_trace(tdb, "tdb_lockall_read"); 470 return _tdb_lockall(tdb, F_RDLCK, F_SETLKW);686 return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false); 471 687 } 472 688 473 689 /* lock entire database with read lock - nonblock varient */ 474 int tdb_lockall_read_nonblock(struct tdb_context *tdb)475 { 476 int ret = _tdb_lockall(tdb, F_RDLCK, F_SETLK);690 _PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb) 691 { 692 int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false); 477 693 tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret); 478 694 return ret; … … 480 696 481 697 /* unlock entire database with read lock */ 482 int tdb_unlockall_read(struct tdb_context *tdb)698 _PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb) 483 699 { 484 700 tdb_trace(tdb, "tdb_unlockall_read"); 485 return _tdb_unlockall(tdb, F_RDLCK);701 return tdb_allrecord_unlock(tdb, F_RDLCK, false); 486 702 } 487 703 488 704 /* lock/unlock one hash chain. This is meant to be used to reduce 489 705 contention - it cannot guarantee how many records will be locked */ 490 int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)706 _PUBLIC_ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key) 491 707 { 492 708 int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); … … 498 714 to reduce contention - it cannot guarantee how many records will be 499 715 locked */ 500 int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)716 _PUBLIC_ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key) 501 717 { 502 718 int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); … … 506 722 507 723 /* mark a chain as locked without actually locking it. Warning! use with great caution! */ 508 int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key) 509 { 510 int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); 724 _PUBLIC_ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key) 725 { 726 int ret = tdb_nest_lock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))), 727 F_WRLCK, TDB_LOCK_MARK_ONLY); 511 728 tdb_trace_1rec(tdb, "tdb_chainlock_mark", key); 512 729 return ret; … … 514 731 515 732 /* unmark a chain as locked without actually locking it. Warning! use with great caution! */ 516 int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)733 _PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key) 517 734 { 518 735 tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key); 519 return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); 520 } 521 522 int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) 736 return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))), 737 F_WRLCK, true); 738 } 739 740 _PUBLIC_ int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) 523 741 { 524 742 tdb_trace_1rec(tdb, "tdb_chainunlock", key); … … 526 744 } 527 745 528 int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)746 _PUBLIC_ int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key) 529 747 { 530 748 int ret; … … 534 752 } 535 753 536 int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)754 _PUBLIC_ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key) 537 755 { 538 756 tdb_trace_1rec(tdb, "tdb_chainunlock_read", key); … … 540 758 } 541 759 542 543 544 760 /* record lock stops delete underneath */ 545 761 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off) 546 762 { 547 if (tdb-> global_lock.count) {548 return 0; 549 } 550 return off ? tdb ->methods->tdb_brlock(tdb, off, F_RDLCK, F_SETLKW, 0, 1) : 0;763 if (tdb->allrecord_lock.count) { 764 return 0; 765 } 766 return off ? tdb_brlock(tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT) : 0; 551 767 } 552 768 … … 562 778 if (i->off == off) 563 779 return -1; 564 return tdb->methods->tdb_brlock(tdb, off, F_WRLCK, F_SETLK, 1, 1); 565 } 566 567 /* 568 Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not 569 an error to fail to get the lock here. 570 */ 780 if (tdb->allrecord_lock.count) { 781 if (tdb->allrecord_lock.ltype == F_WRLCK) { 782 return 0; 783 } 784 return -1; 785 } 786 return tdb_brlock(tdb, F_WRLCK, off, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE); 787 } 788 571 789 int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off) 572 790 { 573 return tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLK, 0, 1); 791 if (tdb->allrecord_lock.count) { 792 return 0; 793 } 794 return tdb_brunlock(tdb, F_WRLCK, off, 1); 574 795 } 575 796 … … 580 801 uint32_t count = 0; 581 802 582 if (tdb-> global_lock.count) {803 if (tdb->allrecord_lock.count) { 583 804 return 0; 584 805 } … … 589 810 if (i->off == off) 590 811 count++; 591 return (count == 1 ? tdb->methods->tdb_brlock(tdb, off, F_UNLCK, F_SETLKW, 0, 1) : 0); 592 } 812 return (count == 1 ? tdb_brunlock(tdb, F_RDLCK, off, 1) : 0); 813 } 814 815 bool tdb_have_extra_locks(struct tdb_context *tdb) 816 { 817 unsigned int extra = tdb->num_lockrecs; 818 819 /* A transaction holds the lock for all records. */ 820 if (!tdb->transaction && tdb->allrecord_lock.count) { 821 return true; 822 } 823 824 /* We always hold the active lock if CLEAR_IF_FIRST. */ 825 if (find_nestlock(tdb, ACTIVE_LOCK)) { 826 extra--; 827 } 828 829 /* In a transaction, we expect to hold the transaction lock */ 830 if (tdb->transaction && find_nestlock(tdb, TRANSACTION_LOCK)) { 831 extra--; 832 } 833 834 return extra; 835 } 836 837 /* The transaction code uses this to remove all locks. */ 838 void tdb_release_transaction_locks(struct tdb_context *tdb) 839 { 840 unsigned int i, active = 0; 841 842 if (tdb->allrecord_lock.count != 0) { 843 tdb_brunlock(tdb, tdb->allrecord_lock.ltype, FREELIST_TOP, 0); 844 tdb->allrecord_lock.count = 0; 845 } 846 847 for (i=0;i<tdb->num_lockrecs;i++) { 848 struct tdb_lock_type *lck = &tdb->lockrecs[i]; 849 850 /* Don't release the active lock! Copy it to first entry. */ 851 if (lck->off == ACTIVE_LOCK) { 852 tdb->lockrecs[active++] = *lck; 853 } else { 854 tdb_brunlock(tdb, lck->ltype, lck->off, 1); 855 } 856 } 857 tdb->num_lockrecs = active; 858 if (tdb->num_lockrecs == 0) { 859 SAFE_FREE(tdb->lockrecs); 860 } 861 } -
vendor/current/lib/tdb/common/open.c
r414 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 31 31 static struct tdb_context *tdbs = NULL; 32 32 33 34 /* This is based on the hash algorithm from gdbm */ 35 static unsigned int default_tdb_hash(TDB_DATA *key) 36 { 37 uint32_t value; /* Used to compute the hash value. */ 38 uint32_t i; /* Used to cycle through random values. */ 39 40 /* Set the initial value from the key size. */ 41 for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) 42 value = (value + (key->dptr[i] << (i*5 % 24))); 43 44 return (1103515243 * value + 12345); 45 } 46 33 /* We use two hashes to double-check they're using the right hash function. */ 34 void tdb_header_hash(struct tdb_context *tdb, 35 uint32_t *magic1_hash, uint32_t *magic2_hash) 36 { 37 TDB_DATA hash_key; 38 uint32_t tdb_magic = TDB_MAGIC; 39 40 hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD); 41 hash_key.dsize = sizeof(TDB_MAGIC_FOOD); 42 *magic1_hash = tdb->hash_fn(&hash_key); 43 44 hash_key.dptr = (unsigned char *)CONVERT(tdb_magic); 45 hash_key.dsize = sizeof(tdb_magic); 46 *magic2_hash = tdb->hash_fn(&hash_key); 47 48 /* Make sure at least one hash is non-zero! */ 49 if (*magic1_hash == 0 && *magic2_hash == 0) 50 *magic1_hash = 1; 51 } 47 52 48 53 /* initialise a new database with a specified hash size */ … … 52 57 size_t size; 53 58 int ret = -1; 54 ssize_t written;55 59 56 60 /* We make it up in memory, then write it out if not internal */ … … 64 68 newdb->version = TDB_VERSION; 65 69 newdb->hash_size = hash_size; 70 71 tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash); 72 73 /* Make sure older tdbs (which don't check the magic hash fields) 74 * will refuse to open this TDB. */ 75 if (tdb->flags & TDB_INCOMPATIBLE_HASH) 76 newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC; 77 66 78 if (tdb->flags & TDB_INTERNAL) { 67 79 tdb->map_size = size; … … 84 96 memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); 85 97 /* we still have "ret == -1" here */ 86 written = write(tdb->fd, newdb, size); 87 if (written == size) { 98 if (tdb_write_all(tdb->fd, newdb, size)) 88 99 ret = 0; 89 } else if (written != -1) {90 /* call write once again, this usually should return -1 and91 * set errno appropriately */92 size -= written;93 written = write(tdb->fd, newdb+written, size);94 if (written == size) {95 ret = 0;96 } else if (written >= 0) {97 /* a second incomplete write - we give up.98 * guessing the errno... */99 errno = ENOSPC;100 }101 }102 100 103 101 fail: … … 112 110 { 113 111 struct tdb_context *i; 114 112 115 113 for (i = tdbs; i; i = i->next) { 116 114 if (i->device == device && i->inode == ino) { … … 132 130 133 131 @param name may be NULL for internal databases. */ 134 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,132 _PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, 135 133 int open_flags, mode_t mode) 136 134 { … … 144 142 } 145 143 146 147 struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, 144 static bool check_header_hash(struct tdb_context *tdb, 145 bool default_hash, uint32_t *m1, uint32_t *m2) 146 { 147 tdb_header_hash(tdb, m1, m2); 148 if (tdb->header.magic1_hash == *m1 && 149 tdb->header.magic2_hash == *m2) { 150 return true; 151 } 152 153 /* If they explicitly set a hash, always respect it. */ 154 if (!default_hash) 155 return false; 156 157 /* Otherwise, try the other inbuilt hash. */ 158 if (tdb->hash_fn == tdb_old_hash) 159 tdb->hash_fn = tdb_jenkins_hash; 160 else 161 tdb->hash_fn = tdb_old_hash; 162 return check_header_hash(tdb, false, m1, m2); 163 } 164 165 _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, 148 166 int open_flags, mode_t mode, 149 167 const struct tdb_logging_context *log_ctx, … … 156 174 uint32_t vertest; 157 175 unsigned v; 176 const char *hash_alg; 177 uint32_t magic1, magic2; 158 178 159 179 if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { … … 177 197 tdb->log.log_private = NULL; 178 198 } 179 tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash; 199 200 if (name == NULL && (tdb_flags & TDB_INTERNAL)) { 201 name = "__TDB_INTERNAL__"; 202 } 203 204 if (name == NULL) { 205 tdb->name = discard_const_p(char, "__NULL__"); 206 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n")); 207 tdb->name = NULL; 208 errno = EINVAL; 209 goto fail; 210 } 211 212 /* now make a copy of the name, as the caller memory might went away */ 213 if (!(tdb->name = (char *)strdup(name))) { 214 /* 215 * set the name as the given string, so that tdb_name() will 216 * work in case of an error. 217 */ 218 tdb->name = discard_const_p(char, name); 219 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n", 220 name)); 221 tdb->name = NULL; 222 errno = ENOMEM; 223 goto fail; 224 } 225 226 if (hash_fn) { 227 tdb->hash_fn = hash_fn; 228 hash_alg = "the user defined"; 229 } else { 230 /* This controls what we use when creating a tdb. */ 231 if (tdb->flags & TDB_INCOMPATIBLE_HASH) { 232 tdb->hash_fn = tdb_jenkins_hash; 233 } else { 234 tdb->hash_fn = tdb_old_hash; 235 } 236 hash_alg = "either default"; 237 } 180 238 181 239 /* cache the page size */ … … 193 251 goto fail; 194 252 } 195 253 196 254 if (hash_size == 0) 197 255 hash_size = DEFAULT_HASH_SIZE; … … 212 270 } 213 271 272 if (getenv("TDB_NO_FSYNC")) { 273 tdb->flags |= TDB_NOSYNC; 274 } 275 214 276 /* 215 277 * TDB_ALLOW_NESTING is the default behavior. … … 242 304 243 305 /* ensure there is only one process initialising at once */ 244 if (tdb ->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {245 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get globallock on %s: %s\n",306 if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) { 307 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n", 246 308 name, strerror(errno))); 247 309 goto fail; /* errno set by tdb_brlock */ … … 251 313 if ((tdb_flags & TDB_CLEAR_IF_FIRST) && 252 314 (!tdb->read_only) && 253 (locked = (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) {315 (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) { 254 316 open_flags |= O_CREAT; 255 317 if (ftruncate(tdb->fd, 0) == -1) { … … 290 352 goto fail; 291 353 292 if (tdb->header.rwlocks != 0) { 354 if (tdb->header.rwlocks != 0 && 355 tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) { 293 356 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n")); 357 goto fail; 358 } 359 360 if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) { 361 /* older TDB without magic hash references */ 362 tdb->hash_fn = tdb_old_hash; 363 } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) { 364 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " 365 "%s was not created with %s hash function we are using\n" 366 "magic1_hash[0x%08X %s 0x%08X] " 367 "magic2_hash[0x%08X %s 0x%08X]\n", 368 name, hash_alg, 369 tdb->header.magic1_hash, 370 (tdb->header.magic1_hash == magic1) ? "==" : "!=", 371 magic1, 372 tdb->header.magic2_hash, 373 (tdb->header.magic2_hash == magic2) ? "==" : "!=", 374 magic2)); 375 errno = EINVAL; 294 376 goto fail; 295 377 } … … 304 386 } 305 387 306 if (!(tdb->name = (char *)strdup(name))) {307 errno = ENOMEM;308 goto fail;309 }310 311 388 tdb->map_size = st.st_size; 312 389 tdb->device = st.st_dev; … … 314 391 tdb_mmap(tdb); 315 392 if (locked) { 316 if (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {393 if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) { 317 394 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " 318 "failed to take ACTIVE_LOCK on %s: %s\n",395 "failed to release ACTIVE_LOCK on %s: %s\n", 319 396 name, strerror(errno))); 320 397 goto fail; … … 329 406 if (tdb_flags & TDB_CLEAR_IF_FIRST) { 330 407 /* leave this lock in place to indicate it's in use */ 331 if (tdb ->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)408 if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { 332 409 goto fail; 410 } 333 411 } 334 412 … … 357 435 /* Internal (memory-only) databases skip all the code above to 358 436 * do with disk files, and resume here by releasing their 359 * global lock and hooking into the active list. */ 360 if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1) 361 goto fail; 437 * open lock and hooking into the active list. */ 438 if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) { 439 goto fail; 440 } 362 441 tdb->next = tdbs; 363 442 tdbs = tdb; … … 379 458 tdb_munmap(tdb); 380 459 } 381 SAFE_FREE(tdb->name);382 460 if (tdb->fd != -1) 383 461 if (close(tdb->fd) != 0) 384 462 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n")); 463 SAFE_FREE(tdb->lockrecs); 464 SAFE_FREE(tdb->name); 385 465 SAFE_FREE(tdb); 386 466 errno = save_errno; … … 393 473 */ 394 474 395 void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)475 _PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead) 396 476 { 397 477 tdb->max_dead_records = max_dead; … … 403 483 * @returns -1 for error; 0 for success. 404 484 **/ 405 int tdb_close(struct tdb_context *tdb)485 _PUBLIC_ int tdb_close(struct tdb_context *tdb) 406 486 { 407 487 struct tdb_context **i; 408 488 int ret = 0; 409 489 490 if (tdb->transaction) { 491 tdb_transaction_cancel(tdb); 492 } 410 493 tdb_trace(tdb, "tdb_close"); 411 if (tdb->transaction) {412 _tdb_transaction_cancel(tdb);413 }414 494 415 495 if (tdb->map_ptr) { … … 444 524 445 525 /* register a loging function */ 446 void tdb_set_logging_function(struct tdb_context *tdb,447 const struct tdb_logging_context *log_ctx)526 _PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb, 527 const struct tdb_logging_context *log_ctx) 448 528 { 449 529 tdb->log = *log_ctx; 450 530 } 451 531 452 void *tdb_get_logging_private(struct tdb_context *tdb)532 _PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb) 453 533 { 454 534 return tdb->log.log_private; … … 466 546 } 467 547 468 if (tdb ->num_locks != 0 || tdb->global_lock.count) {548 if (tdb_have_extra_locks(tdb)) { 469 549 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n")); 470 550 goto fail; … … 501 581 #endif /* fake pread or pwrite */ 502 582 503 if (active_lock && 504 (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) { 583 /* We may still think we hold the active lock. */ 584 tdb->num_lockrecs = 0; 585 SAFE_FREE(tdb->lockrecs); 586 587 if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { 505 588 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n")); 506 589 goto fail; … … 516 599 /* reopen a tdb - this can be used after a fork to ensure that we have an independent 517 600 seek pointer from our parent and to re-establish locks */ 518 int tdb_reopen(struct tdb_context *tdb)601 _PUBLIC_ int tdb_reopen(struct tdb_context *tdb) 519 602 { 520 603 return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST); … … 522 605 523 606 /* reopen all tdb's */ 524 int tdb_reopen_all(int parent_longlived)607 _PUBLIC_ int tdb_reopen_all(int parent_longlived) 525 608 { 526 609 struct tdb_context *tdb; -
vendor/current/lib/tdb/common/tdb.c
r414 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 28 28 #include "tdb_private.h" 29 29 30 TDB_DATA tdb_null;30 _PUBLIC_ TDB_DATA tdb_null; 31 31 32 32 /* … … 34 34 the TDB_SEQNUM flag 35 35 */ 36 void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)36 _PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb) 37 37 { 38 38 tdb_off_t seqnum=0; 39 39 40 40 if (!(tdb->flags & TDB_SEQNUM)) { 41 41 return; … … 60 60 } 61 61 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) { 63 64 return; 64 65 } … … 66 67 tdb_increment_seqnum_nonblock(tdb); 67 68 68 tdb_ brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);69 tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false); 69 70 } 70 71 … … 80 81 { 81 82 tdb_off_t rec_ptr; 82 83 83 84 /* read in the hash top */ 84 85 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 154 155 } 155 156 } 156 157 157 158 158 /* must be long enough key, data and tailer */ … … 171 171 return tdb_rec_write(tdb, rec_ptr, &rec); 172 172 } 173 173 174 174 return 0; 175 175 } … … 200 200 } 201 201 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) 203 203 { 204 204 TDB_DATA ret = _tdb_fetch(tdb, key); … … 213 213 * should be fast and should not block on other syscalls. 214 214 * 215 * DON T 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. 216 216 * 217 217 * For mmapped tdb's that do not have a transaction open it points the parsing … … 222 222 * This is interesting for all readers of potentially large data structures in 223 223 * the tdb records, ldb indexes being one example. 224 * 225 * Return -1 if the record was not found. 224 226 */ 225 227 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, 227 229 int (*parser)(TDB_DATA key, TDB_DATA data, 228 230 void *private_data), … … 238 240 239 241 if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) { 242 /* record not found */ 240 243 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1); 241 244 tdb->ecode = TDB_ERR_NOEXIST; 242 return 0;245 return -1; 243 246 } 244 247 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0); … … 261 264 { 262 265 struct tdb_record rec; 263 266 264 267 if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0) 265 268 return 0; … … 268 271 } 269 272 270 int tdb_exists(struct tdb_context *tdb, TDB_DATA key)273 _PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key) 271 274 { 272 275 uint32_t hash = tdb->hash_fn(&key); … … 319 322 tdb_off_t rec_ptr; 320 323 struct tdb_record rec; 321 324 322 325 /* read in the hash top */ 323 326 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 348 351 return -1; 349 352 } 350 353 351 354 /* read in the hash top */ 352 355 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 427 430 } 428 431 429 int tdb_delete(struct tdb_context *tdb, TDB_DATA key)432 _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key) 430 433 { 431 434 uint32_t hash = tdb->hash_fn(&key); … … 444 447 { 445 448 tdb_off_t rec_ptr; 446 449 447 450 /* read in the hash top */ 448 451 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) … … 597 600 return 0 on success, -1 on failure 598 601 */ 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) 600 603 { 601 604 uint32_t hash; … … 620 623 621 624 /* 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) 623 626 { 624 627 uint32_t hash; … … 659 662 ret = _tdb_store(tdb, key, dbuf, 0, hash); 660 663 tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf); 661 664 662 665 failed: 663 666 tdb_unlock(tdb, BUCKET(hash), F_WRLCK); … … 671 674 useful for external logging functions 672 675 */ 673 const char *tdb_name(struct tdb_context *tdb)676 _PUBLIC_ const char *tdb_name(struct tdb_context *tdb) 674 677 { 675 678 return tdb->name; … … 681 684 of the fd 682 685 */ 683 int tdb_fd(struct tdb_context *tdb)686 _PUBLIC_ int tdb_fd(struct tdb_context *tdb) 684 687 { 685 688 return tdb->fd; … … 690 693 useful for external tdb routines that wish to log tdb errors 691 694 */ 692 tdb_log_func tdb_log_fn(struct tdb_context *tdb)695 _PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb) 693 696 { 694 697 return tdb->log.log_fn; … … 706 709 test of a possible tdb change. 707 710 */ 708 int tdb_get_seqnum(struct tdb_context *tdb)711 _PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb) 709 712 { 710 713 tdb_off_t seqnum=0; … … 714 717 } 715 718 716 int tdb_hash_size(struct tdb_context *tdb)719 _PUBLIC_ int tdb_hash_size(struct tdb_context *tdb) 717 720 { 718 721 return tdb->header.hash_size; 719 722 } 720 723 721 size_t tdb_map_size(struct tdb_context *tdb)724 _PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb) 722 725 { 723 726 return tdb->map_size; 724 727 } 725 728 726 int tdb_get_flags(struct tdb_context *tdb)729 _PUBLIC_ int tdb_get_flags(struct tdb_context *tdb) 727 730 { 728 731 return tdb->flags; 729 732 } 730 733 731 void tdb_add_flags(struct tdb_context *tdb, unsigned flags)734 _PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flags) 732 735 { 733 736 if ((flags & TDB_ALLOW_NESTING) && … … 749 752 } 750 753 751 void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)754 _PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flags) 752 755 { 753 756 if ((flags & TDB_ALLOW_NESTING) && … … 773 776 enable sequence number handling on an open tdb 774 777 */ 775 void tdb_enable_seqnum(struct tdb_context *tdb)778 _PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb) 776 779 { 777 780 tdb->flags |= TDB_SEQNUM; … … 805 808 /* 806 809 wipe the entire database, deleting all records. This can be done 807 very fast by using a globallock. The entire data portion of the810 very fast by using a allrecord lock. The entire data portion of the 808 811 file becomes a single entry in the freelist. 809 812 810 813 This code carefully steps around the recovery area, leaving it alone 811 814 */ 812 int tdb_wipe_all(struct tdb_context *tdb)815 _PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb) 813 816 { 814 817 int i; … … 917 920 repack a tdb 918 921 */ 919 int tdb_repack(struct tdb_context *tdb)922 _PUBLIC_ int tdb_repack(struct tdb_context *tdb) 920 923 { 921 924 struct tdb_context *tmp_db; … … 987 990 } 988 991 992 /* Even on files, we can get partial writes due to signals. */ 993 bool 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 989 1006 #ifdef TDB_TRACE 990 1007 static void tdb_trace_write(struct tdb_context *tdb, const char *str) 991 1008 { 992 if ( write(tdb->tracefd, str, strlen(str)) !=strlen(str)) {1009 if (!tdb_write_alltdb->tracefd, str, strlen(str)) { 993 1010 close(tdb->tracefd); 994 1011 tdb->tracefd = -1; -
vendor/current/lib/tdb/common/tdb_private.h
r414 r740 5 5 6 6 Copyright (C) Andrew Tridgell 2005 7 7 8 8 ** NOTE! The following LGPL license applies to the tdb 9 9 ** library. This does NOT imply that all of Samba is released 10 10 ** under the LGPL 11 11 12 12 This library is free software; you can redistribute it and/or 13 13 modify it under the terms of the GNU Lesser General Public … … 50 50 #define TDB_DEAD_MAGIC (0xFEE1DEAD) 51 51 #define TDB_RECOVERY_MAGIC (0xf53bc0e7U) 52 #define TDB_RECOVERY_INVALID_MAGIC (0x0) 53 #define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U) 52 54 #define TDB_ALIGNMENT 4 53 55 #define DEFAULT_HASH_SIZE 131 … … 102 104 103 105 /* lock offsets */ 104 #define GLOBAL_LOCK0106 #define OPEN_LOCK 0 105 107 #define ACTIVE_LOCK 4 106 108 #define TRANSACTION_LOCK 8 … … 147 149 tdb_off_t recovery_start; /* offset of transaction recovery region */ 148 150 tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */ 149 tdb_off_t reserved[29]; 151 uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */ 152 uint32_t magic2_hash; /* hash of TDB_MAGIC. */ 153 tdb_off_t reserved[27]; 150 154 }; 151 155 152 156 struct tdb_lock_type { 153 int list;157 uint32_t off; 154 158 uint32_t count; 155 159 uint32_t ltype; … … 163 167 }; 164 168 169 enum tdb_lock_flags { 170 /* WAIT == F_SETLKW, NOWAIT == F_SETLK */ 171 TDB_LOCK_NOWAIT = 0, 172 TDB_LOCK_WAIT = 1, 173 /* If set, don't log an error on failure. */ 174 TDB_LOCK_PROBE = 2, 175 /* If set, don't actually lock at all. */ 176 TDB_LOCK_MARK_ONLY = 4, 177 }; 165 178 166 179 struct tdb_methods { … … 170 183 int (*tdb_oob)(struct tdb_context *, tdb_off_t , int ); 171 184 int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t ); 172 int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_t);173 185 }; 174 186 … … 181 193 int traverse_read; /* read-only traversal */ 182 194 int traverse_write; /* read-write traversal */ 183 struct tdb_lock_type global_lock;195 struct tdb_lock_type allrecord_lock; /* .offset == upgradable */ 184 196 int num_lockrecs; 185 197 struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */ … … 194 206 unsigned int (*hash_fn)(TDB_DATA *key); 195 207 int open_flags; /* flags used in the open - needed by reopen */ 196 unsigned int num_locks; /* number of chain locks held */197 208 const struct tdb_methods *methods; 198 209 struct tdb_transaction *transaction; 199 210 int page_size; 200 211 int max_dead_records; 201 int transaction_lock_count;202 212 #ifdef TDB_TRACE 203 213 int tracefd; … … 214 224 int tdb_lock(struct tdb_context *tdb, int list, int ltype); 215 225 int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype); 226 int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype, 227 enum tdb_lock_flags flags); 228 int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype, 229 bool mark_lock); 216 230 int tdb_unlock(struct tdb_context *tdb, int list, int ltype); 217 int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len); 218 int tdb_transaction_lock(struct tdb_context *tdb, int ltype); 219 int tdb_transaction_unlock(struct tdb_context *tdb); 220 int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len); 231 int tdb_brlock(struct tdb_context *tdb, 232 int rw_type, tdb_off_t offset, size_t len, 233 enum tdb_lock_flags flags); 234 int tdb_brunlock(struct tdb_context *tdb, 235 int rw_type, tdb_off_t offset, size_t len); 236 bool tdb_have_extra_locks(struct tdb_context *tdb); 237 void tdb_release_transaction_locks(struct tdb_context *tdb); 238 int tdb_transaction_lock(struct tdb_context *tdb, int ltype, 239 enum tdb_lock_flags lockflags); 240 int tdb_transaction_unlock(struct tdb_context *tdb, int ltype); 241 int tdb_recovery_area(struct tdb_context *tdb, 242 const struct tdb_methods *methods, 243 tdb_off_t *recovery_offset, 244 struct tdb_record *rec); 245 int tdb_allrecord_lock(struct tdb_context *tdb, int ltype, 246 enum tdb_lock_flags flags, bool upgradable); 247 int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock); 248 int tdb_allrecord_upgrade(struct tdb_context *tdb); 221 249 int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off); 222 250 int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off); … … 230 258 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off); 231 259 int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off); 232 int _tdb_transaction_cancel(struct tdb_context *tdb);260 bool tdb_needs_recovery(struct tdb_context *tdb); 233 261 int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); 234 262 int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); … … 246 274 int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, 247 275 struct tdb_record *rec); 248 249 276 bool tdb_write_all(int fd, const void *buf, size_t count); 277 int tdb_transaction_recover(struct tdb_context *tdb); 278 void tdb_header_hash(struct tdb_context *tdb, 279 uint32_t *magic1_hash, uint32_t *magic2_hash); 280 unsigned int tdb_old_hash(TDB_DATA *key); 281 size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off); -
vendor/current/lib/tdb/common/transaction.c
r414 r740 9 9 ** library. This does NOT imply that all of Samba is released 10 10 ** under the LGPL 11 11 12 12 This library is free software; you can redistribute it and/or 13 13 modify it under the terms of the GNU Lesser General Public … … 60 60 existing transaction record. If the inner transaction is cancelled 61 61 then a subsequent commit will fail 62 62 63 63 - keep a mirrored copy of the tdb hash chain heads to allow for the 64 64 fast hash heads scan on traverse, updating the mirrored copy in … … 77 77 78 78 - check for a valid recovery record on open of the tdb, while the 79 globallock is held. Automatically recover from the transaction79 open lock is held. Automatically recover from the transaction 80 80 recovery area if needed, then continue with the open as 81 81 usual. This allows for smooth crash recovery with no administrator … … 136 136 tdb_off_t magic_offset; 137 137 138 /* set when the GLOBAL_LOCK has been taken */139 bool global_lock_taken;140 141 138 /* old file size before transaction */ 142 139 tdb_len_t old_map_size; 143 140 144 /* we should re-pack on commit*/145 bool need_repack;141 /* did we expand in this transaction */ 142 bool expanded; 146 143 }; 147 144 … … 189 186 } 190 187 } 191 188 192 189 /* now copy it out of this block */ 193 190 memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len); … … 296 293 } 297 294 } 298 295 299 296 /* overwrite part of an existing block */ 300 297 if (buf == NULL) { … … 407 404 } 408 405 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 420 408 return 0; 421 409 } … … 427 415 transaction_oob, 428 416 transaction_expand_file, 429 transaction_brlock430 417 }; 431 418 … … 435 422 transaction is allowed to be pending per tdb_context 436 423 */ 437 int tdb_transaction_start(struct tdb_context *tdb) 424 static int _tdb_transaction_start(struct tdb_context *tdb, 425 enum tdb_lock_flags lockflags) 438 426 { 439 427 /* some sanity checks */ … … 456 444 } 457 445 458 if (tdb ->num_locks != 0 || tdb->global_lock.count) {446 if (tdb_have_extra_locks(tdb)) { 459 447 /* the caller must not have any locks when starting a 460 448 transaction as otherwise we'll be screwed by lack … … 487 475 discussed with Volker, there are a number of ways we could 488 476 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) { 490 478 SAFE_FREE(tdb->transaction->blocks); 491 479 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 495 486 /* get a read lock from the freelist to the end of file. This 496 487 is upgraded to a write lock during the commit */ 497 if (tdb_ brlock(tdb, FREELIST_TOP, F_RDLCK, F_SETLKW, 0, 0) == -1) {488 if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, true) == -1) { 498 489 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n")); 499 tdb->ecode = TDB_ERR_LOCK; 500 goto fail; 490 goto fail_allrecord_lock; 501 491 } 502 492 … … 529 519 tdb_trace(tdb, "tdb_transaction_start"); 530 520 return 0; 531 521 532 522 fail: 533 tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0); 534 tdb_transaction_unlock(tdb); 523 tdb_allrecord_unlock(tdb, F_RDLCK, false); 524 fail_allrecord_lock: 525 tdb_transaction_unlock(tdb, F_WRLCK); 535 526 SAFE_FREE(tdb->transaction->blocks); 536 527 SAFE_FREE(tdb->transaction->hash_heads); … … 539 530 } 540 531 532 _PUBLIC_ int tdb_transaction_start(struct tdb_context *tdb) 533 { 534 return _tdb_transaction_start(tdb, TDB_LOCK_WAIT); 535 } 536 537 _PUBLIC_ int tdb_transaction_start_nonblock(struct tdb_context *tdb) 538 { 539 return _tdb_transaction_start(tdb, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE); 540 } 541 541 542 542 /* … … 549 549 } 550 550 551 #ifdef HAVE_FDATASYNC 552 if (fdatasync(tdb->fd) != 0) { 553 #else 551 554 if (fsync(tdb->fd) != 0) { 555 #endif 552 556 tdb->ecode = TDB_ERR_IO; 553 557 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); … … 570 574 571 575 572 int _tdb_transaction_cancel(struct tdb_context *tdb)576 static int _tdb_transaction_cancel(struct tdb_context *tdb) 573 577 { 574 578 int i, ret = 0; … … 597 601 if (tdb->transaction->magic_offset) { 598 602 const struct tdb_methods *methods = tdb->transaction->io_methods; 599 uint32_t zero = 0;603 const uint32_t invalid = TDB_RECOVERY_INVALID_MAGIC; 600 604 601 605 /* remove the recovery marker */ 602 if (methods->tdb_write(tdb, tdb->transaction->magic_offset, & zero, 4) == -1 ||606 if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &invalid, 4) == -1 || 603 607 transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) { 604 608 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n")); … … 607 611 } 608 612 609 if (tdb->transaction->global_lock_taken) { 610 tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); 611 tdb->transaction->global_lock_taken = false; 612 } 613 614 /* remove any global lock created during the transaction */ 615 if (tdb->global_lock.count != 0) { 616 tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size); 617 tdb->global_lock.count = 0; 618 } 619 620 /* remove any locks created during the transaction */ 621 if (tdb->num_locks != 0) { 622 for (i=0;i<tdb->num_lockrecs;i++) { 623 tdb_brlock(tdb,FREELIST_TOP+4*tdb->lockrecs[i].list, 624 F_UNLCK,F_SETLKW, 0, 1); 625 } 626 tdb->num_locks = 0; 627 tdb->num_lockrecs = 0; 628 SAFE_FREE(tdb->lockrecs); 629 } 613 /* This also removes the OPEN_LOCK, if we have it. */ 614 tdb_release_transaction_locks(tdb); 630 615 631 616 /* restore the normal io methods */ 632 617 tdb->methods = tdb->transaction->io_methods; 633 618 634 tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 0);635 tdb_transaction_unlock(tdb);636 619 SAFE_FREE(tdb->transaction->hash_heads); 637 620 SAFE_FREE(tdb->transaction); 638 621 639 622 return ret; 640 623 } … … 643 626 cancel the current transaction 644 627 */ 645 int tdb_transaction_cancel(struct tdb_context *tdb)628 _PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb) 646 629 { 647 630 tdb_trace(tdb, "tdb_transaction_cancel"); … … 676 659 } 677 660 661 int tdb_recovery_area(struct tdb_context *tdb, 662 const struct tdb_methods *methods, 663 tdb_off_t *recovery_offset, 664 struct tdb_record *rec) 665 { 666 if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, recovery_offset) == -1) { 667 return -1; 668 } 669 670 if (*recovery_offset == 0) { 671 rec->rec_len = 0; 672 return 0; 673 } 674 675 if (methods->tdb_read(tdb, *recovery_offset, rec, sizeof(*rec), 676 DOCONV()) == -1) { 677 return -1; 678 } 679 680 /* ignore invalid recovery regions: can happen in crash */ 681 if (rec->magic != TDB_RECOVERY_MAGIC && 682 rec->magic != TDB_RECOVERY_INVALID_MAGIC) { 683 *recovery_offset = 0; 684 rec->rec_len = 0; 685 } 686 return 0; 687 } 688 678 689 /* 679 690 allocate the recovery area, or use an existing recovery area if it is … … 689 700 tdb_off_t recovery_head; 690 701 691 if (tdb_ ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {702 if (tdb_recovery_area(tdb, methods, &recovery_head, &rec) == -1) { 692 703 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n")); 693 return -1;694 }695 696 rec.rec_len = 0;697 698 if (recovery_head != 0 &&699 methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {700 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));701 704 return -1; 702 705 } … … 794 797 memset(rec, 0, sizeof(*rec)); 795 798 796 rec->magic = 0;799 rec->magic = TDB_RECOVERY_INVALID_MAGIC; 797 800 rec->data_len = recovery_size; 798 801 rec->rec_len = recovery_max_size; 799 802 rec->key_len = old_map_size; 800 CONVERT( rec);803 CONVERT(*rec); 801 804 802 805 /* build the recovery data into a single blob to allow us to do a single … … 816 819 length = tdb->transaction->last_block_size; 817 820 } 818 821 819 822 if (offset >= old_map_size) { 820 823 continue; … … 845 848 tailer = sizeof(*rec) + recovery_max_size; 846 849 memcpy(p, &tailer, 4); 847 CONVERT(p); 850 if (DOCONV()) { 851 tdb_convert(p, 4); 852 } 848 853 849 854 /* write the recovery data to the recovery area */ … … 929 934 930 935 methods = tdb->transaction->io_methods; 931 936 932 937 /* if there are any locks pending then the caller has not 933 938 nested their locks properly, so fail the transaction */ 934 if (tdb ->num_locks || tdb->global_lock.count) {939 if (tdb_have_extra_locks(tdb)) { 935 940 tdb->ecode = TDB_ERR_LOCK; 936 941 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n")); … … 940 945 941 946 /* upgrade the main transaction lock region to a write lock */ 942 if (tdb_ brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {947 if (tdb_allrecord_upgrade(tdb) == -1) { 943 948 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n")); 944 tdb->ecode = TDB_ERR_LOCK;945 949 _tdb_transaction_cancel(tdb); 946 950 return -1; 947 951 } 948 952 949 /* get the globallock - this prevents new users attaching to the database953 /* get the open lock - this prevents new users attaching to the database 950 954 during the commit */ 951 if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { 952 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n")); 953 tdb->ecode = TDB_ERR_LOCK; 955 if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) { 956 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get open lock\n")); 954 957 _tdb_transaction_cancel(tdb); 955 958 return -1; 956 959 } 957 958 tdb->transaction->global_lock_taken = true;959 960 960 961 if (!(tdb->flags & TDB_NOSYNC)) { … … 983 984 } 984 985 985 /* Keep the globallock until the actual commit */986 /* Keep the open lock until the actual commit */ 986 987 987 988 return 0; … … 991 992 prepare to commit the current transaction 992 993 */ 993 int tdb_transaction_prepare_commit(struct tdb_context *tdb)994 { 994 _PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb) 995 { 995 996 tdb_trace(tdb, "tdb_transaction_prepare_commit"); 996 997 return _tdb_transaction_prepare_commit(tdb); 997 998 } 998 999 1000 /* A repack is worthwhile if the largest is less than half total free. */ 1001 static bool repack_worthwhile(struct tdb_context *tdb) 1002 { 1003 tdb_off_t ptr; 1004 struct tdb_record rec; 1005 tdb_len_t total = 0, largest = 0; 1006 1007 if (tdb_ofs_read(tdb, FREELIST_TOP, &ptr) == -1) { 1008 return false; 1009 } 1010 1011 while (ptr != 0 && tdb_rec_free_read(tdb, ptr, &rec) == 0) { 1012 total += rec.rec_len; 1013 if (rec.rec_len > largest) { 1014 largest = rec.rec_len; 1015 } 1016 ptr = rec.next; 1017 } 1018 1019 return total > largest * 2; 1020 } 1021 999 1022 /* 1000 1023 commit the current transaction 1001 1024 */ 1002 int tdb_transaction_commit(struct tdb_context *tdb)1003 { 1025 _PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb) 1026 { 1004 1027 const struct tdb_methods *methods; 1005 1028 int i; 1006 bool need_repack ;1029 bool need_repack = false; 1007 1030 1008 1031 if (tdb->transaction == NULL) { … … 1057 1080 if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) { 1058 1081 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n")); 1059 1082 1060 1083 /* we've overwritten part of the data and 1061 1084 possibly expanded the file, so we need to … … 1071 1094 SAFE_FREE(tdb->transaction->blocks[i]); 1072 1095 } 1096 1097 /* Do this before we drop lock or blocks. */ 1098 if (tdb->transaction->expanded) { 1099 need_repack = repack_worthwhile(tdb); 1100 } 1073 1101 1074 1102 SAFE_FREE(tdb->transaction->blocks); … … 1095 1123 #endif 1096 1124 1097 need_repack = tdb->transaction->need_repack;1098 1099 1125 /* use a transaction cancel to free memory and remove the 1100 1126 transaction locks */ … … 1111 1137 /* 1112 1138 recover from an aborted transaction. Must be called with exclusive 1113 database write access already established (including the global1139 database write access already established (including the open 1114 1140 lock to prevent new processes attaching) 1115 1141 */ … … 1212 1238 return -1; 1213 1239 } 1214 1215 /* reduce the file size to the old size */1216 tdb_munmap(tdb);1217 if (ftruncate(tdb->fd, recovery_eof) != 0) {1218 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to reduce to recovery size\n"));1219 tdb->ecode = TDB_ERR_IO;1220 return -1;1221 }1222 tdb->map_size = recovery_eof;1223 tdb_mmap(tdb);1224 1240 1225 1241 if (transaction_sync(tdb, 0, recovery_eof) == -1) { … … 1235 1251 return 0; 1236 1252 } 1253 1254 /* Any I/O failures we say "needs recovery". */ 1255 bool tdb_needs_recovery(struct tdb_context *tdb) 1256 { 1257 tdb_off_t recovery_head; 1258 struct tdb_record rec; 1259 1260 /* find the recovery area */ 1261 if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { 1262 return true; 1263 } 1264 1265 if (recovery_head == 0) { 1266 /* we have never allocated a recovery record */ 1267 return false; 1268 } 1269 1270 /* read the recovery record */ 1271 if (tdb->methods->tdb_read(tdb, recovery_head, &rec, 1272 sizeof(rec), DOCONV()) == -1) { 1273 return true; 1274 } 1275 1276 return (rec.magic == TDB_RECOVERY_MAGIC); 1277 } -
vendor/current/lib/tdb/common/traverse.c
r414 r740 7 7 Copyright (C) Paul `Rusty' Russell 2000 8 8 Copyright (C) Jeremy Allison 2000-2003 9 9 10 10 ** NOTE! The following LGPL license applies to the tdb 11 11 ** library. This does NOT imply that all of Samba is released 12 12 ** under the LGPL 13 13 14 14 This library is free software; you can redistribute it and/or 15 15 modify it under the terms of the GNU Lesser General Public … … 45 45 hashes are used. In that case we spend most of our 46 46 time in tdb_brlock(), locking empty hash chains. 47 47 48 48 To avoid this, we do an unlocked pre-check to see 49 49 if the hash chain is empty before starting to look … … 53 53 lock, so instead we get the lock and re-fetch the 54 54 value below. 55 55 56 56 Notice that not doing this optimisation on the 57 57 first hash chain is critical. We must guarantee … … 63 63 could miss them anyway without this trick, so the 64 64 semantics don't change. 65 65 66 66 With a non-indexed ldb search this trick gains us a 67 67 factor of around 80 in speed on a linux 2.6.x … … 213 213 a write style traverse - temporarily marks the db read only 214 214 */ 215 int tdb_traverse_read(struct tdb_context *tdb,215 _PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb, 216 216 tdb_traverse_func fn, void *private_data) 217 217 { … … 221 221 /* we need to get a read lock on the transaction lock here to 222 222 cope with the lock ordering semantics of solaris10 */ 223 if (tdb_transaction_lock(tdb, F_RDLCK )) {223 if (tdb_transaction_lock(tdb, F_RDLCK, TDB_LOCK_WAIT)) { 224 224 return -1; 225 225 } … … 230 230 tdb->traverse_read--; 231 231 232 tdb_transaction_unlock(tdb );232 tdb_transaction_unlock(tdb, F_RDLCK); 233 233 234 234 return ret; … … 242 242 alignment restrictions malloc gives you. 243 243 */ 244 int tdb_traverse(struct tdb_context *tdb,244 _PUBLIC_ int tdb_traverse(struct tdb_context *tdb, 245 245 tdb_traverse_func fn, void *private_data) 246 246 { … … 252 252 } 253 253 254 if (tdb_transaction_lock(tdb, F_WRLCK )) {254 if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) { 255 255 return -1; 256 256 } … … 261 261 tdb->traverse_write--; 262 262 263 tdb_transaction_unlock(tdb );263 tdb_transaction_unlock(tdb, F_WRLCK); 264 264 265 265 return ret; … … 268 268 269 269 /* find the first entry in the database and return its key */ 270 TDB_DATA tdb_firstkey(struct tdb_context *tdb)270 _PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb) 271 271 { 272 272 TDB_DATA key; … … 299 299 300 300 /* find the next entry in the database, returning its key */ 301 TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)301 _PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey) 302 302 { 303 303 uint32_t oldhash; -
vendor/current/lib/tdb/docs/README
r414 r740 106 106 107 107 ---------------------------------------------------------------------- 108 int 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 ---------------------------------------------------------------------- 108 127 int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key); 109 128 -
vendor/current/lib/tdb/include/tdb.h
r414 r740 31 31 #endif 32 32 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 */ 55 85 enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, 56 86 TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT, … … 58 88 TDB_ERR_NESTING}; 59 89 60 /* debugging uses one of the following levels */90 /** Debugging uses one of the following levels */ 61 91 enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR, 62 92 TDB_DEBUG_WARNING, TDB_DEBUG_TRACE}; 63 93 94 /** The tdb data structure */ 64 95 typedef struct TDB_DATA { 65 96 unsigned char *dptr; … … 79 110 #endif 80 111 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. */ 82 113 typedef struct tdb_context TDB_CONTEXT; 83 114 … … 91 122 }; 92 123 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 */ 93 153 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, 94 154 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 */ 95 195 struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, 96 196 int open_flags, mode_t mode, 97 197 const struct tdb_logging_context *log_ctx, 98 198 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 */ 99 207 void tdb_set_max_dead(struct tdb_context *tdb, int max_dead); 100 208 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 */ 101 219 int 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 */ 102 234 int 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 */ 103 243 void 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 */ 104 254 enum 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 */ 105 263 const 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 */ 106 280 TDB_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 */ 107 305 int 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 */ 111 319 int 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 */ 112 341 int 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 */ 113 359 int 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 */ 114 368 int 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 */ 115 380 TDB_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 */ 116 394 TDB_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 */ 416 int 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 */ 435 int 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 */ 119 450 int 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 */ 120 462 int 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 */ 121 477 int 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 */ 122 490 int 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 */ 123 502 int 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 */ 124 517 int 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 */ 125 530 int 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 */ 126 544 int 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 */ 127 558 int 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 */ 128 569 const 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 */ 129 581 int 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 */ 130 594 tdb_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 */ 131 605 void *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 */ 132 635 int 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 */ 648 int 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 */ 133 665 int 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 */ 134 679 int 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 */ 135 694 int 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 */ 137 714 int 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 */ 138 723 int 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 */ 139 732 size_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 */ 140 741 int 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 */ 141 750 void 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 */ 142 759 void 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 */ 143 768 void 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 */ 144 781 void 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 */ 790 unsigned 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 */ 145 813 int tdb_check(struct tdb_context *tdb, 146 814 int (*check) (TDB_DATA key, TDB_DATA data, void *private_data), 147 815 void *private_data); 816 817 /* @} ******************************************************************/ 148 818 149 819 /* Low level locking functions: use with care */ … … 167 837 int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); 168 838 int tdb_freelist_size(struct tdb_context *tdb); 839 char *tdb_summary(struct tdb_context *tdb); 169 840 170 841 extern TDB_DATA tdb_null; -
vendor/current/lib/tdb/libtdb.m4
r414 r740 14 14 fi 15 15 TDB_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 "16 TDB_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" 17 17 AC_SUBST(TDB_OBJ) 18 18 AC_SUBST(LIBREPLACEOBJ) … … 20 20 TDB_LIBS="" 21 21 AC_SUBST(TDB_LIBS) 22 23 TDB_DEPS="" 24 if test x$libreplace_cv_HAVE_FDATASYNC_IN_LIBRT = xyes ; then 25 TDB_DEPS="$TDB_DEPS -lrt" 26 fi 27 AC_SUBST(TDB_DEPS) 22 28 23 29 TDB_CFLAGS="-I$tdbdir/include" -
vendor/current/lib/tdb/manpages/tdbbackup.8.xml
r414 r740 1 1 <?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"> 3 3 <refentry id="tdbbackup.8"> 4 4 … … 8 8 <refmiscinfo class="source">Samba</refmiscinfo> 9 9 <refmiscinfo class="manual">System Administration tools</refmiscinfo> 10 <refmiscinfo class="version">3. 5</refmiscinfo>10 <refmiscinfo class="version">3.6</refmiscinfo> 11 11 </refmeta> 12 12 -
vendor/current/lib/tdb/manpages/tdbdump.8.xml
r414 r740 1 1 <?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"> 3 3 <refentry id="tdbdump.8"> 4 4 … … 8 8 <refmiscinfo class="source">Samba</refmiscinfo> 9 9 <refmiscinfo class="manual">System Administration tools</refmiscinfo> 10 <refmiscinfo class="version">3. 5</refmiscinfo>10 <refmiscinfo class="version">3.6</refmiscinfo> 11 11 </refmeta> 12 12 -
vendor/current/lib/tdb/manpages/tdbtool.8.xml
r414 r740 1 1 <?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"> 3 3 <refentry id="tdbtool.8"> 4 4 … … 8 8 <refmiscinfo class="source">Samba</refmiscinfo> 9 9 <refmiscinfo class="manual">System Administration tools</refmiscinfo> 10 <refmiscinfo class="version">3. 5</refmiscinfo>10 <refmiscinfo class="version">3.6</refmiscinfo> 11 11 </refmeta> 12 12 -
vendor/current/lib/tdb/pytdb.c
r414 r740 10 10 ** library. This does NOT imply that all of Samba is released 11 11 ** under the LGPL 12 12 13 13 This library is free software; you can redistribute it and/or 14 14 modify it under the terms of the GNU Lesser General Public … … 25 25 */ 26 26 27 #include <Python.h> 27 28 #include "replace.h" 28 29 #include "system/filesys.h" 29 30 30 #include <Python.h>31 31 #ifndef Py_RETURN_NONE 32 32 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None … … 42 42 } PyTdbObject; 43 43 44 PyAPI_DATA(PyTypeObject)PyTdb;44 staticforward PyTypeObject PyTdb; 45 45 46 46 static void PyErr_SetTDBError(TDB_CONTEXT *tdb) … … 78 78 static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs) 79 79 { 80 char *name ;80 char *name = NULL; 81 81 int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600; 82 82 TDB_CONTEXT *ctx; … … 84 84 const char *kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL }; 85 85 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 } 88 92 89 93 ctx = tdb_open(name, hash_size, tdb_flags, flags, mode); … … 94 98 95 99 ret = PyObject_New(PyTdbObject, &PyTdb); 100 if (!ret) { 101 tdb_close(ctx); 102 return NULL; 103 } 104 96 105 ret->ctx = ctx; 97 106 ret->closed = false; … … 113 122 } 114 123 115 static PyObject *obj_transaction_ recover(PyTdbObject *self)116 { 117 int ret = tdb_transaction_ recover(self->ctx);124 static PyObject *obj_transaction_prepare_commit(PyTdbObject *self) 125 { 126 int ret = tdb_transaction_prepare_commit(self->ctx); 118 127 PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); 119 128 Py_RETURN_NONE; … … 267 276 } 268 277 278 static 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 289 static 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 } 269 299 270 300 typedef struct { … … 306 336 307 337 ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator); 338 if (!ret) 339 return NULL; 308 340 ret->current = tdb_firstkey(self->ctx); 309 341 ret->iteratee = self; … … 316 348 int ret = tdb_wipe_all(self->ctx); 317 349 PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); 350 Py_RETURN_NONE; 351 } 352 353 static 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 360 static PyObject *obj_enable_seqnum(PyTdbObject *self) 361 { 362 tdb_enable_seqnum(self->ctx); 363 Py_RETURN_NONE; 364 } 365 366 static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self) 367 { 368 tdb_increment_seqnum_nonblock(self->ctx); 318 369 Py_RETURN_NONE; 319 370 } … … 326 377 "S.transaction_commit() -> None\n" 327 378 "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" }, 331 382 { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS, 332 383 "S.transaction_start() -> None\n" … … 352 403 { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None" 353 404 "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" }, 354 407 { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" }, 355 408 { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n" 356 409 "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" }, 357 416 { NULL } 358 417 }; … … 376 435 } 377 436 437 static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure) 438 { 439 return PyInt_FromLong(tdb_freelist_size(self->ctx)); 440 } 441 378 442 static PyObject *obj_get_flags(PyTdbObject *self, void *closure) 379 443 { … … 385 449 return PyString_FromString(tdb_name(self->ctx)); 386 450 } 451 452 static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure) 453 { 454 return PyInt_FromLong(tdb_get_seqnum(self->ctx)); 455 } 456 387 457 388 458 static PyGetSetDef tdb_object_getsetters[] = { 389 459 { (char *)"hash_size", (getter)obj_get_hash_size, NULL, NULL }, 390 460 { (char *)"map_size", (getter)obj_get_map_size, NULL, NULL }, 461 { (char *)"freelist_size", (getter)obj_get_freelist_size, NULL, NULL }, 391 462 { (char *)"flags", (getter)obj_get_flags, NULL, NULL }, 392 463 { (char *)"max_dead", NULL, (setter)obj_set_max_dead, NULL }, 393 464 { (char *)"filename", (getter)obj_get_filename, NULL, (char *)"The filename of this TDB file."}, 465 { (char *)"seqnum", (getter)obj_get_seqnum, NULL, NULL }, 394 466 { NULL } 395 467 }; … … 397 469 static PyObject *tdb_object_repr(PyTdbObject *self) 398 470 { 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 } 400 476 } 401 477 … … 404 480 if (!self->closed) 405 481 tdb_close(self->ctx); 406 PyObject_Del(self);482 self->ob_type->tp_free(self); 407 483 } 408 484 … … 463 539 .mp_ass_subscript = (objobjargproc)obj_setitem, 464 540 }; 465 PyTypeObject PyTdb = {541 static PyTypeObject PyTdb = { 466 542 .tp_name = "Tdb", 467 543 .tp_basicsize = sizeof(PyTdbObject), … … 483 559 }; 484 560 561 void inittdb(void); 485 562 void inittdb(void) 486 563 { … … 508 585 PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT)); 509 586 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 510 594 PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText")); 595 596 PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION)); 511 597 512 598 Py_INCREF(&PyTdb); -
vendor/current/lib/tdb/python/tdbdump.py
r414 r740 1 #!/usr/bin/ python1 #!/usr/bin/env python 2 2 # Trivial reimplementation of tdbdump in Python 3 3 -
vendor/current/lib/tdb/python/tests/simple.py
r414 r740 1 #!/usr/bin/ python1 #!/usr/bin/env python 2 2 # Some simple tests for the Python bindings for TDB 3 3 # Note that this tests the interface of the Python bindings … … 13 13 14 14 class OpenTdbTests(TestCase): 15 15 16 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) 17 19 18 20 class CloseTdbTests(TestCase): 21 19 22 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) 21 25 self.assertNotEqual(None, self.tdb) 22 26 … … 26 30 27 31 32 class 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 28 41 class SimpleTdbTests(TestCase): 42 29 43 def setUp(self): 30 44 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) 32 47 self.assertNotEqual(None, self.tdb) 33 48 … … 82 97 self.tdb.map_size 83 98 99 def test_freelist_size(self): 100 self.tdb.freelist_size 101 84 102 def test_name(self): 85 103 self.tdb.filename … … 104 122 self.assertEquals("1", self.tdb["bloe"]) 105 123 106 def test_ iterator(self):124 def test_transaction_prepare_commit(self): 107 125 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"]) 111 131 112 132 def test_iterkeys(self): … … 123 143 self.assertEquals(0, len(list(self.tdb))) 124 144 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 125 158 def test_len(self): 126 159 self.assertEquals(0, len(list(self.tdb))) … … 128 161 self.assertEquals(1, len(list(self.tdb))) 129 162 163 def test_add_flags(self): 164 self.tdb.add_flags(tdb.NOMMAP) 165 self.tdb.remove_flags(tdb.NOMMAP) 166 167 168 class VersionTests(TestCase): 169 170 def test_present(self): 171 self.assertTrue(isinstance(tdb.__version__, str)) 172 130 173 131 174 if __name__ == '__main__': -
vendor/current/lib/tdb/tdb.pc.in
r414 r740 7 7 Description: A trivial database 8 8 Version: @PACKAGE_VERSION@ 9 Libs: -L${libdir} -ltdb9 Libs: @LIB_RPATH@ -L${libdir} -ltdb 10 10 Cflags: -I${includedir} 11 11 URL: http://tdb.samba.org/ -
vendor/current/lib/tdb/tools/tdbbackup.c
r414 r740 153 153 } 154 154 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"); 157 158 tdb_close(tdb); 158 159 tdb_close(tdb_new); … … 178 179 tdb_close(tdb); 179 180 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"); 186 191 } 187 192 -
vendor/current/lib/tdb/tools/tdbtest.c
r414 r740 216 216 } 217 217 218 static 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 218 236 int main(int argc, const char *argv[]) 219 237 { … … 221 239 int loops = 10000; 222 240 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, 228 250 O_RDWR | O_CREAT | O_TRUNC, 0600); 229 251 gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, … … 262 284 gdbm_close(gdbm); 263 285 286 free(test_gdbm[0]); 287 free(test_tdb); 288 264 289 return 0; 265 290 } -
vendor/current/lib/tdb/tools/tdbtool.c
r414 r740 410 410 static void info_tdb(void) 411 411 { 412 int count;413 total_bytes = 0; 414 if ( (count = tdb_traverse(tdb, traverse_fn, NULL)) == -1)412 char *summary = tdb_summary(tdb); 413 414 if (!summary) { 415 415 printf("Error = %s\n", tdb_errorstr(tdb)); 416 else 417 printf("%d records totalling %d bytes\n", count, total_bytes); 416 } else { 417 printf("%s", summary); 418 free(summary); 419 } 418 420 } 419 421 -
vendor/current/lib/tdb/tools/tdbtorture.c
r414 r740 31 31 static int error_count; 32 32 static int always_transaction = 0; 33 static int hash_size = 2; 34 static int loopnum; 35 static int count_pipe; 36 static struct tdb_logging_context log_ctx; 33 37 34 38 #ifdef PRINTF_ATTRIBUTE … … 49 53 fflush(stdout); 50 54 #if 0 51 {55 if (level != TDB_DEBUG_TRACE) { 52 56 char *ptr; 57 signal(SIGUSR1, SIG_IGN); 53 58 asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid()); 54 59 system(ptr); … … 212 217 static void usage(void) 213 218 { 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"); 215 220 exit(0); 216 221 } 217 222 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, 223 static 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 231 static 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, 263 234 O_RDWR | O_CREAT, 0600, &log_ctx, NULL); 264 235 if (!db) { … … 266 237 } 267 238 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 277 239 srand(seed + i); 278 240 srandom(seed + i); 279 241 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++) { 281 247 addrec_db(); 282 248 } … … 302 268 tdb_close(db); 303 269 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 273 static 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 291 int 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) { 309 365 int status, j; 310 366 pid_t pid; 367 311 368 if (error_count != 0) { 312 369 /* try and stop the test on any failure */ 313 for (j= 1;j<num_procs;j++) {370 for (j=0;j<num_procs;j++) { 314 371 if (pids[j] != 0) { 315 372 kill(pids[j], SIGTERM); … … 317 374 } 318 375 } 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 320 391 if (pid == -1) { 321 392 perror("failed to wait for child\n"); 322 393 exit(1); 323 394 } 324 for (j=1;j<num_procs;j++) { 395 396 for (j=0;j<num_procs;j++) { 325 397 if (pids[j] == pid) break; 326 398 } … … 329 401 exit(1); 330 402 } 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)); 334 421 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--; 337 432 } 338 433 339 434 free(pids); 340 435 436 done: 341 437 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); 342 448 printf("OK\n"); 343 449 } 344 450 451 free(test_tdb); 345 452 return error_count; 346 453 }
Note:
See TracChangeset
for help on using the changeset viewer.