Browse Source

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
maint
Junio C Hamano 16 years ago
parent
commit
20f3749977
  1. 45
      builtin-add.c
  2. 12
      builtin-clean.c
  3. 7
      builtin-ls-files.c
  4. 10
      cache.h
  5. 111
      dir.c
  6. 5
      dir.h
  7. 4
      preload-index.c
  8. 90
      symlinks.c
  9. 2
      unpack-trees.c
  10. 2
      wt-status.c

45
builtin-add.c

@ -97,35 +97,6 @@ static void treat_gitlinks(const char **pathspec) @@ -97,35 +97,6 @@ static void treat_gitlinks(const char **pathspec)
}
}

static void fill_directory(struct dir_struct *dir, const char **pathspec,
int ignored_too)
{
const char *path, *base;
int baselen;

/* Set up the default git porcelain excludes */
memset(dir, 0, sizeof(*dir));
if (!ignored_too) {
dir->flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(dir);
}

/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
baselen = common_prefix(pathspec);
path = ".";
base = "";
if (baselen)
path = base = xmemdupz(*pathspec, baselen);

/* Read the directory and prune it */
read_directory(dir, path, base, baselen, pathspec);
if (pathspec)
prune_directory(dir, pathspec, baselen);
}

static void refresh(int verbose, const char **pathspec)
{
char *seen;
@ -343,9 +314,21 @@ int cmd_add(int argc, const char **argv, const char *prefix) @@ -343,9 +314,21 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die("index file corrupt");
treat_gitlinks(pathspec);

if (add_new_files)
if (add_new_files) {
int baselen;

/* Set up the default git porcelain excludes */
memset(&dir, 0, sizeof(dir));
if (!ignored_too) {
dir.flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(&dir);
}

/* This picks up the paths that are not tracked */
fill_directory(&dir, pathspec, ignored_too);
baselen = fill_directory(&dir, pathspec);
if (pathspec)
prune_directory(&dir, pathspec, baselen);
}

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

12
builtin-clean.c

@ -33,7 +33,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix) @@ -33,7 +33,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
const char *path, *base;
static const char **pathspec;
struct strbuf buf = STRBUF_INIT;
const char *qname;
@ -78,16 +77,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) @@ -78,16 +77,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
pathspec = get_pathspec(prefix, argv);
read_cache();

/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
baselen = common_prefix(pathspec);
path = ".";
base = "";
if (baselen)
path = base = xmemdupz(*pathspec, baselen);
read_directory(&dir, path, base, baselen, pathspec);
fill_directory(&dir, pathspec);

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

7
builtin-ls-files.c

@ -161,12 +161,7 @@ static void show_files(struct dir_struct *dir, const char *prefix) @@ -161,12 +161,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)

