Commit 51b9a2e9 authored by Rusty Russell's avatar Rusty Russell

Import from SAMBA tdb:

commit 936d76802f98d04d9743b2ca8eeeaadd4362db51
Author: Andrew Tridgell <tridge@samba.org>
Date:   Tue Dec 16 14:38:17 2008 +1100

    imported the tdb_repack() code from CTDB
    
    The tdb_repack() function repacks a TDB so that it has a single
    freelist entry. The file doesn't shrink, but it does remove all
    freelist fragmentation. This code originated in the CTDB vacuuming
    code, but will now be used in ldb to cope with fragmentation from
    re-indexing
parent 43ae196c
......@@ -846,6 +846,98 @@ failed:
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;
tdb_trace(tdb, "tdb_repack");
if (tdb_transaction_start(tdb) != 0) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_repack: 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, "tdb_repack: 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, "tdb_repack: 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, "tdb_repack: 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, "tdb_repack: 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, "tdb_repack: 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, "tdb_repack: 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, "tdb_repack: Failed to commit\n"));
return -1;
}
return 0;
}
#ifdef TDB_TRACE
static void tdb_trace_write(struct tdb_context *tdb, const char *str)
{
......
......@@ -161,11 +161,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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment