Skip to content

Commit

Permalink
Merge branch 'jk/object-filter-with-bitmap'
Browse files Browse the repository at this point in the history
The object reachability bitmap machinery and the partial cloning
machinery were not prepared to work well together, because some
object-filtering criteria that partial clones use inherently rely
on object traversal, but the bitmap machinery is an optimization
to bypass that object traversal.  There however are some cases
where they can work together, and they were taught about them.

* jk/object-filter-with-bitmap:
  rev-list --count: comment on the use of count_right++
  pack-objects: support filters with bitmaps
  pack-bitmap: implement BLOB_LIMIT filtering
  pack-bitmap: implement BLOB_NONE filtering
  bitmap: add bitmap_unset() function
  rev-list: use bitmap filters for traversal
  pack-bitmap: basic noop bitmap filter infrastructure
  rev-list: allow commit-only bitmap traversals
  t5310: factor out bitmap traversal comparison
  rev-list: allow bitmaps when counting objects
  rev-list: make --count work with --objects
  rev-list: factor out bitmap-optimized routines
  pack-bitmap: refuse to do a bitmap traversal with pathspecs
  rev-list: fallback to non-bitmap traversal when filtering
  pack-bitmap: fix leak of haves/wants object lists
  pack-bitmap: factor out type iterator initialization
  • Loading branch information
gitster committed Mar 2, 2020
2 parents 80648bb + 20a5fd8 commit 0df82d9
Show file tree
Hide file tree
Showing 14 changed files with 511 additions and 70 deletions.
6 changes: 3 additions & 3 deletions builtin/pack-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -3184,7 +3184,7 @@ static int pack_options_allow_reuse(void)

static int get_object_list_from_bitmap(struct rev_info *revs)
{
if (!(bitmap_git = prepare_bitmap_walk(revs)))
if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options)))
return -1;

if (pack_options_allow_reuse() &&
Expand All @@ -3198,7 +3198,8 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
display_progress(progress_state, nr_result);
}

traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap);
traverse_bitmap_commit_list(bitmap_git, revs,
&add_object_entry_from_bitmap);
return 0;
}

Expand Down Expand Up @@ -3562,7 +3563,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (filter_options.choice) {
if (!pack_to_stdout)
die(_("cannot use --filter without --stdout"));
use_bitmap_index = 0;
}

/*
Expand Down
121 changes: 97 additions & 24 deletions builtin/rev-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,26 @@ static int finish_object(struct object *obj, const char *name, void *cb_data)
static void show_object(struct object *obj, const char *name, void *cb_data)
{
struct rev_list_info *info = cb_data;
struct rev_info *revs = info->revs;

if (finish_object(obj, name, cb_data))
return;
display_progress(progress, ++progress_counter);
if (info->flags & REV_LIST_QUIET)
return;

if (revs->count) {
/*
* The object count is always accumulated in the .count_right
* field for traversal that is not a left-right traversal,
* and cmd_rev_list() made sure that a .count request that
* wants to count non-commit objects, which is handled by
* the show_object() callback, does not ask for .left_right.
*/
revs->count_right++;
return;
}

if (arg_show_object_names)
show_object_with_name(stdout, obj, name);
else
Expand Down Expand Up @@ -364,6 +379,79 @@ static inline int parse_missing_action_value(const char *value)
return 0;
}

static int try_bitmap_count(struct rev_info *revs,
struct list_objects_filter_options *filter)
{
uint32_t commit_count = 0,
tag_count = 0,
tree_count = 0,
blob_count = 0;
int max_count;
struct bitmap_index *bitmap_git;

/* This function only handles counting, not general traversal. */
if (!revs->count)
return -1;

/*
* A bitmap result can't know left/right, etc, because we don't
* actually traverse.
*/
if (revs->left_right || revs->cherry_mark)
return -1;

/*
* If we're counting reachable objects, we can't handle a max count of
* commits to traverse, since we don't know which objects go with which
* commit.
*/
if (revs->max_count >= 0 &&
(revs->tag_objects || revs->tree_objects || revs->blob_objects))
return -1;

/*
* This must be saved before doing any walking, since the revision
* machinery will count it down to zero while traversing.
*/
max_count = revs->max_count;

bitmap_git = prepare_bitmap_walk(revs, filter);
if (!bitmap_git)
return -1;

count_bitmap_commit_list(bitmap_git, &commit_count,
revs->tree_objects ? &tree_count : NULL,
revs->blob_objects ? &blob_count : NULL,
revs->tag_objects ? &tag_count : NULL);
if (max_count >= 0 && max_count < commit_count)
commit_count = max_count;

printf("%d\n", commit_count + tree_count + blob_count + tag_count);
free_bitmap_index(bitmap_git);
return 0;
}

