X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Ftdb.c;h=62607bf1e5d8eb2f4c9bf9002aa9b30e299a9af9;hp=c6bd8072ea9c4b18d55ee7b1ca5c4e64e550805d;hb=56023cca5f66a40646a1e807c3d10af6e5913623;hpb=57359c26e9626aa986ee0538efd13a44a466f39d diff --git a/ccan/tdb2/tdb.c b/ccan/tdb2/tdb.c index c6bd8072..62607bf1 100644 --- a/ccan/tdb2/tdb.c +++ b/ccan/tdb2/tdb.c @@ -50,7 +50,7 @@ static enum TDB_ERROR replace_data(struct tdb_context *tdb, new_off = alloc(tdb, key.dsize, dbuf.dsize, h->h, TDB_USED_MAGIC, growing); if (TDB_OFF_IS_ERR(new_off)) { - return new_off; + return TDB_OFF_TO_ERR(new_off); } /* We didn't like the existing one: remove it. */ @@ -122,7 +122,7 @@ enum TDB_ERROR tdb_store(struct tdb_context *tdb, off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL); if (TDB_OFF_IS_ERR(off)) { - return tdb->last_error = off; + return tdb->last_error = TDB_OFF_TO_ERR(off); } /* Now we have lock on this hash bucket. */ @@ -191,7 +191,7 @@ enum TDB_ERROR tdb_append(struct tdb_context *tdb, off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL); if (TDB_OFF_IS_ERR(off)) { - return tdb->last_error = off; + return tdb->last_error = TDB_OFF_TO_ERR(off); } if (off) { @@ -259,7 +259,7 @@ enum TDB_ERROR tdb_fetch(struct tdb_context *tdb, struct tdb_data key, off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL); if (TDB_OFF_IS_ERR(off)) { - return tdb->last_error = off; + return tdb->last_error = TDB_OFF_TO_ERR(off); } if (!off) { @@ -290,7 +290,7 @@ bool tdb_exists(struct tdb_context *tdb, TDB_DATA key) off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL); if (TDB_OFF_IS_ERR(off)) { - tdb->last_error = off; + tdb->last_error = TDB_OFF_TO_ERR(off); return false; } tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK); @@ -314,7 +314,7 @@ enum TDB_ERROR tdb_delete(struct tdb_context *tdb, struct tdb_data key) off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL); if (TDB_OFF_IS_ERR(off)) { - return tdb->last_error = off; + return tdb->last_error = TDB_OFF_TO_ERR(off); } if (!off) { @@ -367,16 +367,6 @@ static bool readonly_changable(struct tdb_context *tdb, const char *caller) caller); return false; } - - if (tdb->file->allrecord_lock.count != 0 - || tdb->file->num_lockrecs != 0) { - tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL, - TDB_LOG_USE_ERROR, - "%s: can't change" - " TDB_RDONLY holding locks", - caller); - return false; - } return true; } @@ -465,16 +455,16 @@ void tdb_remove_flag(struct tdb_context *tdb, unsigned flag) const char *tdb_errorstr(enum TDB_ERROR ecode) { /* Gcc warns if you miss a case in the switch, so use that. */ - switch (ecode) { - case TDB_SUCCESS: return "Success"; - case TDB_ERR_CORRUPT: return "Corrupt database"; - case TDB_ERR_IO: return "IO Error"; - case TDB_ERR_LOCK: return "Locking error"; - case TDB_ERR_OOM: return "Out of memory"; - case TDB_ERR_EXISTS: return "Record exists"; - case TDB_ERR_EINVAL: return "Invalid parameter"; - case TDB_ERR_NOEXIST: return "Record does not exist"; - case TDB_ERR_RDONLY: return "write not permitted"; + switch (TDB_ERR_TO_OFF(ecode)) { + case TDB_ERR_TO_OFF(TDB_SUCCESS): return "Success"; + case TDB_ERR_TO_OFF(TDB_ERR_CORRUPT): return "Corrupt database"; + case TDB_ERR_TO_OFF(TDB_ERR_IO): return "IO Error"; + case TDB_ERR_TO_OFF(TDB_ERR_LOCK): return "Locking error"; + case TDB_ERR_TO_OFF(TDB_ERR_OOM): return "Out of memory"; + case TDB_ERR_TO_OFF(TDB_ERR_EXISTS): return "Record exists"; + case TDB_ERR_TO_OFF(TDB_ERR_EINVAL): return "Invalid parameter"; + case TDB_ERR_TO_OFF(TDB_ERR_NOEXIST): return "Record does not exist"; + case TDB_ERR_TO_OFF(TDB_ERR_RDONLY): return "write not permitted"; } return "Invalid error code"; } @@ -533,7 +523,7 @@ enum TDB_ERROR tdb_parse_record_(struct tdb_context *tdb, off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL); if (TDB_OFF_IS_ERR(off)) { - return tdb->last_error = off; + return tdb->last_error = TDB_OFF_TO_ERR(off); } if (!off) { @@ -571,14 +561,14 @@ int64_t tdb_get_seqnum(struct tdb_context *tdb) val = tdb1_get_seqnum(tdb); if (tdb->last_error != TDB_SUCCESS) - return tdb->last_error; + return TDB_ERR_TO_OFF(tdb->last_error); else return val; } off = tdb_read_off(tdb, offsetof(struct tdb_header, seqnum)); if (TDB_OFF_IS_ERR(off)) - tdb->last_error = off; + tdb->last_error = TDB_OFF_TO_ERR(off); else tdb->last_error = TDB_SUCCESS; return off; @@ -589,3 +579,64 @@ int tdb_fd(const struct tdb_context *tdb) { return tdb->file->fd; } + +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, + struct traverse_state *state) +{ + state->error = tdb_store(state->dest_db, key, data, TDB_INSERT); + if (state->error != TDB_SUCCESS) { + return -1; + } + return 0; +} + +enum TDB_ERROR tdb_repack(struct tdb_context *tdb) +{ + struct tdb_context *tmp_db; + struct traverse_state state; + + state.error = tdb_transaction_start(tdb); + if (state.error != TDB_SUCCESS) { + return state.error; + } + + tmp_db = tdb_open("tmpdb", TDB_INTERNAL, O_RDWR|O_CREAT, 0, NULL); + if (tmp_db == NULL) { + state.error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR, + __location__ + " Failed to create tmp_db"); + tdb_transaction_cancel(tdb); + return tdb->last_error = state.error; + } + + state.dest_db = tmp_db; + if (tdb_traverse(tdb, repack_traverse, &state) < 0) { + goto fail; + } + + state.error = tdb_wipe_all(tdb); + if (state.error != TDB_SUCCESS) { + goto fail; + } + + state.dest_db = tdb; + if (tdb_traverse(tmp_db, repack_traverse, &state) < 0) { + goto fail; + } + + tdb_close(tmp_db); + return tdb_transaction_commit(tdb); + +fail: + tdb_transaction_cancel(tdb); + tdb_close(tmp_db); + return state.error; +}