imported the tdb_repack() code from CTDB
authorAndrew Tridgell <tridge@samba.org>
Tue, 16 Dec 2008 03:38:17 +0000 (14:38 +1100)
committerAndrew Tridgell <tridge@samba.org>
Tue, 16 Dec 2008 03:38:17 +0000 (14:38 +1100)
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

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

index c7cec297f6cd0c5c27d81067b4a84a5224dd36ad..8c61ec1a89d0e6303a507e24455940d9eeff13ab 100644 (file)
@@ -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;
+}
index c41c9941f0691074b59ec73e36f4ff003a9e9ef9..94b5e366b90cd28002ca4c21e405a0f2197b5ffb 100644 (file)
@@ -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;