diff --git a/bloom.c b/bloom.c index 9a8386ac67602a..e22c0108f3937d 100644 --- a/bloom.c +++ b/bloom.c @@ -138,6 +138,11 @@ void fill_bloom_key(const char *data, key->hashes[i] = hash0 + i * hash1; } +void clear_bloom_key(struct bloom_key *key) +{ + FREE_AND_NULL(key->hashes); +} + void add_key_to_filter(const struct bloom_key *key, struct bloom_filter *filter, const struct bloom_filter_settings *settings) diff --git a/bloom.h b/bloom.h index a51e3715296ebe..d0c69172e6773f 100644 --- a/bloom.h +++ b/bloom.h @@ -72,6 +72,7 @@ void fill_bloom_key(const char *data, size_t len, struct bloom_key *key, const struct bloom_filter_settings *settings); +void clear_bloom_key(struct bloom_key *key); void add_key_to_filter(const struct bloom_key *key, struct bloom_filter *filter, diff --git a/line-log.c b/line-log.c index 520ee715bcdb02..7dc411da8f6a2a 100644 --- a/line-log.c +++ b/line-log.c @@ -15,6 +15,7 @@ #include "userdiff.h" #include "line-log.h" #include "argv-array.h" +#include "bloom.h" static void range_set_grow(struct range_set *rs, size_t extra) { @@ -1146,6 +1147,37 @@ int line_log_print(struct rev_info *rev, struct commit *commit) return 1; } +static int bloom_filter_check(struct rev_info *rev, + struct commit *commit, + struct line_log_data *range) +{ + struct bloom_filter *filter; + struct bloom_key key; + int result = 0; + + if (!commit->parents) + return 1; + + if (!rev->bloom_filter_settings || + !(filter = get_bloom_filter(rev->repo, commit, 0))) + return 1; + + if (!range) + return 0; + + while (!result && range) { + fill_bloom_key(range->path, strlen(range->path), &key, rev->bloom_filter_settings); + + if (bloom_filter_contains(filter, &key, rev->bloom_filter_settings)) + result = 1; + + clear_bloom_key(&key); + range = range->next; + } + + return result; +} + static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *commit, struct line_log_data *range) { @@ -1159,6 +1191,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c queue_diffs(range, &rev->diffopt, &queue, commit, parent); changed = process_all_files(&parent_range, rev, &queue, range); + if (parent) add_line_range(rev, parent, parent_range); free_line_log_data(parent_range); @@ -1233,7 +1266,11 @@ int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit int changed = 0; if (range) { - if (!commit->parents || !commit->parents->next) + if (commit->parents && !bloom_filter_check(rev, commit, range)) { + struct line_log_data *prange = line_log_data_copy(range); + add_line_range(rev, commit->parents->item, prange); + clear_commit_line_range(rev, commit); + } else if (!commit->parents || !commit->parents->next) changed = process_ranges_ordinary_commit(rev, commit, range); else changed = process_ranges_merge_commit(rev, commit, range); diff --git a/revision.c b/revision.c index 3356ede9a20bd3..cbf4b61aa67e65 100644 --- a/revision.c +++ b/revision.c @@ -689,6 +689,9 @@ static void prepare_to_use_bloom_filter(struct rev_info *revs) if (!revs->bloom_filter_settings) return; + if (!revs->pruning.pathspec.nr) + return; + pi = &revs->pruning.pathspec.items[0]; last_index = pi->len - 1; @@ -3501,7 +3504,7 @@ int prepare_revision_walk(struct rev_info *revs) FOR_EACH_OBJECT_PROMISOR_ONLY); } - if (revs->pruning.pathspec.nr == 1 && !revs->reflog_info) + if (!revs->reflog_info) prepare_to_use_bloom_filter(revs); if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED) commit_list_sort_by_date(&revs->commits);