/* For cached/deleted files we don't need to even do the readdir */
if (show_others || show_killed) {
const char *path = ".", *base = "";
int baselen = prefix_len;

if (baselen)
path = base = prefix;
read_directory(dir, path, base, baselen, pathspec);
fill_directory(dir, pathspec);
if (show_others)
show_other_files(dir);
if (show_killed)

10
cache.h

@ -744,7 +744,17 @@ struct checkout { @@ -744,7 +744,17 @@ struct checkout {
};

extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);

struct cache_def {
char path[PATH_MAX + 1];
int len;
int flags;
int track_flags;
int prefix_len_stat_func;
};

extern int has_symlink_leading_path(const char *name, int len);
extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
extern int has_symlink_or_noent_leading_path(const char *name, int len);
extern int has_dirs_only_path(const char *name, int len, int prefix_len);
extern void invalidate_lstat_cache(const char *name, int len);

111
dir.c

@ -14,12 +14,11 @@ struct path_simplify { @@ -14,12 +14,11 @@ struct path_simplify {
const char *path;
};

static int read_directory_recursive(struct dir_struct *dir,
const char *path, const char *base, int baselen,
static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
int check_only, const struct path_simplify *simplify);
static int get_dtype(struct dirent *de, const char *path);
static int get_dtype(struct dirent *de, const char *path, int len);

int common_prefix(const char **pathspec)
static int common_prefix(const char **pathspec)
{
const char *path, *slash, *next;
int prefix;
@ -52,6 +51,26 @@ int common_prefix(const char **pathspec) @@ -52,6 +51,26 @@ int common_prefix(const char **pathspec)
return prefix;
}

int fill_directory(struct dir_struct *dir, const char **pathspec)
{
const char *path;
int len;

/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
len = common_prefix(pathspec);
path = "";

if (len)
path = xmemdupz(*pathspec, len);

/* Read the directory and prune it */
read_directory(dir, path, len, pathspec);
return len;
}

/*
* Does 'match' match the given name?
* A match is found if
@ -307,7 +326,7 @@ static int excluded_1(const char *pathname, @@ -307,7 +326,7 @@ static int excluded_1(const char *pathname,

if (x->flags & EXC_FLAG_MUSTBEDIR) {
if (*dtype == DT_UNKNOWN)
*dtype = get_dtype(NULL, pathname);
*dtype = get_dtype(NULL, pathname, pathlen);
if (*dtype != DT_DIR)
continue;
}
@ -505,7 +524,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir, @@ -505,7 +524,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
/* This is the "show_other_directories" case */
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
return show_directory;
if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
if (!read_directory_recursive(dir, dirname, len, 1, simplify))
return ignore_directory;
return show_directory;
}
@ -547,11 +566,52 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si @@ -547,11 +566,52 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
return 0;
}

static int get_dtype(struct dirent *de, const char *path)
static int get_index_dtype(const char *path, int len)
{
int pos;
struct cache_entry *ce;

ce = cache_name_exists(path, len, 0);
if (ce) {
if (!ce_uptodate(ce))
return DT_UNKNOWN;
if (S_ISGITLINK(ce->ce_mode))
return DT_DIR;
/*
* Nobody actually cares about the
* difference between DT_LNK and DT_REG
*/
return DT_REG;
}

/* Try to look it up as a directory */
pos = cache_name_pos(path, len);
if (pos >= 0)
return DT_UNKNOWN;
pos = -pos-1;
while (pos < active_nr) {
ce = active_cache[pos++];
if (strncmp(ce->name, path, len))
break;
if (ce->name[len] > '/')
break;
if (ce->name[len] < '/')
continue;
if (!ce_uptodate(ce))
break; /* continue? */
return DT_DIR;
}
return DT_UNKNOWN;
}

