untracked cache: mark what dirs should be recursed/saved
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Sun, 8 Mar 2015 10:12:30 +0000 (17:12 +0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 12 Mar 2015 20:45:16 +0000 (13:45 -0700)
If we redo this thing in a functional style, we would have one struct
untracked_dir as input tree and another as output. The input is used
for verification. The output is a brand new tree, reflecting current
worktree.

But that means recreate a lot of dir nodes even if a lot could be
shared between input and output trees in good cases. So we go with the
messy but efficient way, combining both input and output trees into
one. We need a way to know which node in this combined tree belongs to
the output. This is the purpose of this "recurse" flag.

"valid" bit can't be used for this because it's about data of the node
except the subdirs. When we invalidate a directory, we want to keep
cached data of the subdirs intact even though we don't really know
what subdir still exists (yet). Then we check worktree to see what
actual subdir remains on disk. Those will have 'recurse' bit set
again. If cached data for those are still valid, we may be able to
avoid computing exclude files for them. Those subdirs that are deleted
will have 'recurse' remained clear and their 'valid' bits do not
matter.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
dir.c
dir.h
diff --git a/dir.c b/dir.c
index 54153741059811ad354d8ff6ed5587c8aba84adb..2d0582e8a8f36dcc5dea7f42892736908afb1746 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -615,9 +615,12 @@ static void invalidate_gitignore(struct untracked_cache *uc,
 static void invalidate_directory(struct untracked_cache *uc,
                                 struct untracked_cache_dir *dir)
 {
+       int i;
        uc->dir_invalidated++;
        dir->valid = 0;
        dir->untracked_nr = 0;
+       for (i = 0; i < dir->dirs_nr; i++)
+               dir->dirs[i]->recurse = 0;
 }
 
 /*
@@ -1578,6 +1581,10 @@ static int read_cached_dir(struct cached_dir *cdir)
        }
        while (cdir->nr_dirs < cdir->untracked->dirs_nr) {
                struct untracked_cache_dir *d = cdir->untracked->dirs[cdir->nr_dirs];
+               if (!d->recurse) {
+                       cdir->nr_dirs++;
+                       continue;
+               }
                cdir->ucd = d;
                cdir->nr_dirs++;
                return 0;
@@ -1599,8 +1606,10 @@ static void close_cached_dir(struct cached_dir *cdir)
         * We have gone through this directory and found no untracked
         * entries. Mark it valid.
         */
-       if (cdir->untracked)
+       if (cdir->untracked) {
                cdir->untracked->valid = 1;
+               cdir->untracked->recurse = 1;
+       }
 }
 
 /*
@@ -1843,6 +1852,9 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_excludes_file = dir->ss_excludes_file;
        }
+
+       /* Make sure this directory is not dropped out at saving phase */
+       root->recurse = 1;
        return root;
 }
 
diff --git a/dir.h b/dir.h
index ff3d99bcb05af52767a8b7834bd9db83df4dad73..95baf014ca6356039deeda6bc4259d15f54a3c20 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -115,8 +115,9 @@ struct untracked_cache_dir {
        unsigned int untracked_alloc, dirs_nr, dirs_alloc;
        unsigned int untracked_nr;
        unsigned int check_only : 1;
-       /* all data in this struct are good */
+       /* all data except 'dirs' in this struct are good */
        unsigned int valid : 1;
+       unsigned int recurse : 1;
        /* null SHA-1 means this directory does not have .gitignore */
        unsigned char exclude_sha1[20];
        char name[FLEX_ARRAY];