Skip to content

Commit 20f3749

Browse files
committed
Merge branch 'lt/dir-cleanup'
* lt/dir-cleanup: Make index preloading check the whole path to the file Export thread-safe version of 'has_symlink_leading_path()' Prepare symlink caching for thread-safety Avoid using 'lstat()' to figure out directories Avoid doing extra 'lstat()'s for d_type if we have an up-to-date cache entry Simplify read_directory[_recursive]() arguments Add 'fill_directory()' helper function for directory traversal
2 parents 73ccb91 + f62ce3d commit 20f3749

File tree

10 files changed

+167
-121
lines changed

10 files changed

+167
-121
lines changed

builtin-add.c

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -97,35 +97,6 @@ static void treat_gitlinks(const char **pathspec)
9797
}
9898
}
9999

100-
static void fill_directory(struct dir_struct *dir, const char **pathspec,
101-
int ignored_too)
102-
{
103-
const char *path, *base;
104-
int baselen;
105-
106-
/* Set up the default git porcelain excludes */
107-
memset(dir, 0, sizeof(*dir));
108-
if (!ignored_too) {
109-
dir->flags |= DIR_COLLECT_IGNORED;
110-
setup_standard_excludes(dir);
111-
}
112-
113-
/*
114-
* Calculate common prefix for the pathspec, and
115-
* use that to optimize the directory walk
116-
*/
117-
baselen = common_prefix(pathspec);
118-
path = ".";
119-
base = "";
120-
if (baselen)
121-
path = base = xmemdupz(*pathspec, baselen);
122-
123-
/* Read the directory and prune it */
124-
read_directory(dir, path, base, baselen, pathspec);
125-
if (pathspec)
126-
prune_directory(dir, pathspec, baselen);
127-
}
128-
129100
static void refresh(int verbose, const char **pathspec)
130101
{
131102
char *seen;
@@ -343,9 +314,21 @@ int cmd_add(int argc, const char **argv, const char *prefix)
343314
die("index file corrupt");
344315
treat_gitlinks(pathspec);
345316

346-
if (add_new_files)
317+
if (add_new_files) {
318+
int baselen;
319+
320+
/* Set up the default git porcelain excludes */
321+
memset(&dir, 0, sizeof(dir));
322+
if (!ignored_too) {
323+
dir.flags |= DIR_COLLECT_IGNORED;
324+
setup_standard_excludes(&dir);
325+
}
326+
347327
/* This picks up the paths that are not tracked */
348-
fill_directory(&dir, pathspec, ignored_too);
328+
baselen = fill_directory(&dir, pathspec);
329+
if (pathspec)
330+
prune_directory(&dir, pathspec, baselen);
331+
}
349332

350333
if (refresh_only) {
351334
refresh(verbose, pathspec);

builtin-clean.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
3333
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
3434
struct strbuf directory = STRBUF_INIT;
3535
struct dir_struct dir;
36-
const char *path, *base;
3736
static const char **pathspec;
3837
struct strbuf buf = STRBUF_INIT;
3938
const char *qname;
@@ -78,16 +77,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
7877
pathspec = get_pathspec(prefix, argv);
7978
read_cache();
8079

81-
/*
82-
* Calculate common prefix for the pathspec, and
83-
* use that to optimize the directory walk
84-
*/
85-
baselen = common_prefix(pathspec);
86-
path = ".";
87-
base = "";
88-
if (baselen)
89-
path = base = xmemdupz(*pathspec, baselen);
90-
read_directory(&dir, path, base, baselen, pathspec);
80+
fill_directory(&dir, pathspec);
9181

9282
if (pathspec)
9383
seen = xmalloc(argc > 0 ? argc : 1);

builtin-ls-files.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)
161161

162162
/* For cached/deleted files we don't need to even do the readdir */
163163
if (show_others || show_killed) {
164-
const char *path = ".", *base = "";
165-
int baselen = prefix_len;
166-
167-
if (baselen)
168-
path = base = prefix;
169-
read_directory(dir, path, base, baselen, pathspec);
164+
fill_directory(dir, pathspec);
170165
if (show_others)
171166
show_other_files(dir);
172167
if (show_killed)

cache.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,17 @@ struct checkout {
744744
};
745745

746746
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
747+
748+
struct cache_def {
749+
char path[PATH_MAX + 1];
750+
int len;
751+
int flags;
752+
int track_flags;
753+
int prefix_len_stat_func;
754+
};
755+
747756
extern int has_symlink_leading_path(const char *name, int len);
757+
extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
748758
extern int has_symlink_or_noent_leading_path(const char *name, int len);
749759
extern int has_dirs_only_path(const char *name, int len, int prefix_len);
750760
extern void invalidate_lstat_cache(const char *name, int len);

dir.c

Lines changed: 86 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ struct path_simplify {
1414
const char *path;
1515
};
1616

17-
static int read_directory_recursive(struct dir_struct *dir,
18-
const char *path, const char *base, int baselen,
17+
static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
1918
int check_only, const struct path_simplify *simplify);
20-
static int get_dtype(struct dirent *de, const char *path);
19+
static int get_dtype(struct dirent *de, const char *path, int len);
2120

22-
int common_prefix(const char **pathspec)
21+
static int common_prefix(const char **pathspec)
2322
{
2423
const char *path, *slash, *next;
2524
int prefix;
@@ -52,6 +51,26 @@ int common_prefix(const char **pathspec)
5251
return prefix;
5352
}
5453

54+
int fill_directory(struct dir_struct *dir, const char **pathspec)
55+
{
56+
const char *path;
57+
int len;
58+
59+
/*
60+
* Calculate common prefix for the pathspec, and
61+
* use that to optimize the directory walk
62+
*/
63+
len = common_prefix(pathspec);
64+
path = "";
65+
66+
if (len)
67+
path = xmemdupz(*pathspec, len);
68+
69+
/* Read the directory and prune it */
70+
read_directory(dir, path, len, pathspec);
71+
return len;
72+
}
73+
5574
/*
5675
* Does 'match' match the given name?
5776
* A match is found if
@@ -307,7 +326,7 @@ static int excluded_1(const char *pathname,
307326

308327
if (x->flags & EXC_FLAG_MUSTBEDIR) {
309328
if (*dtype == DT_UNKNOWN)
310-
*dtype = get_dtype(NULL, pathname);
329+
*dtype = get_dtype(NULL, pathname, pathlen);
311330
if (*dtype != DT_DIR)
312331
continue;
313332
}
@@ -505,7 +524,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
505524
/* This is the "show_other_directories" case */
506525
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
507526
return show_directory;
508-
if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
527+
if (!read_directory_recursive(dir, dirname, len, 1, simplify))
509528
return ignore_directory;
510529
return show_directory;
511530
}
@@ -547,11 +566,52 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
547566
return 0;
548567
}
549568

