]> git.ipfire.org Git - thirdparty/git.git/commitdiff
pack-bitmap: implement BLOB_NONE filtering
authorJeff King <peff@peff.net>
Fri, 14 Feb 2020 18:22:36 +0000 (13:22 -0500)
committerJunio C Hamano <gitster@pobox.com>
Fri, 14 Feb 2020 18:46:22 +0000 (10:46 -0800)
We can easily support BLOB_NONE filters with bitmaps. Since we know the
types of all of the objects, we just need to clear the result bits of
any blobs.

Note two subtleties in the implementation (which I also called out in
comments):

  - we have to include any blobs that were specifically asked for (and
    not reached through graph traversal) to match the non-bitmap version

  - we have to handle in-pack and "ext_index" objects separately.
    Arguably prepare_bitmap_walk() could be adding these ext_index
    objects to the type bitmaps. But it doesn't for now, so let's match
    the rest of the bitmap code here (it probably wouldn't be an
    efficiency improvement to do so since the cost of extending those
    bitmaps is about the same as our loop here, but it might make the
    code a bit simpler).

Here are perf results for the new test on git.git:

  Test                                    HEAD^             HEAD
  --------------------------------------------------------------------------------
  5310.9: rev-list count with blob:none   1.67(1.62+0.05)   0.22(0.21+0.02) -86.8%

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
pack-bitmap.c
t/perf/p5310-pack-bitmaps.sh
t/t6113-rev-list-bitmap-filters.sh

index 48c8694f927fa388d0236bdc59310a2ccc92fed3..dcf8a9aadfbc2e2916181ea808c9dfd32575731f 100644 (file)
@@ -712,6 +712,73 @@ static int in_bitmapped_pack(struct bitmap_index *bitmap_git,
        return 0;
 }
 
+static struct bitmap *find_tip_blobs(struct bitmap_index *bitmap_git,
+                                    struct object_list *tip_objects)
+{
+       struct bitmap *result = bitmap_new();
+       struct object_list *p;
+
+       for (p = tip_objects; p; p = p->next) {
+               int pos;
+
+               if (p->item->type != OBJ_BLOB)
+                       continue;
+
+               pos = bitmap_position(bitmap_git, &p->item->oid);
+               if (pos < 0)
+                       continue;
+
+               bitmap_set(result, pos);
+       }
+
+       return result;
+}
+
+static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
+                                   struct object_list *tip_objects,
+                                   struct bitmap *to_filter)
+{
+       struct eindex *eindex = &bitmap_git->ext_index;
+       struct bitmap *tips;
+       struct ewah_iterator it;
+       eword_t mask;
+       uint32_t i;
+
+       /*
+        * The non-bitmap version of this filter never removes
+        * blobs which the other side specifically asked for,
+        * so we must match that behavior.
+        */
+       tips = find_tip_blobs(bitmap_git, tip_objects);
+
+       /*
+        * We can use the blob type-bitmap to work in whole words
+        * for the objects that are actually in the bitmapped packfile.
+        */
+       for (i = 0, init_type_iterator(&it, bitmap_git, OBJ_BLOB);
+            i < to_filter->word_alloc && ewah_iterator_next(&mask, &it);
+            i++) {
+               if (i < tips->word_alloc)
+                       mask &= ~tips->words[i];
+               to_filter->words[i] &= ~mask;
+       }
+
+       /*
+        * Clear any blobs that weren't in the packfile (and so would not have
+        * been caught by the loop above. We'll have to check them
+        * individually.
+        */
+       for (i = 0; i < eindex->count; i++) {
+               uint32_t pos = i + bitmap_git->pack->num_objects;
+               if (eindex->objects[i]->type == OBJ_BLOB &&
+                   bitmap_get(to_filter, pos) &&
+                   !bitmap_get(tips, pos))
+                       bitmap_unset(to_filter, pos);
+       }
+
+       bitmap_free(tips);
+}
+
 static int filter_bitmap(struct bitmap_index *bitmap_git,
                         struct object_list *tip_objects,
                         struct bitmap *to_filter,
@@ -720,6 +787,13 @@ static int filter_bitmap(struct bitmap_index *bitmap_git,
        if (!filter || filter->choice == LOFC_DISABLED)
                return 0;
 
+       if (filter->choice == LOFC_BLOB_NONE) {
+               if (bitmap_git)
+                       filter_bitmap_blob_none(bitmap_git, tip_objects,
+                                               to_filter);
+               return 0;
+       }
+
        /* filter choice not handled */
        return -1;
 }
index e52f66ec9ed878f6f838e4a416f165ae4f294df7..936742314cf4d077c109abae37c09fede68965e4 100755 (executable)
@@ -47,6 +47,11 @@ test_perf 'rev-list (objects)' '
        git rev-list --all --use-bitmap-index --objects >/dev/null
 '
 
+test_perf 'rev-list count with blob:none' '
+       git rev-list --use-bitmap-index --count --objects --all \
+               --filter=blob:none >/dev/null
+'
+
 test_expect_success 'create partial bitmap state' '
        # pick a commit to represent the repo tip in the past
        cutoff=$(git rev-list HEAD~100 -1) &&
index 977f8d0930020f2e6910b5e530ac2ffeae517786..f4e6d582f069342d2d3175090bf12b20f07251eb 100755 (executable)
@@ -21,4 +21,18 @@ test_expect_success 'filters fallback to non-bitmap traversal' '
        test_cmp expect actual
 '
 
+test_expect_success 'blob:none filter' '
+       git rev-list --objects --filter=blob:none HEAD >expect &&
+       git rev-list --use-bitmap-index \
+                    --objects --filter=blob:none HEAD >actual &&
+       test_bitmap_traversal expect actual
+'
+
+test_expect_success 'blob:none filter with specified blob' '
+       git rev-list --objects --filter=blob:none HEAD HEAD:two.t >expect &&
+       git rev-list --use-bitmap-index \
+                    --objects --filter=blob:none HEAD HEAD:two.t >actual &&
+       test_bitmap_traversal expect actual
+'
+
 test_done