diff options
Diffstat (limited to 'lib/tdb/common')
-rw-r--r-- | lib/tdb/common/transaction.c | 37 |
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); |