00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "tdb_private.h"
00030
00031 TDB_DATA tdb_null;
00032
00033
00034
00035
00036
00037 static void tdb_increment_seqnum(struct tdb_context *tdb)
00038 {
00039 tdb_off_t seqnum=0;
00040
00041 if (!(tdb->flags & TDB_SEQNUM)) {
00042 return;
00043 }
00044
00045 if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) {
00046 return;
00047 }
00048
00049
00050
00051
00052 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
00053 seqnum++;
00054 tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
00055
00056 tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);
00057 }
00058
00059 static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
00060 {
00061 return memcmp(data.dptr, key.dptr, data.dsize);
00062 }
00063
00064
00065
00066 static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, u32 hash,
00067 struct list_struct *r)
00068 {
00069 tdb_off_t rec_ptr;
00070
00071
00072 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
00073 return 0;
00074
00075
00076 while (rec_ptr) {
00077 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
00078 return 0;
00079
00080 if (!TDB_DEAD(r) && hash==r->full_hash
00081 && key.dsize==r->key_len
00082 && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
00083 r->key_len, tdb_key_compare,
00084 NULL) == 0) {
00085 return rec_ptr;
00086 }
00087 rec_ptr = r->next;
00088 }
00089 return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
00090 }
00091
00092
00093 tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash, int locktype,
00094 struct list_struct *rec)
00095 {
00096 u32 rec_ptr;
00097
00098 if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
00099 return 0;
00100 if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
00101 tdb_unlock(tdb, BUCKET(hash), locktype);
00102 return rec_ptr;
00103 }
00104
00105
00106
00107
00108
00109
00110 static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash, TDB_DATA dbuf)
00111 {
00112 struct list_struct rec;
00113 tdb_off_t rec_ptr;
00114
00115
00116 if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
00117 return -1;
00118
00119
00120 if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) {
00121 tdb->ecode = TDB_SUCCESS;
00122 return -1;
00123 }
00124
00125 if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
00126 dbuf.dptr, dbuf.dsize) == -1)
00127 return -1;
00128
00129 if (dbuf.dsize != rec.data_len) {
00130
00131 rec.data_len = dbuf.dsize;
00132 return tdb_rec_write(tdb, rec_ptr, &rec);
00133 }
00134
00135 return 0;
00136 }
00137
00138
00139
00140
00141
00142
00143
00144 TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
00145 {
00146 tdb_off_t rec_ptr;
00147 struct list_struct rec;
00148 TDB_DATA ret;
00149 u32 hash;
00150
00151
00152 hash = tdb->hash_fn(&key);
00153 if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
00154 return tdb_null;
00155
00156 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
00157 rec.data_len);
00158 ret.dsize = rec.data_len;
00159 tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
00160 return ret;
00161 }
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
00180 int (*parser)(TDB_DATA key, TDB_DATA data,
00181 void *private_data),
00182 void *private_data)
00183 {
00184 tdb_off_t rec_ptr;
00185 struct list_struct rec;
00186 int ret;
00187 u32 hash;
00188
00189
00190 hash = tdb->hash_fn(&key);
00191
00192 if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
00193 return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
00194 }
00195
00196 ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
00197 rec.data_len, parser, private_data);
00198
00199 tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
00200
00201 return ret;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210 static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash)
00211 {
00212 struct list_struct rec;
00213
00214 if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
00215 return 0;
00216 tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
00217 return 1;
00218 }
00219
00220 int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
00221 {
00222 u32 hash = tdb->hash_fn(&key);
00223 return tdb_exists_hash(tdb, key, hash);
00224 }
00225
00226
00227 int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct*rec)
00228 {
00229 tdb_off_t last_ptr, i;
00230 struct list_struct lastrec;
00231
00232 if (tdb->read_only || tdb->traverse_read) return -1;
00233
00234 if (tdb_write_lock_record(tdb, rec_ptr) == -1) {
00235
00236 rec->magic = TDB_DEAD_MAGIC;
00237 return tdb_rec_write(tdb, rec_ptr, rec);
00238 }
00239 if (tdb_write_unlock_record(tdb, rec_ptr) != 0)
00240 return -1;
00241
00242
00243 if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
00244 return -1;
00245 for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
00246 if (tdb_rec_read(tdb, i, &lastrec) == -1)
00247 return -1;
00248
00249
00250 if (last_ptr == 0)
00251 last_ptr = TDB_HASH_TOP(rec->full_hash);
00252 if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1)
00253 return -1;
00254
00255
00256 if (tdb_free(tdb, rec_ptr, rec) == -1)
00257 return -1;
00258 return 0;
00259 }
00260
00261 static int tdb_count_dead(struct tdb_context *tdb, u32 hash)
00262 {
00263 int res = 0;
00264 tdb_off_t rec_ptr;
00265 struct list_struct rec;
00266
00267
00268 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
00269 return 0;
00270
00271 while (rec_ptr) {
00272 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1)
00273 return 0;
00274
00275 if (rec.magic == TDB_DEAD_MAGIC) {
00276 res += 1;
00277 }
00278 rec_ptr = rec.next;
00279 }
00280 return res;
00281 }
00282
00283
00284
00285
00286 static int tdb_purge_dead(struct tdb_context *tdb, u32 hash)
00287 {
00288 int res = -1;
00289 struct list_struct rec;
00290 tdb_off_t rec_ptr;
00291
00292 if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
00293 return -1;
00294 }
00295
00296
00297 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
00298 goto fail;
00299
00300 while (rec_ptr) {
00301 tdb_off_t next;
00302
00303 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) {
00304 goto fail;
00305 }
00306
00307 next = rec.next;
00308
00309 if (rec.magic == TDB_DEAD_MAGIC
00310 && tdb_do_delete(tdb, rec_ptr, &rec) == -1) {
00311 goto fail;
00312 }
00313 rec_ptr = next;
00314 }
00315 res = 0;
00316 fail:
00317 tdb_unlock(tdb, -1, F_WRLCK);
00318 return res;
00319 }
00320
00321
00322 static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash)
00323 {
00324 tdb_off_t rec_ptr;
00325 struct list_struct rec;
00326 int ret;
00327
00328 if (tdb->max_dead_records != 0) {
00329
00330
00331
00332
00333
00334
00335 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
00336 return -1;
00337
00338 if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {
00339
00340
00341
00342
00343 tdb_purge_dead(tdb, hash);
00344 }
00345
00346 if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
00347 tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
00348 return -1;
00349 }
00350
00351
00352
00353
00354 rec.magic = TDB_DEAD_MAGIC;
00355 ret = tdb_rec_write(tdb, rec_ptr, &rec);
00356 }
00357 else {
00358 if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK,
00359 &rec)))
00360 return -1;
00361
00362 ret = tdb_do_delete(tdb, rec_ptr, &rec);
00363 }
00364
00365 if (ret == 0) {
00366 tdb_increment_seqnum(tdb);
00367 }
00368
00369 if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
00370 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
00371 return ret;
00372 }
00373
00374 int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
00375 {
00376 u32 hash = tdb->hash_fn(&key);
00377 return tdb_delete_hash(tdb, key, hash);
00378 }
00379
00380
00381
00382
00383 static tdb_off_t tdb_find_dead(struct tdb_context *tdb, u32 hash,
00384 struct list_struct *r, tdb_len_t length)
00385 {
00386 tdb_off_t rec_ptr;
00387
00388
00389 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
00390 return 0;
00391
00392
00393 while (rec_ptr) {
00394 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
00395 return 0;
00396
00397 if (TDB_DEAD(r) && r->rec_len >= length) {
00398
00399
00400
00401
00402 return rec_ptr;
00403 }
00404 rec_ptr = r->next;
00405 }
00406 return 0;
00407 }
00408
00409
00410
00411
00412
00413
00414 int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
00415 {
00416 struct list_struct rec;
00417 u32 hash;
00418 tdb_off_t rec_ptr;
00419 char *p = NULL;
00420 int ret = -1;
00421
00422 if (tdb->read_only || tdb->traverse_read) {
00423 tdb->ecode = TDB_ERR_RDONLY;
00424 return -1;
00425 }
00426
00427
00428 hash = tdb->hash_fn(&key);
00429 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
00430 return -1;
00431
00432
00433 if (flag == TDB_INSERT) {
00434 if (tdb_exists_hash(tdb, key, hash)) {
00435 tdb->ecode = TDB_ERR_EXISTS;
00436 goto fail;
00437 }
00438 } else {
00439
00440 if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
00441 goto done;
00442 }
00443 if (tdb->ecode == TDB_ERR_NOEXIST &&
00444 flag == TDB_MODIFY) {
00445
00446
00447 goto fail;
00448 }
00449 }
00450
00451 tdb->ecode = TDB_SUCCESS;
00452
00453
00454
00455
00456 if (flag != TDB_INSERT)
00457 tdb_delete_hash(tdb, key, hash);
00458
00459
00460
00461
00462 if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
00463 tdb->ecode = TDB_ERR_OOM;
00464 goto fail;
00465 }
00466
00467 memcpy(p, key.dptr, key.dsize);
00468 if (dbuf.dsize)
00469 memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
00470
00471 if (tdb->max_dead_records != 0) {
00472
00473
00474
00475
00476
00477
00478 rec_ptr = tdb_find_dead(
00479 tdb, hash, &rec,
00480 key.dsize + dbuf.dsize + sizeof(tdb_off_t));
00481
00482 if (rec_ptr != 0) {
00483 rec.key_len = key.dsize;
00484 rec.data_len = dbuf.dsize;
00485 rec.full_hash = hash;
00486 rec.magic = TDB_MAGIC;
00487 if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
00488 || tdb->methods->tdb_write(
00489 tdb, rec_ptr + sizeof(rec),
00490 p, key.dsize + dbuf.dsize) == -1) {
00491 goto fail;
00492 }
00493 goto done;
00494 }
00495 }
00496
00497
00498
00499
00500
00501
00502
00503 if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
00504 goto fail;
00505 }
00506
00507 if ((tdb->max_dead_records != 0)
00508 && (tdb_purge_dead(tdb, hash) == -1)) {
00509 tdb_unlock(tdb, -1, F_WRLCK);
00510 goto fail;
00511 }
00512
00513
00514 rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
00515
00516 tdb_unlock(tdb, -1, F_WRLCK);
00517
00518 if (rec_ptr == 0) {
00519 goto fail;
00520 }
00521
00522
00523 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
00524 goto fail;
00525
00526 rec.key_len = key.dsize;
00527 rec.data_len = dbuf.dsize;
00528 rec.full_hash = hash;
00529 rec.magic = TDB_MAGIC;
00530
00531
00532 if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
00533 || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
00534 || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
00535
00536 goto fail;
00537 }
00538
00539 done:
00540 ret = 0;
00541 fail:
00542 if (ret == 0) {
00543 tdb_increment_seqnum(tdb);
00544 }
00545
00546 SAFE_FREE(p);
00547 tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
00548 return ret;
00549 }
00550
00551
00552
00553 int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
00554 {
00555 u32 hash;
00556 TDB_DATA dbuf;
00557 int ret = -1;
00558
00559
00560 hash = tdb->hash_fn(&key);
00561 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
00562 return -1;
00563
00564 dbuf = tdb_fetch(tdb, key);
00565
00566 if (dbuf.dptr == NULL) {
00567 dbuf.dptr = (char *)malloc(new_dbuf.dsize);
00568 } else {
00569 char *new_dptr = (char *)realloc(dbuf.dptr,
00570 dbuf.dsize + new_dbuf.dsize);
00571 if (new_dptr == NULL) {
00572 free(dbuf.dptr);
00573 }
00574 dbuf.dptr = new_dptr;
00575 }
00576
00577 if (dbuf.dptr == NULL) {
00578 tdb->ecode = TDB_ERR_OOM;
00579 goto failed;
00580 }
00581
00582 memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
00583 dbuf.dsize += new_dbuf.dsize;
00584
00585 ret = tdb_store(tdb, key, dbuf, 0);
00586
00587 failed:
00588 tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
00589 SAFE_FREE(dbuf.dptr);
00590 return ret;
00591 }
00592
00593
00594
00595
00596
00597
00598 const char *tdb_name(struct tdb_context *tdb)
00599 {
00600 return tdb->name;
00601 }
00602
00603
00604
00605
00606
00607
00608 int tdb_fd(struct tdb_context *tdb)
00609 {
00610 return tdb->fd;
00611 }
00612
00613
00614
00615
00616
00617 tdb_log_func tdb_log_fn(struct tdb_context *tdb)
00618 {
00619 return tdb->log.log_fn;
00620 }
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 int tdb_get_seqnum(struct tdb_context *tdb)
00634 {
00635 tdb_off_t seqnum=0;
00636
00637 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
00638 return seqnum;
00639 }
00640
00641 int tdb_hash_size(struct tdb_context *tdb)
00642 {
00643 return tdb->header.hash_size;
00644 }
00645
00646 size_t tdb_map_size(struct tdb_context *tdb)
00647 {
00648 return tdb->map_size;
00649 }
00650
00651 int tdb_get_flags(struct tdb_context *tdb)
00652 {
00653 return tdb->flags;
00654 }
00655