To read or write a commit graph we require access to the repository that the graph should be read from or written for as well as the object directory to derive its location. Instead of passing in these two bits of information explicitly though, we pass in a `struct odb_source`, which carries with it both of these pieces of information. But ultimately, this is somewhat flawed as we now assume that the source even has an on-disk representation, and furthermore we assume that the commit graphs would live in ".git/objects/info". This is true for the "files" backend, but it's not necessarily true for any other backend that we may eventually want to introduce. So eventually, we'll want to evolve the commit-graph subsystem to become agnostic of the backend's layout and let the backend itself decide where to read a commit graph from or where to write it to. We're not there yet to do that switch, but the current design is already causing issues for the intent of this patch series where we want to move alternates into the "files" backend. Convert the subsystem to take a repository plus an object directory path instead. This unblocks moving around alternates, and it's also a step in the right direction for moving commit graphs into the source in a later series. Note that we previously compared the `struct odb_source` pointers of two commit graphs to figure out whether they were located in the same object directory, whereas we now have to compare their paths. Callers may pass in those paths in different forms though, for example relative to the current working directory or as absolute paths. Convert the object directory into an absolute path both when loading and when writing commit graphs so that the comparisons become more robust. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
231 lines
7.4 KiB
C
231 lines
7.4 KiB
C
#ifndef COMMIT_GRAPH_H
|
|
#define COMMIT_GRAPH_H
|
|
|
|
#include "odb.h"
|
|
#include "oidset.h"
|
|
|
|
#define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
|
|
#define GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE "GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE"
|
|
#define GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS "GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS"
|
|
|
|
/*
|
|
* This environment variable controls whether commits looked up via the
|
|
* commit graph will be double checked to exist in the object database.
|
|
*/
|
|
#define GIT_COMMIT_GRAPH_PARANOIA "GIT_COMMIT_GRAPH_PARANOIA"
|
|
|
|
/*
|
|
* This method is only used to enhance coverage of the commit-graph
|
|
* feature in the test suite with the GIT_TEST_COMMIT_GRAPH and
|
|
* GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS environment variables. Do not
|
|
* call this method outside of a builtin, and only if you know what
|
|
* you are doing!
|
|
*/
|
|
void git_test_write_commit_graph_or_die(struct repository *repo);
|
|
|
|
struct commit;
|
|
struct bloom_filter_settings;
|
|
struct repository;
|
|
struct object_database;
|
|
struct string_list;
|
|
|
|
char *get_commit_graph_filename(const char *dir);
|
|
char *get_commit_graph_chain_filename(const char *dir);
|
|
int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
|
|
int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st,
|
|
const struct git_hash_algo *hash_algo);
|
|
|
|
/*
|
|
* Given a commit struct, try to fill the commit struct info, including:
|
|
* 1. tree object
|
|
* 2. date
|
|
* 3. parents.
|
|
*
|
|
* Returns 1 if and only if the commit was found in the packed graph.
|
|
*
|
|
* See parse_commit_buffer() for the fallback after this call.
|
|
*/
|
|
int parse_commit_in_graph(struct repository *r, struct commit *item);
|
|
|
|
/*
|
|
* Fills `*pos` with the graph position of `c`, and returns the graph `c` is
|
|
* found in, or NULL otherwise. Initializes the commit-graphs 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.
|
|
*/
|
|
struct commit_graph *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
|
|
* commit if the ID exists both in the graph and in the object database such
|
|
* that we don't return commits whose object has been pruned. Otherwise, this
|
|
* function returns `NULL`.
|
|
*/
|
|
struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id);
|
|
|
|
/*
|
|
* It is possible that we loaded commit contents from the commit buffer,
|
|
* but we also want to ensure the commit-graph content is correctly
|
|
* checked and filled. Fill the graph_pos and generation members of
|
|
* the given commit.
|
|
*/
|
|
void load_commit_graph_info(struct repository *r, struct commit *item);
|
|
|
|
struct tree *get_commit_tree_in_graph(struct repository *r,
|
|
const struct commit *c);
|
|
|
|
struct commit_graph {
|
|
const unsigned char *data;
|
|
size_t data_len;
|
|
|
|
struct repository *repo;
|
|
const struct git_hash_algo *hash_algo;
|
|
unsigned char num_chunks;
|
|
uint32_t num_commits;
|
|
struct object_id oid;
|
|
char *dir;
|
|
char *filename;
|
|
|
|
uint32_t num_commits_in_base;
|
|
unsigned int read_generation_data;
|
|
struct commit_graph *base_graph;
|
|
|
|
const uint32_t *chunk_oid_fanout;
|
|
const unsigned char *chunk_oid_lookup;
|
|
const unsigned char *chunk_commit_data;
|
|
const unsigned char *chunk_generation_data;
|
|
const unsigned char *chunk_generation_data_overflow;
|
|
size_t chunk_generation_data_overflow_size;
|
|
const unsigned char *chunk_extra_edges;
|
|
size_t chunk_extra_edges_size;
|
|
const unsigned char *chunk_base_graphs;
|
|
size_t chunk_base_graphs_size;
|
|
const unsigned char *chunk_bloom_indexes;
|
|
const unsigned char *chunk_bloom_data;
|
|
size_t chunk_bloom_data_size;
|
|
|
|
struct topo_level_slab *topo_levels;
|
|
struct bloom_filter_settings *bloom_filter_settings;
|
|
};
|
|
|
|
/*
|
|
* Load commit graphs from the given object directory `dir`. The directory may
|
|
* be given as a relative path; it is canonicalized internally so that graphs
|
|
* loaded from the same directory compare equal regardless of how the caller
|
|
* spelled the path.
|
|
*/
|
|
struct commit_graph *load_commit_graph_one_fd_st(struct repository *repo,
|
|
const char *dir,
|
|
int fd, struct stat *st);
|
|
struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,
|
|
int fd, struct stat *st,
|
|
int *incomplete_chain);
|
|
struct commit_graph *read_commit_graph_one(struct repository *repo,
|
|
const char *dir);
|
|
|
|
struct repo_settings;
|
|
|
|
/*
|
|
* Callers should initialize the repo_settings with prepare_repo_settings()
|
|
* prior to calling parse_commit_graph().
|
|
*/
|
|
struct commit_graph *parse_commit_graph(struct repository *r,
|
|
void *graph_map, size_t graph_size);
|
|
|
|
/*
|
|
* Return 1 if and only if the repository has a commit-graph
|
|
* file and generation numbers are computed in that file.
|
|
*/
|
|
int generation_numbers_enabled(struct repository *r);
|
|
|
|
/*
|
|
* Return 1 if and only if the repository has a commit-graph
|
|
* file and generation data chunk has been written for the file.
|
|
*/
|
|
int corrected_commit_dates_enabled(struct repository *r);
|
|
|
|
struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r);
|
|
|
|
enum commit_graph_write_flags {
|
|
COMMIT_GRAPH_WRITE_APPEND = (1 << 0),
|
|
COMMIT_GRAPH_WRITE_PROGRESS = (1 << 1),
|
|
COMMIT_GRAPH_WRITE_SPLIT = (1 << 2),
|
|
COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 3),
|
|
COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS = (1 << 4),
|
|
};
|
|
|
|
enum commit_graph_split_flags {
|
|
COMMIT_GRAPH_SPLIT_UNSPECIFIED = 0,
|
|
COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED = 1,
|
|
COMMIT_GRAPH_SPLIT_REPLACE = 2
|
|
};
|
|
|
|
struct commit_graph_opts {
|
|
int size_multiple;
|
|
int max_commits;
|
|
timestamp_t expire_time;
|
|
enum commit_graph_split_flags split_flags;
|
|
int max_new_filters;
|
|
};
|
|
|
|
/*
|
|
* The write_commit_graph* methods return zero on success
|
|
* and a negative value on failure. Note that if the repository
|
|
* is not compatible with the commit-graph feature, then the
|
|
* methods will return 0 without writing a commit-graph.
|
|
*
|
|
* The object directory `dir` may be given as a relative path; it is
|
|
* canonicalized internally so that it compares equal to the directory of
|
|
* graphs that have already been loaded.
|
|
*/
|
|
int write_commit_graph_reachable(struct repository *repo,
|
|
const char *dir,
|
|
enum commit_graph_write_flags flags,
|
|
const struct commit_graph_opts *opts);
|
|
int write_commit_graph(struct repository *r,
|
|
const char *dir,
|
|
const struct string_list *pack_indexes,
|
|
struct oidset *commits,
|
|
enum commit_graph_write_flags flags,
|
|
const struct commit_graph_opts *opts);
|
|
|
|
#define COMMIT_GRAPH_VERIFY_SHALLOW (1 << 0)
|
|
|
|
int verify_commit_graph(struct commit_graph *g, int flags);
|
|
|
|
void close_commit_graph(struct object_database *);
|
|
void free_commit_graph(struct commit_graph *);
|
|
|
|
/*
|
|
* Disable further use of the commit graph in this process when parsing a
|
|
* "struct commit".
|
|
*/
|
|
void disable_commit_graph(struct repository *r);
|
|
|
|
struct commit_graph_data {
|
|
uint32_t graph_pos;
|
|
timestamp_t generation;
|
|
};
|
|
|
|
/*
|
|
* Commits should be parsed before accessing generation, graph positions.
|
|
*/
|
|
timestamp_t commit_graph_generation(const struct commit *);
|
|
uint32_t commit_graph_position(const struct commit *);
|
|
|
|
/*
|
|
* After this method, all commits reachable from those in the given
|
|
* list will have non-zero, non-infinite generation numbers.
|
|
*/
|
|
void ensure_generations_valid(struct repository *r,
|
|
struct commit **commits, size_t nr);
|
|
|
|
#endif
|