Skip to content

Commit 73a6a8b

Browse files
committed
Merge branch 'fscache'
2 parents 6207391 + b1a0f3f commit 73a6a8b

File tree

12 files changed

+634
-70
lines changed

12 files changed

+634
-70
lines changed

Documentation/config/core.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,12 @@ relatively high IO latencies. When enabled, Git will do the
564564
index comparison to the filesystem data in parallel, allowing
565565
overlapping IO's. Defaults to true.
566566

567+
core.fscache::
568+
Enable additional caching of file system data for some operations.
569+
+
570+
Git for Windows uses this to bulk-read and cache lstat data of entire
571+
directories (instead of doing lstat file by file).
572+
567573
core.unsetenvvars::
568574
Windows-only: comma-separated list of environment variables'
569575
names that need to be unset before spawning any other process.

builtin/commit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
14181418
PATHSPEC_PREFER_FULL,
14191419
prefix, argv);
14201420

1421+
enable_fscache(1);
14211422
if (status_format != STATUS_FORMAT_PORCELAIN &&
14221423
status_format != STATUS_FORMAT_PORCELAIN_V2)
14231424
progress_flag = REFRESH_PROGRESS;

compat/mingw.c

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ enum hide_dotfiles_type {
229229
static int core_restrict_inherited_handles = -1;
230230
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
231231
static char *unset_environment_variables;
232+
int core_fscache;
232233

233234
int mingw_core_config(const char *var, const char *value, void *cb)
234235
{
@@ -240,6 +241,11 @@ int mingw_core_config(const char *var, const char *value, void *cb)
240241
return 0;
241242
}
242243

244+
if (!strcmp(var, "core.fscache")) {
245+
core_fscache = git_config_bool(var, value);
246+
return 0;
247+
}
248+
243249
if (!strcmp(var, "core.unsetenvvars")) {
244250
free(unset_environment_variables);
245251
unset_environment_variables = xstrdup(value);
@@ -705,24 +711,6 @@ int mingw_chmod(const char *filename, int mode)
705711
return _wchmod(wfilename, mode);
706712
}
707713

708-
/*
709-
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
710-
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
711-
*/
712-
static inline long long filetime_to_hnsec(const FILETIME *ft)
713-
{
714-
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
715-
/* Windows to Unix Epoch conversion */
716-
return winTime - 116444736000000000LL;
717-
}
718-
719-
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
720-
{
721-
long long hnsec = filetime_to_hnsec(ft);
722-
ts->tv_sec = (time_t)(hnsec / 10000000);
723-
ts->tv_nsec = (hnsec % 10000000) * 100;
724-
}
725-
726714
/**
727715
* Verifies that safe_create_leading_directories() would succeed.
728716
*/
@@ -862,6 +850,8 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
862850
return do_lstat(follow, alt_name, buf);
863851
}
864852

853+
int (*lstat)(const char *file_name, struct stat *buf) = mingw_lstat;
854+
865855
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
866856
{
867857
BY_HANDLE_FILE_INFORMATION fdata;

compat/mingw.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ typedef _sigset_t sigset_t;
1111
#undef _POSIX_THREAD_SAFE_FUNCTIONS
1212
#endif
1313

14+
extern int core_fscache;
15+
1416
int mingw_core_config(const char *var, const char *value, void *cb);
1517
#define platform_core_config mingw_core_config
1618

@@ -344,6 +346,17 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
344346
return 0;
345347
}
346348

349+
/*
350+
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
351+
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
352+
*/
353+
static inline long long filetime_to_hnsec(const FILETIME *ft)
354+
{
355+
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
356+
/* Windows to Unix Epoch conversion */
357+
return winTime - 116444736000000000LL;
358+
}
359+
347360
/*
348361
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
349362
* including our own struct stat with 64 bit st_size and nanosecond-precision
@@ -360,6 +373,13 @@ struct timespec {
360373
#endif
361374
#endif
362375

376+
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
377+
{
378+
long long hnsec = filetime_to_hnsec(ft);
379+
ts->tv_sec = (time_t)(hnsec / 10000000);
380+
ts->tv_nsec = (hnsec % 10000000) * 100;
381+
}
382+
363383
struct mingw_stat {
364384
_dev_t st_dev;
365385
_ino_t st_ino;
@@ -392,7 +412,7 @@ int mingw_fstat(int fd, struct stat *buf);
392412
#ifdef lstat
393413
#undef lstat
394414
#endif
395-
#define lstat mingw_lstat
415+
extern int (*lstat)(const char *file_name, struct stat *buf);
396416

397417

398418
int mingw_utime(const char *file_name, const struct utimbuf *times);

compat/win32/dirent.c

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
#include "../../git-compat-util.h"
22

3-
struct DIR {
4-
struct dirent dd_dir; /* includes d_type */
3+
typedef struct dirent_DIR {
4+
struct DIR base_dir; /* extend base struct DIR */
55
HANDLE dd_handle; /* FindFirstFile handle */
66
int dd_stat; /* 0-based index */
7-
};
7+
struct dirent dd_dir; /* includes d_type */
8+
} dirent_DIR;
9+
10+
DIR *(*opendir)(const char *dirname) = dirent_opendir;
811