static int get_dtype(struct dirent *de, const char *path, int len)
{
int dtype = de ? DTYPE(de) : DT_UNKNOWN;
struct stat st;

if (dtype != DT_UNKNOWN)
return dtype;
dtype = get_index_dtype(path, len);
if (dtype != DT_UNKNOWN)
return dtype;
if (lstat(path, &st))
@ -574,15 +634,15 @@ static int get_dtype(struct dirent *de, const char *path) @@ -574,15 +634,15 @@ static int get_dtype(struct dirent *de, const char *path)
* Also, we ignore the name ".git" (even if it is not a directory).
* That likely will not change.
*/
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)
static int read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
{
DIR *fdir = opendir(*path ? path : ".");
DIR *fdir = opendir(*base ? base : ".");
int contents = 0;

if (fdir) {
struct dirent *de;
char fullname[PATH_MAX + 1];
memcpy(fullname, base, baselen);
char path[PATH_MAX + 1];
memcpy(path, base, baselen);

while ((de = readdir(fdir)) != NULL) {
int len, dtype;
@ -593,17 +653,18 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co @@ -593,17 +653,18 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
continue;
len = strlen(de->d_name);
/* Ignore overly long pathnames! */
if (len + baselen + 8 > sizeof(fullname))
if (len + baselen + 8 > sizeof(path))
continue;
memcpy(fullname + baselen, de->d_name, len+1);
if (simplify_away(fullname, baselen + len, simplify))
memcpy(path + baselen, de->d_name, len+1);
len = baselen + len;
if (simplify_away(path, len, simplify))
continue;

dtype = DTYPE(de);
exclude = excluded(dir, fullname, &dtype);
exclude = excluded(dir, path, &dtype);
if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
&& in_pathspec(fullname, baselen + len, simplify))
dir_add_ignored(dir, fullname, baselen + len);
&& in_pathspec(path, len, simplify))
dir_add_ignored(dir, path,len);

/*
* 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 @@ -613,7 +674,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
continue;

if (dtype == DT_UNKNOWN)
dtype = get_dtype(de, fullname);
dtype = get_dtype(de, path, len);

/*
* Do we want to see just the ignored files?
@ -630,9 +691,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co @@ -630,9 +691,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
default:
continue;
case DT_DIR:
memcpy(fullname + baselen + len, "/", 2);
memcpy(path + len, "/", 2);
len++;
switch (treat_directory(dir, fullname, baselen + len, simplify)) {
switch (treat_directory(dir, path, len, simplify)) {
case show_directory:
if (exclude != !!(dir->flags
& DIR_SHOW_IGNORED))
@ -640,7 +701,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co @@ -640,7 +701,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
break;
case recurse_into_directory:
contents += read_directory_recursive(dir,
fullname, fullname, baselen + len, 0, simplify);
path, len, 0, simplify);
continue;
case ignore_directory:
continue;
@ -654,7 +715,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co @@ -654,7 +715,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
if (check_only)
goto exit_early;
else
dir_add_name(dir, fullname, baselen + len);
dir_add_name(dir, path, len);
}
exit_early:
closedir(fdir);
@ -717,15 +778,15 @@ static void free_simplify(struct path_simplify *simplify) @@ -717,15 +778,15 @@ static void free_simplify(struct path_simplify *simplify)
free(simplify);
}

int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
{
struct path_simplify *simplify;

if (has_symlink_leading_path(path, strlen(path)))
if (has_symlink_leading_path(path, len))
return dir->nr;

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

5
dir.h

@ -61,14 +61,13 @@ struct dir_struct { @@ -61,14 +61,13 @@ struct dir_struct {
char basebuf[PATH_MAX];
};

extern int common_prefix(const char **pathspec);

#define MATCHED_RECURSIVELY 1
#define MATCHED_FNMATCH 2
#define MATCHED_EXACTLY 3
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);

extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);
extern int fill_directory(struct dir_struct *dir, const char **pathspec);
extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);

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

4
preload-index.c

@ -34,7 +34,9 @@ static void *preload_thread(void *_data) @@ -34,7 +34,9 @@ static void *preload_thread(void *_data)
struct thread_data *p = _data;
struct index_state *index = p->index;
struct cache_entry **cep = index->cache + p->offset;
struct cache_def cache;

memset(&cache, 0, sizeof(cache));
nr = p->nr;
if (nr + p->offset > index->cache_nr)
nr = index->cache_nr - p->offset;
@ -49,6 +51,8 @@ static void *preload_thread(void *_data) @@ -49,6 +51,8 @@ static void *preload_thread(void *_data)
continue;
if (!ce_path_match(ce, p->pathspec))
continue;
if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
continue;
if (lstat(ce->name, &st))
continue;
if (ie_match_stat(index, ce, &st, CE_MATCH_RACY_IS_DIRTY))

90
symlinks.c

@ -32,19 +32,13 @@ static int longest_path_match(const char *name_a, int len_a, @@ -32,19 +32,13 @@ static int longest_path_match(const char *name_a, int len_a,
return match_len;
}

static struct cache_def {
char path[PATH_MAX + 1];
int len;
int flags;
int track_flags;
int prefix_len_stat_func;
} cache;
static struct cache_def default_cache;

static inline void reset_lstat_cache(void)
static inline void reset_lstat_cache(struct cache_def *cache)
{
cache.path[0] = '\0';
cache.len = 0;
cache.flags = 0;
cache->path[0] = '\0';
cache->len = 0;
cache->flags = 0;
/*
* The track_flags and prefix_len_stat_func members is only
* set by the safeguard rule inside lstat_cache()
@ -70,23 +64,23 @@ static inline void reset_lstat_cache(void) @@ -70,23 +64,23 @@ static inline void reset_lstat_cache(void)
* of the prefix, where the cache should use the stat() function
* instead of the lstat() function to test each path component.
*/
static int lstat_cache(const char *name, int len,
static int lstat_cache(struct cache_def *cache, const char *name, int len,
int track_flags, int prefix_len_stat_func)
{
int match_len, last_slash, last_slash_dir, previous_slash;
int match_flags, ret_flags, save_flags, max_len, ret;
struct stat st;

if (cache.track_flags != track_flags ||
cache.prefix_len_stat_func != prefix_len_stat_func) {
if (cache->track_flags != track_flags ||
cache->prefix_len_stat_func != prefix_len_stat_func) {
/*
* As a safeguard rule we clear the cache if the
* values of track_flags and/or prefix_len_stat_func
* does not match with the last supplied values.
*/
reset_lstat_cache();
cache.track_flags = track_flags;
cache.prefix_len_stat_func = prefix_len_stat_func;
reset_lstat_cache(cache);
cache->track_flags = track_flags;
cache->prefix_len_stat_func = prefix_len_stat_func;
match_len = last_slash = 0;
} else {
/*
@ -94,10 +88,10 @@ static int lstat_cache(const char *name, int len, @@ -94,10 +88,10 @@ static int lstat_cache(const char *name, int len,
* the 2 "excluding" path types.
*/
match_len = last_slash =
longest_path_match(name, len, cache.path, cache.len,
longest_path_match(name, len, cache->path, cache->len,
&previous_slash);
match_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (match_flags && match_len == cache.len)
match_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (match_flags && match_len == cache->len)
return match_flags;
/*
* If we now have match_len > 0, we would know that
@ -121,18 +115,18 @@ static int lstat_cache(const char *name, int len, @@ -121,18 +115,18 @@ static int lstat_cache(const char *name, int len,
max_len = len < PATH_MAX ? len : PATH_MAX;
while (match_len < max_len) {
do {
cache.path[match_len] = name[match_len];
cache->path[match_len] = name[match_len];
match_len++;
} while (match_len < max_len && name[match_len] != '/');
if (match_len >= max_len && !(track_flags & FL_FULLPATH))
break;
last_slash = match_len;
cache.path[last_slash] = '\0';
cache->path[last_slash] = '\0';

if (last_slash <= prefix_len_stat_func)
ret = stat(cache.path, &st);
ret = stat(cache->path, &st);
else
ret = lstat(cache.path, &st);
ret = lstat(cache->path, &st);

if (ret) {
ret_flags = FL_LSTATERR;
@ -156,9 +150,9 @@ static int lstat_cache(const char *name, int len, @@ -156,9 +150,9 @@ static int lstat_cache(const char *name, int len,
*/
save_flags = ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {
cache.path[last_slash] = '\0';
cache.len = last_slash;
cache.flags = save_flags;
cache->path[last_slash] = '\0';
cache->len = last_slash;
cache->flags = save_flags;
} else if ((track_flags & FL_DIR) &&
last_slash_dir > 0 && last_slash_dir <= PATH_MAX) {
/*
@ -172,11 +166,11 @@ static int lstat_cache(const char *name, int len, @@ -172,11 +166,11 @@ static int lstat_cache(const char *name, int len,
* can still cache the path components before the last
* one (the found symlink or non-existing component).
*/
cache.path[last_slash_dir] = '\0';
cache.len = last_slash_dir;
cache.flags = FL_DIR;
cache->path[last_slash_dir] = '\0';
cache->len = last_slash_dir;
cache->flags = FL_DIR;
} else {
reset_lstat_cache();
reset_lstat_cache(cache);
}
return ret_flags;
}
@ -188,16 +182,17 @@ static int lstat_cache(const char *name, int len, @@ -188,16 +182,17 @@ static int lstat_cache(const char *name, int len,
void invalidate_lstat_cache(const char *name, int len)
{
int match_len, previous_slash;
struct cache_def *cache = &default_cache; /* FIXME */

match_len = longest_path_match(name, len, cache.path, cache.len,
match_len = longest_path_match(name, len, cache->path, cache->len,
&previous_slash);
if (len == match_len) {
if ((cache.track_flags & FL_DIR) && previous_slash > 0) {
cache.path[previous_slash] = '\0';
cache.len = previous_slash;
cache.flags = FL_DIR;
if ((cache->track_flags & FL_DIR) && previous_slash > 0) {
cache->path[previous_slash] = '\0';
cache->len = previous_slash;
cache->flags = FL_DIR;
} else {
reset_lstat_cache();
reset_lstat_cache(cache);
}
}
}
@ -207,19 +202,26 @@ void invalidate_lstat_cache(const char *name, int len) @@ -207,19 +202,26 @@ void invalidate_lstat_cache(const char *name, int len)
*/
void clear_lstat_cache(void)
{
reset_lstat_cache();
struct cache_def *cache = &default_cache; /* FIXME */
reset_lstat_cache(cache);
}

#define USE_ONLY_LSTAT 0

/*
* Return non-zero if path 'name' has a leading symlink component
*/
int threaded_has_symlink_leading_path(struct cache_def *cache, const char *name, int len)
{
return lstat_cache(cache, name, len, FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) & FL_SYMLINK;
}

/*
* Return non-zero if path 'name' has a leading symlink component
*/
int has_symlink_leading_path(const char *name, int len)
{
return lstat_cache(name, len,
FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) &
FL_SYMLINK;
return threaded_has_symlink_leading_path(&default_cache, name, len);
}

/*
@ -228,7 +230,8 @@ int has_symlink_leading_path(const char *name, int len) @@ -228,7 +230,8 @@ int has_symlink_leading_path(const char *name, int len)
*/
int has_symlink_or_noent_leading_path(const char *name, int len)
{
return lstat_cache(name, len,
struct cache_def *cache = &default_cache; /* FIXME */
return lstat_cache(cache, name, len,
FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) &
(FL_SYMLINK|FL_NOENT);
}
@ -242,7 +245,8 @@ int has_symlink_or_noent_leading_path(const char *name, int len) @@ -242,7 +245,8 @@ int has_symlink_or_noent_leading_path(const char *name, int len)
*/
int has_dirs_only_path(const char *name, int len, int prefix_len)
{
return lstat_cache(name, len,
struct cache_def *cache = &default_cache; /* FIXME */
return lstat_cache(cache, name, len,
FL_DIR|FL_FULLPATH, prefix_len) &
FL_DIR;
}

2
unpack-trees.c

@ -551,7 +551,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, @@ -551,7 +551,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
memset(&d, 0, sizeof(d));
if (o->dir)
d.exclude_per_dir = o->dir->exclude_per_dir;
i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
i = read_directory(&d, pathbuf, namelen+1, NULL);
if (i)
return o->gently ? -1 :
error(ERRORMSG(o, not_uptodate_dir), ce->name);

2
wt-status.c

@ -255,7 +255,7 @@ static void wt_status_print_untracked(struct wt_status *s) @@ -255,7 +255,7 @@ static void wt_status_print_untracked(struct wt_status *s)
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
setup_standard_excludes(&dir);

read_directory(&dir, ".", "", 0, NULL);
fill_directory(&dir, NULL);
for(i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
if (!cache_name_is_other(ent->name, ent->len))

Loading…
Cancel
Save