diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2011-04-18 22:15:11 +0930 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2011-04-18 22:15:11 +0930 |
commit | 094ab60053bcc0bc3542af8144e394d83270053e (patch) | |
tree | 4a9a447f5ac9457a755381beef2137ae11073fbc /lib/tdb | |
parent | 6aa72dae8fc341de5b497f831ded1f8f519fa8fb (diff) | |
download | samba-094ab60053bcc0bc3542af8144e394d83270053e.tar.gz samba-094ab60053bcc0bc3542af8144e394d83270053e.tar.bz2 samba-094ab60053bcc0bc3542af8144e394d83270053e.zip |
tdb: tdb_repack() only when it's worthwhile.
tdb_repack() is expensive and consumes memory, so we can spend some
effort to see if it's worthwhile. In particular, tdbbackup doesn't
need to repack: it started with an empty database!
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'lib/tdb')
-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); |