550-
static int get_dtype(struct dirent *de, const char *path)
569+
static int get_index_dtype(const char *path, int len)
570+
{
571+
int pos;
572+
struct cache_entry *ce;
573+
574+
ce = cache_name_exists(path, len, 0);
575+
if (ce) {
576+
if (!ce_uptodate(ce))
577+
return DT_UNKNOWN;
578+
if (S_ISGITLINK(ce->ce_mode))
579+
return DT_DIR;
580+
/*
581+
* Nobody actually cares about the
582+
* difference between DT_LNK and DT_REG
583+
*/
584+
return DT_REG;
585+
}
586+
587+
/* Try to look it up as a directory */
588+
pos = cache_name_pos(path, len);
589+
if (pos >= 0)
590+
return DT_UNKNOWN;
591+
pos = -pos-1;
592+
while (pos < active_nr) {
593+
ce = active_cache[pos++];
594+
if (strncmp(ce->name, path, len))
595+
break;
596+
if (ce->name[len] > '/')
597+
break;
598+
if (ce->name[len] < '/')
599+
continue;
600+
if (!ce_uptodate(ce))
601+
break; /* continue? */
602+
return DT_DIR;
603+
}
604+
return DT_UNKNOWN;
605+
}
606+
607+
static int get_dtype(struct dirent *de, const char *path, int len)
551608
{
552609
int dtype = de ? DTYPE(de) : DT_UNKNOWN;
553610
struct stat st;
554611

612+
if (dtype != DT_UNKNOWN)
613+
return dtype;
614+
dtype = get_index_dtype(path, len);
555615
if (dtype != DT_UNKNOWN)
556616
return dtype;
557617
if (lstat(path, &st))
@@ -574,15 +634,15 @@ static int get_dtype(struct dirent *de, const char *path)
574634
* Also, we ignore the name ".git" (even if it is not a directory).
575635
* That likely will not change.
576636
*/
577-
static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
637+
static int read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
578638
{
579-
DIR *fdir = opendir(*path ? path : ".");
639+
DIR *fdir = opendir(*base ? base : ".");
580640
int contents = 0;
581641

582642
if (fdir) {
583643
struct dirent *de;
584-
char fullname[PATH_MAX + 1];
585-
memcpy(fullname, base, baselen);
644+
char path[PATH_MAX + 1];
645+
memcpy(path, base, baselen);
586646

587647
while ((de = readdir(fdir)) != NULL) {
588648
int len, dtype;
@@ -593,17 +653,18 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
593653
continue;
594654
len = strlen(de->d_name);
595655
/* Ignore overly long pathnames! */
596-
if (len + baselen + 8 > sizeof(fullname))
656+
if (len + baselen + 8 > sizeof(path))
597657
continue;
598-
memcpy(fullname + baselen, de->d_name, len+1);
599-
if (simplify_away(fullname, baselen + len, simplify))
658+
memcpy(path + baselen, de->d_name, len+1);
659+
len = baselen + len;
660+
if (simplify_away(path, len, simplify))
600661
continue;
601662

602663
dtype = DTYPE(de);
603-
exclude = excluded(dir, fullname, &dtype);
664+
exclude = excluded(dir, path, &dtype);
604665
if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
605-
&& in_pathspec(fullname, baselen + len, simplify))
606-
dir_add_ignored(dir, fullname, baselen + len);
666+
&& in_pathspec(path, len, simplify))
667+
dir_add_ignored(dir, path,len);
607668

608669
/*
609670
* Excluded? If we don't explicitly want to show
@@ -613,7 +674,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
613674
continue;
614675

615676
if (dtype == DT_UNKNOWN)
616-
dtype = get_dtype(de, fullname);
677+
dtype = get_dtype(de, path, len);
617678

618679
/*
619680
* Do we want to see just the ignored files?
@@ -630,17 +691,17 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
630691
default:
631692
continue;
632693
case DT_DIR:
633-
memcpy(fullname + baselen + len, "/", 2);
694+
memcpy(path + len, "/", 2);
634695
len++;
635-
switch (treat_directory(dir, fullname, baselen + len, simplify)) {
696+
switch (treat_directory(dir, path, len, simplify)) {
636697
case show_directory:
637698
if (exclude != !!(dir->flags
638699
& DIR_SHOW_IGNORED))
639700
continue;
640701
break;
641702
case recurse_into_directory:
642703
contents += read_directory_recursive(dir,
643-
fullname, fullname, baselen + len, 0, simplify);
704+
path, len, 0, simplify);
644705
continue;
645706
case ignore_directory:
646707
continue;
@@ -654,7 +715,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
654715
if (check_only)
655716
goto exit_early;
656717
else
657-
dir_add_name(dir, fullname, baselen + len);
718+
dir_add_name(dir, path, len);
658719
}
659720
exit_early:
660721
closedir(fdir);
@@ -717,15 +778,15 @@ static void free_simplify(struct path_simplify *simplify)
717778
free(simplify);
718779
}
719780

720-
int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
781+
int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
721782
{
722783
struct path_simplify *simplify;
723784

724-
if (has_symlink_leading_path(path, strlen(path)))
785+
if (has_symlink_leading_path(path, len))
725786
return dir->nr;
726787

727788
simplify = create_simplify(pathspec);
728-
read_directory_recursive(dir, path, base, baselen, 0, simplify);
789+
read_directory_recursive(dir, path, len, 0, simplify);
729790
free_simplify(simplify);
730791
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
731792
qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);

dir.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,13 @@ struct dir_struct {
6161
char basebuf[PATH_MAX];
6262
};
6363

64-
extern int common_prefix(const char **pathspec);
65-
6664
#define MATCHED_RECURSIVELY 1
6765
#define MATCHED_FNMATCH 2
6866
#define MATCHED_EXACTLY 3
6967
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
7068

71-
extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);
69+
extern int fill_directory(struct dir_struct *dir, const char **pathspec);
70+
extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
7271

7372
extern int excluded(struct dir_struct *, const char *, int *);
7473
extern void add_excludes_from_file(struct dir_struct *, const char *fname);

preload-index.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ static void *preload_thread(void *_data)
3434
struct thread_data *p = _data;
3535
struct index_state *index = p->index;
3636
struct cache_entry **cep = index->cache + p->offset;
37+
struct cache_def cache;
3738

39+
memset(&cache, 0, sizeof(cache));
3840
nr = p->nr;
3941
if (nr + p->offset > index->cache_nr)
4042
nr = index->cache_nr - p->offset;
@@ -49,6 +51,8 @@ static void *preload_thread(void *_data)
4951
continue;
5052
if (!ce_path_match(ce, p->pathspec))
5153
continue;
54+
if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
55+
continue;
5256
if (lstat(ce->name, &st))
5357
continue;
5458
if (ie_match_stat(index, ce, &st, CE_MATCH_RACY_IS_DIRTY))

0 commit comments

Comments
 (0)