Skip to content

Commit 2e616ca

Browse files
committed
Merge pull request #994 from jeffhostetler/jeffhostetler/fscache_nfd
fscache: add not-found directory cache to fscache
2 parents cb0f9bd + 67ce234 commit 2e616ca

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
@@ -187,7 +188,8 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
187188
* Dir should not contain trailing '/'. Use an empty string for the current
188189
* directory (not "."!).
189190
*/
190-
static struct fsentry *fsentry_create_list(const struct fsentry *dir)
191+
static struct fsentry *fsentry_create_list(const struct fsentry *dir,
192+
int *dir_not_found)
191193
{
192194
wchar_t pattern[MAX_LONG_PATH + 2]; /* + 2 for "\*" */
193195
WIN32_FIND_DATAW fdata;
@@ -196,6 +198,8 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
196198
struct fsentry *list, **phead;
197199
DWORD err;
198200

201+
*dir_not_found = 0;
202+
199203
/* convert name to UTF-16 and check length */
200204
if ((wlen = xutftowcs_path_ex(pattern, dir->name, MAX_LONG_PATH,
201205
dir->len, MAX_PATH - 2, core_long_paths)) < 0)
@@ -214,12 +218,16 @@ static struct fsentry *fsentry_create_list(const struct fsentry *dir)
214218
h = FindFirstFileW(pattern, &fdata);
215219
if (h == INVALID_HANDLE_VALUE) {
216220
err = GetLastError();
221+
*dir_not_found = 1; /* or empty directory */
217222
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
223+
trace_printf_key(&trace_fscache, "fscache: error(%d) '%.*s'\n",
224+
errno, dir->len, dir->name);
218225
return NULL;
219226
}
220227

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

224232
/* walk directory and build linked list of fsentry structures */
225233
phead = &list->next;
@@ -304,12 +312,16 @@ static struct fsentry *fscache_get_wait(struct fsentry *key)
304312
static struct fsentry *fscache_get(struct fsentry *key)
305313
{
306314
struct fsentry *fse, *future, *waiter;
315+
int dir_not_found;
307316

308317
EnterCriticalSection(&mutex);
309318
/* check if entry is in cache */
310319
fse = fscache_get_wait(key);
311320
if (fse) {
312-
fsentry_addref(fse);
321+
if (fse->st_mode)
322+
fsentry_addref(fse);
323+
else
324+
fse = NULL; /* non-existing directory */
313325
LeaveCriticalSection(&mutex);
314326
return fse;
315327
}
@@ -318,7 +330,10 @@ static struct fsentry *fscache_get(struct fsentry *key)
318330
fse = fscache_get_wait(key->list);
319331
if (fse) {
320332
LeaveCriticalSection(&mutex);
321-
/* dir entry without file entry -> file doesn't exist */
333+
/*
334+
* dir entry without file entry, or dir does not
335+
* exist -> file doesn't exist
336+
*/
322337
errno = ENOENT;
323338
return NULL;
324339
}
@@ -332,7 +347,7 @@ static struct fsentry *fscache_get(struct fsentry *key)
332347

333348
/* create the directory listing (outside mutex!) */
334349
LeaveCriticalSection(&mutex);
335-
fse = fsentry_create_list(future);
350+
fse = fsentry_create_list(future, &dir_not_found);
336351
EnterCriticalSection(&mutex);
337352

338353
/* remove future entry and signal waiting threads */
@@ -346,6 +361,17 @@ static struct fsentry *fscache_get(struct fsentry *key)
346361

347362
/* leave on error (errno set by fsentry_create_list) */
348363
if (!fse) {
364+
if (dir_not_found && key->list) {
365+
/*
366+
* Record that the directory does not exist (or is
367+
* empty, which for all practical matters is the same
368+
* thing as far as fscache is concerned).
369+
*/
370+
fse = fsentry_alloc(key->list->list,
371+
key->list->name, key->list->len);
372+
fse->st_mode = 0;
373+
hashmap_add(&map, fse);
374+
}
349375
LeaveCriticalSection(&mutex);
350376
return NULL;
351377
}
@@ -357,6 +383,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
357383
if (key->list)
358384
fse = hashmap_get(&map, key, NULL);
359385

386+
if (fse && !fse->st_mode)
387+
fse = NULL; /* non-existing directory */
388+
360389
/* return entry or ENOENT */
361390
if (fse)
362391
fsentry_addref(fse);
@@ -400,6 +429,7 @@ int fscache_enable(int enable)
400429
fscache_clear();
401430
LeaveCriticalSection(&mutex);
402431
}
432+
trace_printf_key(&trace_fscache, "fscache: enable(%d)\n", enable);
403433
return result;
404434
}
405435

t/t1090-sparse-checkout-scope.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,24 @@ test_expect_success 'in partial clone, sparse checkout only fetches needed blobs
9696
test_cmp expect actual
9797
'
9898

99+
test_expect_success MINGW 'no unnecessary opendir() with fscache' '
100+
git clone . fscache-test &&
101+
(
102+
cd fscache-test &&
103+
git config core.fscache 1 &&
104+
echo "/excluded/*" >.git/info/sparse-checkout &&
105+
for f in $(test_seq 10)
106+
do
107+
sha1=$(echo $f | git hash-object -w --stdin) &&
108+
git update-index --add \
109+
--cacheinfo 100644,$sha1,excluded/$f || break
110+
done &&
111+
test_tick &&
112+
git commit -m excluded &&
113+
GIT_TRACE_FSCACHE=1 git status >out 2>err &&
114+
grep excluded err >grep.out &&
115+
test_line_count = 1 grep.out
116+
)
117+
'
118+
99119
test_done

0 commit comments

Comments
 (0)