--- v2
+++ v8
@@ -1,114 +1,66 @@
From: Derrick Stolee <dstolee@microsoft.com>
-By testing 'git -c core.fsmonitor= status -uno', we can check for the
-simplest index operations that can be made sparse-aware. The necessary
-implementation details are already integrated with sparse-checkout, so
-modify command_requires_full_index to be zero for cmd_status().
+As we further integrate the sparse-index into unpack-trees, we need to
+ensure that we compare sparse directory entries correctly with other
+entries. This affects searching for an exact path as well as sorting
+index entries.
-In refresh_index(), we loop through the index entries to refresh their
-stat() information. However, sparse directories have no stat()
-information to populate. Ignore these entries.
+Sparse directory entries contain the trailing directory separator. This
+is important for the sorting, in particular. Thus, within
+do_compare_entry() we stop using S_IFREG in all cases, since sparse
+directories should use S_IFDIR to indicate that the comparison should
+treat the entry name as a dirctory.
-This allows 'git status' to no longer expand a sparse index to a full
-one. This is further tested by dropping the "-uno" option and adding an
-untracked file into the worktree.
-
-The performance test p2000-sparse-checkout-operations.sh demonstrates
-these improvements:
-
-Test HEAD~1 HEAD
------------------------------------------------------------------------------
-2000.2: git status (full-index-v3) 0.31(0.30+0.05) 0.31(0.29+0.06) +0.0%
-2000.3: git status (full-index-v4) 0.31(0.29+0.07) 0.34(0.30+0.08) +9.7%
-2000.4: git status (sparse-index-v3) 2.35(2.28+0.10) 0.04(0.04+0.05) -98.3%
-2000.5: git status (sparse-index-v4) 2.35(2.24+0.15) 0.05(0.04+0.06) -97.9%
-
-Note that since HEAD~1 was expanding the sparse index by parsing trees,
-it was artificially slower than the full index case. Thus, the 98%
-improvement is misleading, and instead we should celebrate the 0.34s to
-0.05s improvement of 85%. This is more indicative of the peformance
-gains we are expecting by using a sparse index.
-
-Note: we are dropping the assignment of core.fsmonitor here. This is not
-necessary for the test script as we are not altering the config any
-other way. Correct integration with FS Monitor will be validated in
-later changes.
+Within compare_entry(), it first calls do_compare_entry() to check the
+leading portion of the name. When the input path is a directory name, we
+could match exactly already. Thus, we should return 0 if we have an
+exact string match on a sparse directory entry. The final check is a
+length comparison between the strings.
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
---
- builtin/commit.c | 3 +++
- read-cache.c | 10 ++++++++--
- t/t1092-sparse-checkout-compatibility.sh | 13 +++++++++----
- 3 files changed, 20 insertions(+), 6 deletions(-)
+ unpack-trees.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
-diff --git a/builtin/commit.c b/builtin/commit.c
-index cf0c36d1dcb2..e529da7beadd 100644
---- a/builtin/commit.c
-+++ b/builtin/commit.c
-@@ -1404,6 +1404,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
- if (argc == 2 && !strcmp(argv[1], "-h"))
- usage_with_options(builtin_status_usage, builtin_status_options);
+diff --git a/unpack-trees.c b/unpack-trees.c
+index 87c1ed204c8..b113cc750f2 100644
+--- a/unpack-trees.c
++++ b/unpack-trees.c
+@@ -983,6 +983,7 @@ static int do_compare_entry(const struct cache_entry *ce,
+ int pathlen, ce_len;
+ const char *ce_name;
+ int cmp;
++ unsigned ce_mode;
-+ prepare_repo_settings(the_repository);
-+ the_repository->settings.command_requires_full_index = 0;
+ /*
+ * If we have not precomputed the traverse path, it is quicker
+@@ -1005,7 +1006,8 @@ static int do_compare_entry(const struct cache_entry *ce,
+ ce_len -= pathlen;
+ ce_name = ce->name + pathlen;
+
+- return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
++ ce_mode = S_ISSPARSEDIR(ce->ce_mode) ? S_IFDIR : S_IFREG;
++ return df_name_compare(ce_name, ce_len, ce_mode, name, namelen, mode);
+ }
+
+ static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
+@@ -1014,6 +1016,16 @@ static int compare_entry(const struct cache_entry *ce, const struct traverse_inf
+ if (cmp)
+ return cmp;
+
++ /*
++ * At this point, we know that we have a prefix match. If ce
++ * is a sparse directory, then allow an exact match. This only
++ * works when the input name is a directory, since ce->name
++ * ends in a directory separator.
++ */
++ if (S_ISSPARSEDIR(ce->ce_mode) &&
++ ce->ce_namelen == traverse_path_len(info, tree_entry_len(n)) + 1)
++ return 0;
+
- status_init_config(&s, git_status_config);
- argc = parse_options(argc, argv, prefix,
- builtin_status_options,
-diff --git a/read-cache.c b/read-cache.c
-index 29ffa9ac5db9..f80e26831b36 100644
---- a/read-cache.c
-+++ b/read-cache.c
-@@ -1578,8 +1578,7 @@ 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;
-@@ -1594,6 +1593,13 @@ int refresh_index(struct index_state *istate, unsigned int flags,
- if (ignore_skip_worktree && ce_skip_worktree(ce))
- continue;
-
-+ /*
-+ * If this entry is a sparse directory, then there isn't
-+ * any stat() information to update. Ignore the entry.
-+ */
-+ if (S_ISSPARSEDIR(ce->ce_mode))
-+ continue;
-+
- if (pathspec && !ce_path_match(istate, ce, pathspec, seen))
- filtered = 1;
-
-diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
-index 0dc551b25f67..5a8fe88dc894 100755
---- a/t/t1092-sparse-checkout-compatibility.sh
-+++ b/t/t1092-sparse-checkout-compatibility.sh
-@@ -453,12 +453,17 @@ test_expect_success 'sparse-index is expanded and converted back' '
- GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
- git -C sparse-index -c core.fsmonitor="" reset --hard &&
- test_region index convert_to_sparse trace2.txt &&
-- test_region index ensure_full_index trace2.txt &&
-+ test_region index ensure_full_index trace2.txt
-+'
-
-- rm trace2.txt &&
-+test_expect_success 'sparse-index is not expanded' '
-+ init_repos &&
-+
-+ rm -f trace2.txt &&
-+ echo >>sparse-index/untracked.txt &&
- GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
-- git -C sparse-index -c core.fsmonitor="" status -uno &&
-- test_region index ensure_full_index trace2.txt
-+ git -C sparse-index status &&
-+ test_region ! index ensure_full_index trace2.txt
- '
-
- test_done
+ /*
+ * Even if the beginning compared identically, the ce should
+ * compare as bigger than a directory leading up to it!
--
gitgitgadget