Recycle data buffers for tree generation in fast-import.
authorShawn O. Pearce <spearce@spearce.org>
Mon, 28 Aug 2006 17:02:51 +0000 (13:02 -0400)
committerShawn O. Pearce <spearce@spearce.org>
Sun, 14 Jan 2007 07:15:10 +0000 (02:15 -0500)
We only ever generate at most two tree streams at a time. Since most
trees are around the same size we can simply recycle the buffers from
one tree generation to the next rather than constantly xmalloc'ing
and free'ing them. This should perform slightly better when handling
a large number of trees as malloc has less work to do.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
fast-import.c
index 6b011204150111d40cf8eb50117b24236eb214c8..8d15a057393f81041b734d18dbbc0a7c9357cf0d 100644 (file)
@@ -134,6 +134,7 @@ struct last_object
        void *data;
        unsigned long len;
        unsigned int depth;
+       int no_free;
        unsigned char sha1[20];
 };
 
@@ -195,6 +196,12 @@ struct tag
        unsigned char sha1[20];
 };
 
+struct dbuf
+{
+       void *buffer;
+       size_t capacity;
+};
+
 
 /* Stats and misc. counters */
 static unsigned long max_depth = 10;
@@ -243,6 +250,8 @@ static unsigned int tree_entry_alloc = 1000;
 static void *avail_tree_entry;
 static unsigned int avail_tree_table_sz = 100;
 static struct avail_tree_content **avail_tree_table;
+static struct dbuf old_tree;
+static struct dbuf new_tree;
 
 /* Branch data */
 static unsigned long max_active_branches = 5;
@@ -680,7 +689,7 @@ static int store_object(
        if (delta)
                free(delta);
        if (last) {
-               if (last->data)
+               if (last->data && !last->no_free)
                        free(last->data);
                last->data = dat;
                last->len = datlen;
@@ -897,11 +906,14 @@ static int tecmp1 (const void *_a, const void *_b)
                b->name->str_dat, b->name->str_len, b->versions[1].mode);
 }
 
-static void* mktree(struct tree_content *t, int v, unsigned long *szp)
+static void mktree(struct tree_content *t,
+       int v,
+       unsigned long *szp,
+       struct dbuf *b)
 {
        size_t maxlen = 0;
        unsigned int i;
-       char *buf, *c;
+       char *c;
 
        if (!v)
                qsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp0);
@@ -913,7 +925,16 @@ static void* mktree(struct tree_content *t, int v, unsigned long *szp)
                        maxlen += t->entries[i]->name->str_len + 34;
        }
 
-       buf = c = xmalloc(maxlen);
+       if (b->buffer) {
+               if (b->capacity < maxlen)
+                       b->capacity = ((maxlen / 1024) + 1) * 1024;
+               b->buffer = xrealloc(b->buffer, b->capacity);
+       } else {
+               b->capacity = ((maxlen / 1024) + 1) * 1024;
+               b->buffer = xmalloc(b->capacity);
+       }
+
+       c = b->buffer;
        for (i = 0; i < t->entry_count; i++) {
                struct tree_entry *e = t->entries[i];
                if (!e->versions[v].mode)
@@ -925,17 +946,14 @@ static void* mktree(struct tree_content *t, int v, unsigned long *szp)
                hashcpy((unsigned char*)c, e->versions[v].sha1);
                c += 20;
        }
-
-       *szp = c - buf;
-       return buf;
+       *szp = c - (char*)b->buffer;
 }
 
 static void store_tree(struct tree_entry *root)
 {
        struct tree_content *t = root->tree;
        unsigned int i, j, del;
-       unsigned long vers1len;
-       void **vers1dat;
+       unsigned long new_len;
        struct last_object lo;
 
        if (!is_null_sha1(root->versions[1].sha1))
@@ -951,16 +969,16 @@ static void store_tree(struct tree_entry *root)
                lo.data = NULL;
                lo.depth = 0;
        } else {
-               lo.data = mktree(t, 0, &lo.len);
+               mktree(t, 0, &lo.len, &old_tree);
+               lo.data = old_tree.buffer;
                lo.depth = t->delta_depth;
+               lo.no_free = 1;
                hashcpy(lo.sha1, root->versions[0].sha1);
        }
-       vers1dat = mktree(t, 1, &vers1len);
+       mktree(t, 1, &new_len, &new_tree);
 
-       store_object(OBJ_TREE, vers1dat, vers1len,
+       store_object(OBJ_TREE, new_tree.buffer, new_len,
                &lo, root->versions[1].sha1, 0);
-       /* note: lo.dat (if created) was freed by store_object */
-       free(vers1dat);
 
        t->delta_depth = lo.depth;
        hashcpy(root->versions[0].sha1, root->versions[1].sha1);