untracked cache: mark what dirs should be recursed/saved

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>

Nguyễn Thái Ngọc Duy committed Mar 8, 2015 at 17:12 UTC 26cb0182b8b2e119f469750b3511fac4624f6667
2 files changed +15 -2
dir.c
+13 -1
@@ -615,9 +615,12 @@ static void invalidate_gitignore(struct untracked_cache *uc,
615 static void invalidate_directory(struct untracked_cache *uc,
616 struct untracked_cache_dir *dir)
617 {
618 + int i;
619 uc->dir_invalidated++;
620 dir->valid = 0;
621 dir->untracked_nr = 0;
622 + for (i = 0; i < dir->dirs_nr; i++)
623 + dir->dirs[i]->recurse = 0;
624 }
625
626 /*
@@ -1578,6 +1581,10 @@ static int read_cached_dir(struct cached_dir *cdir)
1581 }
1582 while (cdir->nr_dirs < cdir->untracked->dirs_nr) {
1583 struct untracked_cache_dir *d = cdir->untracked->dirs[cdir->nr_dirs];
1584 + if (!d->recurse) {
1585 + cdir->nr_dirs++;
1586 + continue;
1587 + }
1588 cdir->ucd = d;
1589 cdir->nr_dirs++;
1590 return 0;
@@ -1599,8 +1606,10 @@ static void close_cached_dir(struct cached_dir *cdir)
1606 * We have gone through this directory and found no untracked
1607 * entries. Mark it valid.
1608 */
1602 - if (cdir->untracked)
1609 + if (cdir->untracked) {
1610 cdir->untracked->valid = 1;
1611 + cdir->untracked->recurse = 1;
1612 + }
1613 }
1614
1615 /*
@@ -1843,6 +1852,9 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
1852 invalidate_gitignore(dir->untracked, root);
1853 dir->untracked->ss_excludes_file = dir->ss_excludes_file;
1854 }
1855 +
1856 + /* Make sure this directory is not dropped out at saving phase */
1857 + root->recurse = 1;
1858 return root;
1859 }
1860
dir.h
+2 -1
@@ -115,8 +115,9 @@ struct untracked_cache_dir {
115 unsigned int untracked_alloc, dirs_nr, dirs_alloc;
116 unsigned int untracked_nr;
117 unsigned int check_only : 1;
118 - /* all data in this struct are good */
118 + /* all data except 'dirs' in this struct are good */
119 unsigned int valid : 1;
120 + unsigned int recurse : 1;
121 /* null SHA-1 means this directory does not have .gitignore */
122 unsigned char exclude_sha1[20];
123 char name[FLEX_ARRAY];