Skip to content

Commit 5900c1c

Browse files
committed
Merge branch 'fscache'
2 parents 0c27fab + 3b75ddf commit 5900c1c

24 files changed

+851
-78
lines changed

Documentation/config/core.adoc

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

693+
core.fscache::
694+
Enable additional caching of file system data for some operations.
695+
+
696+
Git for Windows uses this to bulk-read and cache lstat data of entire
697+
directories (instead of doing lstat file by file).
698+
693699
core.unsetenvvars::
694700
Windows-only: comma-separated list of environment variables'
695701
names that need to be unset before spawning any other process.

builtin/add.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ int cmd_add(int argc,
476476
die_in_unpopulated_submodule(repo->index, prefix);
477477
die_path_inside_submodule(repo->index, &pathspec);
478478

479+
enable_fscache(1);
480+
/* We do not really re-read the index but update the up-to-date flags */
481+
preload_index(repo->index, &pathspec, 0);
482+
479483
if (add_new_files) {
480484
int baselen;
481485

@@ -588,5 +592,6 @@ int cmd_add(int argc,
588592
free(ps_matched);
589593
dir_clear(&dir);
590594
clear_pathspec(&pathspec);
595+
enable_fscache(0);
591596
return exit_status;
592597
}

builtin/checkout.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
408408
if (pc_workers > 1)
409409
init_parallel_checkout();
410410

411+
enable_fscache(1);
411412
for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
412413
struct cache_entry *ce = the_repository->index->cache[pos];
413414
if (ce->ce_flags & CE_MATCHED) {
@@ -433,6 +434,7 @@ static int checkout_worktree(const struct checkout_opts *opts,
433434
errs |= run_parallel_checkout(&state, pc_workers, pc_threshold,
434435
NULL, NULL);
435436
mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
437+
enable_fscache(0);
436438
remove_marked_cache_entries(the_repository->index, 1);
437439
remove_scheduled_dirs();
438440
errs |= finish_delayed_checkout(&state, opts->show_progress);

builtin/commit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,7 @@ struct repository *repo UNUSED)
16021602
PATHSPEC_PREFER_FULL,
16031603
prefix, argv);
16041604

1605+
enable_fscache(1);
16051606
if (status_format != STATUS_FORMAT_PORCELAIN &&
16061607
status_format != STATUS_FORMAT_PORCELAIN_V2)
16071608
progress_flag = REFRESH_PROGRESS;

compat/mingw.c

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ enum hide_dotfiles_type {
249249

250250
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
251251
static char *unset_environment_variables;
252+
int core_fscache;
252253

253254
int mingw_core_config(const char *var, const char *value,
254255
const struct config_context *ctx UNUSED,
@@ -262,6 +263,11 @@ int mingw_core_config(const char *var, const char *value,
262263
return 0;
263264
}
264265

266+
if (!strcmp(var, "core.fscache")) {
267+
core_fscache = git_config_bool(var, value);
268+
return 0;
269+
}
270+
265271
if (!strcmp(var, "core.unsetenvvars")) {
266272
if (!value)
267273
return config_error_nonbool(var);
@@ -882,24 +888,6 @@ int mingw_chmod(const char *filename, int mode)
882888
return _wchmod(wfilename, mode);
883889
}
884890

885-
/*
886-
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
887-
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
888-
*/
889-
static inline long long filetime_to_hnsec(const FILETIME *ft)
890-
{
891-
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
892-
/* Windows to Unix Epoch conversion */
893-
return winTime - 116444736000000000LL;
894-
}
895-
896-
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
897-
{
898-
long long hnsec = filetime_to_hnsec(ft);
899-
ts->tv_sec = (time_t)(hnsec / 10000000);
900-
ts->tv_nsec = (hnsec % 10000000) * 100;
901-
}
902-
903891
/**
904892
* Verifies that safe_create_leading_directories() would succeed.
905893
*/
@@ -1039,6 +1027,8 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
10391027
return do_lstat(follow, alt_name, buf);
10401028
}
10411029

1030+
int (*lstat)(const char *file_name, struct stat *buf) = mingw_lstat;
1031+
10421032
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
10431033
{
10441034
BY_HANDLE_FILE_INFORMATION fdata;

compat/mingw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "mingw-posix.h"
22

3+
extern int core_fscache;
4+
35
struct config_context;
46
int mingw_core_config(const char *var, const char *value,
57
const struct config_context *ctx, void *cb);

compat/win32/dirent.c

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

3-
struct DIR {
4-
struct dirent dd_dir; /* includes d_type */
3+
#pragma GCC diagnostic push
4+
#pragma GCC diagnostic ignored "-Wpedantic"
5+
typedef struct dirent_DIR {
6+
struct DIR base_dir; /* extend base struct DIR */
57
HANDLE dd_handle; /* FindFirstFile handle */
68
int dd_stat; /* 0-based index */
7-
};
9+
struct dirent dd_dir; /* includes d_type */
10+
} dirent_DIR;
11+
#pragma GCC diagnostic pop
12+
13+
DIR *(*opendir)(const char *dirname) = dirent_opendir;
814

915
static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
1016
{
11-
/* convert UTF-16 name to UTF-8 */
12-
xwcstoutf(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
17+
/* convert UTF-16 name to UTF-8 (d_name points to dirent_DIR.dd_name) */
18+
xwcstoutf(ent->d_name, fdata->cFileName, MAX_PATH * 3);
1319

1420
/* Set file type, based on WIN32_FIND_DATA */
1521
if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -18,41 +24,7 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
1824
ent->d_type = DT_REG;
1925
}
2026

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)
27+
static struct dirent *dirent_readdir(dirent_DIR *dir)
5628
{
5729
if (!dir) {
5830
errno = EBADF; /* No set_errno for mingw */
@@ -79,7 +51,7 @@ struct dirent *readdir(DIR *dir)
7951
return &dir->dd_dir;
8052
}
8153

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

compat/win32/dirent.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,34 @@
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+
#define opendir git_opendir
27+
28+
/* current dirent implementation */
29+
extern DIR *(*opendir)(const char *dirname);
30+
31+
#define readdir(dir) (dir->preaddir(dir))
32+
#define closedir(dir) (dir->pclosedir(dir))
1933

2034
#endif /* DIRENT_H */

0 commit comments

Comments
 (0)