Skip to content

Commit

Permalink
Merge branch 'fscache'
Browse files Browse the repository at this point in the history
  • Loading branch information
dscho committed Nov 21, 2024
2 parents 2765f70 + b184cc9 commit db50d8a
Show file tree
Hide file tree
Showing 12 changed files with 648 additions and 70 deletions.
6 changes: 6 additions & 0 deletions Documentation/config/core.txt
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,12 @@ relatively high IO latencies. When enabled, Git will do the
index comparison to the filesystem data in parallel, allowing
overlapping IO's. Defaults to true.

core.fscache::
Enable additional caching of file system data for some operations.
+
Git for Windows uses this to bulk-read and cache lstat data of entire
directories (instead of doing lstat file by file).

core.unsetenvvars::
Windows-only: comma-separated list of environment variables'
names that need to be unset before spawning any other process.
Expand Down
1 change: 1 addition & 0 deletions builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,7 @@ struct repository *repo UNUSED)
PATHSPEC_PREFER_FULL,
prefix, argv);

enable_fscache(1);
if (status_format != STATUS_FORMAT_PORCELAIN &&
status_format != STATUS_FORMAT_PORCELAIN_V2)
progress_flag = REFRESH_PROGRESS;
Expand Down
26 changes: 8 additions & 18 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ enum hide_dotfiles_type {
static int core_restrict_inherited_handles = -1;
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
static char *unset_environment_variables;
int core_fscache;

int mingw_core_config(const char *var, const char *value,
const struct config_context *ctx UNUSED,
Expand All @@ -258,6 +259,11 @@ int mingw_core_config(const char *var, const char *value,
return 0;
}

if (!strcmp(var, "core.fscache")) {
core_fscache = git_config_bool(var, value);
return 0;
}

if (!strcmp(var, "core.unsetenvvars")) {
if (!value)
return config_error_nonbool(var);
Expand Down Expand Up @@ -856,24 +862,6 @@ int mingw_chmod(const char *filename, int mode)
return _wchmod(wfilename, mode);
}

/*
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
*/
static inline long long filetime_to_hnsec(const FILETIME *ft)
{
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
/* Windows to Unix Epoch conversion */
return winTime - 116444736000000000LL;
}

static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
{
long long hnsec = filetime_to_hnsec(ft);
ts->tv_sec = (time_t)(hnsec / 10000000);
ts->tv_nsec = (hnsec % 10000000) * 100;
}

/**
* Verifies that safe_create_leading_directories() would succeed.
*/
Expand Down Expand Up @@ -1013,6 +1001,8 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
return do_lstat(follow, alt_name, buf);
}

int (*lstat)(const char *file_name, struct stat *buf) = mingw_lstat;

static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
{
BY_HANDLE_FILE_INFORMATION fdata;
Expand Down
22 changes: 21 additions & 1 deletion compat/mingw.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ typedef _sigset_t sigset_t;
#undef _POSIX_THREAD_SAFE_FUNCTIONS
#endif

extern int core_fscache;

struct config_context;
int mingw_core_config(const char *var, const char *value,
const struct config_context *ctx, void *cb);
Expand Down Expand Up @@ -356,6 +358,17 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
return 0;
}

/*
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
*/
static inline long long filetime_to_hnsec(const FILETIME *ft)
{
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
/* Windows to Unix Epoch conversion */
return winTime - 116444736000000000LL;
}

/*
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
* including our own struct stat with 64 bit st_size and nanosecond-precision
Expand All @@ -372,6 +385,13 @@ struct timespec {
#endif
#endif

static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
{
long long hnsec = filetime_to_hnsec(ft);
ts->tv_sec = (time_t)(hnsec / 10000000);
ts->tv_nsec = (hnsec % 10000000) * 100;
}

struct mingw_stat {
_dev_t st_dev;
_ino_t st_ino;
Expand Down Expand Up @@ -404,7 +424,7 @@ int mingw_fstat(int fd, struct stat *buf);
#ifdef lstat
#undef lstat
#endif
#define lstat mingw_lstat
extern int (*lstat)(const char *file_name, struct stat *buf);


int mingw_utime(const char *file_name, const struct utimbuf *times);
Expand Down
90 changes: 49 additions & 41 deletions compat/win32/dirent.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
#include "../../git-compat-util.h"

struct DIR {
struct dirent dd_dir; /* includes d_type */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
typedef struct dirent_DIR {
struct DIR base_dir; /* extend base struct DIR */
HANDLE dd_handle; /* FindFirstFile handle */
int dd_stat; /* 0-based index */
};
struct dirent dd_dir; /* includes d_type */
} dirent_DIR;
#pragma GCC diagnostic pop