912
static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
1013
{
11-
/* convert UTF-16 name to UTF-8 */
12-
xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
14+
/* convert UTF-16 name to UTF-8 (d_name points to dirent_DIR.dd_name) */
15+
xwcstoutf(ent->d_name, fdata->cFileName, MAX_PATH * 3);
1316

1417
/* Set file type, based on WIN32_FIND_DATA */
1518
if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -18,41 +21,7 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
1821
ent->d_type = DT_REG;
1922
}
2023

21-
DIR *opendir(const char *name)
22-
{
23-
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
24-
WIN32_FIND_DATAW fdata;
25-
HANDLE h;
26-
int len;
27-
DIR *dir;
28-
29-
/* convert name to UTF-16 and check length < MAX_PATH */
30-
if ((len = xutftowcs_path(pattern, name)) < 0)
31-
return NULL;
32-
33-
/* append optional '/' and wildcard '*' */
34-
if (len && !is_dir_sep(pattern[len - 1]))
35-
pattern[len++] = '/';
36-
pattern[len++] = '*';
37-
pattern[len] = 0;
38-
39-
/* open find handle */
40-
h = FindFirstFileW(pattern, &fdata);
41-
if (h == INVALID_HANDLE_VALUE) {
42-
DWORD err = GetLastError();
43-
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
44-
return NULL;
45-
}
46-
47-
/* initialize DIR structure and copy first dir entry */
48-
dir = xmalloc(sizeof(DIR));
49-
dir->dd_handle = h;
50-
dir->dd_stat = 0;
51-
finddata2dirent(&dir->dd_dir, &fdata);
52-
return dir;
53-
}
54-
55-
struct dirent *readdir(DIR *dir)
24+
static struct dirent *dirent_readdir(dirent_DIR *dir)
5625
{
5726
if (!dir) {
5827
errno = EBADF; /* No set_errno for mingw */
@@ -79,7 +48,7 @@ struct dirent *readdir(DIR *dir)
7948
return &dir->dd_dir;
8049
}
8150

82-
int closedir(DIR *dir)
51+
static int dirent_closedir(dirent_DIR *dir)
8352
{
8453
if (!dir) {
8554
errno = EBADF;
@@ -90,3 +59,39 @@ int closedir(DIR *dir)
9059
free(dir);
9160
return 0;
9261
}
62+
63+
DIR *dirent_opendir(const char *name)
64+
{
65+
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
66+
WIN32_FIND_DATAW fdata;
67+
HANDLE h;
68+
int len;
69+
dirent_DIR *dir;
70+
71+
/* convert name to UTF-16 and check length < MAX_PATH */
72+
if ((len = xutftowcs_path(pattern, name)) < 0)
73+
return NULL;
74+
75+
/* append optional '/' and wildcard '*' */
76+
if (len && !is_dir_sep(pattern[len - 1]))
77+
pattern[len++] = '/';
78+
pattern[len++] = '*';
79+
pattern[len] = 0;
80+
81+
/* open find handle */
82+
h = FindFirstFileW(pattern, &fdata);
83+
if (h == INVALID_HANDLE_VALUE) {
84+
DWORD err = GetLastError();
85+
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
86+
return NULL;
87+
}
88+
89+
/* initialize DIR structure and copy first dir entry */
90+
dir = xmalloc(sizeof(dirent_DIR) + MAX_PATH);
91+
dir->base_dir.preaddir = (struct dirent *(*)(DIR *dir)) dirent_readdir;
92+
dir->base_dir.pclosedir = (int (*)(DIR *dir)) dirent_closedir;
93+
dir->dd_handle = h;
94+
dir->dd_stat = 0;
95+
finddata2dirent(&dir->dd_dir, &fdata);
96+
return (DIR*) dir;
97+
}

compat/win32/dirent.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
#ifndef DIRENT_H
22
#define DIRENT_H
33

4-
typedef struct DIR DIR;
5-
64
#define DT_UNKNOWN 0
75
#define DT_DIR 1
86
#define DT_REG 2
97
#define DT_LNK 3
108

119
struct dirent {
12-
unsigned char d_type; /* file type to prevent lstat after readdir */
13-
char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
10+
unsigned char d_type; /* file type to prevent lstat after readdir */
11+
char d_name[FLEX_ARRAY]; /* file name */
1412
};
1513

16-
DIR *opendir(const char *dirname);
17-
struct dirent *readdir(DIR *dir);
18-
int closedir(DIR *dir);
14+
/*
15+
* Base DIR structure, contains pointers to readdir/closedir implementations so
16+
* that opendir may choose a concrete implementation on a call-by-call basis.
17+
*/
18+
typedef struct DIR {
19+
struct dirent *(*preaddir)(struct DIR *dir);
20+
int (*pclosedir)(struct DIR *dir);
21+
} DIR;
22+
23+
/* default dirent implementation */
24+
extern DIR *dirent_opendir(const char *dirname);
25+
26+
/* current dirent implementation */
27+
extern DIR *(*opendir)(const char *dirname);
28+
29+
#define readdir(dir) (dir->preaddir(dir))
30+
#define closedir(dir) (dir->pclosedir(dir))
1931

2032
#endif /* DIRENT_H */

0 commit comments

Comments
 (0)