static int try_bitmap_traversal(struct rev_info *revs,
struct list_objects_filter_options *filter)
{
struct bitmap_index *bitmap_git;

/*
* We can't use a bitmap result with a traversal limit, since the set
* of commits we'd get would be essentially random.
*/
if (revs->max_count >= 0)
return -1;

bitmap_git = prepare_bitmap_walk(revs, filter);
if (!bitmap_git)
return -1;

traverse_bitmap_commit_list(bitmap_git, revs, &show_object_fast);
free_bitmap_index(bitmap_git);
return 0;
}

int cmd_rev_list(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
Expand Down Expand Up @@ -521,8 +609,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (revs.show_notes)
die(_("rev-list does not support display of notes"));

if (filter_options.choice && use_bitmap_index)
die(_("cannot combine --use-bitmap-index with object filtering"));
if (revs.count &&
(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
(revs.left_right || revs.cherry_mark))
die(_("marked counting is incompatible with --objects"));

save_commit_buffer = (revs.verbose_header ||
revs.grep_filter.pattern_list ||
Expand All @@ -533,28 +623,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (show_progress)
progress = start_delayed_progress(show_progress, 0);

if (use_bitmap_index && !revs.prune) {
if (revs.count && !revs.left_right && !revs.cherry_mark) {
uint32_t commit_count;
int max_count = revs.max_count;
struct bitmap_index *bitmap_git;
if ((bitmap_git = prepare_bitmap_walk(&revs))) {
count_bitmap_commit_list(bitmap_git, &commit_count, NULL, NULL, NULL);
if (max_count >= 0 && max_count < commit_count)
commit_count = max_count;
printf("%d\n", commit_count);
free_bitmap_index(bitmap_git);
return 0;
}
} else if (revs.max_count < 0 &&
revs.tag_objects && revs.tree_objects && revs.blob_objects) {
struct bitmap_index *bitmap_git;
if ((bitmap_git = prepare_bitmap_walk(&revs))) {
traverse_bitmap_commit_list(bitmap_git, &show_object_fast);
free_bitmap_index(bitmap_git);
return 0;
}
}
if (use_bitmap_index) {
if (!try_bitmap_count(&revs, &filter_options))
return 0;
if (!try_bitmap_traversal(&revs, &filter_options))
return 0;
}

if (prepare_revision_walk(&revs))
Expand Down
8 changes: 8 additions & 0 deletions ewah/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ void bitmap_set(struct bitmap *self, size_t pos)
self->words[block] |= EWAH_MASK(pos);
}

void bitmap_unset(struct bitmap *self, size_t pos)
{
size_t block = EWAH_BLOCK(pos);

if (block < self->word_alloc)
self->words[block] &= ~EWAH_MASK(pos);
}

int bitmap_get(struct bitmap *self, size_t pos)
{
size_t block = EWAH_BLOCK(pos);
Expand Down
1 change: 1 addition & 0 deletions ewah/ewok.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ struct bitmap {
struct bitmap *bitmap_new(void);
struct bitmap *bitmap_word_alloc(size_t word_alloc);
void bitmap_set(struct bitmap *self, size_t pos);
void bitmap_unset(struct bitmap *self, size_t pos);
int bitmap_get(struct bitmap *self, size_t pos);
void bitmap_reset(struct bitmap *self);
void bitmap_free(struct bitmap *self);
Expand Down
9 changes: 9 additions & 0 deletions object.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,15 @@ int object_list_contains(struct object_list *list, struct object *obj)
return 0;
}

void object_list_free(struct object_list **list)
{
while (*list) {
struct object_list *p = *list;
*list = p->next;
free(p);
}
}

/*
* A zero-length string to which object_array_entry::name can be
* initialized without requiring a malloc/free.
Expand Down
2 changes: 2 additions & 0 deletions object.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ struct object_list *object_list_insert(struct object *item,

int object_list_contains(struct object_list *list, struct object *obj);

void object_list_free(struct object_list **list);

/* Object array handling .. */
void add_object_array(struct object *obj, const char *name, struct object_array *array);
void add_object_array_with_path(struct object *obj, const char *name, struct object_array *array, unsigned mode, const char *path);
Expand Down
Loading

0 comments on commit 0df82d9

Please sign in to comment.