X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Ftdb1_tdb.c;h=9730dceffc2b5b7b8bccbeaef1ca6bacd689c2a4;hp=0a4f8b5503a7841fe0420e523a27a3d3ae42fd31;hb=a3e4ebff2eb9dc2e386160b8acf77d70236f4def;hpb=ceb2f3eacbad917ee990afbc3dd800bfb0607887 diff --git a/ccan/tdb2/tdb1_tdb.c b/ccan/tdb2/tdb1_tdb.c index 0a4f8b55..9730dcef 100644 --- a/ccan/tdb2/tdb1_tdb.c +++ b/ccan/tdb2/tdb1_tdb.c @@ -28,8 +28,6 @@ #include "tdb1_private.h" #include -TDB_DATA tdb1_null; - /* non-blocking increment of the tdb sequence number if the tdb has been opened using the TDB_SEQNUM flag @@ -91,11 +89,18 @@ static tdb1_off_t tdb1_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash if (tdb1_rec_read(tdb, rec_ptr, r) == -1) return 0; - if (!TDB1_DEAD(r) && hash==r->full_hash - && key.dsize==r->key_len - && tdb1_parse_data(tdb, key, rec_ptr + sizeof(*r), - r->key_len, tdb1_key_compare, - NULL) == 0) { + tdb->stats.compares++; + if (TDB1_DEAD(r)) { + tdb->stats.compare_wrong_bucket++; + } else if (key.dsize != r->key_len) { + tdb->stats.compare_wrong_keylen++; + } else if (hash != r->full_hash) { + tdb->stats.compare_wrong_rechash++; + } else if (tdb1_parse_data(tdb, key, rec_ptr + sizeof(*r), + r->key_len, tdb1_key_compare, + NULL) != 0) { + tdb->stats.compare_wrong_keycmp++; + } else { return rec_ptr; } /* detect tight infinite loop */ @@ -191,8 +196,11 @@ static TDB_DATA _tdb1_fetch(struct tdb_context *tdb, TDB_DATA key) /* find which hash bucket it is in */ hash = tdb_hash(tdb, key.dptr, key.dsize); - if (!(rec_ptr = tdb1_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) - return tdb1_null; + if (!(rec_ptr = tdb1_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) { + ret.dptr = NULL; + ret.dsize = 0; + return ret; + } ret.dptr = tdb1_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len, rec.data_len); @@ -209,32 +217,15 @@ enum TDB_ERROR tdb1_fetch(struct tdb_context *tdb, TDB_DATA key, TDB_DATA *data) return TDB_SUCCESS; } -/* - * Find an entry in the database and hand the record's data to a parsing - * function. The parsing function is executed under the chain read lock, so it - * should be fast and should not block on other syscalls. - * - * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS. - * - * For mmapped tdb's that do not have a transaction open it points the parsing - * function directly at the mmap area, it avoids the malloc/memcpy in this - * case. If a transaction is open or no mmap is available, it has to do - * malloc/read/parse/free. - * - * This is interesting for all readers of potentially large data structures in - * the tdb records, ldb indexes being one example. - * - * Return -1 if the record was not found. - */ - -int tdb1_parse_record(struct tdb_context *tdb, TDB_DATA key, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data) +enum TDB_ERROR tdb1_parse_record(struct tdb_context *tdb, TDB_DATA key, + enum TDB_ERROR (*parser)(TDB_DATA key, + TDB_DATA data, + void *private_data), + void *private_data) { tdb1_off_t rec_ptr; struct tdb1_record rec; - int ret; + enum TDB_ERROR ret; uint32_t hash; /* find which hash bucket it is in */ @@ -242,8 +233,7 @@ int tdb1_parse_record(struct tdb_context *tdb, TDB_DATA key, if (!(rec_ptr = tdb1_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) { /* record not found */ - tdb->last_error = TDB_ERR_NOEXIST; - return -1; + return TDB_ERR_NOEXIST; } ret = tdb1_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len, @@ -608,7 +598,9 @@ int tdb1_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) assert(tdb->flags & TDB_VERSION1); if ((tdb->flags & TDB_RDONLY) || tdb->tdb1.traverse_read) { - tdb->last_error = TDB_ERR_RDONLY; + tdb->last_error = tdb_logerr(tdb, TDB_ERR_RDONLY, + TDB_LOG_USE_ERROR, + "tdb_store: read-only tdb"); return -1; } @@ -801,6 +793,7 @@ int tdb1_wipe_all(struct tdb_context *tdb) } } + tdb1_increment_seqnum_nonblock(tdb); tdb_unlockall(tdb); return 0; @@ -809,108 +802,6 @@ failed: return -1; } -struct traverse_state { - enum TDB_ERROR error; - struct tdb_context *dest_db; -}; - -/* - traverse function for repacking - */ -static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data) -{ - struct traverse_state *state = (struct traverse_state *)private_data; - if (tdb1_store(state->dest_db, key, data, TDB_INSERT) != 0) { - state->error = state->dest_db->last_error; - return -1; - } - return 0; -} - -/* - repack a tdb - */ -int tdb1_repack(struct tdb_context *tdb) -{ - struct tdb_context *tmp_db; - struct traverse_state state; - union tdb_attribute hsize; - - hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE; - hsize.base.next = NULL; - hsize.tdb1_hashsize.hsize = tdb->tdb1.header.hash_size; - - if (tdb1_transaction_start(tdb) != 0) { - tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR, - __location__ " Failed to start transaction"); - return -1; - } - - tmp_db = tdb_open("tmpdb", TDB_INTERNAL, O_RDWR|O_CREAT, 0, &hsize); - if (tmp_db == NULL) { - tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR, - __location__ " Failed to create tmp_db"); - tdb1_transaction_cancel(tdb); - return -1; - } - - state.error = TDB_SUCCESS; - state.dest_db = tmp_db; - - if (tdb1_traverse(tdb, repack_traverse, &state) == -1) { - tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR, - __location__ " Failed to traverse copying out"); - tdb1_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (state.error != TDB_SUCCESS) { - tdb->last_error = tdb_logerr(tdb, state.error, TDB_LOG_ERROR, - __location__ " Error during traversal"); - tdb1_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (tdb1_wipe_all(tdb) != 0) { - tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR, - __location__ " Failed to wipe database\n"); - tdb1_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - state.error = TDB_SUCCESS; - state.dest_db = tdb; - - if (tdb1_traverse(tmp_db, repack_traverse, &state) == -1) { - tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR, - __location__ " Failed to traverse copying back"); - tdb1_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (state.error) { - tdb->last_error = tdb_logerr(tdb, state.error, TDB_LOG_ERROR, - __location__ " Error during second traversal"); - tdb1_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - tdb_close(tmp_db); - - if (tdb1_transaction_commit(tdb) != 0) { - tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR, - __location__ " Failed to commit"); - return -1; - } - - return 0; -} - /* Even on files, we can get partial writes due to signals. */ bool tdb1_write_all(int fd, const void *buf, size_t count) {