Merge branch 'ds/sparse-index-protections'
Builds on top of the sparse-index infrastructure to mark operations that are not ready to mark with the sparse index, causing them to fall back on fully-populated index that they always have worked with. * ds/sparse-index-protections: (47 commits) name-hash: use expand_to_path() sparse-index: expand_to_path() name-hash: don't add directories to name_hash revision: ensure full index resolve-undo: ensure full index read-cache: ensure full index pathspec: ensure full index merge-recursive: ensure full index entry: ensure full index dir: ensure full index update-index: ensure full index stash: 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 checkout: ensure full index ...
This commit is contained in:
79
read-cache.c
79
read-cache.c
@ -25,6 +25,7 @@
|
||||
#include "fsmonitor.h"
|
||||
#include "thread-utils.h"
|
||||
#include "progress.h"
|
||||
#include "sparse-index.h"
|
||||
|
||||
/* Mask for the name length in ce_flags in the on-disk index */
|
||||
|
||||
@ -47,6 +48,7 @@
|
||||
#define CACHE_EXT_FSMONITOR 0x46534D4E /* "FSMN" */
|
||||
#define CACHE_EXT_ENDOFINDEXENTRIES 0x454F4945 /* "EOIE" */
|
||||
#define CACHE_EXT_INDEXENTRYOFFSETTABLE 0x49454F54 /* "IEOT" */
|
||||
#define CACHE_EXT_SPARSE_DIRECTORIES 0x73646972 /* "sdir" */
|
||||
|
||||
/* changes that can be kept in $GIT_DIR/index (basically all extensions) */
|
||||
#define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
|
||||
@ -101,6 +103,9 @@ static const char *alternate_index_output;
|
||||
|
||||
static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
|
||||
{
|
||||
if (S_ISSPARSEDIR(ce->ce_mode))
|
||||
istate->sparse_index = 1;
|
||||
|
||||
istate->cache[nr] = ce;
|
||||
add_name_hash(istate, ce);
|
||||
}
|
||||
@ -544,7 +549,7 @@ int cache_name_stage_compare(const char *name1, int len1, int stage1, const char
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage)
|
||||
static int index_name_stage_pos(struct index_state *istate, const char *name, int namelen, int stage)
|
||||
{
|
||||
int first, last;
|
||||
|
||||
@ -562,10 +567,31 @@ static int index_name_stage_pos(const struct index_state *istate, const char *na
|
||||
}
|
||||
first = next+1;
|
||||
}
|
||||
|
||||
if (istate->sparse_index &&
|
||||
first > 0) {
|
||||
/* Note: first <= istate->cache_nr */
|
||||
struct cache_entry *ce = istate->cache[first - 1];
|
||||
|
||||
/*
|
||||
* If we are in a sparse-index _and_ the entry before the
|
||||
* insertion position is a sparse-directory entry that is
|
||||
* an ancestor of 'name', then we need to expand the index
|
||||
* and search again. This will only trigger once, because
|
||||
* thereafter the index is fully expanded.
|
||||
*/
|
||||
if (S_ISSPARSEDIR(ce->ce_mode) &&
|
||||
ce_namelen(ce) < namelen &&
|
||||
!strncmp(name, ce->name, ce_namelen(ce))) {
|
||||
ensure_full_index(istate);
|
||||
return index_name_stage_pos(istate, name, namelen, stage);
|
||||
}
|
||||
}
|
||||
|
||||
return -first-1;
|
||||
}
|
||||
|
||||
int index_name_pos(const struct index_state *istate, const char *name, int namelen)
|
||||
int index_name_pos(struct index_state *istate, const char *name, int namelen)
|
||||
{
|
||||
return index_name_stage_pos(istate, name, namelen, 0);
|
||||
}
|
||||
@ -999,8 +1025,14 @@ inside:
|
||||
|
||||
c = *path++;
|
||||
if ((c == '.' && !verify_dotfile(path, mode)) ||
|
||||
is_dir_sep(c) || c == '\0')
|
||||
is_dir_sep(c))
|
||||
return 0;
|
||||
/*
|
||||
* allow terminating directory separators for
|
||||
* sparse directory entries.
|
||||
*/
|
||||
if (c == '\0')
|
||||
return S_ISDIR(mode);
|
||||
} else if (c == '\\' && protect_ntfs) {
|
||||
if (is_ntfs_dotgit(path))
|
||||
return 0;
|
||||
@ -1545,6 +1577,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,
|
||||
*/
|
||||
preload_index(istate, pathspec, 0);
|
||||
trace2_region_enter("index", "refresh", NULL);
|
||||
/* TODO: audit for interaction with sparse-index. */
|
||||
ensure_full_index(istate);
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
struct cache_entry *ce, *new_entry;
|
||||
int cache_errno = 0;
|
||||
@ -1760,6 +1794,10 @@ static int read_index_extension(struct index_state *istate,
|
||||
case CACHE_EXT_INDEXENTRYOFFSETTABLE:
|
||||
/* already handled in do_read_index() */
|
||||
break;
|
||||
case CACHE_EXT_SPARSE_DIRECTORIES:
|
||||
/* no content, only an indicator */
|
||||
istate->sparse_index = 1;
|
||||
break;
|
||||
default:
|
||||
if (*ext < 'A' || 'Z' < *ext)
|
||||
return error(_("index uses %.4s extension, which we do not understand"),
|
||||
@ -2273,6 +2311,12 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
|
||||
trace2_data_intmax("index", the_repository, "read/cache_nr",
|
||||
istate->cache_nr);
|
||||
|
||||
if (!istate->repo)
|
||||
istate->repo = the_repository;
|
||||
prepare_repo_settings(istate->repo);
|
||||
if (istate->repo->settings.command_requires_full_index)
|
||||
ensure_full_index(istate);
|
||||
|
||||
return istate->cache_nr;
|
||||
|
||||
unmap:
|
||||
@ -2457,6 +2501,8 @@ int repo_index_has_changes(struct repository *repo,
|
||||
diff_flush(&opt);
|
||||
return opt.flags.has_changes != 0;
|
||||
} else {
|
||||
/* TODO: audit for interaction with sparse-index. */
|
||||
ensure_full_index(istate);
|
||||
for (i = 0; sb && i < istate->cache_nr; i++) {
|
||||
if (i)
|
||||
strbuf_addch(sb, ' ');
|
||||
@ -3012,6 +3058,10 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
|
||||
if (err)
|
||||
return -1;
|
||||
}
|
||||
if (istate->sparse_index) {
|
||||
if (write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* CACHE_EXT_ENDOFINDEXENTRIES must be written as the last entry before the SHA1
|
||||
@ -3071,6 +3121,14 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
|
||||
unsigned flags)
|
||||
{
|
||||
int ret;
|
||||
int was_full = !istate->sparse_index;
|
||||
|
||||
ret = convert_to_sparse(istate);
|
||||
|
||||
if (ret) {
|
||||
warning(_("failed to convert to a sparse-index"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO trace2: replace "the_repository" with the actual repo instance
|
||||
@ -3082,6 +3140,9 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
|
||||
trace2_region_leave_printf("index", "do_write_index", the_repository,
|
||||
"%s", get_lock_file_path(lock));
|
||||
|
||||
if (was_full)
|
||||
ensure_full_index(istate);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
if (flags & COMMIT_LOCK)
|
||||
@ -3172,9 +3233,10 @@ static int write_shared_index(struct index_state *istate,
|
||||
struct tempfile **temp)
|
||||
{
|
||||
struct split_index *si = istate->split_index;
|
||||
int ret;
|
||||
int ret, was_full = !istate->sparse_index;
|
||||
|
||||
move_cache_to_base_index(istate);
|
||||
convert_to_sparse(istate);
|
||||
|
||||
trace2_region_enter_printf("index", "shared/do_write_index",
|
||||
the_repository, "%s", get_tempfile_path(*temp));
|
||||
@ -3182,6 +3244,9 @@ static int write_shared_index(struct index_state *istate,
|
||||
trace2_region_leave_printf("index", "shared/do_write_index",
|
||||
the_repository, "%s", get_tempfile_path(*temp));
|
||||
|
||||
if (was_full)
|
||||
ensure_full_index(istate);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = adjust_shared_perm(get_tempfile_path(*temp));
|
||||
@ -3350,8 +3415,8 @@ int repo_read_index_unmerged(struct repository *repo)
|
||||
* We helpfully remove a trailing "/" from directories so that
|
||||
* the output of read_directory can be used as-is.
|
||||
*/
|
||||
int index_name_is_other(const struct index_state *istate, const char *name,
|
||||
int namelen)
|
||||
int index_name_is_other(struct index_state *istate, const char *name,
|
||||
int namelen)
|
||||
{
|
||||
int pos;
|
||||
if (namelen && name[namelen - 1] == '/')
|
||||
@ -3369,7 +3434,7 @@ int index_name_is_other(const struct index_state *istate, const char *name,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *read_blob_data_from_index(const struct index_state *istate,
|
||||
void *read_blob_data_from_index(struct index_state *istate,
|
||||
const char *path, unsigned long *size)
|
||||
{
|
||||
int pos, len;
|
||||
|
Reference in New Issue
Block a user