Skip to content

Commit 1e0ea5c

Browse files
jeffhostetlergitster
authored andcommitted
fsmonitor: config settings are repository-specific
Move fsmonitor config settings to a new and opaque `struct fsmonitor_settings` structure. Add a lazily-loaded pointer to this into `struct repo_settings` Create an `enum fsmonitor_mode` type in `struct fsmonitor_settings` to represent the state of fsmonitor. This lets us represent which, if any, fsmonitor provider (hook or IPC) is enabled. Create `fsm_settings__get_*()` getters to lazily look up fsmonitor- related config settings. Get rid of the `core_fsmonitor` global variable. Move the code to lookup the existing `core.fsmonitor` config value into the fsmonitor settings. Create a hook pathname variable in `struct fsmonitor-settings` and only set it when in hook mode. Extend the definition of `core.fsmonitor` to be either a boolean or a hook pathname. When true, the builtin FSMonitor is used. When false or unset, no FSMonitor (neither builtin nor hook) is used. The existing `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 and global visibility leads to confusion when we add the IPC-based provider. So lets hide the details in fsmonitor-settings.c and let it decide which provider to use in the case of multiple settings. This avoids cluttering up repo-settings.c with these private details. A future commit in builtin-fsmonitor series will add the ability to disqualify worktrees for various reasons, such as being mounted from a remote volume, where fsmonitor should not be started. Having the config settings hidden in fsmonitor-settings.c allows such worktree restrictions to override the config values used. Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d2bd862 commit 1e0ea5c

12 files changed

+196
-49
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,7 @@ LIB_OBJS += fmt-merge-msg.o
908908
LIB_OBJS += fsck.o
909909
LIB_OBJS += fsmonitor.o
910910
LIB_OBJS += fsmonitor-ipc.o
911+
LIB_OBJS += fsmonitor-settings.o
911912
LIB_OBJS += gettext.o
912913
LIB_OBJS += gpg-interface.o
913914
LIB_OBJS += graph.o

builtin/update-index.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -1236,14 +1236,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
12361236
}
12371237

12381238
if (fsmonitor > 0) {
1239-
if (git_config_get_fsmonitor() == 0)
1239+
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
1240+
if (fsm_mode == FSMONITOR_MODE_DISABLED) {
12401241
warning(_("core.fsmonitor is unset; "
12411242
"set it if you really want to "
12421243
"enable fsmonitor"));
1244+
}
12431245
add_fsmonitor(&the_index);
12441246
report(_("fsmonitor enabled"));
12451247
} else if (!fsmonitor) {
1246-
if (git_config_get_fsmonitor() == 1)
1248+
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
1249+
if (fsm_mode > FSMONITOR_MODE_DISABLED)
12471250
warning(_("core.fsmonitor is set; "
12481251
"remove it if you really want to "
12491252
"disable fsmonitor"));

cache.h

-1
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,6 @@ extern int core_preload_index;
999999
extern int precomposed_unicode;
10001000
extern int protect_hfs;
10011001
extern int protect_ntfs;
1002-
extern const char *core_fsmonitor;
10031002

10041003
extern int core_apply_sparse_checkout;
10051004
extern int core_sparse_checkout_cone;

config.c

-14
Original file line numberDiff line numberDiff line change
@@ -2626,20 +2626,6 @@ int git_config_get_max_percent_split_change(void)
26262626
return -1; /* default value */
26272627
}
26282628

2629-
int git_config_get_fsmonitor(void)
2630-
{
2631-
if (git_config_get_pathname("core.fsmonitor", &core_fsmonitor))
2632-
core_fsmonitor = getenv("GIT_TEST_FSMONITOR");
2633-
2634-
if (core_fsmonitor && !*core_fsmonitor)
2635-
core_fsmonitor = NULL;
2636-
2637-
if (core_fsmonitor)
2638-
return 1;
2639-
2640-
return 0;
2641-
}
2642-
26432629
int git_config_get_index_threads(int *dest)
26442630
{
26452631
int is_bool, val;

config.h

-1
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,6 @@ int git_config_get_pathname(const char *key, const char **dest);
597597
int git_config_get_index_threads(int *dest);
598598
int git_config_get_split_index(void);
599599
int git_config_get_max_percent_split_change(void);
600-
int git_config_get_fsmonitor(void);
601600

602601
/* This dies if the configured or default date is in the future */
603602
int git_config_get_expiry(const char *key, const char **output);

environment.c

-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ int protect_hfs = PROTECT_HFS_DEFAULT;
8484
#define PROTECT_NTFS_DEFAULT 1
8585
#endif
8686
int protect_ntfs = PROTECT_NTFS_DEFAULT;
87-
const char *core_fsmonitor;
8887

8988
/*
9089
* The character that begins a commented line in user-editable file

fsmonitor-settings.c

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#include "cache.h"
2+
#include "config.h"
3+
#include "repository.h"
4+
#include "fsmonitor-settings.h"
5+
6+
/*
7+
* We keep this structure defintion private and have getters
8+
* for all fields so that we can lazy load it as needed.
9+
*/
10+
struct fsmonitor_settings {
11+
enum fsmonitor_mode mode;
12+
char *hook_path;
13+
};
14+
15+
static void lookup_fsmonitor_settings(struct repository *r)
16+
{
17+
struct fsmonitor_settings *s;
18+
const char *const_str;
19+
int bool_value;
20+
21+
if (r->settings.fsmonitor)
22+
return;
23+
24+
CALLOC_ARRAY(s, 1);
25+
s->mode = FSMONITOR_MODE_DISABLED;
26+
27+
r->settings.fsmonitor = s;
28+
29+
/*
30+
* Overload the existing "core.fsmonitor" config setting (which
31+
* has historically been either unset or a hook pathname) to
32+
* now allow a boolean value to enable the builtin FSMonitor
33+
* or to turn everything off. (This does imply that you can't
34+
* use a hook script named "true" or "false", but that's OK.)
35+
*/
36+
switch (repo_config_get_maybe_bool(r, "core.fsmonitor", &bool_value)) {
37+
38+
case 0: /* config value was set to <bool> */
39+
if (bool_value)
40+
fsm_settings__set_ipc(r);
41+
return;
42+
43+
case 1: /* config value was unset */
44+
const_str = getenv("GIT_TEST_FSMONITOR");
45+
break;
46+
47+
case -1: /* config value set to an arbitrary string */
48+
if (repo_config_get_pathname(r, "core.fsmonitor", &const_str))
49+
return; /* should not happen */
50+
break;
51+
52+
default: /* should not happen */
53+
return;
54+
}
55+
56+
if (!const_str || !*const_str)
57+
return;
58+
59+
fsm_settings__set_hook(r, const_str);
60+
}
61+
62+
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
63+
{
64+
if (!r)
65+
r = the_repository;
66+
67+
lookup_fsmonitor_settings(r);
68+
69+
return r->settings.fsmonitor->mode;
70+
}
71+
72+
const char *fsm_settings__get_hook_path(struct repository *r)
73+
{
74+
if (!r)
75+
r = the_repository;
76+
77+
lookup_fsmonitor_settings(r);
78+
79+
return r->settings.fsmonitor->hook_path;
80+
}
81+
82+
void fsm_settings__set_ipc(struct repository *r)
83+
{
84+
if (!r)
85+
r = the_repository;
86+
87+
lookup_fsmonitor_settings(r);
88+
89+
r->settings.fsmonitor->mode = FSMONITOR_MODE_IPC;
90+
FREE_AND_NULL(r->settings.fsmonitor->hook_path);
91+
}
92+
93+
void fsm_settings__set_hook(struct repository *r, const char *path)
94+
{
95+
if (!r)
96+
r = the_repository;
97+
98+
lookup_fsmonitor_settings(r);
99+
100+
r->settings.fsmonitor->mode = FSMONITOR_MODE_HOOK;
101+
FREE_AND_NULL(r->settings.fsmonitor->hook_path);
102+
r->settings.fsmonitor->hook_path = strdup(path);
103+
}
104+
105+
void fsm_settings__set_disabled(struct repository *r)
106+
{
107+
if (!r)
108+
r = the_repository;
109+
110+
lookup_fsmonitor_settings(r);
111+
112+
r->settings.fsmonitor->mode = FSMONITOR_MODE_DISABLED;
113+
FREE_AND_NULL(r->settings.fsmonitor->hook_path);
114+
}

fsmonitor-settings.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef FSMONITOR_SETTINGS_H
2+
#define FSMONITOR_SETTINGS_H
3+
4+
struct repository;
5+
6+
enum fsmonitor_mode {
7+
FSMONITOR_MODE_DISABLED = 0,
8+
FSMONITOR_MODE_HOOK = 1, /* core.fsmonitor=<hook_path> */
9+
FSMONITOR_MODE_IPC = 2, /* core.fsmonitor=<true> */
10+
};
11+
12+
void fsm_settings__set_ipc(struct repository *r);
13+
void fsm_settings__set_hook(struct repository *r, const char *path);
14+
void fsm_settings__set_disabled(struct repository *r);
15+
16+
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
17+
const char *fsm_settings__get_hook_path(struct repository *r);
18+
19+
struct fsmonitor_settings;
20+
21+
#endif /* FSMONITOR_SETTINGS_H */

fsmonitor.c

+38-25
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "dir.h"
44
#include "ewah/ewok.h"
55
#include "fsmonitor.h"
6+
#include "fsmonitor-ipc.h"
67
#include "run-command.h"
78
#include "strbuf.h"
89

@@ -148,15 +149,18 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
148149
/*
149150
* Call the query-fsmonitor hook passing the last update token of the saved results.
150151
*/
151-
static int query_fsmonitor(int version, const char *last_update, struct strbuf *query_result)
152+
static int query_fsmonitor_hook(struct repository *r,
153+
int version,
154+
const char *last_update,
155+
struct strbuf *query_result)
152156
{
153157
struct child_process cp = CHILD_PROCESS_INIT;
154158
int result;
155159

156-
if (!core_fsmonitor)
160+
if (fsm_settings__get_mode(r) != FSMONITOR_MODE_HOOK)
157161
return -1;
158162

159-
strvec_push(&cp.args, core_fsmonitor);
163+
strvec_push(&cp.args, fsm_settings__get_hook_path(r));
160164
strvec_pushf(&cp.args, "%d", version);
161165
strvec_pushf(&cp.args, "%s", last_update);
162166
cp.use_shell = 1;
@@ -225,31 +229,43 @@ void refresh_fsmonitor(struct index_state *istate)
225229
char *buf;
226230
unsigned int i;
227231
int is_trivial = 0;
232+
struct repository *r = istate->repo ? istate->repo : the_repository;
233+
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
228234

229-
if (!core_fsmonitor || istate->fsmonitor_has_run_once)
235+
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
236+
istate->fsmonitor_has_run_once)
230237
return;
231238

232-
hook_version = fsmonitor_hook_version();
233-
234239
istate->fsmonitor_has_run_once = 1;
235240

236241
trace_printf_key(&trace_fsmonitor, "refresh fsmonitor");
242+
243+
if (fsm_mode == FSMONITOR_MODE_IPC) {
244+
/* TODO */
245+
return;
246+
}
247+
248+
assert(fsm_mode == FSMONITOR_MODE_HOOK);
249+
250+
hook_version = fsmonitor_hook_version();
251+
237252
/*
238-
* This could be racy so save the date/time now and query_fsmonitor
253+
* This could be racy so save the date/time now and query_fsmonitor_hook
239254
* should be inclusive to ensure we don't miss potential changes.
240255
*/
241256
last_update = getnanotime();
242257
if (hook_version == HOOK_INTERFACE_VERSION1)
243258
strbuf_addf(&last_update_token, "%"PRIu64"", last_update);
244259

245260
/*
246-
* If we have a last update token, call query_fsmonitor for the set of
261+
* If we have a last update token, call query_fsmonitor_hook for the set of
247262
* changes since that token, else assume everything is possibly dirty
248263
* and check it all.
249264
*/
250265
if (istate->fsmonitor_last_update) {
251266
if (hook_version == -1 || hook_version == HOOK_INTERFACE_VERSION2) {
252-
query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION2,
267+
query_success = !query_fsmonitor_hook(
268+
r, HOOK_INTERFACE_VERSION2,
253269
istate->fsmonitor_last_update, &query_result);
254270

255271
if (query_success) {
@@ -280,7 +296,8 @@ void refresh_fsmonitor(struct index_state *istate)
280296
}
281297

282298
if (hook_version == HOOK_INTERFACE_VERSION1) {
283-
query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION1,
299+
query_success = !query_fsmonitor_hook(
300+
r, HOOK_INTERFACE_VERSION1,
284301
istate->fsmonitor_last_update, &query_result);
285302
if (query_success)
286303
is_trivial = query_result.buf[0] == '/';
@@ -290,9 +307,12 @@ void refresh_fsmonitor(struct index_state *istate)
290307
trace2_data_intmax("fsm_hook", NULL,
291308
"query/trivial-response", 1);
292309

293-
trace_performance_since(last_update, "fsmonitor process '%s'", core_fsmonitor);
294-
trace_printf_key(&trace_fsmonitor, "fsmonitor process '%s' returned %s",
295-
core_fsmonitor, query_success ? "success" : "failure");
310+
trace_performance_since(last_update, "fsmonitor process '%s'",
311+
fsm_settings__get_hook_path(r));
312+
trace_printf_key(&trace_fsmonitor,
313+
"fsmonitor process '%s' returned %s",
314+
fsm_settings__get_hook_path(r),
315+
query_success ? "success" : "failure");
296316
}
297317

298318
/*
@@ -429,7 +449,8 @@ void remove_fsmonitor(struct index_state *istate)
429449
void tweak_fsmonitor(struct index_state *istate)
430450
{
431451
unsigned int i;
432-
int fsmonitor_enabled = git_config_get_fsmonitor();
452+
int fsmonitor_enabled = (fsm_settings__get_mode(istate->repo)
453+
> FSMONITOR_MODE_DISABLED);
433454

434455
if (istate->fsmonitor_dirty) {
435456
if (fsmonitor_enabled) {
@@ -449,16 +470,8 @@ void tweak_fsmonitor(struct index_state *istate)
449470
istate->fsmonitor_dirty = NULL;
450471
}
451472

452-
switch (fsmonitor_enabled) {
453-
case -1: /* keep: do nothing */
454-
break;
455-
case 0: /* false */
456-
remove_fsmonitor(istate);
457-
break;
458-
case 1: /* true */
473+
if (fsmonitor_enabled)
459474
add_fsmonitor(istate);
460-
break;
461-
default: /* unknown value: do nothing */
462-
break;
463-
}
475+
else
476+
remove_fsmonitor(istate);
464477
}

fsmonitor.h

+12-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "cache.h"
55
#include "dir.h"
6+
#include "fsmonitor-settings.h"
67

78
extern struct trace_key trace_fsmonitor;
89

@@ -57,7 +58,10 @@ int fsmonitor_is_trivial_response(const struct strbuf *query_result);
5758
*/
5859
static inline int is_fsmonitor_refreshed(const struct index_state *istate)
5960
{
60-
return !core_fsmonitor || istate->fsmonitor_has_run_once;
61+
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(istate->repo);
62+
63+
return fsm_mode <= FSMONITOR_MODE_DISABLED ||
64+
istate->fsmonitor_has_run_once;
6165
}
6266

6367
/*
@@ -67,7 +71,10 @@ static inline int is_fsmonitor_refreshed(const struct index_state *istate)
6771
*/
6872
static inline void mark_fsmonitor_valid(struct index_state *istate, struct cache_entry *ce)
6973
{
70-
if (core_fsmonitor && !(ce->ce_flags & CE_FSMONITOR_VALID)) {
74+
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(istate->repo);
75+
76+
if (fsm_mode > FSMONITOR_MODE_DISABLED &&
77+
!(ce->ce_flags & CE_FSMONITOR_VALID)) {
7178
istate->cache_changed = 1;
7279
ce->ce_flags |= CE_FSMONITOR_VALID;
7380
trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_clean '%s'", ce->name);
@@ -83,7 +90,9 @@ static inline void mark_fsmonitor_valid(struct index_state *istate, struct cache
8390
*/
8491
static inline void mark_fsmonitor_invalid(struct index_state *istate, struct cache_entry *ce)
8592
{
86-
if (core_fsmonitor) {
93+
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(istate->repo);
94+
95+
if (fsm_mode > FSMONITOR_MODE_DISABLED) {
8796
ce->ce_flags &= ~CE_FSMONITOR_VALID;
8897
untracked_cache_invalidate_path(istate, ce->name, 1);
8998
trace_printf_key(&trace_fsmonitor, "mark_fsmonitor_invalid '%s'", ce->name);

0 commit comments

Comments
 (0)