diff options
Diffstat (limited to 'lib/tdb')
-rw-r--r-- | lib/tdb/common/tdb.c | 89 | ||||
-rw-r--r-- | lib/tdb/include/tdb.h | 5 | ||||
-rw-r--r-- | lib/tdb/tools/tdbbackup.c | 25 |
3 files changed, 112 insertions, 7 deletions
diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c index c7cec297f6..8c61ec1a89 100644 --- a/lib/tdb/common/tdb.c +++ b/lib/tdb/common/tdb.c @@ -800,3 +800,92 @@ failed: tdb_unlockall(tdb); return -1; } + +struct traverse_state { + bool 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) +{ + struct traverse_state *state = (struct traverse_state *)private; + if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) { + state->error = true; + return -1; + } + return 0; +} + +/* + repack a tdb + */ +int tdb_repack(struct tdb_context *tdb) +{ + struct tdb_context *tmp_db; + struct traverse_state state; + + if (tdb_transaction_start(tdb) != 0) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n")); + return -1; + } + + tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0); + if (tmp_db == NULL) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n")); + tdb_transaction_cancel(tdb); + return -1; + } + + state.error = false; + state.dest_db = tmp_db; + + if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n")); + tdb_transaction_cancel(tdb); + tdb_close(tmp_db); + return -1; + } + + if (state.error) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n")); + tdb_transaction_cancel(tdb); + tdb_close(tmp_db); + return -1; + } + + if (tdb_wipe_all(tdb) != 0) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n")); + tdb_transaction_cancel(tdb); + tdb_close(tmp_db); + return -1; + } + + state.error = false; + state.dest_db = tdb; + + if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n")); + tdb_transaction_cancel(tdb); + tdb_close(tmp_db); + return -1; + } + + if (state.error) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n")); + tdb_transaction_cancel(tdb); + tdb_close(tmp_db); + return -1; + } + + tdb_close(tmp_db); + + if (tdb_transaction_commit(tdb) != 0) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n")); + return -1; + } + + return 0; +} diff --git a/lib/tdb/include/tdb.h b/lib/tdb/include/tdb.h index c41c9941f0..94b5e366b9 100644 --- a/lib/tdb/include/tdb.h +++ b/lib/tdb/include/tdb.h @@ -152,11 +152,14 @@ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key); void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr); +/* wipe and repack */ +int tdb_wipe_all(struct tdb_context *tdb); +int tdb_repack(struct tdb_context *tdb); + /* Debug functions. Not used in production. */ void tdb_dump_all(struct tdb_context *tdb); int tdb_printfreelist(struct tdb_context *tdb); int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); -int tdb_wipe_all(struct tdb_context *tdb); int tdb_freelist_size(struct tdb_context *tdb); extern TDB_DATA tdb_null; diff --git a/lib/tdb/tools/tdbbackup.c b/lib/tdb/tools/tdbbackup.c index 6f3ca48314..83c0e16399 100644 --- a/lib/tdb/tools/tdbbackup.c +++ b/lib/tdb/tools/tdbbackup.c @@ -126,9 +126,17 @@ static int backup_tdb(const char *old_name, const char *new_name, int hash_size) return 1; } - /* lock the old tdb */ - if (tdb_lockall(tdb) != 0) { - fprintf(stderr,"Failed to lock %s\n", old_name); + if (tdb_transaction_start(tdb) != 0) { + printf("Failed to start transaction on old tdb\n"); + tdb_close(tdb); + tdb_close(tdb_new); + unlink(tmp_name); + free(tmp_name); + return 1; + } + + if (tdb_transaction_start(tdb_new) != 0) { + printf("Failed to start transaction on new tdb\n"); tdb_close(tdb); tdb_close(tdb_new); unlink(tmp_name); @@ -152,6 +160,14 @@ static int backup_tdb(const char *old_name, const char *new_name, int hash_size) /* close the old tdb */ tdb_close(tdb); + if (tdb_transaction_commit(tdb_new) != 0) { + fprintf(stderr, "Failed to commit new tdb\n"); + tdb_close(tdb_new); + unlink(tmp_name); + free(tmp_name); + return 1; + } + /* close the new tdb and re-open read-only */ tdb_close(tdb_new); tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0); @@ -173,9 +189,6 @@ static int backup_tdb(const char *old_name, const char *new_name, int hash_size) return 1; } - /* make sure the new tdb has reached stable storage */ - fsync(tdb_fd(tdb_new)); - /* close the new tdb and rename it to .bak */ tdb_close(tdb_new); if (rename(tmp_name, new_name) != 0) { |