mirror of
https://github.com/git/git
synced 2024-10-02 14:45:21 +00:00
fsmonitor: handle version 2 of the hooks that will use opaque token
Some file monitors like watchman will use something other than a timestamp to keep better track of what changes happen in between calls to query the fsmonitor. The clockid in watchman is a string. Now that the index is storing an opaque token for the last update the code needs to be updated to pass that opaque token to a verion 2 of the fsmonitor hook. Because there are repos that already have version 1 of the hook and we want them to continue to work when git is updated, we need to handle both version 1 and version 2 of the hook. In order to do that a config value is being added core.fsmonitorHookVersion to force what version of the hook should be used. When this is not set it will default to -1 and then the code will attempt to call version 2 of the hook first. If that fails it will fallback to trying version 1. Signed-off-by: Kevin Willford <Kevin.Willford@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
56c6910028
commit
8da2c57629
75
fsmonitor.c
75
fsmonitor.c
|
@ -8,7 +8,8 @@
|
||||||
|
|
||||||
#define INDEX_EXTENSION_VERSION1 (1)
|
#define INDEX_EXTENSION_VERSION1 (1)
|
||||||
#define INDEX_EXTENSION_VERSION2 (2)
|
#define INDEX_EXTENSION_VERSION2 (2)
|
||||||
#define HOOK_INTERFACE_VERSION (1)
|
#define HOOK_INTERFACE_VERSION1 (1)
|
||||||
|
#define HOOK_INTERFACE_VERSION2 (2)
|
||||||
|
|
||||||
struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR);
|
struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR);
|
||||||
|
|
||||||
|
@ -25,6 +26,22 @@ static void fsmonitor_ewah_callback(size_t pos, void *is)
|
||||||
ce->ce_flags &= ~CE_FSMONITOR_VALID;
|
ce->ce_flags &= ~CE_FSMONITOR_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fsmonitor_hook_version(void)
|
||||||
|
{
|
||||||
|
int hook_version;
|
||||||
|
|
||||||
|
if (git_config_get_int("core.fsmonitorhookversion", &hook_version))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (hook_version == HOOK_INTERFACE_VERSION1 ||
|
||||||
|
hook_version == HOOK_INTERFACE_VERSION2)
|
||||||
|
return hook_version;
|
||||||
|
|
||||||
|
warning("Invalid hook version '%i' in core.fsmonitorhookversion. "
|
||||||
|
"Must be 1 or 2.", hook_version);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int read_fsmonitor_extension(struct index_state *istate, const void *data,
|
int read_fsmonitor_extension(struct index_state *istate, const void *data,
|
||||||
unsigned long sz)
|
unsigned long sz)
|
||||||
{
|
{
|
||||||
|
@ -158,8 +175,8 @@ static void fsmonitor_refresh_callback(struct index_state *istate, const char *n
|
||||||
void refresh_fsmonitor(struct index_state *istate)
|
void refresh_fsmonitor(struct index_state *istate)
|
||||||
{
|
{
|
||||||
struct strbuf query_result = STRBUF_INIT;
|
struct strbuf query_result = STRBUF_INIT;
|
||||||
int query_success = 0;
|
int query_success = 0, hook_version = -1;
|
||||||
size_t bol; /* beginning of line */
|
size_t bol = 0; /* beginning of line */
|
||||||
uint64_t last_update;
|
uint64_t last_update;
|
||||||
struct strbuf last_update_token = STRBUF_INIT;
|
struct strbuf last_update_token = STRBUF_INIT;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
@ -167,6 +184,9 @@ void refresh_fsmonitor(struct index_state *istate)
|
||||||
|
|
||||||
if (!core_fsmonitor || istate->fsmonitor_has_run_once)
|
if (!core_fsmonitor || istate->fsmonitor_has_run_once)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
hook_version = fsmonitor_hook_version();
|
||||||
|
|
||||||
istate->fsmonitor_has_run_once = 1;
|
istate->fsmonitor_has_run_once = 1;
|
||||||
|
|
||||||
trace_printf_key(&trace_fsmonitor, "refresh fsmonitor");
|
trace_printf_key(&trace_fsmonitor, "refresh fsmonitor");
|
||||||
|
@ -175,27 +195,60 @@ void refresh_fsmonitor(struct index_state *istate)
|
||||||
* should be inclusive to ensure we don't miss potential changes.
|
* should be inclusive to ensure we don't miss potential changes.
|
||||||
*/
|
*/
|
||||||
last_update = getnanotime();
|
last_update = getnanotime();
|
||||||
strbuf_addf(&last_update_token, "%"PRIu64"", last_update);
|
if (hook_version == HOOK_INTERFACE_VERSION1)
|
||||||
|
strbuf_addf(&last_update_token, "%"PRIu64"", last_update);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a last update time, call query_fsmonitor for the set of
|
* If we have a last update token, call query_fsmonitor for the set of
|
||||||
* changes since that time, else assume everything is possibly dirty
|
* changes since that token, else assume everything is possibly dirty
|
||||||
* and check it all.
|
* and check it all.
|
||||||
*/
|
*/
|
||||||
if (istate->fsmonitor_last_update) {
|
if (istate->fsmonitor_last_update) {
|
||||||
query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION,
|
if (hook_version == -1 || hook_version == HOOK_INTERFACE_VERSION2) {
|
||||||
istate->fsmonitor_last_update, &query_result);
|
query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION2,
|
||||||
|
istate->fsmonitor_last_update, &query_result);
|
||||||
|
|
||||||
|
if (query_success) {
|
||||||
|
if (hook_version < 0)
|
||||||
|
hook_version = HOOK_INTERFACE_VERSION2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First entry will be the last update token
|
||||||
|
* Need to use a char * variable because static
|
||||||
|
* analysis was suggesting to use strbuf_addbuf
|
||||||
|
* but we don't want to copy the entire strbuf
|
||||||
|
* only the the chars up to the first NUL
|
||||||
|
*/
|
||||||
|
buf = query_result.buf;
|
||||||
|
strbuf_addstr(&last_update_token, buf);
|
||||||
|
if (!last_update_token.len) {
|
||||||
|
warning("Empty last update token.");
|
||||||
|
query_success = 0;
|
||||||
|
} else {
|
||||||
|
bol = last_update_token.len + 1;
|
||||||
|
}
|
||||||
|
} else if (hook_version < 0) {
|
||||||
|
hook_version = HOOK_INTERFACE_VERSION1;
|
||||||
|
if (!last_update_token.len)
|
||||||
|
strbuf_addf(&last_update_token, "%"PRIu64"", last_update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hook_version == HOOK_INTERFACE_VERSION1) {
|
||||||
|
query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION1,
|
||||||
|
istate->fsmonitor_last_update, &query_result);
|
||||||
|
}
|
||||||
|
|
||||||
trace_performance_since(last_update, "fsmonitor process '%s'", core_fsmonitor);
|
trace_performance_since(last_update, "fsmonitor process '%s'", core_fsmonitor);
|
||||||
trace_printf_key(&trace_fsmonitor, "fsmonitor process '%s' returned %s",
|
trace_printf_key(&trace_fsmonitor, "fsmonitor process '%s' returned %s",
|
||||||
core_fsmonitor, query_success ? "success" : "failure");
|
core_fsmonitor, query_success ? "success" : "failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* a fsmonitor process can return '/' to indicate all entries are invalid */
|
/* a fsmonitor process can return '/' to indicate all entries are invalid */
|
||||||
if (query_success && query_result.buf[0] != '/') {
|
if (query_success && query_result.buf[bol] != '/') {
|
||||||
/* Mark all entries returned by the monitor as dirty */
|
/* Mark all entries returned by the monitor as dirty */
|
||||||
buf = query_result.buf;
|
buf = query_result.buf;
|
||||||
bol = 0;
|
for (i = bol; i < query_result.len; i++) {
|
||||||
for (i = 0; i < query_result.len; i++) {
|
|
||||||
if (buf[i] != '\0')
|
if (buf[i] != '\0')
|
||||||
continue;
|
continue;
|
||||||
fsmonitor_refresh_callback(istate, buf + bol);
|
fsmonitor_refresh_callback(istate, buf + bol);
|
||||||
|
|
|
@ -32,11 +32,12 @@ write_integration_script () {
|
||||||
echo "$0: exactly 2 arguments expected"
|
echo "$0: exactly 2 arguments expected"
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
if test "$1" != 1
|
if test "$1" != 2
|
||||||
then
|
then
|
||||||
echo "Unsupported core.fsmonitor hook version." >&2
|
echo "Unsupported core.fsmonitor hook version." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
printf "last_update_token\0"
|
||||||
printf "untracked\0"
|
printf "untracked\0"
|
||||||
printf "dir1/untracked\0"
|
printf "dir1/untracked\0"
|
||||||
printf "dir2/untracked\0"
|
printf "dir2/untracked\0"
|
||||||
|
@ -107,6 +108,7 @@ EOF
|
||||||
# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
|
# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
|
||||||
test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
|
test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
|
||||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||||
|
printf "last_update_token\0"
|
||||||
EOF
|
EOF
|
||||||
git update-index --fsmonitor &&
|
git update-index --fsmonitor &&
|
||||||
git update-index --fsmonitor-valid dir1/modified &&
|
git update-index --fsmonitor-valid dir1/modified &&
|
||||||
|
@ -167,6 +169,7 @@ EOF
|
||||||
# test that newly added files are marked valid
|
# test that newly added files are marked valid
|
||||||
test_expect_success 'newly added files are marked valid' '
|
test_expect_success 'newly added files are marked valid' '
|
||||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||||
|
printf "last_update_token\0"
|
||||||
EOF
|
EOF
|
||||||
git add new &&
|
git add new &&
|
||||||
git add dir1/new &&
|
git add dir1/new &&
|
||||||
|
@ -207,6 +210,7 @@ EOF
|
||||||
# test that *only* files returned by the integration script get flagged as invalid
|
# test that *only* files returned by the integration script get flagged as invalid
|
||||||
test_expect_success '*only* files returned by the integration script get flagged as invalid' '
|
test_expect_success '*only* files returned by the integration script get flagged as invalid' '
|
||||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||||
|
printf "last_update_token\0"
|
||||||
printf "dir1/modified\0"
|
printf "dir1/modified\0"
|
||||||
EOF
|
EOF
|
||||||
clean_repo &&
|
clean_repo &&
|
||||||
|
@ -276,6 +280,7 @@ do
|
||||||
# (if enabled) files unless it is told about them.
|
# (if enabled) files unless it is told about them.
|
||||||
test_expect_success "status doesn't detect unreported modifications" '
|
test_expect_success "status doesn't detect unreported modifications" '
|
||||||
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
write_script .git/hooks/fsmonitor-test<<-\EOF &&
|
||||||
|
printf "last_update_token\0"
|
||||||
:>marker
|
:>marker
|
||||||
EOF
|
EOF
|
||||||
clean_repo &&
|
clean_repo &&
|
||||||
|
|
|
@ -17,7 +17,6 @@ fi
|
||||||
|
|
||||||
if test "$1" != 1
|
if test "$1" != 1
|
||||||
then
|
then
|
||||||
echo "Unsupported core.fsmonitor hook version." >&2
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,7 @@ if ($version == 1) {
|
||||||
# subtract one second to make sure watchman will return all changes
|
# subtract one second to make sure watchman will return all changes
|
||||||
$time = int ($time / 1000000000) - 1;
|
$time = int ($time / 1000000000) - 1;
|
||||||
} else {
|
} else {
|
||||||
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
exit 1;
|
||||||
"Falling back to scanning...\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
my $git_work_tree;
|
my $git_work_tree;
|
||||||
|
|
Loading…
Reference in a new issue