Port from SAMBA ctdb: commit 936d76802f98d04d9743b2ca8eeeaadd4362db51 Author: Andrew...
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 29 Jul 2009 06:32:51 +0000 (16:02 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 4 Aug 2009 07:13:21 +0000 (16:43 +0930)
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

lib/tdb/common/tdb.c
lib/tdb/include/tdb.h

index b4dc86a82cb13d61bb5cc43dbeeb61bfc35ec9e4..a0125f17dabb4966dd01e5425d063ce7c5c9e462 100644 (file)
@@ -805,3 +805,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;
+}
index ca6fef8737f4aa8afb00f43ac6cf538fe482e83c..ca23dde6c569c5f643b9e1c156c30c0a23cae975 100644 (file)
@@ -154,11 +154,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;