DIR *(*opendir)(const char *dirname) = dirent_opendir;

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

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

DIR *opendir(const char *name)
{
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
WIN32_FIND_DATAW fdata;
HANDLE h;
int len;
DIR *dir;

/* convert name to UTF-16 and check length < MAX_PATH */
if ((len = xutftowcs_path(pattern, name)) < 0)
return NULL;

/* append optional '/' and wildcard '*' */
if (len && !is_dir_sep(pattern[len - 1]))
pattern[len++] = '/';
pattern[len++] = '*';
pattern[len] = 0;

/* open find handle */
h = FindFirstFileW(pattern, &fdata);
if (h == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
return NULL;
}

/* initialize DIR structure and copy first dir entry */
dir = xmalloc(sizeof(DIR));
dir->dd_handle = h;
dir->dd_stat = 0;
finddata2dirent(&dir->dd_dir, &fdata);
return dir;
}

struct dirent *readdir(DIR *dir)
static struct dirent *dirent_readdir(dirent_DIR *dir)
{
if (!dir) {
errno = EBADF; /* No set_errno for mingw */
Expand All @@ -79,7 +51,7 @@ struct dirent *readdir(DIR *dir)
return &dir->dd_dir;
}

int closedir(DIR *dir)
static int dirent_closedir(dirent_DIR *dir)
{
if (!dir) {
errno = EBADF;
Expand All @@ -90,3 +62,39 @@ int closedir(DIR *dir)
free(dir);
return 0;
}

DIR *dirent_opendir(const char *name)
{
wchar_t pattern[MAX_PATH + 2]; /* + 2 for '/' '*' */
WIN32_FIND_DATAW fdata;
HANDLE h;
int len;
dirent_DIR *dir;

/* convert name to UTF-16 and check length < MAX_PATH */
if ((len = xutftowcs_path(pattern, name)) < 0)
return NULL;

/* append optional '/' and wildcard '*' */
if (len && !is_dir_sep(pattern[len - 1]))
pattern[len++] = '/';
pattern[len++] = '*';
pattern[len] = 0;

/* open find handle */
h = FindFirstFileW(pattern, &fdata);
if (h == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
return NULL;
}

/* initialize DIR structure and copy first dir entry */
dir = xmalloc(sizeof(dirent_DIR) + MAX_PATH);
dir->base_dir.preaddir = (struct dirent *(*)(DIR *dir)) dirent_readdir;
dir->base_dir.pclosedir = (int (*)(DIR *dir)) dirent_closedir;
dir->dd_handle = h;
dir->dd_stat = 0;
finddata2dirent(&dir->dd_dir, &fdata);
return (DIR*) dir;
}
26 changes: 19 additions & 7 deletions compat/win32/dirent.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
#ifndef DIRENT_H
#define DIRENT_H

typedef struct DIR DIR;

#define DT_UNKNOWN 0
#define DT_DIR 1
#define DT_REG 2
#define DT_LNK 3

struct dirent {
unsigned char d_type; /* file type to prevent lstat after readdir */
char d_name[MAX_PATH * 3]; /* file name (* 3 for UTF-8 conversion) */
unsigned char d_type; /* file type to prevent lstat after readdir */
char d_name[FLEX_ARRAY]; /* file name */
};

DIR *opendir(const char *dirname);
struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);
/*
* Base DIR structure, contains pointers to readdir/closedir implementations so
* that opendir may choose a concrete implementation on a call-by-call basis.
*/
typedef struct DIR {
struct dirent *(*preaddir)(struct DIR *dir);
int (*pclosedir)(struct DIR *dir);
} DIR;

/* default dirent implementation */
extern DIR *dirent_opendir(const char *dirname);

/* current dirent implementation */
extern DIR *(*opendir)(const char *dirname);

#define readdir(dir) (dir->preaddir(dir))
#define closedir(dir) (dir->pclosedir(dir))

#endif /* DIRENT_H */
Loading

0 comments on commit db50d8a

Please sign in to comment.