mirror of
https://github.com/git/git.git
synced 2026-08-09 01:21:47 +00:00
Blame and "git log --stat" recover hunk coordinates by diffing blob pairs, and recompute them on every run. Add a cache of those coordinates at $GIT_DIR/objects/info/diff-hunks, beside the commit-graph, so a later run can look them up instead of decompressing the blobs and running xdiff again. The store is a single chunk-format file (see gitformat-chunk(5)): an 8-byte header, a DHIX index of fixed-size entries sorted by key, a DHDT segment of hunk records, and a trailing hash checksum. An entry is keyed by the two blob object ids and the xdl_opts the pair was diffed under, so a stored result is served only where that exact key recurs, independent of path. A zero-context diff trims unchanged lines from hunk edges and can pick a different but equally valid set of hunks than an untrimmed diff, so a recording caller stores a pair only when its trimmed and untrimmed diffs are identical; such an entry answers any consumer at any context, and the rare divergent pair is always computed. Identical hunk blocks are interned once and shared across keys. The library provides a reader (repo_diff_hunks_store and _replay, gated by core.diffHunks), loaded once and cached on the object database as the commit-graph is, and a writer that accumulates entries and flushes them in one atomic pass. An absent, corrupt, or disabled store reads as all misses. A record with no hunks is invalid too: replaying it would claim the pair equivalent, which the store never asserts, so it reads as a miss. Ordinary reads are diagnostic-free. Loading parses the chunk table through read_table_of_contents_quiet(), new in chunk-format, which prints nothing on a malformed table and takes the repository's hash algorithm rather than the_hash_algo, so the file is bounds-checked under the algorithm it is keyed by. The flush closes the repository's mmapped store and forgets that loading was attempted before committing the lockfile. A warming run that also reads may hold the file it is replacing mapped, and the rename must not land on a live mapping, which Windows refuses; a read after the flush then observes the committed file. commit-graph closes its graph before committing for the same reason. Writing is off by default, enabled per run by GIT_DIFF_HUNKS_WRITE or persistently by diffHunks.write, the environment winning. A writer seeds from the existing store, so a flush merges rather than replaces. The seed's checksum is verified first: a corrupt store is discarded, not rewritten with a fresh checksum verify could no longer catch. An entry that fails the shared diff_provider_check_hunk() or names no blob is dropped with a warning, since it would only ever read as a miss. A seed that discarded or dropped anything forces the flush even when the warming run computed nothing new. The writer fsyncs through a new diff-hunks core.fsync component. "git diff-hunks" inspects and manages the file: "verify" checks the checksum, chunk table, sort order, entry bounds, and every entry's hunk sequence against that shared check, so a store whose entries could only read as misses fails verify; "clear" removes the file. Later patches wire the readers and the writer into the diff and blame paths. Signed-off-by: Michael Montalbo <mmontalbo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
54 lines
1.3 KiB
C
54 lines
1.3 KiB
C
#include "builtin.h"
|
|
#include "config.h"
|
|
#include "diff-hunks.h"
|
|
#include "gettext.h"
|
|
#include "parse-options.h"
|
|
#include "repository.h"
|
|
|
|
static const char * const diff_hunks_usage[] = {
|
|
N_("git diff-hunks verify"),
|
|
N_("git diff-hunks clear"),
|
|
NULL
|
|
};
|
|
|
|
static int cmd_diff_hunks_verify(int argc, const char **argv,
|
|
const char *prefix UNUSED,
|
|
struct repository *r)
|
|
{
|
|
struct option options[] = { OPT_END() };
|
|
|
|
argc = parse_options(argc, argv, NULL, options, diff_hunks_usage, 0);
|
|
if (argc)
|
|
usage_with_options(diff_hunks_usage, options);
|
|
return diff_hunks_verify(r) ? 1 : 0;
|
|
}
|
|
|
|
static int cmd_diff_hunks_clear(int argc, const char **argv,
|
|
const char *prefix UNUSED,
|
|
struct repository *r)
|
|
{
|
|
struct option options[] = { OPT_END() };
|
|
|
|
argc = parse_options(argc, argv, NULL, options, diff_hunks_usage, 0);
|
|
if (argc)
|
|
usage_with_options(diff_hunks_usage, options);
|
|
return diff_hunks_clear(r) ? 1 : 0;
|
|
}
|
|
|
|
int cmd_diff_hunks(int argc, const char **argv, const char *prefix,
|
|
struct repository *repo)
|
|
{
|
|
parse_opt_subcommand_fn *fn = NULL;
|
|
struct option options[] = {
|
|
OPT_SUBCOMMAND("verify", &fn, cmd_diff_hunks_verify),
|
|
OPT_SUBCOMMAND("clear", &fn, cmd_diff_hunks_clear),
|
|
OPT_END()
|
|
};
|
|
|
|
repo_config(repo, git_default_config, NULL);
|
|
|
|
argc = parse_options(argc, argv, prefix, options, diff_hunks_usage, 0);
|
|
|
|
return fn(argc, argv, prefix, repo);
|
|
}
|