I think this is wrong.
When we are looking at a directory P in the working tree, there are
three cases:
(1) P exists in the index. Everything inside the directory P in
the working tree needs to go when P is checked out from the
index.
(2) P does not exist in the index, but there is P/Q in the index.
We know P will stay a directory when we check out the contents
of the index, but we do not know yet if there is a directory
P/Q in the working tree to be killed, so we need to recurse.
(3) P does not exist in the index, and there is no P/Q in the index
to require P to be a directory, either. Only in this case, we
know that everything inside P will not be killed without
recursing.
The patch will break with the second case, I think.
From: Junio C Hamano <hidden> Date: 2016-06-15 22:58:26
"ls-files -o" and "ls-files -k" both traverse the working tree down
to find either all untracked paths or those that will be "killed"
(removed from the working tree to make room) when the paths recorded
in the index are checked out.
It is necessary to traverse the working tree fully when enumerating
all the "other" paths, but when we are only interested in "killed"
paths, we can take advantage of the fact that paths that do not
overlap with entries in the index can never be killed.
The first one is an independent clean-up. No public API in the
working tree traversal takes alternate in-core index, so there is no
reason to explicitly use the_index and index_* functions from the
in-core index API.
The second one is rerolled from the "something like this" patch I
sent earlier, but corrects the "we see a directory, it is not in the
index, but a file in it is" case.
And the third one adds a testcase that illustrates why the earlier
"something like this" patch is not sufficient.
These are designed to apply on top of v1.8.3, and needs a bit of
conflict resolution for the upcoming v1.8.4 codebase; I'll queue
them in 'pu' for now.
Note that t3010, especially after merged to 'pu', will use many
different ways to create a test file. Some redirect "date" into it,
some redirect ":" into it, some "touch" it, and some just redirect
with no command.
date >file1
: >file2
touch file3
>file4
We should consolidate them all to just do ">file4" after making sure
the contents do not matter (we kind of know it already, as "date"
will output string that is not repeatable). Use of "touch" for
anything other than updating the timestamp is especially bad, as it
is misleading.
Junio C Hamano (3):
dir.c: use the cache_* macro to access the current index
ls-files -k: a directory only can be killed if the index has a non-directory
t3010: update to demonstrate "ls-files -k" optimization pitfalls
builtin/ls-files.c | 2 ++
dir.c | 40 +++++++++++++++++++++++++++++--------
dir.h | 3 ++-
t/t3010-ls-files-killed-modified.sh | 12 ++++++++---
4 files changed, 45 insertions(+), 12 deletions(-)
--
1.8.4-rc3-232-ga8053f8
From: Junio C Hamano <hidden> Date: 2016-06-15 22:58:26
These codepaths always start from the_index and use index_*
functions, but there is no reason to do so. Use the compatibility
cache_* macro to access the current in-core index like everybody
else.
While at it, fix typo in the comment for a function to check if a
path within a directory appears in the index.
Signed-off-by: Junio C Hamano <redacted>
---
dir.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
From: Junio C Hamano <hidden> Date: 2016-06-15 22:58:26
An earlier draft of the previous step used cache_name_exists() to
check the directory we were looking at, which missed the second case
described in its log message. Demonstrate why it is not sufficient.
Signed-off-by: Junio C Hamano <redacted>
---
t/t3010-ls-files-killed-modified.sh | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
@@ -11,6 +11,7 @@ This test prepares the following in the cache:path1-asymlinkpath2/file2-afileinadirectorypath3/file3-afileinadirectory+pathx/ju-afileinadirectory andthefollowingonthefilesystem:
@@ -21,6 +22,7 @@ and the following on the filesystem:path4-afilepath5-asymlinkpath6/file6-afileinadirectory+pathx/ju/nk-afileinadirectorytobekilled gitls-files-kshouldreportthatexistingfilesystem objectsexceptpath4,path5andpath6/file6tobekilled.
From: Junio C Hamano <hidden> Date: 2016-06-15 22:58:26
"ls-files -o" and "ls-files -k" both traverse the working tree down
to find either all untracked paths or those that will be "killed"
(removed from the working tree to make room) when the paths recorded
in the index are checked out. It is necessary to traverse the
working tree fully when enumerating all the "other" paths, but when
we are only interested in "killed" paths, we can take advantage of
the fact that paths that do not overlap with entries in the index
can never be killed.
The treat_one_path() helper function, which is called during the
recursive traversal, is the ideal place to implement an
optimization.
When we are looking at a directory P in the working tree, there are
three cases:
(1) P exists in the index. Everything inside the directory P in
the working tree needs to go when P is checked out from the
index.
(2) P does not exist in the index, but there is P/Q in the index.
We know P will stay a directory when we check out the contents
of the index, but we do not know yet if there is a directory
P/Q in the working tree to be killed, so we need to recurse.
(3) P does not exist in the index, and there is no P/Q in the index
to require P to be a directory, either. Only in this case, we
know that everything inside P will not be killed without
recursing.
Note that this helper is called by treat_leading_path() that decides
if we need to traverse only subdirectories of a single common
leading directory, which is essential for this optimization to be
correct. This caller checks each level of the leading path
component from shallower directory to deeper ones, and that is what
allows us to only check if the path appears in the index. If the
call to treat_one_path() weren't there, given a path P/Q/R, the real
traversal may start from directory P/Q/R, even when the index
records P as a regular file, and we would end up having to check if
any leading subpath in P/Q/R, e.g. P, appears in the index.
Signed-off-by: Junio C Hamano <redacted>
---
builtin/ls-files.c | 2 ++
dir.c | 29 +++++++++++++++++++++++++++--
dir.h | 3 ++-
3 files changed, 31 insertions(+), 3 deletions(-)
@@ -213,6 +213,8 @@ static void show_files(struct dir_struct *dir)/* For cached/deleted files we don't need to even do the readdir */if(show_others||show_killed){+if(!show_others)+dir->flags|=DIR_COLLECT_KILLED_ONLY;fill_directory(dir,pathspec);if(show_others)show_other_files(dir);