summaryrefslogtreecommitdiff
path: root/lib/tdb/common
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tdb/common')
-rw-r--r--lib/tdb/common/transaction.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
index 4bc8044219..e110a08dbc 100644
--- a/lib/tdb/common/transaction.c
+++ b/lib/tdb/common/transaction.c
@@ -138,8 +138,8 @@ struct tdb_transaction {
/* old file size before transaction */
tdb_len_t old_map_size;
- /* we should re-pack on commit */
- bool need_repack;
+ /* did we expand in this transaction */
+ bool expanded;
};
@@ -403,7 +403,7 @@ static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
return -1;
}
- tdb->transaction->need_repack = true;
+ tdb->transaction->expanded = true;
return 0;
}
@@ -983,6 +983,28 @@ _PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb)
return _tdb_transaction_prepare_commit(tdb);
}
+/* A repack is worthwhile if the largest is less than half total free. */
+static bool repack_worthwhile(struct tdb_context *tdb)
+{
+ tdb_off_t ptr;
+ struct tdb_record rec;
+ tdb_len_t total = 0, largest = 0;
+
+ if (tdb_ofs_read(tdb, FREELIST_TOP, &ptr) == -1) {
+ return false;
+ }
+
+ while (ptr != 0 && tdb_rec_free_read(tdb, ptr, &rec) == 0) {
+ total += rec.rec_len;
+ if (rec.rec_len > largest) {
+ largest = rec.rec_len;
+ }
+ ptr = rec.next;
+ }
+
+ return total > largest * 2;
+}
+
/*
commit the current transaction
*/
@@ -990,7 +1012,7 @@ _PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb)
{
const struct tdb_methods *methods;
int i;
- bool need_repack;
+ bool need_repack = false;
if (tdb->transaction == NULL) {
TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
@@ -1058,6 +1080,11 @@ _PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb)
SAFE_FREE(tdb->transaction->blocks[i]);
}
+ /* Do this before we drop lock or blocks. */
+ if (tdb->transaction->expanded) {
+ need_repack = repack_worthwhile(tdb);
+ }
+
SAFE_FREE(tdb->transaction->blocks);
tdb->transaction->num_blocks = 0;
@@ -1081,8 +1108,6 @@ _PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb)
utime(tdb->name, NULL);
#endif
- need_repack = tdb->transaction->need_repack;
-
/* use a transaction cancel to free memory and remove the
transaction locks */
_tdb_transaction_cancel(tdb);