Merge branch 'tc/last-modified-bloom' into seen
* tc/last-modified-bloom: fixup! last-modified: keep per-path Bloom filters for wildcard pathspecs fixup! last-modified: check pathspec against Bloom filter first last-modified: keep per-path Bloom filters for wildcard pathspecs last-modified: check pathspec against Bloom filter first revision: add Bloom check that includes parent directories bloom: add helper to check if any key in a vector is present revision: expose check for paths maybe changed in Bloom filter revision: move bloom keyvec precondition into functionseen
commit
f8c5c24fba
12
bloom.c
12
bloom.c
|
|
@ -607,6 +607,18 @@ int bloom_filter_contains_vec(const struct bloom_filter *filter,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int bloom_filter_contains_any_vec(const struct bloom_filter *filter,
|
||||
const struct bloom_keyvec *vec,
|
||||
const struct bloom_filter_settings *settings)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (size_t nr = 0; !ret && nr < vec->count; nr++)
|
||||
ret = bloom_filter_contains(filter, &vec->key[nr], settings);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t test_bloom_murmur3_seeded(uint32_t seed, const char *data, size_t len,
|
||||
int version)
|
||||
{
|
||||
|
|
|
|||
11
bloom.h
11
bloom.h
|
|
@ -164,6 +164,17 @@ int bloom_filter_contains_vec(const struct bloom_filter *filter,
|
|||
const struct bloom_keyvec *v,
|
||||
const struct bloom_filter_settings *settings);
|
||||
|
||||
/*
|
||||
* bloom_filter_contains_any_vec - Check if any key in a key vector is in the
|
||||
* Bloom filter.
|
||||
*
|
||||
* Returns 1 if **any** key in the vector is present in the filter, 0 if none
|
||||
* of them are.
|
||||
*/
|
||||
int bloom_filter_contains_any_vec(const struct bloom_filter *filter,
|
||||
const struct bloom_keyvec *v,
|
||||
const struct bloom_filter_settings *settings);
|
||||
|
||||
uint32_t test_bloom_murmur3_seeded(uint32_t seed, const char *data, size_t len,
|
||||
int version);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "quote.h"
|
||||
#include "repository.h"
|
||||
#include "revision.h"
|
||||
#include "trace2.h"
|
||||
|
||||
/* Remember to update object flag allocation in object.h */
|
||||
#define PARENT1 (1u<<16) /* used instead of SEEN */
|
||||
|
|
@ -63,6 +64,8 @@ struct last_modified {
|
|||
|
||||
/* 'scratch' to avoid allocating a bitmap every process_parent() */
|
||||
struct bitmap *scratch;
|
||||
|
||||
unsigned int count_bloom_filter_queries;
|
||||
};
|
||||
|
||||
static struct bitmap *active_paths_for(struct last_modified *lm, struct commit *c)
|
||||
|
|
@ -272,6 +275,20 @@ static bool maybe_changed_path(struct last_modified *lm,
|
|||
if (!filter)
|
||||
return true;
|
||||
|
||||
lm->count_bloom_filter_queries++;
|
||||
|
||||
/*
|
||||
* With --show-trees we also track the tree entries containing the
|
||||
* paths, so a change to any of those parent directories matters too.
|
||||
*/
|
||||
if (lm->show_trees) {
|
||||
if (!revs_maybe_changed_in_bloom_with_parents(&lm->rev, filter))
|
||||
return false;
|
||||
} else {
|
||||
if (!revs_maybe_changed_in_bloom(&lm->rev, filter))
|
||||
return false;
|
||||
}
|
||||
|
||||
hashmap_for_each_entry(&lm->paths, &iter, ent, hashent) {
|
||||
if (active && !bitmap_get(active, ent->diff_idx))
|
||||
continue;
|
||||
|
|
@ -358,6 +375,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);
|
||||
|
|
@ -467,6 +492,9 @@ cleanup:
|
|||
if (hashmap_get_size(&lm->paths))
|
||||
BUG("paths remaining beyond boundary in last-modified");
|
||||
|
||||
trace2_data_intmax("last-modified", lm->rev.repo, "bloom_queries",
|
||||
lm->count_bloom_filter_queries);
|
||||
|
||||
clear_prio_queue(¬_queue);
|
||||
clear_prio_queue(&queue);
|
||||
clear_active_paths_for_commit(&lm->active_paths);
|
||||
|
|
|
|||
52
revision.c
52
revision.c
|
|
@ -750,7 +750,9 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
|
|||
struct commit *commit)
|
||||
{
|
||||
struct bloom_filter *filter;
|
||||
int result = 0;
|
||||
|
||||
if (!revs->bloom_keyvecs_nr)
|
||||
return -1;
|
||||
|
||||
if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY)
|
||||
return -1;
|
||||
|
|
@ -762,18 +764,44 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
|
|||
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 (revs_maybe_changed_in_bloom(revs, filter)) {
|
||||
count_bloom_filter_maybe++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (result)
|
||||
count_bloom_filter_maybe++;
|
||||
else
|
||||
count_bloom_filter_definitely_not++;
|
||||
count_bloom_filter_definitely_not++;
|
||||
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool revs_maybe_changed_in_bloom(struct rev_info *revs,
|
||||
struct bloom_filter *filter)
|
||||
{
|
||||
if (!revs->bloom_keyvecs_nr || !filter)
|
||||
return true;
|
||||
|
||||
for (size_t nr = 0; nr < revs->bloom_keyvecs_nr; nr++)
|
||||
if (bloom_filter_contains_vec(filter,
|
||||
revs->bloom_keyvecs[nr],
|
||||
revs->bloom_filter_settings))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool revs_maybe_changed_in_bloom_with_parents(struct rev_info *revs,
|
||||
struct bloom_filter *filter)
|
||||
{
|
||||
if (!revs->bloom_keyvecs_nr || !filter)
|
||||
return true;
|
||||
|
||||
for (size_t nr = 0; nr < revs->bloom_keyvecs_nr; nr++)
|
||||
if (bloom_filter_contains_any_vec(filter,
|
||||
revs->bloom_keyvecs[nr],
|
||||
revs->bloom_filter_settings))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int rev_compare_tree(struct rev_info *revs,
|
||||
|
|
@ -806,7 +834,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 +861,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;
|
||||
|
|
|
|||
20
revision.h
20
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,25 @@ void reset_revision_walk(void);
|
|||
*/
|
||||
int prepare_revision_walk(struct rev_info *revs);
|
||||
|
||||
/**
|
||||
* Consult a changed-path Bloom filter to determine if the commit to which the
|
||||
* filter belongs might have changed any of the paths in the `revs`.
|
||||
* prepare_revision_walk() needs to be called in advance to ensure
|
||||
* pathspec key vectors are set up.
|
||||
*
|
||||
* Returns false iff the commit definitely did not change any of the paths.
|
||||
*/
|
||||
bool revs_maybe_changed_in_bloom(struct rev_info *revs,
|
||||
struct bloom_filter *filter);
|
||||
|
||||
/**
|
||||
* Same as revs_maybe_changed_in_bloom(), but a change to any of the directories
|
||||
* leading up to a path counts as well. Callers that track the tree entries
|
||||
* containing the paths, and not just the paths themselves, need this.
|
||||
*/
|
||||
bool revs_maybe_changed_in_bloom_with_parents(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);
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -269,6 +269,57 @@ test_expect_success 'last-modified merge undoes changes' '
|
|||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'last-modified with Bloom filters and --show-trees' '
|
||||
test_when_finished rm -rf bloom &&
|
||||
git init bloom &&
|
||||
(
|
||||
cd bloom &&
|
||||
mkdir d &&
|
||||
test_commit base-a d/a &&
|
||||
test_commit base-b d/b &&
|
||||
test_commit touch-a d/a &&
|
||||
test_commit touch-b d/b &&
|
||||
|
||||
git commit-graph write --reachable --changed-paths &&
|
||||
GIT_TEST_COMMIT_GRAPH=0 \
|
||||
git -c core.commitGraph=false last-modified -t HEAD -- d/a \
|
||||
>expect &&
|
||||
GIT_TEST_COMMIT_GRAPH=1 \
|
||||
git -c core.commitGraph=true last-modified -t HEAD -- d/a \
|
||||
>actual &&
|
||||
|
||||
test_cmp expect actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'last-modified with Bloom filters and top-level wildcard' '
|
||||
test_when_finished rm -rf wildcard &&
|
||||
git init wildcard &&
|
||||
(
|
||||
cd wildcard &&
|
||||
test_commit base-c a.c &&
|
||||
test_commit base-h a.h &&
|
||||
test_commit touch-c a.c &&
|
||||
mkdir d &&
|
||||
test_commit sub-c d/b.c &&
|
||||
|
||||
git commit-graph write --reachable --changed-paths &&
|
||||
GIT_TEST_COMMIT_GRAPH=0 \
|
||||
GIT_TRACE2_PERF="$(pwd)/off.perf" \
|
||||
git -c core.commitGraph=false last-modified -r HEAD \
|
||||
-- "*.c" >expect &&
|
||||
test_grep "data .* bloom_queries:0$" off.perf &&
|
||||
|
||||
GIT_TEST_COMMIT_GRAPH=1 \
|
||||
GIT_TRACE2_PERF="$(pwd)/on.perf" \
|
||||
git -c core.commitGraph=true last-modified -r HEAD \
|
||||
-- "*.c" >actual &&
|
||||
test_grep "data .* bloom_queries:2$" on.perf &&
|
||||
|
||||
test_cmp expect actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'cannot run last-modified on two commits' '
|
||||
test_must_fail git last-modified HEAD HEAD~1 2>err &&
|
||||
test_grep "last-modified can only operate on one commit at a time" err
|
||||
|
|
|
|||
Loading…
Reference in New Issue