Skip to content

Commit

Permalink
Merge branch 'ds/sparse-index-protections' into seen
Browse files Browse the repository at this point in the history
* ds/sparse-index-protections: (27 commits)
  name-hash: use expand_to_path()
  sparse-index: expand_to_path()
  revision: ensure full index
  resolve-undo: ensure full index
  read-cache: ensure full index
  pathspec: ensure full index
  merge-recursive: ensure full index
  merge-ort: ensure full index
  entry: ensure full index
  dir: ensure full index
  diff-lib: ensure full index
  update-index: ensure full index
  sparse-checkout: ensure full index
  rm: ensure full index
  merge-index: ensure full index
  ls-files: ensure full index
  grep: ensure full index
  fsck: ensure full index
  difftool: ensure full index
  commit: ensure full index
  ...
  • Loading branch information
gitster committed Mar 19, 2021
2 parents 8910a65 + 88351a6 commit 8bc8e10
Show file tree
Hide file tree
Showing 34 changed files with 240 additions and 70 deletions.
32 changes: 29 additions & 3 deletions Documentation/technical/sparse-index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,35 @@ also introduce other features that have been considered for improving the
index, as well.

Next, consumers of the index will be guarded against operating on a
sparse-index by inserting calls to `ensure_full_index()` or
`expand_index_to_path()`. After these guards are in place, we can begin
leaving sparse-directory entries in the in-memory index structure.
sparse-index by inserting calls to `ensure_full_index()` before iterating
over all cache entries. If a specific path is requested, then those will
be protected from within the `index_file_exists()` and `index_name_pos()`
API calls: they will call `ensure_full_index()` if necessary.

During a scan of the codebase, not every iteration of the cache entries
needs an `ensure_full_index()` check. The basic reasons include:

1. The loop is scanning for entries with non-zero stage. These entries
are not collapsed into a sparse-directory entry.

2. The loop is scanning for submodules. These entries are not collapsed
into a sparse-directory entry.

3. The loop is part of the index API, especially around reading or
writing the format.

4. The loop is checking for correct order of cache entries and that is
correct if and only if the sparse-directory entries are in the correct
location.

5. The loop ignores entries with the `SKIP_WORKTREE` bit set, or is
otherwise already aware of sparse directory entries.

6. The sparse-index is disabled at this point when using the split-index
feature, so no effort is made to protect the split-index API.

After these guards are in place, we can begin leaving sparse-directory
entries in the in-memory index structure.

Even after inserting these guards, we will keep expanding sparse-indexes
for most Git commands using the `command_requires_full_index` repository
Expand Down
14 changes: 7 additions & 7 deletions attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
return res;
}

