r13283: added two optimisations to the tdb transactions code. The first is to
authorAndrew Tridgell <tridge@samba.org>
Wed, 1 Feb 2006 10:50:26 +0000 (10:50 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:51:42 +0000 (13:51 -0500)
more agressively coalesce entries in the linked list of the undo
log. The second is to ensure that writes during a transaction into the
hash table don't cause the size of the undo log linked list to grow.

These optimisations don't affect Samba much, but they make a huge
difference to the use of ldb in kde
(This used to be commit a37d9434d1fa181fd3d060ad032ee4ec5135fc52)

source4/lib/tdb/common/transaction.c

index becc6cd0591afda4227316cd45eddba376ad0196..ace4aa51a6213a812e83b12caef6b9028131f166 100644 (file)
@@ -195,7 +195,7 @@ fail:
 static int transaction_write(struct tdb_context *tdb, tdb_off_t off, 
                             const void *buf, tdb_len_t len)
 {
-       struct tdb_transaction_el *el;
+       struct tdb_transaction_el *el, *best_el=NULL;
 
        if (len == 0) {
                return 0;
@@ -213,6 +213,10 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
        for (el=tdb->transaction->elements_last;el;el=el->prev) {
                tdb_len_t partial;
 
+               if (best_el == NULL && off == el->offset+el->length) {
+                       best_el = el;
+               }
+
                if (off+len <= el->offset) {
                        continue;
                }
@@ -248,6 +252,28 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
                return 0;
        }
 
+       /* see if we can append the new entry to an existing entry */
+       if (best_el && best_el->offset + best_el->length == off && 
+           (off+len < tdb->transaction->old_map_size ||
+            off > tdb->transaction->old_map_size)) {
+               unsigned char *data = best_el->data;
+               el = best_el;
+               el->data = realloc(el->data, el->length + len);
+               if (el->data == NULL) {
+                       tdb->ecode = TDB_ERR_OOM;
+                       tdb->transaction->transaction_error = 1;
+                       el->data = data;
+                       return -1;
+               }
+               if (buf) {
+                       memcpy(el->data + el->length, buf, len);
+               } else {
+                       memset(el->data + el->length, TDB_PAD_BYTE, len);
+               }
+               el->length += len;
+               return 0;
+       }
+
        /* add a new entry at the end of the list */
        el = malloc(sizeof(*el));
        if (el == NULL) {
@@ -433,6 +459,15 @@ int tdb_transaction_start(struct tdb_context *tdb)
        tdb->transaction->io_methods = tdb->methods;
        tdb->methods = &transaction_methods;
 
+       /* by calling this transaction write here, we ensure that we don't grow the
+          transaction linked list due to hash table updates */
+       if (transaction_write(tdb, FREELIST_TOP, tdb->transaction->hash_heads, 
+                             TDB_HASHTABLE_SIZE(tdb)) != 0) {
+               TDB_LOG((tdb, 0, "tdb_transaction_start: failed to prime hash table\n"));
+               tdb->ecode = TDB_ERR_IO;
+               goto fail;
+       }
+
        return 0;
        
 fail: