2019-11-12 17:58:20 +01:00
|
|
|
#include "test-tool.h"
|
|
|
|
#include "commit-graph.h"
|
|
|
|
#include "repository.h"
|
|
|
|
#include "object-store.h"
|
2022-03-01 20:48:28 +01:00
|
|
|
#include "bloom.h"
|
2023-03-21 07:26:05 +01:00
|
|
|
#include "setup.h"
|
2019-11-12 17:58:20 +01:00
|
|
|
|
2023-03-28 22:57:25 +02:00
|
|
|
int cmd__read_graph(int argc UNUSED, const char **argv UNUSED)
|
2019-11-12 17:58:20 +01:00
|
|
|
{
|
|
|
|
struct commit_graph *graph = NULL;
|
commit-graph.c: remove path normalization, comparison
As of the previous patch, all calls to 'commit-graph.c' functions which
perform path normalization (for e.g., 'get_commit_graph_filename()') are
of the form 'ctx->odb->path', which is always in normalized form.
Now that there are no callers passing non-normalized paths to these
functions, ensure that future callers are bound by the same restrictions
by making these functions take a 'struct object_directory *' instead of
a 'const char *'. To match, replace all calls with arguments of the form
'ctx->odb->path' with 'ctx->odb' To recover the path, functions that
perform path manipulation simply use 'odb->path'.
Further, avoid string comparisons with arguments of the form
'odb->path', and instead prefer raw pointer comparisons, which
accomplish the same effect, but are far less brittle.
This has a pleasant side-effect of making these functions much more
robust to paths that cannot be normalized by 'normalize_path_copy()',
i.e., because they are outside of the current working directory.
For example, prior to this patch, Valgrind reports that the following
uninitialized memory read [1]:
$ ( cd t && GIT_DIR=../.git valgrind git rev-parse HEAD^ )
because 'normalize_path_copy()' can't normalize '../.git' (since it's
relative to but above of the current working directory) [2].
By using a 'struct object_directory *' directly,
'get_commit_graph_filename()' does not need to normalize, because all
paths are relative to the current working directory since they are
always read from the '->path' of an object directory.
[1]: https://lore.kernel.org/git/20191027042116.GA5801@sigill.intra.peff.net.
[2]: The bug here is that 'get_commit_graph_filename()' returns the
result of 'normalize_path_copy()' without checking the return
value.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-03 22:18:02 +01:00
|
|
|
struct object_directory *odb;
|
2019-11-12 17:58:20 +01:00
|
|
|
|
|
|
|
setup_git_directory();
|
commit-graph.c: remove path normalization, comparison
As of the previous patch, all calls to 'commit-graph.c' functions which
perform path normalization (for e.g., 'get_commit_graph_filename()') are
of the form 'ctx->odb->path', which is always in normalized form.
Now that there are no callers passing non-normalized paths to these
functions, ensure that future callers are bound by the same restrictions
by making these functions take a 'struct object_directory *' instead of
a 'const char *'. To match, replace all calls with arguments of the form
'ctx->odb->path' with 'ctx->odb' To recover the path, functions that
perform path manipulation simply use 'odb->path'.
Further, avoid string comparisons with arguments of the form
'odb->path', and instead prefer raw pointer comparisons, which
accomplish the same effect, but are far less brittle.
This has a pleasant side-effect of making these functions much more
robust to paths that cannot be normalized by 'normalize_path_copy()',
i.e., because they are outside of the current working directory.
For example, prior to this patch, Valgrind reports that the following
uninitialized memory read [1]:
$ ( cd t && GIT_DIR=../.git valgrind git rev-parse HEAD^ )
because 'normalize_path_copy()' can't normalize '../.git' (since it's
relative to but above of the current working directory) [2].
By using a 'struct object_directory *' directly,
'get_commit_graph_filename()' does not need to normalize, because all
paths are relative to the current working directory since they are
always read from the '->path' of an object directory.
[1]: https://lore.kernel.org/git/20191027042116.GA5801@sigill.intra.peff.net.
[2]: The bug here is that 'get_commit_graph_filename()' returns the
result of 'normalize_path_copy()' without checking the return
value.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-03 22:18:02 +01:00
|
|
|
odb = the_repository->objects->odb;
|
2019-11-12 17:58:20 +01:00
|
|
|
|
2020-09-09 17:23:03 +02:00
|
|
|
prepare_repo_settings(the_repository);
|
|
|
|
|
2020-04-14 06:04:04 +02:00
|
|
|
graph = read_commit_graph_one(the_repository, odb);
|
2019-11-12 17:58:20 +01:00
|
|
|
if (!graph)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
printf("header: %08x %d %d %d %d\n",
|
|
|
|
ntohl(*(uint32_t*)graph->data),
|
|
|
|
*(unsigned char*)(graph->data + 4),
|
|
|
|
*(unsigned char*)(graph->data + 5),
|
|
|
|
*(unsigned char*)(graph->data + 6),
|
|
|
|
*(unsigned char*)(graph->data + 7));
|
|
|
|
printf("num_commits: %u\n", graph->num_commits);
|
|
|
|
printf("chunks:");
|
|
|
|
|
|
|
|
if (graph->chunk_oid_fanout)
|
|
|
|
printf(" oid_fanout");
|
|
|
|
if (graph->chunk_oid_lookup)
|
|
|
|
printf(" oid_lookup");
|
|
|
|
if (graph->chunk_commit_data)
|
|
|
|
printf(" commit_metadata");
|
commit-graph: implement generation data chunk
As discovered by Ævar, we cannot increment graph version to
distinguish between generation numbers v1 and v2 [1]. Thus, one of
pre-requistes before implementing generation number v2 was to
distinguish between graph versions in a backwards compatible manner.
We are going to introduce a new chunk called Generation DATa chunk (or
GDAT). GDAT will store corrected committer date offsets whereas CDAT
will still store topological level.
Old Git does not understand GDAT chunk and would ignore it, reading
topological levels from CDAT. New Git can parse GDAT and take advantage
of newer generation numbers, falling back to topological levels when
GDAT chunk is missing (as it would happen with a commit-graph written
by old Git).
We introduce a test environment variable 'GIT_TEST_COMMIT_GRAPH_NO_GDAT'
which forces commit-graph file to be written without generation data
chunk to emulate a commit-graph file written by old Git.
To minimize the space required to store corrrected commit date, Git
stores corrected commit date offsets into the commit-graph file, instea
of corrected commit dates. This saves us 4 bytes per commit, decreasing
the GDAT chunk size by half, but it's possible for the offset to
overflow the 4-bytes allocated for storage. As such overflows are and
should be exceedingly rare, we use the following overflow management
scheme:
We introduce a new commit-graph chunk, Generation Data OVerflow ('GDOV')
to store corrected commit dates for commits with offsets greater than
GENERATION_NUMBER_V2_OFFSET_MAX.
If the offset is greater than GENERATION_NUMBER_V2_OFFSET_MAX, we set
the MSB of the offset and the other bits store the position of corrected
commit date in GDOV chunk, similar to how Extra Edge List is maintained.
We test the overflow-related code with the following repo history:
F - N - U
/ \
U - N - U N
\ /
N - F - N
Where the commits denoted by U have committer date of zero seconds
since Unix epoch, the commits denoted by N have committer date of
1112354055 (default committer date for the test suite) seconds since
Unix epoch and the commits denoted by F have committer date of
(2 ^ 31 - 2) seconds since Unix epoch.
The largest offset observed is 2 ^ 31, just large enough to overflow.
[1]: https://lore.kernel.org/git/87a7gdspo4.fsf@evledraar.gmail.com/
Signed-off-by: Abhishek Kumar <abhishekkumar8222@gmail.com>
Reviewed-by: Taylor Blau <me@ttaylorr.com>
Reviewed-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-01-16 19:11:15 +01:00
|
|
|
if (graph->chunk_generation_data)
|
|
|
|
printf(" generation_data");
|
|
|
|
if (graph->chunk_generation_data_overflow)
|
|
|
|
printf(" generation_data_overflow");
|
2019-11-12 17:58:20 +01:00
|
|
|
if (graph->chunk_extra_edges)
|
|
|
|
printf(" extra_edges");
|
2020-04-06 18:59:54 +02:00
|
|
|
if (graph->chunk_bloom_indexes)
|
|
|
|
printf(" bloom_indexes");
|
|
|
|
if (graph->chunk_bloom_data)
|
|
|
|
printf(" bloom_data");
|
2019-11-12 17:58:20 +01:00
|
|
|
printf("\n");
|
|
|
|
|
2022-03-01 20:48:28 +01:00
|
|
|
printf("options:");
|
|
|
|
if (graph->bloom_filter_settings)
|
|
|
|
printf(" bloom(%"PRIu32",%"PRIu32",%"PRIu32")",
|
|
|
|
graph->bloom_filter_settings->hash_version,
|
|
|
|
graph->bloom_filter_settings->bits_per_entry,
|
|
|
|
graph->bloom_filter_settings->num_hashes);
|
|
|
|
if (graph->read_generation_data)
|
|
|
|
printf(" read_generation_data");
|
|
|
|
if (graph->topo_levels)
|
|
|
|
printf(" topo_levels");
|
|
|
|
printf("\n");
|
|
|
|
|
2019-11-12 17:58:20 +01:00
|
|
|
UNLEAK(graph);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|