Merge branch 'tc/last-modified-bloom' into seen
The 'git last-modified' command has been optimized by using Bloom filters. It now reuses revision walk filtering logic from 'git log' to pre-filter commits, and maintains per-path Bloom filters even when wildcard pathspecs are used. * tc/last-modified-bloom: last-modified: keep per-path Bloom filters for wildcard pathspecs last-modified: check pathspec against Bloom filter first revision: expose check for paths maybe changed in Bloom filter revision: move bloom keyvec precondition into functionseen
commit
e8965b160d
|
|
@ -272,6 +272,9 @@ static bool maybe_changed_path(struct last_modified *lm,
|
|||
if (!filter)
|
||||
return true;
|
||||
|
||||
if (revs_maybe_changed_in_bloom(&lm->rev, filter) == 0)
|
||||
return false;
|
||||
|
||||
hashmap_for_each_entry(&lm->paths, &iter, ent, hashent) {
|
||||
if (active && !bitmap_get(active, ent->diff_idx))
|
||||
continue;
|
||||
|
|
@ -358,6 +361,14 @@ static int last_modified_run(struct last_modified *lm)
|
|||
|
||||
prepare_revision_walk(&lm->rev);
|
||||
|
||||
/*
|
||||
* prepare_revision_walk() clears bloom_filter_settings for pathspecs
|
||||
* without a Bloom key. Restore it so the per-path check keeps working.
|
||||
*/
|
||||
if (!lm->rev.bloom_filter_settings)
|
||||
lm->rev.bloom_filter_settings =
|
||||
get_bloom_filter_settings(lm->rev.repo);
|
||||
|
||||
max_count = lm->rev.max_count;
|
||||
|
||||
init_active_paths_for_commit(&lm->active_paths);
|
||||
|
|
|
|||
32
revision.c
32
revision.c
|
|
@ -750,29 +750,43 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
|
|||
struct commit *commit)
|
||||
{
|
||||
struct bloom_filter *filter;
|
||||
int result = 0;
|
||||
int result;
|
||||
|
||||
if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY)
|
||||
return -1;
|
||||
|
||||
filter = get_bloom_filter(revs->repo, commit);
|
||||
|
||||
if (!filter) {
|
||||
count_bloom_filter_not_present++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = revs_maybe_changed_in_bloom(revs, filter);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (result)
|
||||
count_bloom_filter_maybe++;
|
||||
else
|
||||
count_bloom_filter_definitely_not++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int revs_maybe_changed_in_bloom(struct rev_info *revs,
|
||||
struct bloom_filter *filter)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (!revs->bloom_keyvecs_nr)
|
||||
return -1;
|
||||
|
||||
for (size_t nr = 0; !result && nr < revs->bloom_keyvecs_nr; nr++) {
|
||||
result = bloom_filter_contains_vec(filter,
|
||||
revs->bloom_keyvecs[nr],
|
||||
revs->bloom_filter_settings);
|
||||
}
|
||||
|
||||
if (result)
|
||||
count_bloom_filter_maybe++;
|
||||
else
|
||||
count_bloom_filter_definitely_not++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -806,7 +820,7 @@ static int rev_compare_tree(struct rev_info *revs,
|
|||
return REV_TREE_SAME;
|
||||
}
|
||||
|
||||
if (revs->bloom_keyvecs_nr && !nth_parent) {
|
||||
if (!nth_parent) {
|
||||
bloom_ret = check_maybe_different_in_bloom_filter(revs, commit);
|
||||
|
||||
if (bloom_ret == 0)
|
||||
|
|
@ -833,7 +847,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit,
|
|||
if (!t1)
|
||||
return 0;
|
||||
|
||||
if (!nth_parent && revs->bloom_keyvecs_nr) {
|
||||
if (!nth_parent) {
|
||||
bloom_ret = check_maybe_different_in_bloom_filter(revs, commit);
|
||||
if (!bloom_ret)
|
||||
return 1;
|
||||
|
|
|
|||
17
revision.h
17
revision.h
|
|
@ -68,6 +68,7 @@ struct string_list;
|
|||
struct saved_parents;
|
||||
struct follow_pathspec_slab;
|
||||
struct bloom_keyvec;
|
||||
struct bloom_filter;
|
||||
struct bloom_filter_settings;
|
||||
struct option;
|
||||
struct parse_opt_ctx_t;
|
||||
|
|
@ -495,6 +496,22 @@ void reset_revision_walk(void);
|
|||
*/
|
||||
int prepare_revision_walk(struct rev_info *revs);
|
||||
|
||||
/**
|
||||
* Take in a changed-path Bloom filter that belongs to a commit, and consult it
|
||||
* to see if it might have modified any of the paths in the `revs`.
|
||||
* The caller should look up `filter`, probably with get_bloom_filter().
|
||||
* prepare_revision_walk() needs to be called in advance to ensure
|
||||
* pathspec key vectors are set up.
|
||||
*
|
||||
* Returns -1 if no sensible answer could be given because of missing
|
||||
* preconditions (no pathspec key vectors).
|
||||
* Returns 0 if the commit definitely did not change any of the paths and 1 if
|
||||
* the commit maybe has changed one of them, although that might be a
|
||||
* false-positive.
|
||||
*/
|
||||
int revs_maybe_changed_in_bloom(struct rev_info *revs,
|
||||
struct bloom_filter *filter);
|
||||
|
||||
/* Drain the commits linked list into the priority queue. */
|
||||
void rev_info_commit_list_to_queue(struct rev_info *revs);
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue