Skip to content

Commit

Permalink
Merge branch 'ds/update-index' into seen
Browse files Browse the repository at this point in the history
The implementation of a few commands lost reliance of "the_index"
compatibility macros by explicitly passing the index_state through
the callchain.

Unfortunately the base topic still needs to solidify.

* ds/update-index:
  update-index: remove static globals from callbacks
  update-index: reduce static globals, part 2
  update-index: reduce static globals, part 1
  update-index: remove ce_match_stat(), all macros
  update-index: replace several compatibility macros
  update-index: use add_index_entry()
  update-index: use remove_file_from_index()
  update-index: use index_name_pos() over cache_name_pos()
  update-index: use istate->cache_changed
  update-index: use istate->cache_nr over active_nr
  update-index: use istate->cache over active_cache
  update-index: drop the_index, the_repository
  rm: remove compatilibity macros
  mv: remove index compatibility macros
  • Loading branch information
gitster committed Jan 23, 2021
2 parents 87c7c3b + 3940298 commit 74b06e1
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 195 deletions.
6 changes: 3 additions & 3 deletions Documentation/technical/racy-git.txt
Expand Up @@ -26,7 +26,7 @@ information obtained from the filesystem via `lstat(2)` system
call when they were last updated. When checking if they differ,
Git first runs `lstat(2)` on the files and compares the result
with this information (this is what was originally done by the
`ce_match_stat()` function, but the current code does it in
`ie_match_stat()` function, but the current code does it in
`ce_match_stat_basic()` function). If some of these "cached
stat information" fields do not match, Git can tell that the
files are modified without even looking at their contents.
Expand Down Expand Up @@ -102,7 +102,7 @@ timestamp as the index file itself.

The callers that want to check if an index entry matches the
corresponding file in the working tree continue to call
`ce_match_stat()`, but with this change, `ce_match_stat()` uses
`ie_match_stat()`, but with this change, `ie_match_stat()` uses
`ce_modified_check_fs()` to see if racily clean ones are
actually clean after comparing the cached stat information using
`ce_match_stat_basic()`.
Expand All @@ -128,7 +128,7 @@ Runtime penalty
---------------

The runtime penalty of falling back to `ce_modified_check_fs()`
from `ce_match_stat()` can be very expensive when there are many
from `ie_match_stat()` can be very expensive when there are many
racily clean entries. An obvious way to artificially create
this situation is to give the same timestamp to all the files in
the working tree in a large project, run `git update-index` on
Expand Down
42 changes: 23 additions & 19 deletions builtin/mv.c
Expand Up @@ -3,7 +3,6 @@
*
* Copyright (C) 2006 Johannes Schindelin
*/
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "builtin.h"
#include "config.h"
#include "pathspec.h"
Expand Down Expand Up @@ -75,13 +74,14 @@ static const char *add_slash(const char *path)

#define SUBMODULE_WITH_GITDIR ((const char *)1)

