diff options
| -rw-r--r-- | lib/tdb/common/tdb.c | 89 | ||||
| -rw-r--r-- | lib/tdb/include/tdb.h | 5 | 
2 files changed, 93 insertions, 1 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;  | 
