Merge branch 'tb/commit-graph-genv2-upgrade-fix' into maint
There was a bug in the codepath to upgrade generation information in commit-graph from v1 to v2 format, which has been corrected. source: <cover.1657667404.git.me@ttaylorr.com> * tb/commit-graph-genv2-upgrade-fix: commit-graph: fix corrupt upgrade from generation v1 to v2 commit-graph: introduce `repo_find_commit_pos_in_graph()` t5318: demonstrate commit-graph generation v2 corruption
This commit is contained in:
commit
042159a509
10
bloom.c
10
bloom.c
@ -30,10 +30,9 @@ static inline unsigned char get_bitmask(uint32_t pos)
|
|||||||
|
|
||||||
static int load_bloom_filter_from_graph(struct commit_graph *g,
|
static int load_bloom_filter_from_graph(struct commit_graph *g,
|
||||||
struct bloom_filter *filter,
|
struct bloom_filter *filter,
|
||||||
struct commit *c)
|
uint32_t graph_pos)
|
||||||
{
|
{
|
||||||
uint32_t lex_pos, start_index, end_index;
|
uint32_t lex_pos, start_index, end_index;
|
||||||
uint32_t graph_pos = commit_graph_position(c);
|
|
||||||
|
|
||||||
while (graph_pos < g->num_commits_in_base)
|
while (graph_pos < g->num_commits_in_base)
|
||||||
g = g->base_graph;
|
g = g->base_graph;
|
||||||
@ -203,9 +202,10 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
|
|||||||
filter = bloom_filter_slab_at(&bloom_filters, c);
|
filter = bloom_filter_slab_at(&bloom_filters, c);
|
||||||
|
|
||||||
if (!filter->data) {
|
if (!filter->data) {
|
||||||
load_commit_graph_info(r, c);
|
uint32_t graph_pos;
|
||||||
if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH)
|
if (repo_find_commit_pos_in_graph(r, c, &graph_pos))
|
||||||
load_bloom_filter_from_graph(r->objects->commit_graph, filter, c);
|
load_bloom_filter_from_graph(r->objects->commit_graph,
|
||||||
|
filter, graph_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter->data && filter->len)
|
if (filter->data && filter->len)
|
||||||
|
@ -889,6 +889,14 @@ static int find_commit_pos_in_graph(struct commit *item, struct commit_graph *g,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c,
|
||||||
|
uint32_t *pos)
|
||||||
|
{
|
||||||
|
if (!prepare_commit_graph(r))
|
||||||
|
return 0;
|
||||||
|
return find_commit_pos_in_graph(c, r->objects->commit_graph, pos);
|
||||||
|
}
|
||||||
|
|
||||||
struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id)
|
struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id)
|
||||||
{
|
{
|
||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
@ -946,9 +954,7 @@ int parse_commit_in_graph(struct repository *r, struct commit *item)
|
|||||||
void load_commit_graph_info(struct repository *r, struct commit *item)
|
void load_commit_graph_info(struct repository *r, struct commit *item)
|
||||||
{
|
{
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
if (!prepare_commit_graph(r))
|
if (repo_find_commit_pos_in_graph(r, item, &pos))
|
||||||
return;
|
|
||||||
if (find_commit_pos_in_graph(item, r->objects->commit_graph, &pos))
|
|
||||||
fill_commit_graph_info(item, r->objects->commit_graph, pos);
|
fill_commit_graph_info(item, r->objects->commit_graph, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,21 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
|
|||||||
*/
|
*/
|
||||||
int parse_commit_in_graph(struct repository *r, struct commit *item);
|
int parse_commit_in_graph(struct repository *r, struct commit *item);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fills `*pos` with the graph position of `c`, and returns 1 if `c` is
|
||||||
|
* found in the commit-graph belonging to `r`, or 0 otherwise.
|
||||||
|
* Initializes the commit-graph belonging to `r` if it hasn't been
|
||||||
|
* already.
|
||||||
|
*
|
||||||
|
* Note: this is a low-level helper that does not alter any slab data
|
||||||
|
* associated with `c`. Useful in circumstances where the slab data is
|
||||||
|
* already being modified (e.g., writing the commit-graph itself).
|
||||||
|
*
|
||||||
|
* In most cases, callers should use `parse_commit_in_graph()` instead.
|
||||||
|
*/
|
||||||
|
int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c,
|
||||||
|
uint32_t *pos);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the given commit ID in the commit-graph. This will only return a
|
* Look up the given commit ID in the commit-graph. This will only return a
|
||||||
* commit if the ID exists both in the graph and in the object database such
|
* commit if the ID exists both in the graph and in the object database such
|
||||||
|
@ -811,4 +811,31 @@ test_expect_success 'set up and verify repo with generation data overflow chunk'
|
|||||||
|
|
||||||
graph_git_behavior 'generation data overflow chunk repo' repo left right
|
graph_git_behavior 'generation data overflow chunk repo' repo left right
|
||||||
|
|
||||||
|
test_expect_success 'overflow during generation version upgrade' '
|
||||||
|
git init overflow-v2-upgrade &&
|
||||||
|
(
|
||||||
|
cd overflow-v2-upgrade &&
|
||||||
|
|
||||||
|
# This commit will have a date at two seconds past the Epoch,
|
||||||
|
# and a (v1) generation number of 1, since it is a root commit.
|
||||||
|
#
|
||||||
|
# The offset will then be computed as 1-2, which will underflow
|
||||||
|
# to 2^31, which is greater than the v2 offset small limit of
|
||||||
|
# 2^31-1.
|
||||||
|
#
|
||||||
|
# This is sufficient to need a large offset table for the v2
|
||||||
|
# generation numbers.
|
||||||
|
test_commit --date "@2 +0000" base &&
|
||||||
|
git repack -d &&
|
||||||
|
|
||||||
|
# Test that upgrading from generation v1 to v2 correctly
|
||||||
|
# produces the overflow table.
|
||||||
|
git -c commitGraph.generationVersion=1 commit-graph write &&
|
||||||
|
git -c commitGraph.generationVersion=2 commit-graph write \
|
||||||
|
--changed-paths &&
|
||||||
|
|
||||||
|
git rev-list --all
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user