Skip to content

Commit e7bb30d

Browse files
author
Git for Windows Build Agent
committed
Merge pull request #994 from jeffhostetler/jeffhostetler/fscache_nfd
fscache: add not-found directory cache to fscache
2 parents e3fef52 + 58ad10f commit e7bb30d

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

compat/win32/fscache.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ static int initialized;
77
static volatile long enabled;
88
static struct hashmap map;
99
static CRITICAL_SECTION mutex;
10+
static struct trace_key trace_fscache = TRACE_KEY_INIT(FSCACHE);
1011

1112
/*
1213
* An entry in the file system cache. Used for both entire directory listings
@@ -163,7 +164,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
163164
* Dir should not contain trailing '/'. Use an empty string for the current
164165
* directory (not "."!).
165166
*/
166-
static struct fsentry *fsentry_create_list(const struct fsentry *dir)
167+
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
168+
int *dir_not_found)
167169
{
168170
wchar_t pattern[MAX_LONG_PATH + 2]; /* + 2 for "\*" */
169171
WIN32_FIND_DATAW fdata;
@@ -172,6 +174,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
172174
struct fsentry *list, **phead;
173175
DWORD err;
174176

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

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

200208
/* walk directory and build linked list of fsentry structures */
201209
phead = &list->next;
@@ -299,12 +307,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
299307
static struct fsentry *fscache_get(struct fsentry *key)
300308
{
301309
struct fsentry *fse, *future, *waiter;
310+
int dir_not_found;
302311

303312
EnterCriticalSection(&mutex);
304313
/* check if entry is in cache */
305314
fse = fscache_get_wait(key);
306315
if (fse) {
307-
fsentry_addref(fse);
316+
if (fse->st_mode)
317+
fsentry_addref(fse);
318+
else
319+
fse = NULL; /* non-existing directory */
308320
LeaveCriticalSection(&mutex);
309321
return fse;
310322
}
@@ -313,7 +325,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
313325
fse = fscache_get_wait(key->list);
314326
if (fse) {
315327
LeaveCriticalSection(&mutex);
316-
/* dir entry without file entry -> file doesn't exist */
328+
/*
329+
* dir entry without file entry, or dir does not
330+
* exist -> file doesn't exist
331+
*/
317332
errno = ENOENT;
318333
return NULL;
319334
}
@@ -327,7 +342,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
327342

328343
/* create the directory listing (outside mutex!) */
329344
LeaveCriticalSection(&mutex);
330-
fse = fsentry_create_list(future);
345+
fse = fsentry_create_list(future, &dir_not_found);
331346
EnterCriticalSection(&mutex);
332347

333348
/* remove future entry and signal waiting threads */
@@ -341,6 +356,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
341356

342357
/* leave on error (errno set by fsentry_create_list) */
343358
if (!fse) {
359+
if (dir_not_found && key->list) {
360+
/*
361+
* Record that the directory does not exist (or is
362+
* empty, which for all practical matters is the same
363+
* thing as far as fscache is concerned).
364+
*/
365+
fse = fsentry_alloc(key->list->list,
366+
key->list->name, key->list->len);
367+
fse->st_mode = 0;
368+
hashmap_add(&map, fse);
369+
}
344370
LeaveCriticalSection(&mutex);
345371
return NULL;
346372
}
@@ -352,6 +378,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
352378
if (key->list)
353379
fse = hashmap_get(&map, key, NULL);
354380

381+
if (fse && !fse->st_mode)
382+
fse = NULL; /* non-existing directory */
383+
355384
/* return entry or ENOENT */
356385
if (fse)
357386
fsentry_addref(fse);
@@ -395,6 +424,7 @@ int fscache_enable(int enable)
395424
fscache_clear();
396425
LeaveCriticalSection(&mutex);
397426
}
427+
trace_printf_key(&trace_fscache, "fscache: enable(%d)\n", enable);
398428
return result;
399429
}
400430

t/t1090-sparse-checkout-scope.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,24 @@ test_expect_success 'return to full checkout of master' '
4949
test "$(cat b)" = "modified"
5050
'
5151

52+
test_expect_success MINGW 'no unnecessary opendir() with fscache' '
53+
git clone . fscache-test &&
54+
(
55+
cd fscache-test &&
56+
git config core.fscache 1 &&
57+
echo "/excluded/*" >.git/info/sparse-checkout &&
58+
for f in $(test_seq 10)
59+
do
60+
sha1=$(echo $f | git hash-object -w --stdin) &&
61+
git update-index --add \
62+
--cacheinfo 100644,$sha1,excluded/$f || break
63+
done &&
64+
test_tick &&
65+
git commit -m excluded &&
66+
GIT_TRACE_FSCACHE=1 git status >out 2>err &&
67+
grep excluded err >grep.out &&
68+
test_line_count = 1 grep.out
69+
)
70+
'
71+
5272
test_done

0 commit comments

Comments
 (0)