Skip to content

Commit

Permalink
fsmonitor: config settings are repository-specific
Browse files Browse the repository at this point in the history
Move FSMonitor config settings to a new `struct fsmonitor_settings`
structure.  Add a lazily-loaded pointer to `struct repo_settings`.
Create `fsm_settings__get_*()` getters to lazily look up fsmonitor-
related config settings.

Get rid of the `core_fsmonitor` global variable, and add support for
the new `core.useBuiltinFSMonitor` config setting.  Move config code
to lookup the existing `core.fsmonitor` value to `fsmonitor-settings.[ch]`.

The `core_fsmonitor` global variable was used to store the pathname to
the FSMonitor hook and it was used as a boolean to see if FSMonitor
was enabled.  This dual usage will lead to confusion when we add
support for a builtin FSMonitor based on IPC, since the builtin
FSMonitor doesn't need the hook pathname.

Replace the boolean usage with an `enum fsmonitor_mode` to represent
the state of FSMonitor.  And only set the pathname when in HOOK mode.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
  • Loading branch information
jeffhostetler committed Aug 5, 2021
1 parent 0aaca2f commit 0a756b2
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 51 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -894,6 +894,7 @@ 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
Expand Down
19 changes: 15 additions & 4 deletions builtin/update-index.c
Expand Up @@ -1216,14 +1216,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"));
Expand Down
1 change: 0 additions & 1 deletion cache.h
Expand Up @@ -981,7 +981,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;
Expand Down
14 changes: 0 additions & 14 deletions config.c
Expand Up @@ -2516,20 +2516,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;
Expand Down
1 change: 0 additions & 1 deletion config.h
Expand Up @@ -609,7 +609,6 @@ int git_config_get_index_threads(int *dest);
int git_config_get_untracked_cache(void);
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);
Expand Down
1 change: 0 additions & 1 deletion environment.c
Expand Up @@ -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
Expand Down
97 changes: 97 additions & 0 deletions fsmonitor-settings.c
@@ -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 changes: 21 additions & 0 deletions fsmonitor-settings.h
@@ -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 */
63 changes: 38 additions & 25 deletions fsmonitor.c
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -238,31 +242,43 @@ 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) {
/* TODO */
return;
}

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();
if (hook_version == HOOK_INTERFACE_VERSION1)
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) {
Expand Down Expand Up @@ -292,13 +308,17 @@ 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 */
Expand Down Expand Up @@ -411,7 +431,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) {
Expand All @@ -431,16 +452,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);
}
18 changes: 15 additions & 3 deletions fsmonitor.h
Expand Up @@ -3,6 +3,7 @@

#include "cache.h"
#include "dir.h"
#include "fsmonitor-settings.h"

extern struct trace_key trace_fsmonitor;

Expand Down Expand Up @@ -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;
}

/*
Expand All @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions repo-settings.c
Expand Up @@ -26,6 +26,8 @@ void prepare_repo_settings(struct repository *r)
UPDATE_DEFAULT_BOOL(r->settings.commit_graph_read_changed_paths, 1);
UPDATE_DEFAULT_BOOL(r->settings.gc_write_commit_graph, 1);

r->settings.fsmonitor = NULL; /* lazy loaded */

if (!repo_config_get_int(r, "index.version", &value))
r->settings.index_version = value;
if (!repo_config_get_maybe_bool(r, "core.untrackedcache", &value)) {
Expand Down

0 comments on commit 0a756b2

Please sign in to comment.