зеркало из https://github.com/microsoft/git.git
Merge pull request #994 from jeffhostetler/jeffhostetler/fscache_nfd
fscache: add not-found directory cache to fscache
This commit is contained in:
Коммит
bcbaa80d61
|
@ -4,11 +4,13 @@
|
|||
#include "fscache.h"
|
||||
#include "../../dir.h"
|
||||
#include "../../abspath.h"
|
||||
#include "../../trace.h"
|
||||
|
||||
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
|
||||
|
@ -179,7 +181,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_PATH + 2]; /* + 2 for '/' '*' */
|
||||
WIN32_FIND_DATAW fdata;
|
||||
|
@ -188,6 +191,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 < MAX_PATH */
|
||||
if ((wlen = xutftowcsn(pattern, dir->dirent.d_name, MAX_PATH,
|
||||
dir->len)) < 0) {
|
||||
|
@ -206,12 +211,17 @@ 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->dirent.d_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* allocate object to hold directory listing */
|
||||
list = fsentry_alloc(NULL, dir->dirent.d_name, dir->len);
|
||||
list->st_mode = S_IFDIR;
|
||||
list->dirent.d_type = DT_DIR;
|
||||
|
||||
/* walk directory and build linked list of fsentry structures */
|
||||
phead = &list->next;
|
||||
|
@ -296,12 +306,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;
|
||||
}
|
||||
|
@ -310,7 +324,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;
|
||||
}
|
||||
|
@ -324,7 +341,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 */
|
||||
|
@ -338,6 +355,18 @@ 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->dirent.d_name,
|
||||
key->list->len);
|
||||
fse->st_mode = 0;
|
||||
hashmap_add(&map, &fse->ent);
|
||||
}
|
||||
LeaveCriticalSection(&mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -349,6 +378,9 @@ static struct fsentry *fscache_get(struct fsentry *key)
|
|||
if (key->list)
|
||||
fse = hashmap_get_entry(&map, key, ent, NULL);
|
||||
|
||||
if (fse && !fse->st_mode)
|
||||
fse = NULL; /* non-existing directory */
|
||||
|
||||
/* return entry or ENOENT */
|
||||
if (fse)
|
||||
fsentry_addref(fse);
|
||||
|
@ -392,6 +424,7 @@ int fscache_enable(int enable)
|
|||
fscache_clear();
|
||||
LeaveCriticalSection(&mutex);
|
||||
}
|
||||
trace_printf_key(&trace_fscache, "fscache: enable(%d)\n", enable);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,4 +106,24 @@ test_expect_success 'in partial clone, sparse checkout only fetches needed blobs
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success MINGW '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 || exit 1
|
||||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче