Merge branch 'try-v4-fsmonitor-part2' into try-v4-fsmonitor

This commit is contained in:
Jeff Hostetler
2021-09-29 16:11:30 -04:00
committed by Johannes Schindelin
18 changed files with 537 additions and 84 deletions

View File

@@ -62,22 +62,50 @@ core.protectNTFS::
Defaults to `true` on Windows, and `false` elsewhere.
core.fsmonitor::
If set, the value of this variable is used as a command which
will identify all files that may have changed since the
requested date/time. This information is used to speed up git by
avoiding unnecessary processing of files that have not changed.
See the "fsmonitor-watchman" section of linkgit:githooks[5].
If set, this variable contains the pathname of the "fsmonitor"
hook command.
+
This hook command is used to identify all files that may have changed
since the requested date/time. This information is used to speed up
git by avoiding unnecessary scanning of files that have not changed.
+
See the "fsmonitor-watchman" section of linkgit:githooks[5].
+
Note: The value of this config setting is ignored if the
built-in file system monitor is enabled (see `core.useBuiltinFSMonitor`).
core.fsmonitorHookVersion::
Sets the version of hook that is to be used when calling fsmonitor.
There are currently versions 1 and 2. When this is not set,
version 2 will be tried first and if it fails then version 1
will be tried. Version 1 uses a timestamp as input to determine
which files have changes since that time but some monitors
like watchman have race conditions when used with a timestamp.
Version 2 uses an opaque string so that the monitor can return
something that can be used to determine what files have changed
without race conditions.
Sets the protocol version to be used when invoking the
"fsmonitor" hook.
+
There are currently versions 1 and 2. When this is not set,
version 2 will be tried first and if it fails then version 1
will be tried. Version 1 uses a timestamp as input to determine
which files have changes since that time but some monitors
like Watchman have race conditions when used with a timestamp.
Version 2 uses an opaque string so that the monitor can return
something that can be used to determine what files have changed
without race conditions.
+
Note: The value of this config setting is ignored if the
built-in file system monitor is enabled (see `core.useBuiltinFSMonitor`).
core.useBuiltinFSMonitor::
If set to true, enable the built-in file system monitor
daemon for this working directory (linkgit:git-fsmonitor--daemon[1]).
+
Like hook-based file system monitors, the built-in file system monitor
can speed up Git commands that need to refresh the Git index
(e.g. `git status`) in a working directory with many files. The
built-in monitor eliminates the need to install and maintain an
external third-party tool.
+
The built-in file system monitor is currently available only on a
limited set of supported platforms. Currently, this includes Windows
and MacOS.
+
Note: if this config setting is set to `true`, the values of
`core.fsmonitor` and `core.fsmonitorHookVersion` are ignored.
core.trustctime::
If false, the ctime differences between the index and the

View File

@@ -498,7 +498,9 @@ FILE SYSTEM MONITOR
This feature is intended to speed up git operations for repos that have
large working directories.
It enables git to work together with a file system monitor (see the
It enables git to work together with a file system monitor (see
linkgit:git-fsmonitor--daemon[1]
and the
"fsmonitor-watchman" section of linkgit:githooks[5]) that can
inform it as to what files have been modified. This enables git to avoid
having to lstat() every file to find modified files.
@@ -508,17 +510,18 @@ performance by avoiding the cost of scanning the entire working directory
looking for new files.
If you want to enable (or disable) this feature, it is easier to use
the `core.fsmonitor` configuration variable (see
linkgit:git-config[1]) than using the `--fsmonitor` option to
`git update-index` in each repository, especially if you want to do so
across all repositories you use, because you can set the configuration
variable in your `$HOME/.gitconfig` just once and have it affect all
repositories you touch.
the `core.fsmonitor` or `core.useBuiltinFSMonitor` configuration
variable (see linkgit:git-config[1]) than using the `--fsmonitor`
option to `git update-index` in each repository, especially if you
want to do so across all repositories you use, because you can set the
configuration variable in your `$HOME/.gitconfig` just once and have
it affect all repositories you touch.
When the `core.fsmonitor` configuration variable is changed, the
file system monitor is added to or removed from the index the next time
a command reads the index. When `--[no-]fsmonitor` are used, the file
system monitor is immediately added to or removed from the index.
When the `core.fsmonitor` or `core.useBuiltinFSMonitor` configuration
variable is changed, the file system monitor is added to or removed
from the index the next time a command reads the index. When
`--[no-]fsmonitor` are used, the file system monitor is immediately
added to or removed from the index.
CONFIGURATION
-------------

View File

@@ -593,7 +593,8 @@ fsmonitor-watchman
This hook is invoked when the configuration option `core.fsmonitor` is
set to `.git/hooks/fsmonitor-watchman` or `.git/hooks/fsmonitor-watchmanv2`
depending on the version of the hook to use.
depending on the version of the hook to use, unless overridden via
`core.useBuiltinFSMonitor` (see linkgit:git-config[1]).
Version 1 takes two arguments, a version (1) and the time in elapsed
nanoseconds since midnight, January 1, 1970.

View File

@@ -899,6 +899,8 @@ LIB_OBJS += fetch-pack.o
LIB_OBJS += fmt-merge-msg.o
LIB_OBJS += fsck.o
LIB_OBJS += fsmonitor.o
LIB_OBJS += fsmonitor-ipc.o
LIB_OBJS += fsmonitor-settings.o
LIB_OBJS += gettext.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o

View File

@@ -1214,14 +1214,25 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
}
if (fsmonitor > 0) {
if (git_config_get_fsmonitor() == 0)
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
if (fsm_mode == FSMONITOR_MODE_DISABLED) {
warning(_("core.useBuiltinFSMonitor is unset; "
"set it if you really want to enable the "
"builtin fsmonitor"));
warning(_("core.fsmonitor is unset; "
"set it if you really want to "
"enable fsmonitor"));
"set it if you really want to enable the "
"hook-based fsmonitor"));
}
add_fsmonitor(&the_index);
report(_("fsmonitor enabled"));
} else if (!fsmonitor) {
if (git_config_get_fsmonitor() == 1)
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
if (fsm_mode == FSMONITOR_MODE_IPC)
warning(_("core.useBuiltinFSMonitor is set; "
"remove it if you really want to "
"disable fsmonitor"));
if (fsm_mode == FSMONITOR_MODE_HOOK)
warning(_("core.fsmonitor is set; "
"remove it if you really want to "
"disable fsmonitor"));

View File

@@ -999,7 +999,6 @@ extern int core_preload_index;
extern int precomposed_unicode;
extern int protect_hfs;
extern int protect_ntfs;
extern const char *core_fsmonitor;
extern int core_apply_sparse_checkout;
extern int core_sparse_checkout_cone;

View File

@@ -2508,20 +2508,6 @@ int git_config_get_max_percent_split_change(void)
return -1; /* default value */
}
int git_config_get_fsmonitor(void)
{
if (git_config_get_pathname("core.fsmonitor", &core_fsmonitor))
core_fsmonitor = getenv("GIT_TEST_FSMONITOR");
if (core_fsmonitor && !*core_fsmonitor)
core_fsmonitor = NULL;
if (core_fsmonitor)
return 1;
return 0;
}
int git_config_get_index_threads(int *dest)
{
int is_bool, val;

View File

@@ -611,7 +611,6 @@ int git_config_get_pathname(const char *key, const char **dest);
int git_config_get_index_threads(int *dest);
int git_config_get_split_index(void);
int git_config_get_max_percent_split_change(void);
int git_config_get_fsmonitor(void);
/* This dies if the configured or default date is in the future */
int git_config_get_expiry(const char *key, const char **output);

View File

@@ -84,7 +84,6 @@ int protect_hfs = PROTECT_HFS_DEFAULT;
#define PROTECT_NTFS_DEFAULT 1
#endif
int protect_ntfs = PROTECT_NTFS_DEFAULT;
const char *core_fsmonitor;
/*
* The character that begins a commented line in user-editable file

176
fsmonitor-ipc.c Normal file
View File

@@ -0,0 +1,176 @@
#include "cache.h"
#include "fsmonitor.h"
#include "simple-ipc.h"
#include "fsmonitor-ipc.h"
#include "run-command.h"
#include "strbuf.h"
#include "trace2.h"
#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
int fsmonitor_ipc__is_supported(void)
{
return 1;
}
GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
return ipc_get_active_state(fsmonitor_ipc__get_path());
}
static int spawn_daemon(void)
{
const char *args[] = { "fsmonitor--daemon", "start", NULL };
return run_command_v_opt_tr2(args, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD,
"fsmonitor");
}
int fsmonitor_ipc__send_query(const char *since_token,
struct strbuf *answer)
{
int ret = -1;
int tried_to_spawn = 0;
enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
struct ipc_client_connection *connection = NULL;
struct ipc_client_connect_options options
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
const char *tok = since_token ? since_token : "";
size_t tok_len = since_token ? strlen(since_token) : 0;
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
trace2_region_enter("fsm_client", "query", NULL);
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
&connection);
switch (state) {
case IPC_STATE__LISTENING:
ret = ipc_client_send_command_to_connection(
connection, tok, tok_len, answer);
ipc_client_close_connection(connection);
trace2_data_intmax("fsm_client", NULL,
"query/response-length", answer->len);
if (fsmonitor_is_trivial_response(answer))
trace2_data_intmax("fsm_client", NULL,
"query/trivial-response", 1);
goto done;
case IPC_STATE__NOT_LISTENING:
case IPC_STATE__PATH_NOT_FOUND:
if (tried_to_spawn)
goto done;
tried_to_spawn++;
if (spawn_daemon())
goto done;
/*
* Try again, but this time give the daemon a chance to
* actually create the pipe/socket.
*
* Granted, the daemon just started so it can't possibly have
* any FS cached yet, so we'll always get a trivial answer.
* BUT the answer should include a new token that can serve
* as the basis for subsequent requests.
*/
options.wait_if_not_found = 1;
goto try_again;
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
fsmonitor_ipc__get_path());
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
fsmonitor_ipc__get_path());
goto done;
}
done:
trace2_region_leave("fsm_client", "query", NULL);
return ret;
}
int fsmonitor_ipc__send_command(const char *command,
struct strbuf *answer)
{
struct ipc_client_connection *connection = NULL;
struct ipc_client_connect_options options
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
int ret;
enum ipc_active_state state;
const char *c = command ? command : "";
size_t c_len = command ? strlen(command) : 0;
strbuf_reset(answer);
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
&connection);
if (state != IPC_STATE__LISTENING) {
die("fsmonitor--daemon is not running");
return -1;
}
ret = ipc_client_send_command_to_connection(connection, c, c_len,
answer);
ipc_client_close_connection(connection);
if (ret == -1) {
die("could not send '%s' command to fsmonitor--daemon", c);
return -1;
}
return 0;
}
#else
/*
* A trivial implementation of the fsmonitor_ipc__ API for unsupported
* platforms.
*/
int fsmonitor_ipc__is_supported(void)
{
return 0;
}
const char *fsmonitor_ipc__get_path(void)
{
return NULL;
}
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
return IPC_STATE__OTHER_ERROR;
}
int fsmonitor_ipc__send_query(const char *since_token,
struct strbuf *answer)
{
return -1;
}
int fsmonitor_ipc__send_command(const char *command,
struct strbuf *answer)
{
return -1;
}
#endif

48
fsmonitor-ipc.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef FSMONITOR_IPC_H
#define FSMONITOR_IPC_H
#include "simple-ipc.h"
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
*/
int fsmonitor_ipc__is_supported(void);
/*
* Returns the pathname to the IPC named pipe or Unix domain socket
* where a `git-fsmonitor--daemon` process will listen. This is a
* per-worktree value.
*
* Returns NULL if the daemon is not supported on this platform.
*/
const char *fsmonitor_ipc__get_path(void);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
* listening on the IPC pipe/socket.
*/
enum ipc_active_state fsmonitor_ipc__get_state(void);
/*
* Connect to a `git-fsmonitor--daemon` process via simple-ipc
* and ask for the set of changed files since the given token.
*
* Spawn a daemon process in the background if necessary.
*
* Returns -1 on error; 0 on success.
*/
int fsmonitor_ipc__send_query(const char *since_token,
struct strbuf *answer);
/*
* Connect to a `git-fsmonitor--daemon` process via simple-ipc and
* send a command verb. If no daemon is available, we DO NOT try to
* start one.
*
* Returns -1 on error; 0 on success.
*/
int fsmonitor_ipc__send_command(const char *command,
struct strbuf *answer);
#endif /* FSMONITOR_IPC_H */

97
fsmonitor-settings.c Normal file
View File

@@ -0,0 +1,97 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
/*
* We keep this structure defintion private and have getters
* for all fields so that we can lazy load it as needed.
*/
struct fsmonitor_settings {
enum fsmonitor_mode mode;
char *hook_path;
};
void fsm_settings__set_ipc(struct repository *r)
{
struct fsmonitor_settings *s = r->settings.fsmonitor;
s->mode = FSMONITOR_MODE_IPC;
}
void fsm_settings__set_hook(struct repository *r, const char *path)
{
struct fsmonitor_settings *s = r->settings.fsmonitor;
s->mode = FSMONITOR_MODE_HOOK;
s->hook_path = strdup(path);
}
void fsm_settings__set_disabled(struct repository *r)
{
struct fsmonitor_settings *s = r->settings.fsmonitor;
s->mode = FSMONITOR_MODE_DISABLED;
FREE_AND_NULL(s->hook_path);
}
static int check_for_ipc(struct repository *r)
{
int value;
if (!repo_config_get_bool(r, "core.usebuiltinfsmonitor", &value) &&
value) {
fsm_settings__set_ipc(r);
return 1;
}
return 0;
}
static int check_for_hook(struct repository *r)
{
const char *const_str;
if (repo_config_get_pathname(r, "core.fsmonitor", &const_str))
const_str = getenv("GIT_TEST_FSMONITOR");
if (const_str && *const_str) {
fsm_settings__set_hook(r, const_str);
return 1;
}
return 0;
}
static void lookup_fsmonitor_settings(struct repository *r)
{
struct fsmonitor_settings *s;
CALLOC_ARRAY(s, 1);
r->settings.fsmonitor = s;
if (check_for_ipc(r))
return;
if (check_for_hook(r))
return;
fsm_settings__set_disabled(r);
}
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
{
if (!r->settings.fsmonitor)
lookup_fsmonitor_settings(r);
return r->settings.fsmonitor->mode;
}
const char *fsm_settings__get_hook_path(struct repository *r)
{
if (!r->settings.fsmonitor)
lookup_fsmonitor_settings(r);
return r->settings.fsmonitor->hook_path;
}

21
fsmonitor-settings.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef FSMONITOR_SETTINGS_H
#define FSMONITOR_SETTINGS_H
struct repository;
enum fsmonitor_mode {
FSMONITOR_MODE_DISABLED = 0,
FSMONITOR_MODE_HOOK = 1, /* core.fsmonitor */
FSMONITOR_MODE_IPC = 2, /* core.useBuiltinFSMonitor */
};
void fsm_settings__set_ipc(struct repository *r);
void fsm_settings__set_hook(struct repository *r, const char *path);
void fsm_settings__set_disabled(struct repository *r);
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
struct fsmonitor_settings;
#endif /* FSMONITOR_SETTINGS_H */

View File

@@ -3,6 +3,7 @@
#include "dir.h"
#include "ewah/ewok.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
#include "run-command.h"
#include "strbuf.h"
@@ -148,15 +149,18 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
/*
* Call the query-fsmonitor hook passing the last update token of the saved results.
*/
static int query_fsmonitor(int version, const char *last_update, struct strbuf *query_result)
static int query_fsmonitor_hook(struct repository *r,
int version,
const char *last_update,
struct strbuf *query_result)
{
struct child_process cp = CHILD_PROCESS_INIT;
int result;
if (!core_fsmonitor)
if (fsm_settings__get_mode(r) != FSMONITOR_MODE_HOOK)
return -1;
strvec_push(&cp.args, core_fsmonitor);
strvec_push(&cp.args, fsm_settings__get_hook_path(r));
strvec_pushf(&cp.args, "%d", version);
strvec_pushf(&cp.args, "%s", last_update);
cp.use_shell = 1;
@@ -238,17 +242,57 @@ void refresh_fsmonitor(struct index_state *istate)
struct strbuf last_update_token = STRBUF_INIT;
char *buf;
unsigned int i;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
if (!core_fsmonitor || istate->fsmonitor_has_run_once)
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
return;
hook_version = fsmonitor_hook_version();
istate->fsmonitor_has_run_once = 1;
trace_printf_key(&trace_fsmonitor, "refresh fsmonitor");
if (fsm_mode == FSMONITOR_MODE_IPC) {
query_success = !fsmonitor_ipc__send_query(
istate->fsmonitor_last_update ?
istate->fsmonitor_last_update : "builtin:fake",
&query_result);
if (query_success) {
/*
* The response contains a series of nul terminated
* strings. The first is the new token.
*
* Use `char *buf` as an interlude to trick the CI
* static analysis to let us use `strbuf_addstr()`
* here (and only copy the token) rather than
* `strbuf_addbuf()`.
*/
buf = query_result.buf;
strbuf_addstr(&last_update_token, buf);
bol = last_update_token.len + 1;
} else {
/*
* The builtin daemon is not available on this
* platform -OR- we failed to get a response.
*
* Generate a fake token (rather than a V1
* timestamp) for the index extension. (If
* they switch back to the hook API, we don't
* want ambiguous state.)
*/
strbuf_addstr(&last_update_token, "builtin:fake");
}
goto apply_results;
}
assert(fsm_mode == FSMONITOR_MODE_HOOK);
hook_version = fsmonitor_hook_version();
/*
* This could be racy so save the date/time now and query_fsmonitor
* This could be racy so save the date/time now and query_fsmonitor_hook
* should be inclusive to ensure we don't miss potential changes.
*/
last_update = getnanotime();
@@ -256,13 +300,14 @@ void refresh_fsmonitor(struct index_state *istate)
strbuf_addf(&last_update_token, "%"PRIu64"", last_update);
/*
* If we have a last update token, call query_fsmonitor for the set of
* If we have a last update token, call query_fsmonitor_hook for the set of
* changes since that token, else assume everything is possibly dirty
* and check it all.
*/
if (istate->fsmonitor_last_update) {
if (hook_version == -1 || hook_version == HOOK_INTERFACE_VERSION2) {
query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION2,
query_success = !query_fsmonitor_hook(
r, HOOK_INTERFACE_VERSION2,
istate->fsmonitor_last_update, &query_result);
if (query_success) {
@@ -292,18 +337,39 @@ void refresh_fsmonitor(struct index_state *istate)
}
if (hook_version == HOOK_INTERFACE_VERSION1) {
query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION1,
query_success = !query_fsmonitor_hook(
r, HOOK_INTERFACE_VERSION1,
istate->fsmonitor_last_update, &query_result);
}
trace_performance_since(last_update, "fsmonitor process '%s'", core_fsmonitor);
trace_printf_key(&trace_fsmonitor, "fsmonitor process '%s' returned %s",
core_fsmonitor, query_success ? "success" : "failure");
trace_performance_since(last_update, "fsmonitor process '%s'",
fsm_settings__get_hook_path(r));
trace_printf_key(&trace_fsmonitor,
"fsmonitor process '%s' returned %s",
fsm_settings__get_hook_path(r),
query_success ? "success" : "failure");
}
/* a fsmonitor process can return '/' to indicate all entries are invalid */
apply_results:
/*
* The response from FSMonitor (excluding the header token) is
* either:
*
* [a] a (possibly empty) list of NUL delimited relative
* pathnames of changed paths. This list can contain
* files and directories. Directories have a trailing
* slash.
*
* [b] a single '/' to indicate the provider had no
* information and that we should consider everything
* invalid. We call this a trivial response.
*/
if (query_success && query_result.buf[bol] != '/') {
/* Mark all entries returned by the monitor as dirty */
/*
* Mark all pathnames returned by the monitor as dirty.
*
* This updates both the cache-entries and the untracked-cache.
*/
buf = query_result.buf;
for (i = bol; i < query_result.len; i++) {
if (buf[i] != '\0')
@@ -318,11 +384,15 @@ void refresh_fsmonitor(struct index_state *istate)
if (istate->untracked)
istate->untracked->use_fsmonitor = 1;
} else {
/* We only want to run the post index changed hook if we've actually changed entries, so keep track
* if we actually changed entries or not */
/*
* We received a trivial response, so invalidate everything.
*
* We only want to run the post index changed hook if
* we've actually changed entries, so keep track if we
* actually changed entries or not.
*/
int is_cache_changed = 0;
/* Mark all entries invalid */
for (i = 0; i < istate->cache_nr; i++) {
if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID) {
is_cache_changed = 1;
@@ -330,7 +400,10 @@ void refresh_fsmonitor(struct index_state *istate)
}
}
/* If we're going to check every file, ensure we save the results */
/*
* If we're going to check every file, ensure we save
* the results.
*/
if (is_cache_changed)
istate->cache_changed |= FSMONITOR_CHANGED;
@@ -411,7 +484,8 @@ void remove_fsmonitor(struct index_state *istate)
void tweak_fsmonitor(struct index_state *istate)
{
unsigned int i;
int fsmonitor_enabled = git_config_get_fsmonitor();
struct repository *r = istate->repo ? istate->repo : the_repository;
int fsmonitor_enabled = (fsm_settings__get_mode(r) > FSMONITOR_MODE_DISABLED);
if (istate->fsmonitor_dirty) {
if (fsmonitor_enabled) {
@@ -431,16 +505,8 @@ void tweak_fsmonitor(struct index_state *istate)
istate->fsmonitor_dirty = NULL;
}
switch (fsmonitor_enabled) {
case -1: /* keep: do nothing */
break;
case 0: /* false */
remove_fsmonitor(istate);
break;
case 1: /* true */
if (fsmonitor_enabled)
add_fsmonitor(istate);
break;
default: /* unknown value: do nothing */
break;
}
else
remove_fsmonitor(istate);
}

View File

@@ -3,6 +3,7 @@
#include "cache.h"
#include "dir.h"
#include "fsmonitor-settings.h"
extern struct trace_key trace_fsmonitor;
@@ -57,7 +58,11 @@ int fsmonitor_is_trivial_response(const struct strbuf *query_result);
*/
static inline int is_fsmonitor_refreshed(const struct index_state *istate)
{
return !core_fsmonitor || istate->fsmonitor_has_run_once;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
return fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once;
}
/*
@@ -67,7 +72,11 @@ static inline int is_fsmonitor_refreshed(const struct index_state *istate)
*/
static inline void mark_fsmonitor_valid(struct index_state *istate, struct cache_entry *ce)
{
if (core_fsmonitor && !(ce->ce_flags & CE_FSMONITOR_VALID)) {
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
if (fsm_mode > FSMONITOR_MODE_DISABLED &&
!(ce->ce_flags & CE_FSMONITOR_VALID)) {
istate->cache_changed = 1;
ce->ce_flags |= CE_FSMONITOR_VALID;
trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_clean '%s'", ce->name);
@@ -83,7 +92,10 @@ static inline void mark_fsmonitor_valid(struct index_state *istate, struct cache
*/
static inline void mark_fsmonitor_invalid(struct index_state *istate, struct cache_entry *ce)
{
if (core_fsmonitor) {
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
if (fsm_mode > FSMONITOR_MODE_DISABLED) {
ce->ce_flags &= ~CE_FSMONITOR_VALID;
untracked_cache_invalidate_path(istate, ce->name, 1);
trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_invalid '%s'", ce->name);

View File

@@ -63,6 +63,8 @@ void prepare_repo_settings(struct repository *r)
/*
* Non-boolean config
*/
r->settings.fsmonitor = NULL; /* lazy loaded */
if (!repo_config_get_int(r, "index.version", &value))
r->settings.index_version = value;

View File

@@ -4,6 +4,7 @@
#include "path.h"
struct config_set;
struct fsmonitor_settings;
struct git_hash_algo;
struct index_state;
struct lock_file;
@@ -35,6 +36,8 @@ struct repo_settings {
int command_requires_full_index;
int sparse_index;
struct fsmonitor_settings *fsmonitor; /* lazy loaded */
int index_version;
enum untracked_cache_setting core_untracked_cache;

View File

@@ -405,8 +405,8 @@ every 'git commit-graph write', as if the `--changed-paths` option was
passed in.
GIT_TEST_FSMONITOR=$PWD/t7519/fsmonitor-all exercises the fsmonitor
code path for utilizing a file system monitor to speed up detecting
new or changed files.
code path for utilizing a (hook based) file system monitor to speed up
detecting new or changed files.
GIT_TEST_INDEX_VERSION=<n> exercises the index read/write code path
for the index version specified. Can be set to any valid version