static struct attr_stack *read_attr_from_index(const struct index_state *istate,
static struct attr_stack *read_attr_from_index(struct index_state *istate,
const char *path,
unsigned flags)
{
Expand Down Expand Up @@ -763,7 +763,7 @@ static struct attr_stack *read_attr_from_index(const struct index_state *istate,
return res;
}

static struct attr_stack *read_attr(const struct index_state *istate,
static struct attr_stack *read_attr(struct index_state *istate,
const char *path, unsigned flags)
{
struct attr_stack *res = NULL;
Expand Down Expand Up @@ -855,7 +855,7 @@ static void push_stack(struct attr_stack **attr_stack_p,
}
}

static void bootstrap_attr_stack(const struct index_state *istate,
static void bootstrap_attr_stack(struct index_state *istate,
struct attr_stack **stack)
{
struct attr_stack *e;
Expand Down Expand Up @@ -894,7 +894,7 @@ static void bootstrap_attr_stack(const struct index_state *istate,
push_stack(stack, e, NULL, 0);
}

static void prepare_attr_stack(const struct index_state *istate,
static void prepare_attr_stack(struct index_state *istate,
const char *path, int dirlen,
struct attr_stack **stack)
{
Expand Down Expand Up @@ -1094,7 +1094,7 @@ static void determine_macros(struct all_attrs_item *all_attrs,
* If check->check_nr is non-zero, only attributes in check[] are collected.
* Otherwise all attributes are collected.
*/
static void collect_some_attrs(const struct index_state *istate,
static void collect_some_attrs(struct index_state *istate,
const char *path,
struct attr_check *check)
{
Expand Down Expand Up @@ -1123,7 +1123,7 @@ static void collect_some_attrs(const struct index_state *istate,
fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
}

void git_check_attr(const struct index_state *istate,
void git_check_attr(struct index_state *istate,
const char *path,
struct attr_check *check)
{
Expand All @@ -1140,7 +1140,7 @@ void git_check_attr(const struct index_state *istate,
}
}

void git_all_attrs(const struct index_state *istate,
void git_all_attrs(struct index_state *istate,
const char *path, struct attr_check *check)
{
int i;
Expand Down
4 changes: 2 additions & 2 deletions attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,14 @@ void attr_check_free(struct attr_check *check);
*/
const char *git_attr_name(const struct git_attr *);

void git_check_attr(const struct index_state *istate,
void git_check_attr(struct index_state *istate,
const char *path, struct attr_check *check);

/*
* Retrieve all attributes that apply to the specified path.
* check holds the attributes and their values.
*/
void git_all_attrs(const struct index_state *istate,
void git_all_attrs(struct index_state *istate,
const char *path, struct attr_check *check);

enum git_attr_direction {
Expand Down
1 change: 1 addition & 0 deletions builtin/add.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
{
int i, retval = 0;

ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];

Expand Down
1 change: 1 addition & 0 deletions builtin/checkout-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ static void checkout_all(const char *prefix, int prefix_length)
int i, errs = 0;
struct cache_entry *last_ce = NULL;

ensure_full_index(&the_index);
for (i = 0; i < active_nr ; i++) {
struct cache_entry *ce = active_cache[i];
if (ce_stage(ce) != checkout_stage
Expand Down
2 changes: 2 additions & 0 deletions builtin/checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
NULL);

enable_delayed_checkout(&state);
ensure_full_index(&the_index);
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
if (ce->ce_flags & CE_MATCHED) {
Expand Down Expand Up @@ -522,6 +523,7 @@ static int checkout_paths(const struct checkout_opts *opts,
* Make sure all pathspecs participated in locating the paths
* to be checked out.
*/
ensure_full_index(&the_index);
for (pos = 0; pos < active_nr; pos++)
if (opts->overlay_mode)
mark_ce_for_checkout_overlay(active_cache[pos],
Expand Down
2 changes: 2 additions & 0 deletions builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ static int list_paths(struct string_list *list, const char *with_tree,
free(max_prefix);
}

ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
struct string_list_item *item;
Expand Down Expand Up @@ -968,6 +969,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (get_oid(parent, &oid)) {
int i, ita_nr = 0;

ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++)
if (ce_intent_to_add(active_cache[i]))
ita_nr++;
Expand Down
2 changes: 2 additions & 0 deletions builtin/difftool.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1);
rc = run_command_v_opt(helper_argv, flags);

ensure_full_index(&wtindex);

/*
* If the diff includes working copy files and those
* files were modified during the diff, then the changes
Expand Down
1 change: 1 addition & 0 deletions builtin/fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
verify_index_checksum = 1;
verify_ce_order = 1;
read_cache();
ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
unsigned int mode;
struct blob *blob;
Expand Down
1 change: 1 addition & 0 deletions builtin/grep.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ static int grep_cache(struct grep_opt *opt,
if (repo_read_index(repo) < 0)
die(_("index file corrupt"));

ensure_full_index(repo->index);
for (nr = 0; nr < repo->index->cache_nr; nr++) {
const struct cache_entry *ce = repo->index->cache[nr];

Expand Down
12 changes: 7 additions & 5 deletions builtin/ls-files.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ static const char *tag_modified = "";
static const char *tag_skip_worktree = "";
static const char *tag_resolve_undo = "";

static void write_eolinfo(const struct index_state *istate,
static void write_eolinfo(struct index_state *istate,
const struct cache_entry *ce, const char *path)
{
if (show_eol) {
Expand Down Expand Up @@ -122,7 +122,7 @@ static void print_debug(const struct cache_entry *ce)
}
}

static void show_dir_entry(const struct index_state *istate,
static void show_dir_entry(struct index_state *istate,
const char *tag, struct dir_entry *ent)
{
int len = max_prefix_len;
Expand All @@ -139,7 +139,7 @@ static void show_dir_entry(const struct index_state *istate,
write_name(ent->name);
}

static void show_other_files(const struct index_state *istate,
static void show_other_files(struct index_state *istate,
const struct dir_struct *dir)
{
int i;
Expand All @@ -152,7 +152,7 @@ static void show_other_files(const struct index_state *istate,
}
}

static void show_killed_files(const struct index_state *istate,
static void show_killed_files(struct index_state *istate,
const struct dir_struct *dir)
{
int i;
Expand Down Expand Up @@ -254,7 +254,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,
}
}

static void show_ru_info(const struct index_state *istate)
static void show_ru_info(struct index_state *istate)
{
struct string_list_item *item;

Expand Down Expand Up @@ -317,6 +317,7 @@ static void show_files(struct repository *repo, struct dir_struct *dir)

if (!(show_cached || show_stage || show_deleted || show_modified))
return;
ensure_full_index(repo->index);
for (i = 0; i < repo->index->cache_nr; i++) {
const struct cache_entry *ce = repo->index->cache[i];
struct stat st;
Expand Down Expand Up @@ -495,6 +496,7 @@ void overlay_tree_on_index(struct index_state *istate,
die("bad tree-ish %s", tree_name);

/* Hoist the unmerged entries up to stage #3 to make room */
ensure_full_index(istate);
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce = istate->cache[i];
if (!ce_stage(ce))
Expand Down
2 changes: 2 additions & 0 deletions builtin/merge-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
if (repo_read_index(r) < 0)
die("invalid index");

ensure_full_index(r->index);

i = 1;
if (!strcmp(argv[i], "-o")) {
one_shot = 1;
Expand Down
1 change: 1 addition & 0 deletions builtin/rm.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)

seen = xcalloc(pathspec.nr, 1);

ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
if (ce_skip_worktree(ce))
Expand Down
1 change: 1 addition & 0 deletions builtin/stash.c
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
int i;
char *ps_matched = xcalloc(ps->nr, 1);

ensure_full_index(&the_index);
for (i = 0; i < active_nr; i++)
ce_path_match(&the_index, active_cache[i], ps,
ps_matched);
Expand Down
1 change: 1 addition & 0 deletions builtin/update-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ static int do_reupdate(int ac, const char **av,
*/
has_head = 0;
redo:
ensure_full_index(&the_index);
for (pos = 0; pos < active_nr; pos++) {
const struct cache_entry *ce = active_cache[pos];
struct cache_entry *old = NULL;
Expand Down
7 changes: 4 additions & 3 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ void add_name_hash(struct index_state *istate, struct cache_entry *ce);
void remove_name_hash(struct index_state *istate, struct cache_entry *ce);
void free_name_hash(struct index_state *istate);

void ensure_full_index(struct index_state *istate);

/* Cache entry creation and cleanup */

Expand Down Expand Up @@ -801,7 +802,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na
* index_name_pos(&index, "f", 1) -> -3
* index_name_pos(&index, "g", 1) -> -5
*/
int index_name_pos(const struct index_state *, const char *name, int namelen);
int index_name_pos(struct index_state *, const char *name, int namelen);

/*
* Some functions return the negative complement of an insert position when a
Expand Down Expand Up @@ -859,8 +860,8 @@ int add_to_index_cacheinfo(struct index_state *, unsigned int mode,
int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
int index_name_is_other(const struct index_state *, const char *, int);
void *read_blob_data_from_index(const struct index_state *, const char *, unsigned long *);
int index_name_is_other(struct index_state *, const char *, int);
void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);

/* do stat comparison even if CE_VALID is true */
#define CE_MATCH_IGNORE_VALID 01
Expand Down

0 comments on commit 8bc8e10

Please sign in to comment.