Skip to content

Commit

Permalink
Merge pull request git-for-windows#994 from jeffhostetler/jeffhostetl…
Browse files Browse the repository at this point in the history
…er/fscache_nfd

fscache: add not-found directory cache to fscache
  • Loading branch information
dscho committed Feb 4, 2017
2 parents cbe12be + 1c36ebc commit 38bca3c
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
38 changes: 34 additions & 4 deletions compat/win32/fscache.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ static int initialized;
static volatile long enabled;
static struct hashmap map;
static CRITICAL_SECTION mutex;
static struct trace_key trace_fscache = TRACE_KEY_INIT(FSCACHE);

/*
* An entry in the file system cache. Used for both entire directory listings
Expand Down Expand Up @@ -163,7 +164,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
* Dir should not contain trailing '/'. Use an empty string for the current
* directory (not "."!).
*/
static struct fsentry *fsentry_create_list(const struct fsentry *dir)
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
int *dir_not_found)
{
wchar_t pattern[MAX_LONG_PATH + 2]; /* + 2 for "\*" */
WIN32_FIND_DATAW fdata;
Expand All @@ -172,6 +174,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
struct fsentry *list, **phead;
DWORD err;

*dir_not_found = 0;

/* convert name to UTF-16 and check length */
if ((wlen = xutftowcs_path_ex(pattern, dir->name, MAX_LONG_PATH,
dir->len, MAX_PATH - 2, core_long_paths)) < 0)
Expand All @@ -190,12 +194,16 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
h = FindFirstFileW(pattern, &fdata);
if (h == INVALID_HANDLE_VALUE) {
err = GetLastError();
*dir_not_found = 1; /* or empty directory */
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
trace_printf_key(&trace_fscache, "fscache: error(%d) '%.*s'\n",
errno, dir->len, dir->name);
return NULL;
}

/* allocate object to hold directory listing */
list = fsentry_alloc(NULL, dir->name, dir->len);
list->st_mode = S_IFDIR;

/* walk directory and build linked list of fsentry structures */
phead = &list->next;
Expand Down Expand Up @@ -296,12 +304,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
static struct fsentry *fscache_get(struct fsentry *key)
{
struct fsentry *fse, *future, *waiter;
int dir_not_found;

EnterCriticalSection(&mutex);
/* check if entry is in cache */
fse = fscache_get_wait(key);
if (fse) {
fsentry_addref(fse);
if (fse->st_mode)
fsentry_addref(fse);
else
fse = NULL; /* non-existing directory */
LeaveCriticalSection(&mutex);
return fse;
}
Expand All @@ -310,7 +322,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
fse = fscache_get_wait(key->list);
if (fse) {
LeaveCriticalSection(&mutex);
/* dir entry without file entry -> file doesn't exist */
/*
* dir entry without file entry, or dir does not
* exist -> file doesn't exist
*/
errno = ENOENT;
return NULL;
}
Expand All @@ -324,7 +339,7 @@ static struct fsentry *fscache_get(struct fsentry *key)

/* create the directory listing (outside mutex!) */
LeaveCriticalSection(&mutex);
fse = fsentry_create_list(future);
fse = fsentry_create_list(future, &dir_not_found);
EnterCriticalSection(&mutex);

/* remove future entry and signal waiting threads */
Expand All @@ -338,6 +353,17 @@ static struct fsentry *fscache_get(struct fsentry *key)

/* leave on error (errno set by fsentry_create_list) */
if (!fse) {
if (dir_not_found && key->list) {
/*
* Record that the directory does not exist (or is
* empty, which for all practical matters is the same
* thing as far as fscache is concerned).
*/
fse = fsentry_alloc(key->list->list,
key->list->name, key->list->len);
fse->st_mode = 0;
hashmap_add(&map, fse);
}
LeaveCriticalSection(&mutex);
return NULL;
}
Expand All @@ -349,6 +375,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
if (key->list)
fse = hashmap_get(&map, key, NULL);

if (fse && !fse->st_mode)
fse = NULL; /* non-existing directory */

/* return entry or ENOENT */
if (fse)
fsentry_addref(fse);
Expand Down Expand Up @@ -392,6 +421,7 @@ int fscache_enable(int enable)
fscache_clear();
LeaveCriticalSection(&mutex);
}
trace_printf_key(&trace_fscache, "fscache: enable(%d)\n", enable);
return result;
}

Expand Down
20 changes: 20 additions & 0 deletions t/t1090-sparse-checkout-scope.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,24 @@ test_expect_success 'return to full checkout of master' '
test "$(cat b)" = "modified"
'

test_expect_success 'no unnecessary opendir() with fscache' '
git clone . fscache-test &&
(
cd fscache-test &&
git config core.fscache 1 &&
echo "/excluded/*" >.git/info/sparse-checkout &&
for f in $(test_seq 10)
do
sha1=$(echo $f | git hash-object -w --stdin) &&
git update-index --add \
--cacheinfo 100644,$sha1,excluded/$f || break
done &&
test_tick &&
git commit -m excluded &&
GIT_TRACE_FSCACHE=1 git status >out 2>err &&
grep excluded err >grep.out &&
test_line_count = 1 grep.out
)
'

test_done

0 comments on commit 38bca3c

Please sign in to comment.