]> git.proxmox.com Git - libgit2.git/commitdiff
indexer: avoid memory moves
authorCarlos Martín Nieto <cmn@dwim.me>
Thu, 8 May 2014 20:31:59 +0000 (22:31 +0200)
committerCarlos Martín Nieto <cmn@dwim.me>
Thu, 8 May 2014 20:40:13 +0000 (22:40 +0200)
Our vector does a move of the rest of the array when we remove an
item. Doing this repeatedly can be expensive, and we do this a lot in
the indexer. Instead, set the value to NULL and skip those entries.

perf reported around 30% of `index-pack` time was going into
memmove. With this change, that goes away and we spent most of the time
hashing and inflating data.

src/indexer.c

index adf5ceaa74f470d77e2e5500ce8264f0ded5e3a1..3c8415c7c1eefd007faed34994b7ed2c7d71e46b 100644 (file)
@@ -717,6 +717,9 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats)
 
        /* Loop until we find the first REF delta */
        git_vector_foreach(&idx->deltas, i, delta) {
+               if (!delta)
+                       continue;
+
                curpos = delta->delta_off;
                error = git_packfile_unpack_header(&size, &type, &idx->pack->mwf, &w, &curpos);
                git_mwindow_close(&w);
@@ -756,13 +759,18 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
 {
        unsigned int i;
        struct delta_info *delta;
-       int progressed = 0, progress_cb_result;
+       int progressed = 0, non_null = 0, progress_cb_result;
 
        while (idx->deltas.length > 0) {
                progressed = 0;
+               non_null = 0;
                git_vector_foreach(&idx->deltas, i, delta) {
                        git_rawobj obj;
 
+                       if (!delta)
+                               continue;
+
+                       non_null = 1;
                        idx->off = delta->delta_off;
                        if (git_packfile_unpack(&obj, idx->pack, &idx->off) < 0)
                                continue;
@@ -777,16 +785,15 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
                        if ((progress_cb_result = do_progress_callback(idx, stats)) < 0)
                                return progress_cb_result;
 
-                       /*
-                        * Remove this delta from the list and
-                        * decrease i so we don't skip over the next
-                        * delta.
-                        */
-                       git_vector_remove(&idx->deltas, i);
+                       /* remove from the list */
+                       git_vector_set(NULL, &idx->deltas, i, NULL);
                        git__free(delta);
-                       i--;
                }
 
+               /* if none were actually set, we're done */
+               if (!non_null)
+                       break;
+
                if (!progressed && (fix_thin_pack(idx, stats) < 0)) {
                        giterr_set(GITERR_INDEXER, "missing delta bases");
                        return -1;