static void prepare_move_submodule(const char *src, int first,
static void prepare_move_submodule(struct index_state *istate,
const char *src, int first,
const char **submodule_gitfile)
{
struct strbuf submodule_dotgit = STRBUF_INIT;
if (!S_ISGITLINK(active_cache[first]->ce_mode))
if (!S_ISGITLINK(istate->cache[first]->ce_mode))
die(_("Directory %s is in index and no submodule?"), src);
if (!is_staging_gitmodules_ok(&the_index))
if (!is_staging_gitmodules_ok(istate))
die(_("Please stage your changes to .gitmodules or stash them to proceed"));
strbuf_addf(&submodule_dotgit, "%s/.git", src);
*submodule_gitfile = read_gitfile(submodule_dotgit.buf);
Expand All @@ -92,19 +92,20 @@ static void prepare_move_submodule(const char *src, int first,
strbuf_release(&submodule_dotgit);
}

static int index_range_of_same_dir(const char *src, int length,
static int index_range_of_same_dir(struct index_state *istate,
const char *src, int length,
int *first_p, int *last_p)
{
const char *src_w_slash = add_slash(src);
int first, last, len_w_slash = length + 1;

first = cache_name_pos(src_w_slash, len_w_slash);
first = index_name_pos(istate, src_w_slash, len_w_slash);
if (first >= 0)
die(_("%.*s is in index"), len_w_slash, src_w_slash);

first = -1 - first;
for (last = first; last < active_nr; last++) {
const char *path = active_cache[last]->name;
for (last = first; last < istate->cache_nr; last++) {
const char *path = istate->cache[last]->name;
if (strncmp(path, src_w_slash, len_w_slash))
break;
}
Expand Down Expand Up @@ -133,6 +134,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
struct lock_file lock_file = LOCK_INIT;
struct cache_entry *ce;
struct index_state *istate;

git_config(git_default_config, NULL);

Expand All @@ -141,9 +143,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (--argc < 1)
usage_with_options(builtin_mv_usage, builtin_mv_options);

hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
if (read_cache() < 0)
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
istate = the_repository->index;

source = internal_prefix_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
Expand Down Expand Up @@ -190,12 +193,13 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
&& lstat(dst, &st) == 0)
bad = _("cannot move directory over file");
else if (src_is_dir) {
int first = cache_name_pos(src, length), last;
int first = index_name_pos(istate, src, length);
int last;

if (first >= 0)
prepare_move_submodule(src, first,
prepare_move_submodule(istate, src, first,
submodule_gitfile + i);
else if (index_range_of_same_dir(src, length,
else if (index_range_of_same_dir(istate, src, length,
&first, &last) < 1)
bad = _("source directory is empty");
else { /* last - first >= 1 */
Expand All @@ -212,7 +216,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
dst_len = strlen(dst);

for (j = 0; j < last - first; j++) {
const char *path = active_cache[first + j]->name;
const char *path = istate->cache[first + j]->name;
source[argc + j] = path;
destination[argc + j] =
prefix_path(dst, dst_len, path + length + 1);
Expand All @@ -221,7 +225,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
argc += last - first;
}
} else if (!(ce = cache_file_exists(src, length, ignore_case))) {
} else if (!(ce = index_file_exists(istate, src, length, ignore_case))) {
bad = _("not under version control");
} else if (ce_stage(ce)) {
bad = _("conflicted");
Expand Down Expand Up @@ -291,15 +295,15 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (mode == WORKING_DIRECTORY)
continue;

pos = cache_name_pos(src, strlen(src));
pos = index_name_pos(istate, src, strlen(src));
assert(pos >= 0);
rename_cache_entry_at(pos, dst);
rename_index_entry_at(istate, pos, dst);
}

if (gitmodules_modified)
stage_updated_gitmodules(&the_index);
stage_updated_gitmodules(istate);

if (write_locked_index(&the_index, &lock_file,
if (write_locked_index(istate, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));

Expand Down
56 changes: 30 additions & 26 deletions builtin/rm.c
Expand Up @@ -3,7 +3,6 @@
*
* Copyright (C) Linus Torvalds 2006
*/
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "builtin.h"
#include "config.h"
#include "lockfile.h"
Expand All @@ -29,12 +28,14 @@ static struct {
} *entry;
} list;

static int get_ours_cache_pos(const char *path, int pos)
static int get_ours_cache_pos(struct index_state *istate,
const char *path, int pos)
{
int i = -pos - 1;

while ((i < active_nr) && !strcmp(active_cache[i]->name, path)) {
if (ce_stage(active_cache[i]) == 2)
while ((i < istate->cache_nr) &&
!strcmp(istate->cache[i]->name, path)) {
if (ce_stage(istate->cache[i]) == 2)
return i;
i++;
}
Expand Down Expand Up @@ -62,21 +63,21 @@ static void print_error_files(struct string_list *files_list,
}
}

static void submodules_absorb_gitdir_if_needed(void)
static void submodules_absorb_gitdir_if_needed(struct index_state *istate)
{
int i;
for (i = 0; i < list.nr; i++) {
const char *name = list.entry[i].name;
int pos;
const struct cache_entry *ce;

pos = cache_name_pos(name, strlen(name));
pos = index_name_pos(istate, name, strlen(name));
if (pos < 0) {
pos = get_ours_cache_pos(name, pos);
pos = get_ours_cache_pos(istate, name, pos);
if (pos < 0)
continue;
}
ce = active_cache[pos];
ce = istate->cache[pos];

if (!S_ISGITLINK(ce->ce_mode) ||
!file_exists(ce->name) ||
Expand All @@ -89,7 +90,8 @@ static void submodules_absorb_gitdir_if_needed(void)
}
}

static int check_local_mod(struct object_id *head, int index_only)
static int check_local_mod(struct index_state *istate,
struct object_id *head, int index_only)
{
/*
* Items in list are already sorted in the cache order,
Expand All @@ -115,21 +117,21 @@ static int check_local_mod(struct object_id *head, int index_only)
int local_changes = 0;
int staged_changes = 0;

pos = cache_name_pos(name, strlen(name));
pos = index_name_pos(istate, name, strlen(name));
if (pos < 0) {
/*
* Skip unmerged entries except for populated submodules
* that could lose history when removed.
*/
pos = get_ours_cache_pos(name, pos);
pos = get_ours_cache_pos(istate, name, pos);
if (pos < 0)
continue;

if (!S_ISGITLINK(active_cache[pos]->ce_mode) ||
if (!S_ISGITLINK(istate->cache[pos]->ce_mode) ||
is_empty_dir(name))
continue;
}
ce = active_cache[pos];
ce = istate->cache[pos];

if (lstat(ce->name, &st) < 0) {
if (!is_missing_file_error(errno))
Expand Down Expand Up @@ -166,7 +168,7 @@ static int check_local_mod(struct object_id *head, int index_only)
* Is the index different from the file in the work tree?
* If it's a submodule, is its work tree modified?
*/
if (ce_match_stat(ce, &st, 0) ||
if (ie_match_stat(istate, ce, &st, 0) ||
(S_ISGITLINK(ce->ce_mode) &&
bad_to_remove_submodule(ce->name,
SUBMODULE_REMOVAL_DIE_ON_ERROR |
Expand Down Expand Up @@ -258,6 +260,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
int i, sparse_paths_only;
struct pathspec pathspec;
char *seen;
struct index_state *istate;

git_config(git_default_config, NULL);

Expand Down Expand Up @@ -285,29 +288,30 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (!index_only)
setup_work_tree();

hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);

if (read_cache() < 0)
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));

refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
istate = the_repository->index;
refresh_index(istate, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);

seen = xcalloc(pathspec.nr, 1);

sparse_paths_only = core_apply_sparse_checkout &&
restrict_to_sparse_paths(the_repository);

for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
for (i = 0; i < istate->cache_nr; i++) {
const struct cache_entry *ce = istate->cache[i];
if (sparse_paths_only && ce_skip_worktree(ce))
continue;
if (!ce_path_match(&the_index, ce, &pathspec, seen))
if (!ce_path_match(istate, ce, &pathspec, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
list.entry[list.nr].name = xstrdup(ce->name);
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
!is_staging_gitmodules_ok(&the_index))
!is_staging_gitmodules_ok(istate))
die(_("please stage your changes to .gitmodules or stash them to proceed"));
}

Expand Down Expand Up @@ -337,7 +341,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
}

if (!index_only)
submodules_absorb_gitdir_if_needed();
submodules_absorb_gitdir_if_needed(istate);

/*
* If not forced, the file, the index and the HEAD (if exists)
Expand All @@ -353,7 +357,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
struct object_id oid;
if (get_oid("HEAD", &oid))
oidclr(&oid);
if (check_local_mod(&oid, index_only))
if (check_local_mod(istate, &oid, index_only))
exit(1);
}

Expand All @@ -366,7 +370,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (!quiet)
printf("rm '%s'\n", path);

if (remove_file_from_cache(path))
if (remove_file_from_index(istate, path))
die(_("git rm: unable to remove %s"), path);
}

Expand Down Expand Up @@ -406,10 +410,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
}
strbuf_release(&buf);
if (gitmodules_modified)
stage_updated_gitmodules(&the_index);
stage_updated_gitmodules(istate);
}

if (write_locked_index(&the_index, &lock_file,
if (write_locked_index(istate, &lock_file,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));

Expand Down

0 comments on commit 74b06e1

Please sign in to comment.