From patchwork Tue Mar 1 18:43:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765043 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 96C8CC433EF for ; Tue, 1 Mar 2022 18:43:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235014AbiCASoU (ORCPT ); Tue, 1 Mar 2022 13:44:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54262 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232623AbiCASoS (ORCPT ); Tue, 1 Mar 2022 13:44:18 -0500 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 176BB286D5 for ; Tue, 1 Mar 2022 10:43:37 -0800 (PST) Received: by mail-wr1-x430.google.com with SMTP id bk29so4649386wrb.4 for ; Tue, 01 Mar 2022 10:43:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=GykMGxH+vcSxKSOuzIgVgE2plWrsxxaHhbdq7JLSrgU=; b=DGrIqUPt3UKqGz+RDcfyfrM2OXbigV5jWZ0e260JNq726J8NMzj8swYrmz/kr0HXjG mus6uzU9GCe1FdQ94RK/rVnj5rO1qouNyII5S2RCt6U4akgwlbEXQ18V+w43WT/ElnKE RR7M+rW0zBkZzp7WwiJOuGWq0WClgK7Lu4MetVORg6eOj92vGAJ0oB3qhkfp4rBVRDW8 7hDSDC7jGWl8Rpd3vlLdePYv+e6a4u6aSiWkasn2vMhcvZMzDE6gFdAwIc7JV9S832Zw BXh+PO14Ji9DMsmJN9ylQmLh5jv8RPQxBHMTIuZr0Ijp6jg8D/3c2m1Ddb3mHm5HNihN TCaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=GykMGxH+vcSxKSOuzIgVgE2plWrsxxaHhbdq7JLSrgU=; b=kcMY2y91VyIK+XvS3aRXgiHGGQpP9h5KnnHeOLfdoQWucOgevg4XpYRbTIZ3xyNv/s rBrYVpvGDTtpnMhY5+llRqBMClUX2ZLH/gztudi11B1noIo0yqJfLDJh3DRbx9Hn+Oit hnwroHQz2h5JtIxnP8sUxci3kszJOcEZEbOyMK+05pXOEAc2OmFW4+IHPuO61hwrsNE+ lTO40O4G55lrsHrh7GAV4JrKLJZQAqxympJksHRyjm42DvJNQi49K7chLDa5sTKpb7FJ wbfBEQUlZGMF6VCbcPOtMusKxSq+yw3f1PYA9YWeTjecBpDdg8AmPJsgMRk08tpCcBnZ 1gWw== X-Gm-Message-State: AOAM532+KjCV9y3U7SAvfSxmGopT9neUKXzH0XFVaCaqCFFMl0k91kbf 6AR0pCMvCl+6cf+/pPFpEmN2X98J9j4= X-Google-Smtp-Source: ABdhPJwCUrIf1k++hwg/xFNL50BbduFOx4111AX+12AZOUi8eSnOL4eqOE2I7bOl6KrrNOdQVzv8iA== X-Received: by 2002:adf:d1e9:0:b0:1ea:7d0f:69c7 with SMTP id g9-20020adfd1e9000000b001ea7d0f69c7mr21208548wrd.373.1646160215272; Tue, 01 Mar 2022 10:43:35 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i20-20020a05600c355400b0038164ef5418sm3596937wmq.32.2022.03.01.10.43.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:34 -0800 (PST) Message-Id: <10a34082fcc7ddf693b4a50fb2ce05905ee2986f.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:03 +0000 Subject: [PATCH v6 01/30] fsmonitor: enhance existing comments, clarify trivial response handling Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- fsmonitor.c | 64 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/fsmonitor.c b/fsmonitor.c index ab9bfc60b34..448d0ee33f5 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -168,29 +168,15 @@ static int query_fsmonitor(int version, const char *last_update, struct strbuf * if (result) trace2_data_intmax("fsm_hook", NULL, "query/failed", result); - else { + else trace2_data_intmax("fsm_hook", NULL, "query/response-length", query_result->len); - if (fsmonitor_is_trivial_response(query_result)) - trace2_data_intmax("fsm_hook", NULL, - "query/trivial-response", 1); - } - trace2_region_leave("fsm_hook", "query", NULL); return result; } -int fsmonitor_is_trivial_response(const struct strbuf *query_result) -{ - static char trivial_response[3] = { '\0', '/', '\0' }; - - return query_result->len >= 3 && - !memcmp(trivial_response, - &query_result->buf[query_result->len - 3], 3); -} - static void fsmonitor_refresh_callback(struct index_state *istate, char *name) { int i, len = strlen(name); @@ -238,6 +224,7 @@ void refresh_fsmonitor(struct index_state *istate) struct strbuf last_update_token = STRBUF_INIT; char *buf; unsigned int i; + int is_trivial = 0; if (!core_fsmonitor || istate->fsmonitor_has_run_once) return; @@ -283,6 +270,7 @@ void refresh_fsmonitor(struct index_state *istate) query_success = 0; } else { bol = last_update_token.len + 1; + is_trivial = query_result.buf[bol] == '/'; } } else if (hook_version < 0) { hook_version = HOOK_INTERFACE_VERSION1; @@ -294,16 +282,38 @@ void refresh_fsmonitor(struct index_state *istate) if (hook_version == HOOK_INTERFACE_VERSION1) { query_success = !query_fsmonitor(HOOK_INTERFACE_VERSION1, istate->fsmonitor_last_update, &query_result); + if (query_success) + is_trivial = query_result.buf[0] == '/'; } + if (is_trivial) + trace2_data_intmax("fsm_hook", NULL, + "query/trivial-response", 1); + 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"); } - /* a fsmonitor process can return '/' to indicate all entries are invalid */ - if (query_success && query_result.buf[bol] != '/') { - /* Mark all entries returned by the monitor as dirty */ + /* + * 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 && !is_trivial) { + /* + * 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 +328,16 @@ 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 failed to get a response or 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 +345,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; From patchwork Tue Mar 1 18:43:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765044 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 89D9EC433FE for ; Tue, 1 Mar 2022 18:43:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236986AbiCASoW (ORCPT ); Tue, 1 Mar 2022 13:44:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54328 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235646AbiCASoU (ORCPT ); Tue, 1 Mar 2022 13:44:20 -0500 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1C17628987 for ; Tue, 1 Mar 2022 10:43:38 -0800 (PST) Received: by mail-wr1-x433.google.com with SMTP id d17so21917260wrc.9 for ; Tue, 01 Mar 2022 10:43:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=LLXpAOe7NAW9n+vltqHwzfoKI9K9hb1EXNo89d8N7zg=; b=mpcE9ZiFwhQroNctOdcfqu/UllOWm40xiKUPiSxOVFc3VPCHM3aj/V7dxQiTh8nyUZ gpXgbvoeUD+2bbejOVpDpsB1NzozpGKgj9h2tiv6+xtxcKWyKY65poaEuteQYqoHdKmP GvLmbMGBbG7j/ozLS5bUUuqaH8WbmdDypsu05InJXk2hB5R2TrCkB2DdTWxGwWbsYBFA mzEBsRk1WSwTbN/RgfVdOrCGbwdik63XUWm2DYzPcJWNnYnQFRVl5mA2FOC1notDaEmV WEao0aSrCkPakUtXg2CTGyRhQXbRnbBpj+KnkC7E9b1V0yedYgBup7XupMRRoR6rQvdp g0DA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=LLXpAOe7NAW9n+vltqHwzfoKI9K9hb1EXNo89d8N7zg=; b=sEJpfKKhLoSD9DI6MA6ZM52rYgLNGzLMOF7AebWjLDUTPbbCK2gMWmc4LBgOvtDtGx qhcXgtHu9j5X3/lskSU+/NXo783YcM41blnoj3+YqIcrPSfn1+U4uJhw2JwxrRlU1eNK 63jsXvWYvB8nxLuADWt8cY0Eao+NIC/e1WuwmSJlI7DVBOQHzmZRv5BXEX5IbWaRkFVl FoW0EKlgsc1LKrgw1npTt4i4D6HOUJ5i20eQoo7nnFfeFmdROrWQneiWSv8y1ntr9qK6 IV5prx1c3L/dPMuOelu0VMFxm4BA162QrjZ6NpQErneKK5pZG2r0IwfMBtcfxycmTfzb 7NIA== X-Gm-Message-State: AOAM530LjZi9m5i38uQCpy5wbX9KP9WgfujYQASuipFl+I4KVHku4+N3 Np0pHxfjPIk0k1q8alu1/QWEyZRo2Lg= X-Google-Smtp-Source: ABdhPJw8LRPYlzBz/NkYYpr8i10FF3Dj+xGNcb06kO2389D8DHdITwzSG4IBtqmgsjxbn52i48wUzw== X-Received: by 2002:adf:db43:0:b0:1ef:7195:43cd with SMTP id f3-20020adfdb43000000b001ef719543cdmr16276405wrj.495.1646160216300; Tue, 01 Mar 2022 10:43:36 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v20-20020a7bcb54000000b0037fa63db8aasm3340402wmj.5.2022.03.01.10.43.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:35 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:04 +0000 Subject: [PATCH v6 02/30] fsmonitor-ipc: create client routines for git-fsmonitor--daemon Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Create fsmonitor_ipc__*() client routines to spawn the built-in file system monitor daemon and send it an IPC request using the `Simple IPC` API. Stub in empty fsmonitor_ipc__*() functions for unsupported platforms. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- Makefile | 1 + fsmonitor-ipc.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++ fsmonitor-ipc.h | 48 ++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 fsmonitor-ipc.c create mode 100644 fsmonitor-ipc.h diff --git a/Makefile b/Makefile index 6f0b4b775fe..a19d850e716 100644 --- a/Makefile +++ b/Makefile @@ -907,6 +907,7 @@ 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 += gettext.o LIB_OBJS += gpg-interface.o LIB_OBJS += graph.o diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c new file mode 100644 index 00000000000..91a535f1219 --- /dev/null +++ b/fsmonitor-ipc.c @@ -0,0 +1,171 @@ +#include "cache.h" +#include "fsmonitor.h" +#include "simple-ipc.h" +#include "fsmonitor-ipc.h" +#include "run-command.h" +#include "strbuf.h" +#include "trace2.h" + +#ifndef HAVE_FSMONITOR_DAEMON_BACKEND + +/* + * 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; +} + +#else + +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); + 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; +} + +#endif diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h new file mode 100644 index 00000000000..b6a7067c3af --- /dev/null +++ b/fsmonitor-ipc.h @@ -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 */ From patchwork Tue Mar 1 18:43:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765047 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 51FCFC433F5 for ; Tue, 1 Mar 2022 18:43:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237040AbiCASo1 (ORCPT ); Tue, 1 Mar 2022 13:44:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229796AbiCASoV (ORCPT ); Tue, 1 Mar 2022 13:44:21 -0500 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1B982286D5 for ; Tue, 1 Mar 2022 10:43:39 -0800 (PST) Received: by mail-wm1-x334.google.com with SMTP id bg16-20020a05600c3c9000b00380f6f473b0so1791791wmb.1 for ; Tue, 01 Mar 2022 10:43:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=BUkTNnLn0vOO6EtDitPQWrHeoI2XrM2yFtsFI1Qt7uU=; b=ExSdePOBck4sPofAAdtqMEpGwvP6uluflIBNTMfTgOjfukixeW02FctVma0UGpANe4 Bwg226JxKbfplcFLkfHX24n7KuA4e6IFtfSqj0JDtF02xcWHwzbGNtVvWeRJpHprMUdW CMG2NGcq/pftgUyKL+ouRnFffFd5dyPuRkH9ETXdpoKeoxEGHOet5Pbo7lRv1lI/3+Op vAHii/RlZyB4fJLiki+Z32InfbSwrem/szzntbz3IJNNC+tM3RH1TC2tm3NtJkWZio3O UobTJJTW72iYVQcoF7o8TuEXIa9NJ71O/fcfHrjc+UPskwsrto5quk0vKK+WNPX0I57L d+PA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=BUkTNnLn0vOO6EtDitPQWrHeoI2XrM2yFtsFI1Qt7uU=; b=W1SpO0+FCMJNVV98K3D6j76fHEEJfia2AGJHoKmuJz99Ov6in2yAx6aJJI8NCg2qOn QT/6DpG0fb5mkP33hwI8o68bV3lr6oetpuwJVPxgSkGwUofSIuBug3S9vwCcX4eULypg VJMm3/GtsSNOQQP7TC3cG1uZUrpMvWZqPFV11t87sCX9Sil4T2lRcwb9MEia7oli3Fzo MSOS13vl+8KmUST5xYsTsNGRxLPvFvfBIK5Cy+bnSYmji3YhM07lAzvNZbJvW1acbB4F 99BKi3xYV+zNACo2jjFkARgBZCa/URgJfQ/1l0IoXXmrDQ2T/9xO9XS2OxmdWgCnmKyF O3Yw== X-Gm-Message-State: AOAM531peIpvkzXfz1aWJFFWjDN1iyEstCI5bPG9qH5YH4/wg+8Um2c1 BEUjv9MPNcXcsVJYRwEftGetVk6ta2g= X-Google-Smtp-Source: ABdhPJybLiWzeMslLYq+j4cUp9bAL7BsoatjtLuBEf57G5jrafVoFgVTjLhrTCJtCrN3Dm1YJmNM4w== X-Received: by 2002:a05:600c:3546:b0:381:7a9d:eee2 with SMTP id i6-20020a05600c354600b003817a9deee2mr6591744wmq.24.1646160217322; Tue, 01 Mar 2022 10:43:37 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id w22-20020a7bc756000000b0038171f6bb63sm3204504wmk.35.2022.03.01.10.43.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:36 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:05 +0000 Subject: [PATCH v6 03/30] fsmonitor: config settings are repository-specific Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler 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 Signed-off-by: Junio C Hamano --- Makefile | 1 + builtin/update-index.c | 7 ++- cache.h | 1 - config.c | 14 ----- config.h | 1 - environment.c | 1 - fsmonitor-settings.c | 115 +++++++++++++++++++++++++++++++++++++++++ fsmonitor-settings.h | 21 ++++++++ fsmonitor.c | 63 +++++++++++++--------- fsmonitor.h | 15 ++++-- repository.h | 3 ++ t/README | 4 +- 12 files changed, 197 insertions(+), 49 deletions(-) create mode 100644 fsmonitor-settings.c create mode 100644 fsmonitor-settings.h diff --git a/Makefile b/Makefile index a19d850e716..707a56d4c11 100644 --- a/Makefile +++ b/Makefile @@ -908,6 +908,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 diff --git a/builtin/update-index.c b/builtin/update-index.c index aafe7eeac2a..876112abb21 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -1236,14 +1236,17 @@ 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.fsmonitor is unset; " "set it if you really want to " "enable 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_DISABLED) warning(_("core.fsmonitor is set; " "remove it if you really want to " "disable fsmonitor")); diff --git a/cache.h b/cache.h index 04d4d2db25c..aaf334e2aa4 100644 --- a/cache.h +++ b/cache.h @@ -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; diff --git a/config.c b/config.c index 383b1a4885b..3f9b0739a78 100644 --- a/config.c +++ b/config.c @@ -2626,20 +2626,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; diff --git a/config.h b/config.h index bb49baf1ee0..7654f61c634 100644 --- a/config.h +++ b/config.h @@ -597,7 +597,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); diff --git a/environment.c b/environment.c index fd0501e77a5..00682e638d7 100644 --- a/environment.c +++ b/environment.c @@ -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 diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c new file mode 100644 index 00000000000..3b54e7a51f6 --- /dev/null +++ b/fsmonitor-settings.c @@ -0,0 +1,115 @@ +#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; +}; + +static void lookup_fsmonitor_settings(struct repository *r) +{ + struct fsmonitor_settings *s; + const char *const_str; + int bool_value; + + if (r->settings.fsmonitor) + return; + + CALLOC_ARRAY(s, 1); + + r->settings.fsmonitor = s; + + fsm_settings__set_disabled(r); + + /* + * Overload the existing "core.fsmonitor" config setting (which + * has historically been either unset or a hook pathname) to + * now allow a boolean value to enable the builtin FSMonitor + * or to turn everything off. (This does imply that you can't + * use a hook script named "true" or "false", but that's OK.) + */ + switch (repo_config_get_maybe_bool(r, "core.fsmonitor", &bool_value)) { + + case 0: /* config value was set to */ + if (bool_value) + fsm_settings__set_ipc(r); + return; + + case 1: /* config value was unset */ + const_str = getenv("GIT_TEST_FSMONITOR"); + break; + + case -1: /* config value set to an arbitrary string */ + if (repo_config_get_pathname(r, "core.fsmonitor", &const_str)) + return; /* should not happen */ + break; + + default: /* should not happen */ + return; + } + + if (!const_str || !*const_str) + return; + + fsm_settings__set_hook(r, const_str); +} + +enum fsmonitor_mode fsm_settings__get_mode(struct repository *r) +{ + if (!r) + r = the_repository; + + lookup_fsmonitor_settings(r); + + return r->settings.fsmonitor->mode; +} + +const char *fsm_settings__get_hook_path(struct repository *r) +{ + if (!r) + r = the_repository; + + lookup_fsmonitor_settings(r); + + return r->settings.fsmonitor->hook_path; +} + +void fsm_settings__set_ipc(struct repository *r) +{ + if (!r) + r = the_repository; + + lookup_fsmonitor_settings(r); + + r->settings.fsmonitor->mode = FSMONITOR_MODE_IPC; + FREE_AND_NULL(r->settings.fsmonitor->hook_path); +} + +void fsm_settings__set_hook(struct repository *r, const char *path) +{ + if (!r) + r = the_repository; + + lookup_fsmonitor_settings(r); + + r->settings.fsmonitor->mode = FSMONITOR_MODE_HOOK; + FREE_AND_NULL(r->settings.fsmonitor->hook_path); + r->settings.fsmonitor->hook_path = strdup(path); +} + +void fsm_settings__set_disabled(struct repository *r) +{ + if (!r) + r = the_repository; + + lookup_fsmonitor_settings(r); + + r->settings.fsmonitor->mode = FSMONITOR_MODE_DISABLED; + FREE_AND_NULL(r->settings.fsmonitor->hook_path); +} diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h new file mode 100644 index 00000000000..a4c5d7b4889 --- /dev/null +++ b/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.fsmonitor= */ +}; + +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 */ diff --git a/fsmonitor.c b/fsmonitor.c index 448d0ee33f5..0e961b74d82 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -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; @@ -225,17 +229,28 @@ void refresh_fsmonitor(struct index_state *istate) char *buf; unsigned int i; int is_trivial = 0; + 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(); @@ -243,13 +258,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) { @@ -280,7 +296,8 @@ 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); if (query_success) is_trivial = query_result.buf[0] == '/'; @@ -290,9 +307,12 @@ void refresh_fsmonitor(struct index_state *istate) trace2_data_intmax("fsm_hook", NULL, "query/trivial-response", 1); - 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"); } /* @@ -429,7 +449,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(); + int fsmonitor_enabled = (fsm_settings__get_mode(istate->repo) + > FSMONITOR_MODE_DISABLED); if (istate->fsmonitor_dirty) { if (fsmonitor_enabled) { @@ -449,16 +470,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); } diff --git a/fsmonitor.h b/fsmonitor.h index f20d72631d7..3f41f653691 100644 --- a/fsmonitor.h +++ b/fsmonitor.h @@ -3,6 +3,7 @@ #include "cache.h" #include "dir.h" +#include "fsmonitor-settings.h" extern struct trace_key trace_fsmonitor; @@ -57,7 +58,10 @@ 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; + enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(istate->repo); + + return fsm_mode <= FSMONITOR_MODE_DISABLED || + istate->fsmonitor_has_run_once; } /* @@ -67,7 +71,10 @@ 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)) { + enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(istate->repo); + + 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 +90,9 @@ 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) { + enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(istate->repo); + + 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); diff --git a/repository.h b/repository.h index ca837cb9e91..9bbb4659cc8 100644 --- a/repository.h +++ b/repository.h @@ -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; /* lazily loaded */ + int index_version; enum untracked_cache_setting core_untracked_cache; diff --git a/t/README b/t/README index f48e0542cdc..9ffea1d3147 100644 --- a/t/README +++ b/t/README @@ -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 paths for utilizing a (hook based) file system monitor to speed up +detecting new or changed files. GIT_TEST_INDEX_VERSION= exercises the index read/write code path for the index version specified. Can be set to any valid version From patchwork Tue Mar 1 18:43:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765046 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EB5D2C433F5 for ; Tue, 1 Mar 2022 18:43:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237039AbiCASoZ (ORCPT ); Tue, 1 Mar 2022 13:44:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54390 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232623AbiCASoV (ORCPT ); Tue, 1 Mar 2022 13:44:21 -0500 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B6D132A24B for ; Tue, 1 Mar 2022 10:43:39 -0800 (PST) Received: by mail-wm1-x335.google.com with SMTP id p4so8029940wmg.1 for ; Tue, 01 Mar 2022 10:43:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=oGDRFTIGvSWmNGonDgOtutzgzNzlHM+LdHJYE6AYmv0=; b=IM62jR5/2Mez2apwBKHg3oiA2LB3K3S3UCqUM5mbyWcZJEa8l7J85mHuR1ZWnSe2MW Q4ErZYfBwyEO5opfX6pETeehh/xYlB990DSb+EkZKCHaVFMNtdiU+2YolXEH9BV2IkjX WoArwW+uZ0IwTQf8382Cg9CroyDsH0jos8vKX8wfwTo6TU4ixA05HUo1T4zboCN8bGKv 806bfYv0f/fXdHQGBFSvku3NAvTOyVsLBy4g5yvFq30dlypW32nvuTOF7v46FTwKBfFY ib9hb4GJNtoXV6HhFYPULx1LUvm4Lcn4bkL03CpgN1pB6oR5jibyUBBrm5BtxCBPHUvS ZIyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=oGDRFTIGvSWmNGonDgOtutzgzNzlHM+LdHJYE6AYmv0=; b=PUfrfk3LSQ1UDAE+u/7DtvrurFnuTW+q1gJyHN+ZN9UeyQ5HcxNvI9Rk6Uh8rPKKAY n2Q8RQIuLR1XyROqOZ6Kew8BWMUsKflOOiR3rFQgzt+ph0ebIPp/yd0hmc6o9aLFfhGo ZmfNUx5Uh9ZIhfHIcgjZ4n8RwkHJVqtv+OVSw5kJFhKPT/vCC5oFei2bkaNq0Ci/CEYX MjYhpfCqbKnw1VVFR6jdZyeLWEy4pKLCGIFgf8A63FlNNlYOYvmVaLZ+oQB531Su5YIr ezwTzsacCqFQZIw+fOJh0JgJMy0ZTwJ6ZxZKA/5Xz3RbX1hna2MdXo9MTXcN87hgI/aV TRgg== X-Gm-Message-State: AOAM533WLbXiB5kqHN//u/rx9KXaea9T3xkXTiksugj3rKXsn7fNciOi vTDgKKCohUlSw98CMQpDsN86/itAX+4= X-Google-Smtp-Source: ABdhPJxvQt9qSI8uIzf0bcpnXUobV2XMoAzRUaOBXwidMTfxKQc3IwxsWVjK2dQh+CBmmrT7wTReCg== X-Received: by 2002:a05:600c:297:b0:381:41d3:e22f with SMTP id 23-20020a05600c029700b0038141d3e22fmr15262237wmk.108.1646160218179; Tue, 01 Mar 2022 10:43:38 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 10-20020adf808a000000b001edd413a952sm14582731wrl.95.2022.03.01.10.43.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:37 -0800 (PST) Message-Id: <55974867da5f791fe736221ffa1ae4cf3e204c17.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:06 +0000 Subject: [PATCH v6 04/30] fsmonitor: use IPC to query the builtin FSMonitor daemon Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Use simple IPC to directly communicate with the new builtin file system monitor daemon when `core.fsmonitor` is set to true. Signed-off-by: Johannes Schindelin Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- fsmonitor.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/fsmonitor.c b/fsmonitor.c index 0e961b74d82..a38b5710eb3 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -241,8 +241,41 @@ void refresh_fsmonitor(struct index_state *istate) trace_printf_key(&trace_fsmonitor, "refresh fsmonitor"); if (fsm_mode == FSMONITOR_MODE_IPC) { - /* TODO */ - return; + 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; + is_trivial = query_result.buf[bol] == '/'; + if (is_trivial) + trace2_data_intmax("fsm_client", NULL, + "query/trivial-response", 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); @@ -315,6 +348,7 @@ void refresh_fsmonitor(struct index_state *istate) query_success ? "success" : "failure"); } +apply_results: /* * The response from FSMonitor (excluding the header token) is * either: From patchwork Tue Mar 1 18:43:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765048 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A502C433EF for ; Tue, 1 Mar 2022 18:43:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237029AbiCASoa (ORCPT ); Tue, 1 Mar 2022 13:44:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237010AbiCASoW (ORCPT ); Tue, 1 Mar 2022 13:44:22 -0500 Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B5A39654D for ; Tue, 1 Mar 2022 10:43:40 -0800 (PST) Received: by mail-wm1-x331.google.com with SMTP id r65so423535wma.2 for ; Tue, 01 Mar 2022 10:43:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=C/9cpq+/7LFgJqbFs52lTGJrXKzcUu9HQhf3f89AGVk=; b=cHalcxtpcQ91IcsMVp9swxPtAEN3VnIaCkTJO0eugwQyS+QoCeNf2uC1ZpCzfuTHzP 8N3wD+pBo4p5EU12HId84YR8MEpR9dCFMyaJGZAldf1gd+GqWBuAOkzYdfNKsaUylDqE ce4ymEXFzU2C60nnsRjSHeUve/90n3rdgl+y34ITeVmEnfKPIuRxSCn3J4LifMIHzC+5 IdjTbnCBQY0s5lqnrmmPoNFwOdKVptEXrDk0NlozINIylZi5IHZTdSD1Ouo2QAOhdTVc BGZgvPSj2NQaF6awvPntss5muzosZP23lnQUVKFlxfJh91zfoa6c5kr20g8T2ffv7L77 IfJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=C/9cpq+/7LFgJqbFs52lTGJrXKzcUu9HQhf3f89AGVk=; b=HNnXg2R+G5fA4lgo7zvFM1TNPYCanZo0ZOgKGFAk9jr62nc+n791DjDJUmbmhoHHRu R3w++ARERlG9OlOudgp7sR4jJ/lht3+kkSZhVpY+feycrJcwYDX3jd2ZmSdLUpmAlkkQ b3My6qUz4wyXk2CXTUIo4plGbxZQyxOeyzBwJ0mtN8hJmj5Ekgj1qW1JpGljn8Pj113o LiaOAyt70Jm+p107NO74/I/y1PZHILcn2hIW1HkkH32cPFcG0ItMf9RegAn3cm3WDaJw DtKHzTp9aQ6GDiA/wr0SYU/7ax6wBtltS+PMnRDnJXCjtmo43oPitiF8hLTPXs4rFsJM 4RBw== X-Gm-Message-State: AOAM531GxYQYlA2ntVVU9i54i1y1/mo5NcC/zs1Jwb2My3GyOQAtzEcZ uXHlaQIj6aSpHNwo4DlcqDdxq78blws= X-Google-Smtp-Source: ABdhPJxoMM/IvrKI54IvOT3d46yqzdEfqz8i/GVexgjRniBf0qWVVvT9eFwAzclGfugHf9ZeaOkCSg== X-Received: by 2002:a05:600c:240b:b0:380:f424:f2be with SMTP id 11-20020a05600c240b00b00380f424f2bemr17613360wmp.16.1646160219020; Tue, 01 Mar 2022 10:43:39 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id x2-20020a7bc762000000b00380fd1ba4ebsm5615894wmk.9.2022.03.01.10.43.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:38 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:07 +0000 Subject: [PATCH v6 05/30] fsmonitor: document builtin fsmonitor Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Document how `core.fsmonitor` can be set to a boolean to enable or disable the builtin FSMonitor. Update references to `core.fsmonitor` and `core.fsmonitorHookVersion` and pointers to `Watchman` to refer to it. Create `git-fsmonitor--daemon` manual page and describe its features. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- Documentation/config/core.txt | 60 +++++++++++++++----- Documentation/git-fsmonitor--daemon.txt | 75 +++++++++++++++++++++++++ Documentation/git-update-index.txt | 8 ++- 3 files changed, 126 insertions(+), 17 deletions(-) create mode 100644 Documentation/git-fsmonitor--daemon.txt diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt index c04f62a54a1..6303c36c7ed 100644 --- a/Documentation/config/core.txt +++ b/Documentation/config/core.txt @@ -62,22 +62,54 @@ 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 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. ++ + Otherwise, 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 that if you concurrently use multiple versions of Git, such +as one version on the command line and another version in an IDE +tool, that the definition of `core.fsmonitor` was extended to +allow boolean values in addition to hook pathnames. Git versions +2.35.1 and prior will not understand the boolean values and will +consider the "true" or "false" values as hook pathnames to be +invoked. Git versions 2.26 thru 2.35.1 default to hook protocol +V2 and will fall back to no fsmonitor (full scan). Git versions +prior to 2.26 default to hook protocol V1 and will silently +assume there were no changes to report (no scan), so status +commands may report incomplete results. For this reason, it is +best to upgrade all of your Git versions before using the built-in +file system monitor. 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. core.trustctime:: If false, the ctime differences between the index and the diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt new file mode 100644 index 00000000000..0fedf5a4565 --- /dev/null +++ b/Documentation/git-fsmonitor--daemon.txt @@ -0,0 +1,75 @@ +git-fsmonitor--daemon(1) +======================== + +NAME +---- +git-fsmonitor--daemon - A Built-in File System Monitor + +SYNOPSIS +-------- +[verse] +'git fsmonitor--daemon' start +'git fsmonitor--daemon' run +'git fsmonitor--daemon' stop +'git fsmonitor--daemon' status + +DESCRIPTION +----------- + +A daemon to watch the working directory for file and directory +changes using platform-specific file system notification facilities. + +This daemon communicates directly with commands like `git status` +using the link:technical/api-simple-ipc.html[simple IPC] interface +instead of the slower linkgit:githooks[5] interface. + +This daemon is built into Git so that no third-party tools are +required. + +OPTIONS +------- + +start:: + Starts a daemon in the background. + +run:: + Runs a daemon in the foreground. + +stop:: + Stops the daemon running in the current working + directory, if present. + +status:: + Exits with zero status if a daemon is watching the + current working directory. + +REMARKS +------- + +This daemon is a long running process used to watch a single working +directory and maintain a list of the recently changed files and +directories. Performance of commands such as `git status` can be +increased if they just ask for a summary of changes to the working +directory and can avoid scanning the disk. + +When `core.fsmonitor` is set to `true` (see linkgit:git-config[1]) +commands, such as `git status`, will ask the daemon for changes and +automatically start it (if necessary). + +For more information see the "File System Monitor" section in +linkgit:git-update-index[1]. + +CAVEATS +------- + +The fsmonitor daemon does not currently know about submodules and does +not know to filter out file system events that happen within a +submodule. If fsmonitor daemon is watching a super repo and a file is +modified within the working directory of a submodule, it will report +the change (as happening against the super repo). However, the client +will properly ignore these extra events, so performance may be affected +but it will not cause an incorrect result. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index 2853f168d97..53ea48a04e2 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -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. @@ -509,8 +511,8 @@ 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 +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. From patchwork Tue Mar 1 18:43:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765049 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1464BC433EF for ; Tue, 1 Mar 2022 18:43:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237052AbiCASod (ORCPT ); Tue, 1 Mar 2022 13:44:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54586 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237032AbiCASoX (ORCPT ); Tue, 1 Mar 2022 13:44:23 -0500 Received: from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com [IPv6:2a00:1450:4864:20::32f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8892E286D5 for ; Tue, 1 Mar 2022 10:43:41 -0800 (PST) Received: by mail-wm1-x32f.google.com with SMTP id m42-20020a05600c3b2a00b00382ab337e14so600602wms.3 for ; Tue, 01 Mar 2022 10:43:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=qHwl1k+mT7kL/vCpcTSTxB1s0NWzJtpH1afNGYRMp+8=; b=ArJm/gAqEL1QckNqcWc1v4x2lcQZgRGNiKp64EyqsL/q2TAnKK+BtGRcRHhGHuJwMm 0ylcOcSh0h4HFJbTWLeRn0DW0uGX4mCf+lu+blK65e4BPBagFWr+7MOag3Z21pwnz7/i Mbqo9HndGgBMvZoQjxmM+4tyV5rrKZ/GKdhuCf5P47C93hyX6bkdpAZtqUkDw/X1hCqV ex2bcluuX1cCDsXQKBwOoMlxU4E5crNqLJFKpN1935UhbMIEafCq1s30xvFe9RVubbyW a8lM7kmMp6+sGaYxhiXU0TntSJDe3Z+KWWKIs8XNMDmDgtrbXWG9LuIFo+kHfYp7YVg8 CAww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=qHwl1k+mT7kL/vCpcTSTxB1s0NWzJtpH1afNGYRMp+8=; b=uN2XD/CpPiRyKrRk5h2yXA3N1pt70Qpec7zcwOT7zejjR7jfAVFl1IO5A4LLngcH0/ XK7tV7NM3QW6VzxJH9lzbuGnFg/fkbBwpgUnSu1Ml6X78mWGMXbwhB8vPPqVgQ8jb3uL ez81X268avIsHPTP/84KnwewHFV0XKSX7EGCE1vWqtPwDjl+kfrPl6IoR6hof6El8PDq KYrOv9U9n+Tlo3jGMMni8HKRyZLQRqkEMCup24kVumNQW2WST68kqf7MyWryedj9+LDg i7n40HTkZ3zdCwYh8oqNVjYBwpMYmwr95ksmHIn7Ag0EiOW7aujAXI0969pQxA1002o4 0IxA== X-Gm-Message-State: AOAM530xoOCdBhlZSknoVR+If0L8B7DiDPTMHtqyOfxiya880U7e6WBW PHVmlpvrF2XAcdzwG2OKYFZbcukgaCg= X-Google-Smtp-Source: ABdhPJxQpIc5mw0FT5GeXHEI4RjofXpoNpndjJMKhpiaEgAqrw6biufZccPqaCRZhzTkOae12eAl1A== X-Received: by 2002:a05:600c:14d5:b0:381:504f:ca91 with SMTP id i21-20020a05600c14d500b00381504fca91mr11691683wmh.93.1646160219944; Tue, 01 Mar 2022 10:43:39 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id w6-20020a05600018c600b001efe4a49566sm5985577wrq.78.2022.03.01.10.43.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:39 -0800 (PST) Message-Id: <9ce938c69b5a3e47b8c0a68379892955c2d7da88.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:08 +0000 Subject: [PATCH v6 06/30] fsmonitor--daemon: add a built-in fsmonitor daemon Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Create a built-in file system monitoring daemon that can be used by the existing `fsmonitor` feature (protocol API and index extension) to improve the performance of various Git commands, such as `status`. The `fsmonitor--daemon` feature builds upon the `Simple IPC` API and provides an alternative to hook access to existing fsmonitors such as `watchman`. This commit merely adds the new command without any functionality. Co-authored-by: Johannes Schindelin Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- .gitignore | 1 + Makefile | 1 + builtin.h | 1 + builtin/fsmonitor--daemon.c | 46 +++++++++++++++++++++++++++++++++++++ git.c | 1 + 5 files changed, 50 insertions(+) create mode 100644 builtin/fsmonitor--daemon.c diff --git a/.gitignore b/.gitignore index f817c509ec0..e81de1063a4 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,7 @@ /git-format-patch /git-fsck /git-fsck-objects +/git-fsmonitor--daemon /git-gc /git-get-tar-commit-id /git-grep diff --git a/Makefile b/Makefile index 707a56d4c11..5af1d5b112e 100644 --- a/Makefile +++ b/Makefile @@ -1114,6 +1114,7 @@ BUILTIN_OBJS += builtin/fmt-merge-msg.o BUILTIN_OBJS += builtin/for-each-ref.o BUILTIN_OBJS += builtin/for-each-repo.o BUILTIN_OBJS += builtin/fsck.o +BUILTIN_OBJS += builtin/fsmonitor--daemon.o BUILTIN_OBJS += builtin/gc.o BUILTIN_OBJS += builtin/get-tar-commit-id.o BUILTIN_OBJS += builtin/grep.o diff --git a/builtin.h b/builtin.h index 83379f3832c..40e9ecc8485 100644 --- a/builtin.h +++ b/builtin.h @@ -159,6 +159,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix); int cmd_for_each_repo(int argc, const char **argv, const char *prefix); int cmd_format_patch(int argc, const char **argv, const char *prefix); int cmd_fsck(int argc, const char **argv, const char *prefix); +int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix); int cmd_gc(int argc, const char **argv, const char *prefix); int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix); int cmd_grep(int argc, const char **argv, const char *prefix); diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c new file mode 100644 index 00000000000..f0498793379 --- /dev/null +++ b/builtin/fsmonitor--daemon.c @@ -0,0 +1,46 @@ +#include "builtin.h" +#include "config.h" +#include "parse-options.h" +#include "fsmonitor.h" +#include "fsmonitor-ipc.h" +#include "simple-ipc.h" +#include "khash.h" + +static const char * const builtin_fsmonitor__daemon_usage[] = { + NULL +}; + +#ifdef HAVE_FSMONITOR_DAEMON_BACKEND + +int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) +{ + const char *subcmd; + + struct option options[] = { + OPT_END() + }; + + git_config(git_default_config, NULL); + + argc = parse_options(argc, argv, prefix, options, + builtin_fsmonitor__daemon_usage, 0); + if (argc != 1) + usage_with_options(builtin_fsmonitor__daemon_usage, options); + subcmd = argv[0]; + + die(_("Unhandled subcommand '%s'"), subcmd); +} + +#else +int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) +{ + struct option options[] = { + OPT_END() + }; + + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_fsmonitor__daemon_usage, options); + + die(_("fsmonitor--daemon not supported on this platform")); +} +#endif diff --git a/git.c b/git.c index a25940d72e8..3d8e48cf555 100644 --- a/git.c +++ b/git.c @@ -537,6 +537,7 @@ static struct cmd_struct commands[] = { { "format-patch", cmd_format_patch, RUN_SETUP }, { "fsck", cmd_fsck, RUN_SETUP }, { "fsck-objects", cmd_fsck, RUN_SETUP }, + { "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT }, { "grep", cmd_grep, RUN_SETUP_GENTLY }, From patchwork Tue Mar 1 18:43:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765051 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 634D8C433EF for ; Tue, 1 Mar 2022 18:44:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237085AbiCASo6 (ORCPT ); Tue, 1 Mar 2022 13:44:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55014 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237037AbiCASo1 (ORCPT ); Tue, 1 Mar 2022 13:44:27 -0500 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 68DAE2B26E for ; Tue, 1 Mar 2022 10:43:42 -0800 (PST) Received: by mail-wr1-x42a.google.com with SMTP id bk29so4649655wrb.4 for ; Tue, 01 Mar 2022 10:43:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=3PLwCteJ9y2IKK4YgyfW1TpJLAFrB0rwJ1mFNfWqUuM=; b=ZWVf0P6Faq+EExttFjy3gJ8sB+/PIYdgQkJerRYu3zFi4IRYr0NY8Y2uCog9knVZA+ x1Nj9xLAb+lBHY2IkYhqtf8FFp6Tvg1tKZUGYHtMZA1H4cFEBQzpdCnT++8uOwF3SbK4 xdqs1kouJCuI6oIT2QsQslAEUlYL/+jpbRPNX56rXQSQzK9ql118Apilq5VrYV7er3XM f3ijycmLKeMcBccV3GBiXUs9VnjWcOTU+xlLaVaDHAhc05b8W9FZkJrwaROWEzGa4g0k dzlnL1/LFAt4f5WTsh4zJbqf8qPBs32AQ/Cyo8k2tYE3s+jgiTWY6CC1+JLR/Ic6VxCm 1OkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=3PLwCteJ9y2IKK4YgyfW1TpJLAFrB0rwJ1mFNfWqUuM=; b=xwkw5g7VCf+08JvyeuxOrli2SAKd4Zq+SYbiRXzJiG1WJmPcM147ihSiWzSFKn/R9i knLJI+tuKen/GfqAbuAA93B0gWr3XDWQChwckbG8r5inkJrk0y5AKsoV0vwOFDNomh1H Qgs5vtDfQ07OmVXHcoofc5OtFABsx8jAzP8T/Mkhj0tB3ZOoQID0aMh7rikrSh/oh+3B rE3hssbGwio4bacPtgEbVB2B6rnVFS/k1s7uOXfngNsn0r1RhNTthB9pZwvyAfLOlhvq RTiiyunMN2L1BrQgVl6cjXvo4BAaOj1scwhZurCSVqSztkxAGGWq+yOf9v5u9VdNW8bO saMQ== X-Gm-Message-State: AOAM532guq5BLWbGRHN78tAvfL9JqEIb/8YU5TTMDvtMAMPXwAB3MjwD z3QI3dOPCEfmpdbGpYGuHdpGrxGYXy4= X-Google-Smtp-Source: ABdhPJzakQmAnyZg+CqsZNN9Bycu5XsTygCbnVrD9wWxugyEm1rGSe/4r6Kcueyqbusasmpu8Hu7bg== X-Received: by 2002:a5d:64c1:0:b0:1e4:987a:51b with SMTP id f1-20020a5d64c1000000b001e4987a051bmr21037059wri.471.1646160220753; Tue, 01 Mar 2022 10:43:40 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i15-20020a05600011cf00b001edc2966dd4sm14165452wrx.47.2022.03.01.10.43.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:40 -0800 (PST) Message-Id: <3bd7e6a051e7fca1ac2a78e038587de10fd9401a.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:09 +0000 Subject: [PATCH v6 07/30] fsmonitor--daemon: implement 'stop' and 'status' commands Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Implement `stop` and `status` client commands to control and query the status of a `fsmonitor--daemon` server process (and implicitly start a server process if necessary). Later commits will implement the actual server and monitor the file system. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index f0498793379..5e3178b8bdd 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -7,10 +7,55 @@ #include "khash.h" static const char * const builtin_fsmonitor__daemon_usage[] = { + N_("git fsmonitor--daemon stop"), + N_("git fsmonitor--daemon status"), NULL }; #ifdef HAVE_FSMONITOR_DAEMON_BACKEND +/* + * Acting as a CLIENT. + * + * Send a "quit" command to the `git-fsmonitor--daemon` (if running) + * and wait for it to shutdown. + */ +static int do_as_client__send_stop(void) +{ + struct strbuf answer = STRBUF_INIT; + int ret; + + ret = fsmonitor_ipc__send_command("quit", &answer); + + /* The quit command does not return any response data. */ + strbuf_release(&answer); + + if (ret) + return ret; + + trace2_region_enter("fsm_client", "polling-for-daemon-exit", NULL); + while (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING) + sleep_millisec(50); + trace2_region_leave("fsm_client", "polling-for-daemon-exit", NULL); + + return 0; +} + +static int do_as_client__status(void) +{ + enum ipc_active_state state = fsmonitor_ipc__get_state(); + + switch (state) { + case IPC_STATE__LISTENING: + printf(_("fsmonitor-daemon is watching '%s'\n"), + the_repository->worktree); + return 0; + + default: + printf(_("fsmonitor-daemon is not watching '%s'\n"), + the_repository->worktree); + return 1; + } +} int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) { @@ -28,6 +73,12 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) usage_with_options(builtin_fsmonitor__daemon_usage, options); subcmd = argv[0]; + if (!strcmp(subcmd, "stop")) + return !!do_as_client__send_stop(); + + if (!strcmp(subcmd, "status")) + return !!do_as_client__status(); + die(_("Unhandled subcommand '%s'"), subcmd); } From patchwork Tue Mar 1 18:43:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765050 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61057C433F5 for ; Tue, 1 Mar 2022 18:44:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237102AbiCASoz (ORCPT ); Tue, 1 Mar 2022 13:44:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237023AbiCASo1 (ORCPT ); Tue, 1 Mar 2022 13:44:27 -0500 Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3C66F2A263 for ; Tue, 1 Mar 2022 10:43:43 -0800 (PST) Received: by mail-wr1-x434.google.com with SMTP id u1so21922062wrg.11 for ; Tue, 01 Mar 2022 10:43:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=sSAmNlfeMp/SuWaNgnRs8TTLxikird+cAhYFRFbfq6s=; b=qnCwhso+r4TvkGhw3VyzkXB5uMAVlzOF8k6uXqrTWcJeprvD2DIZx+2A675IY8Lmo2 lhjPW68xktzolT00pnf7nrA2i6UrZvu13N9krwGKNDHYrzhzB5BrM2JChd2tsOKOmKp7 CiSsOwFv0sVzlQckgVQ8RofpIou5zdGseVBU0ytO0E3gG+M33ikTXjaW6AjxuJQvMCy8 C0CC1p2JUnjI/jbT5In/0332A/9PKGy8jfRKeTNcFf/45GdGaWKvgmr4kGolkT14RyOC FKvDAYyGKaT/LzrNooGQjtwU6GJCzbxxGJhs6PtVQGjt8gWvZLFhWfVk//ahO9y0oK88 AfYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=sSAmNlfeMp/SuWaNgnRs8TTLxikird+cAhYFRFbfq6s=; b=Eg6ExdcM82cegr1S9pPoBf09zSPizEz56mvBTooC+rEx/1yQ2CUCKKudd7t2cFXcub 3EOJQ1EsJGpS16S9jeaUi/l6iQbID/8bBCWr05ixW/AtB1GNaQMUwaxs2Fqd0aDvvfPe zTbf9+pZvtzAUc6fTlSqJFbNhhTTdnF/lletzifY9W9cK1YHulJPRSEfDT7/XBw8/Y8p 5lEBZb4bmFjMJETFpScxupF5eLmndeno7ZfORfmRyBmtp7P13aYWJ5HhkOJPzQMOLis6 ka7JbLC+VQfCy4LI4LZhQOQ8JyRGaO4WtJHw3flSJWRpZEGCs1gBuMFfirm/gb1tYiM1 qbZA== X-Gm-Message-State: AOAM531s5x7+xUnJa+NJmVOwf9OUKD/HbWvie0TAnx3DJLXNxEUErf4D NmpctE8o9f1jG64zWnR8UP/vTseLeB8= X-Google-Smtp-Source: ABdhPJwdL2jBaGpjOD2l9UGAK1E6uZxsByTEAyY7tJskvAMLqG17KuH2G5C62pvy3pPFea39qzclKw== X-Received: by 2002:a05:6000:18a1:b0:1ef:8e17:e82c with SMTP id b1-20020a05600018a100b001ef8e17e82cmr12230049wri.254.1646160221534; Tue, 01 Mar 2022 10:43:41 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 17-20020a05600c241100b0037c01ad7152sm4428592wmp.14.2022.03.01.10.43.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:41 -0800 (PST) Message-Id: <92d3e54da7f1e6148ba521b5377af17900f7d42d.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:10 +0000 Subject: [PATCH v6 08/30] compat/fsmonitor/fsm-listen-win32: stub in backend for Windows Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Stub in empty filesystem listener backend for fsmonitor--daemon on Windows. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- Makefile | 13 ++++++++ compat/fsmonitor/fsm-listen-win32.c | 21 +++++++++++++ compat/fsmonitor/fsm-listen.h | 49 +++++++++++++++++++++++++++++ config.mak.uname | 10 ++++++ contrib/buildsystems/CMakeLists.txt | 7 +++++ repo-settings.c | 1 + 6 files changed, 101 insertions(+) create mode 100644 compat/fsmonitor/fsm-listen-win32.c create mode 100644 compat/fsmonitor/fsm-listen.h diff --git a/Makefile b/Makefile index 5af1d5b112e..26567d4f772 100644 --- a/Makefile +++ b/Makefile @@ -470,6 +470,11 @@ all:: # directory, and the JSON compilation database 'compile_commands.json' will be # created at the root of the repository. # +# If your platform supports a built-in fsmonitor backend, set +# FSMONITOR_DAEMON_BACKEND to the "" of the corresponding +# `compat/fsmonitor/fsm-listen-.c` that implements the +# `fsm_listen__*()` routines. +# # Define DEVELOPER to enable more compiler warnings. Compiler version # and family are auto detected, but could be overridden by defining # COMPILER_FEATURES (see config.mak.dev). You can still set @@ -1968,6 +1973,11 @@ ifdef NEED_ACCESS_ROOT_HANDLER COMPAT_OBJS += compat/access.o endif +ifdef FSMONITOR_DAEMON_BACKEND + COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND + COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK = NoThanks endif @@ -2887,6 +2897,9 @@ GIT-BUILD-OPTIONS: FORCE @echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+ @echo SANITIZE_LEAK=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_LEAK)))'\' >>$@+ @echo X=\'$(X)\' >>$@+ +ifdef FSMONITOR_DAEMON_BACKEND + @echo FSMONITOR_DAEMON_BACKEND=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_DAEMON_BACKEND)))'\' >>$@+ +endif ifdef TEST_OUTPUT_DIRECTORY @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+ endif diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c new file mode 100644 index 00000000000..916cbea254f --- /dev/null +++ b/compat/fsmonitor/fsm-listen-win32.c @@ -0,0 +1,21 @@ +#include "cache.h" +#include "config.h" +#include "fsmonitor.h" +#include "fsm-listen.h" + +void fsm_listen__stop_async(struct fsmonitor_daemon_state *state) +{ +} + +void fsm_listen__loop(struct fsmonitor_daemon_state *state) +{ +} + +int fsm_listen__ctor(struct fsmonitor_daemon_state *state) +{ + return -1; +} + +void fsm_listen__dtor(struct fsmonitor_daemon_state *state) +{ +} diff --git a/compat/fsmonitor/fsm-listen.h b/compat/fsmonitor/fsm-listen.h new file mode 100644 index 00000000000..f0539349baf --- /dev/null +++ b/compat/fsmonitor/fsm-listen.h @@ -0,0 +1,49 @@ +#ifndef FSM_LISTEN_H +#define FSM_LISTEN_H + +/* This needs to be implemented by each backend */ + +#ifdef HAVE_FSMONITOR_DAEMON_BACKEND + +struct fsmonitor_daemon_state; + +/* + * Initialize platform-specific data for the fsmonitor listener thread. + * This will be called from the main thread PRIOR to staring the + * fsmonitor_fs_listener thread. + * + * Returns 0 if successful. + * Returns -1 otherwise. + */ +int fsm_listen__ctor(struct fsmonitor_daemon_state *state); + +/* + * Cleanup platform-specific data for the fsmonitor listener thread. + * This will be called from the main thread AFTER joining the listener. + */ +void fsm_listen__dtor(struct fsmonitor_daemon_state *state); + +/* + * The main body of the platform-specific event loop to watch for + * filesystem events. This will run in the fsmonitor_fs_listen thread. + * + * It should call `ipc_server_stop_async()` if the listener thread + * prematurely terminates (because of a filesystem error or if it + * detects that the .git directory has been deleted). (It should NOT + * do so if the listener thread receives a normal shutdown signal from + * the IPC layer.) + * + * It should set `state->error_code` to -1 if the daemon should exit + * with an error. + */ +void fsm_listen__loop(struct fsmonitor_daemon_state *state); + +/* + * Gently request that the fsmonitor listener thread shutdown. + * It does not wait for it to stop. The caller should do a JOIN + * to wait for it. + */ +void fsm_listen__stop_async(struct fsmonitor_daemon_state *state); + +#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */ +#endif /* FSM_LISTEN_H */ diff --git a/config.mak.uname b/config.mak.uname index 4352ea39e9b..26074f56bed 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -435,6 +435,11 @@ ifeq ($(uname_S),Windows) # so we don't need this: # # SNPRINTF_RETURNS_BOGUS = YesPlease + + # The builtin FSMonitor requires Named Pipes and Threads on Windows. + # These are always available, so we do not have to conditionally + # support it. + FSMONITOR_DAEMON_BACKEND = win32 NO_SVN_TESTS = YesPlease RUNTIME_PREFIX = YesPlease HAVE_WPGMPTR = YesWeDo @@ -619,6 +624,11 @@ ifeq ($(uname_S),MINGW) NO_STRTOUMAX = YesPlease NO_MKDTEMP = YesPlease NO_SVN_TESTS = YesPlease + + # The builtin FSMonitor requires Named Pipes and Threads on Windows. + # These are always available, so we do not have to conditionally + # support it. + FSMONITOR_DAEMON_BACKEND = win32 RUNTIME_PREFIX = YesPlease HAVE_WPGMPTR = YesWeDo NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index e44232f85d3..0963629db7f 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -285,6 +285,13 @@ else() endif() endif() +if(SUPPORTS_SIMPLE_IPC) + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c) + endif() +endif() + set(EXE_EXTENSION ${CMAKE_EXECUTABLE_SUFFIX}) #header checks diff --git a/repo-settings.c b/repo-settings.c index b4fbd16cdcc..2dfcb2b6542 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -2,6 +2,7 @@ #include "config.h" #include "repository.h" #include "midx.h" +#include "compat/fsmonitor/fsm-listen.h" static void repo_cfg_bool(struct repository *r, const char *key, int *dest, int def) From patchwork Tue Mar 1 18:43:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765053 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4C643C433EF for ; Tue, 1 Mar 2022 18:44:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237073AbiCASpE (ORCPT ); Tue, 1 Mar 2022 13:45:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55088 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237045AbiCASo2 (ORCPT ); Tue, 1 Mar 2022 13:44:28 -0500 Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 00D2F41F9C for ; Tue, 1 Mar 2022 10:43:43 -0800 (PST) Received: by mail-wr1-x42f.google.com with SMTP id e10so4375801wro.13 for ; Tue, 01 Mar 2022 10:43:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=JoyUcWYc53GOiCIk4ZkiWSvvHTSDt24PFwNxe1AnEQQ=; b=Gn8eIb7NmGyFDyWQ/XWLPVed/s0afzP+fhZ1iM9UB71jgkOGZ0dWCqSbOJtfUMf9H9 W036ZU423wiwi+zrLEsbfg60u2gkezKbCpQJaSVBvDIHR9ndqLxBi8rjQ54WrJR4rajR IeSWUh2ofvb/y6MsjxwadQWNmtHBIP16hq0Ypt6FN/veIkTRdRYXtI3e3woXz6k355SE drXV5L3MnCIAhhogjHJ+eT2znLnE7j9O9zyERTsPv4wIsuYguSoPuV1ur+xIqLsXhO6v HYqoN4Eysk5V5bANjxs8unxyjX9d2eG+ZIUDNpMsXfC27DJ+eIYeCTbORYXQxGrimMLF eDMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=JoyUcWYc53GOiCIk4ZkiWSvvHTSDt24PFwNxe1AnEQQ=; b=cw8Jqeqq8VykJss+TpuSbVS1734BIuyttQsgBqpv2YFoKkKQ9369vd3fH7SNGa1GUS k0xC5WbDYe+b+4QDcsSJdA3oDL7Y9ViPuHug+9mrWCMNK4fEpNKH+cRADByCpewGe1Oh XMDohPTrmvLoCjq9wXgfX3UWkudJ1kB56gRq1q/xHPsb1sBcYTFndNN4/Dvo6okwVwXS BFababazppjFED3SWXraJU415z6PIrhqLAUfqK1YGEn9Lrock2XDdADhtQhSET99miMz OIYT4Oc9y1pFvaG8SUV8Z6NxBJgkdxYqcJFBn2h80ik4Amz+wu3x5AieH9EydP1F+lDc UHxA== X-Gm-Message-State: AOAM532nWMNx/mSX0DegKH28azWGr2lAqDJQvhZPyUyzFK9e1Ah1usze SFE+md7tXx2NMQJov6ldeXWC3FSHDeI= X-Google-Smtp-Source: ABdhPJyogS5+YIYV+QhYlNVc60aFvkeeF8tti8/bBAe0GVCEoQxnVVKdQH3/U9aR4Igkr1KF742SdQ== X-Received: by 2002:a5d:4a0c:0:b0:1ef:5a8d:efe5 with SMTP id m12-20020a5d4a0c000000b001ef5a8defe5mr18266491wrq.354.1646160222486; Tue, 01 Mar 2022 10:43:42 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id o15-20020a05600c4fcf00b00381614e5b60sm3589591wmq.34.2022.03.01.10.43.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:42 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:11 +0000 Subject: [PATCH v6 09/30] compat/fsmonitor/fsm-listen-darwin: stub in backend for Darwin Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Stub in empty implementation of fsmonitor--daemon backend for Darwin (aka MacOS). Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- compat/fsmonitor/fsm-listen-darwin.c | 20 ++++++++++++++++++++ config.mak.uname | 10 ++++++++++ contrib/buildsystems/CMakeLists.txt | 3 +++ 3 files changed, 33 insertions(+) create mode 100644 compat/fsmonitor/fsm-listen-darwin.c diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c new file mode 100644 index 00000000000..c84e3344ab9 --- /dev/null +++ b/compat/fsmonitor/fsm-listen-darwin.c @@ -0,0 +1,20 @@ +#include "cache.h" +#include "fsmonitor.h" +#include "fsm-listen.h" + +int fsm_listen__ctor(struct fsmonitor_daemon_state *state) +{ + return -1; +} + +void fsm_listen__dtor(struct fsmonitor_daemon_state *state) +{ +} + +void fsm_listen__stop_async(struct fsmonitor_daemon_state *state) +{ +} + +void fsm_listen__loop(struct fsmonitor_daemon_state *state) +{ +} diff --git a/config.mak.uname b/config.mak.uname index 26074f56bed..501970902da 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -157,6 +157,16 @@ ifeq ($(uname_S),Darwin) MSGFMT = /usr/local/opt/gettext/bin/msgfmt endif endif + + # The builtin FSMonitor on MacOS builds upon Simple-IPC. Both require + # Unix domain sockets and PThreads. + ifndef NO_PTHREADS + ifndef NO_UNIX_SOCKETS + FSMONITOR_DAEMON_BACKEND = darwin + endif + endif + + BASIC_LDFLAGS += -framework CoreServices endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 0963629db7f..ee0d7257b77 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -289,6 +289,9 @@ if(SUPPORTS_SIMPLE_IPC) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c) endif() endif() From patchwork Tue Mar 1 18:43:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765052 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 81A73C433EF for ; Tue, 1 Mar 2022 18:44:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237092AbiCASpB (ORCPT ); Tue, 1 Mar 2022 13:45:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55116 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229796AbiCASo2 (ORCPT ); Tue, 1 Mar 2022 13:44:28 -0500 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E71B657491 for ; Tue, 1 Mar 2022 10:43:44 -0800 (PST) Received: by mail-wr1-x435.google.com with SMTP id r10so21974792wrp.3 for ; Tue, 01 Mar 2022 10:43:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=1yHJ5otY9FrTLG95kozvyCYv3I7K7fGlxzvZNmfMDDM=; b=aUOPDF3hj4rSHknUCIPAI3abnA59RJgEf3VOfmnb0ISEL5HTwI7v6AfH6tLee/vNcF foeJWfzjypVLaWg2lDfo5u2u4yqbi7LJEpuGs4HLpMCRZtLx7wSKbk9rGK5W7fjVDTqU e1OxvR7qz5qbPQQVjdTAXxN9ue9VvbsDnOt5aMnP/m2ESei4hDiYv5NDssAH2PaFlpxi eEiKvV/2sQ8usMDYpyIXwqBt+IXA+3xpRQ4X137tu1Ctprs4fZFxVAzajh1cIjjxaeRD EaJDtZjd0zV8ORy1oZdNoZXp+w518BC9+hKaeKSQrLnzH5b1tVHZ2vPdid5ja1qKSuZ/ kaFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=1yHJ5otY9FrTLG95kozvyCYv3I7K7fGlxzvZNmfMDDM=; b=MVUBjcvv2536JIw1Oy+J5jij8PRiA6w/GPodET75iyJIYPDxad4ismnq/dtQEoeDYN sHTCM+KtLnu1+AXaIdo1ffvj9TGR3PqZAzWXbu5QlnthQ8ZfvRBqkCBbNjS8MXjzwoiE ICqc+p7ZbD3Q9JZlqBD1yaCB0TnIdNKOmFUWIvlr1puGhgikuTRBbRJPBeJlX1MBNViU K/Ygna6kCAsgEn6ibVO4XfnJlyQLO3px93zAq1hBIIRvYj24rSmVC88RKJ37juetKC5G IPU1kxJyKKEowJ9Ev0iXLxNN2rYswy4/i5CiY+HQaLoHh0WlEy3aRHI37gC6UTydkX/e mZOA== X-Gm-Message-State: AOAM5304fMysE+cU6DSTSdlmq69ekOb2+zxoGvGKSb1Sd3uvJLfuS7g3 UflsdgBrTKhXe5YOXrhqqmlGdfeeNlY= X-Google-Smtp-Source: ABdhPJzNEMgRcZFDymElNtr0KYIgvxJ83V7tZ+9E9VayDkp/iX0LKhr/rqYjH7tKZZNsr+ou4MSFdA== X-Received: by 2002:adf:f5c3:0:b0:1ed:c1da:9684 with SMTP id k3-20020adff5c3000000b001edc1da9684mr20728964wrp.245.1646160223234; Tue, 01 Mar 2022 10:43:43 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id o2-20020a056000010200b001ea9626b8fasm8329118wrx.19.2022.03.01.10.43.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:42 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:12 +0000 Subject: [PATCH v6 10/30] fsmonitor--daemon: implement 'run' command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Implement `run` command to try to begin listening for file system events. This version defines the thread structure with a single fsmonitor_fs_listen thread to watch for file system events and a simple IPC thread pool to watch for connection from Git clients over a well-known named pipe or Unix domain socket. This commit does not actually do anything yet because the platform backends are still just stubs. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 228 +++++++++++++++++++++++++++++++++++- fsmonitor--daemon.h | 34 ++++++ 2 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 fsmonitor--daemon.h diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 5e3178b8bdd..950614f82f6 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -3,16 +3,52 @@ #include "parse-options.h" #include "fsmonitor.h" #include "fsmonitor-ipc.h" +#include "compat/fsmonitor/fsm-listen.h" +#include "fsmonitor--daemon.h" #include "simple-ipc.h" #include "khash.h" static const char * const builtin_fsmonitor__daemon_usage[] = { + N_("git fsmonitor--daemon run []"), N_("git fsmonitor--daemon stop"), N_("git fsmonitor--daemon status"), NULL }; #ifdef HAVE_FSMONITOR_DAEMON_BACKEND +/* + * Global state loaded from config. + */ +#define FSMONITOR__IPC_THREADS "fsmonitor.ipcthreads" +static int fsmonitor__ipc_threads = 8; + +#define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup" +static int fsmonitor__announce_startup = 0; + +static int fsmonitor_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, FSMONITOR__IPC_THREADS)) { + int i = git_config_int(var, value); + if (i < 1) + return error(_("value of '%s' out of range: %d"), + FSMONITOR__IPC_THREADS, i); + fsmonitor__ipc_threads = i; + return 0; + } + + if (!strcmp(var, FSMONITOR__ANNOUNCE_STARTUP)) { + int is_bool; + int i = git_config_bool_or_int(var, value, &is_bool); + if (i < 0) + return error(_("value of '%s' not bool or int: %d"), + var, i); + fsmonitor__announce_startup = i; + return 0; + } + + return git_default_config(var, value, cb); +} + /* * Acting as a CLIENT. * @@ -57,15 +93,198 @@ static int do_as_client__status(void) } } +static ipc_server_application_cb handle_client; + +static int handle_client(void *data, + const char *command, size_t command_len, + ipc_server_reply_cb *reply, + struct ipc_server_reply_data *reply_data) +{ + /* struct fsmonitor_daemon_state *state = data; */ + int result; + + /* + * The Simple IPC API now supports {char*, len} arguments, but + * FSMonitor always uses proper null-terminated strings, so + * we can ignore the command_len argument. (Trust, but verify.) + */ + if (command_len != strlen(command)) + BUG("FSMonitor assumes text messages"); + + trace2_region_enter("fsmonitor", "handle_client", the_repository); + trace2_data_string("fsmonitor", the_repository, "request", command); + + result = 0; /* TODO Do something here. */ + + trace2_region_leave("fsmonitor", "handle_client", the_repository); + + return result; +} + +static void *fsm_listen__thread_proc(void *_state) +{ + struct fsmonitor_daemon_state *state = _state; + + trace2_thread_start("fsm-listen"); + + trace_printf_key(&trace_fsmonitor, "Watching: worktree '%s'", + state->path_worktree_watch.buf); + if (state->nr_paths_watching > 1) + trace_printf_key(&trace_fsmonitor, "Watching: gitdir '%s'", + state->path_gitdir_watch.buf); + + fsm_listen__loop(state); + + trace2_thread_exit(); + return NULL; +} + +static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state) +{ + struct ipc_server_opts ipc_opts = { + .nr_threads = fsmonitor__ipc_threads, + + /* + * We know that there are no other active threads yet, + * so we can let the IPC layer temporarily chdir() if + * it needs to when creating the server side of the + * Unix domain socket. + */ + .uds_disallow_chdir = 0 + }; + + /* + * Start the IPC thread pool before the we've started the file + * system event listener thread so that we have the IPC handle + * before we need it. + */ + if (ipc_server_run_async(&state->ipc_server_data, + fsmonitor_ipc__get_path(), &ipc_opts, + handle_client, state)) + return error_errno( + _("could not start IPC thread pool on '%s'"), + fsmonitor_ipc__get_path()); + + /* + * Start the fsmonitor listener thread to collect filesystem + * events. + */ + if (pthread_create(&state->listener_thread, NULL, + fsm_listen__thread_proc, state) < 0) { + ipc_server_stop_async(state->ipc_server_data); + ipc_server_await(state->ipc_server_data); + + return error(_("could not start fsmonitor listener thread")); + } + + /* + * The daemon is now fully functional in background threads. + * Wait for the IPC thread pool to shutdown (whether by client + * request or from filesystem activity). + */ + ipc_server_await(state->ipc_server_data); + + /* + * The fsmonitor listener thread may have received a shutdown + * event from the IPC thread pool, but it doesn't hurt to tell + * it again. And wait for it to shutdown. + */ + fsm_listen__stop_async(state); + pthread_join(state->listener_thread, NULL); + + return state->error_code; +} + +static int fsmonitor_run_daemon(void) +{ + struct fsmonitor_daemon_state state; + int err; + + memset(&state, 0, sizeof(state)); + + pthread_mutex_init(&state.main_lock, NULL); + state.error_code = 0; + state.current_token_data = NULL; + + /* Prepare to (recursively) watch the directory. */ + strbuf_init(&state.path_worktree_watch, 0); + strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree())); + state.nr_paths_watching = 1; + + /* + * We create and delete cookie files somewhere inside the .git + * directory to help us keep sync with the file system. If + * ".git" is not a directory, then is not inside the + * cone of , so set up a second watch to watch + * the so that we get events for the cookie files. + */ + strbuf_init(&state.path_gitdir_watch, 0); + strbuf_addbuf(&state.path_gitdir_watch, &state.path_worktree_watch); + strbuf_addstr(&state.path_gitdir_watch, "/.git"); + if (!is_directory(state.path_gitdir_watch.buf)) { + strbuf_reset(&state.path_gitdir_watch); + strbuf_addstr(&state.path_gitdir_watch, absolute_path(get_git_dir())); + state.nr_paths_watching = 2; + } + + /* + * Confirm that we can create platform-specific resources for the + * filesystem listener before we bother starting all the threads. + */ + if (fsm_listen__ctor(&state)) { + err = error(_("could not initialize listener thread")); + goto done; + } + + err = fsmonitor_run_daemon_1(&state); + +done: + pthread_mutex_destroy(&state.main_lock); + fsm_listen__dtor(&state); + + ipc_server_free(state.ipc_server_data); + + strbuf_release(&state.path_worktree_watch); + strbuf_release(&state.path_gitdir_watch); + + return err; +} + +static int try_to_run_foreground_daemon(void) +{ + /* + * Technically, we don't need to probe for an existing daemon + * process, since we could just call `fsmonitor_run_daemon()` + * and let it fail if the pipe/socket is busy. + * + * However, this method gives us a nicer error message for a + * common error case. + */ + if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING) + die("fsmonitor--daemon is already running '%s'", + the_repository->worktree); + + if (fsmonitor__announce_startup) { + fprintf(stderr, _("running fsmonitor-daemon in '%s'\n"), + the_repository->worktree); + fflush(stderr); + } + + return !!fsmonitor_run_daemon(); +} + int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) { const char *subcmd; struct option options[] = { + OPT_INTEGER(0, "ipc-threads", + &fsmonitor__ipc_threads, + N_("use ipc worker threads")), OPT_END() }; - git_config(git_default_config, NULL); + git_config(fsmonitor_config, NULL); argc = parse_options(argc, argv, prefix, options, builtin_fsmonitor__daemon_usage, 0); @@ -73,6 +292,13 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) usage_with_options(builtin_fsmonitor__daemon_usage, options); subcmd = argv[0]; + if (fsmonitor__ipc_threads < 1) + die(_("invalid 'ipc-threads' value (%d)"), + fsmonitor__ipc_threads); + + if (!strcmp(subcmd, "run")) + return !!try_to_run_foreground_daemon(); + if (!strcmp(subcmd, "stop")) return !!do_as_client__send_stop(); diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h new file mode 100644 index 00000000000..3009c1a83de --- /dev/null +++ b/fsmonitor--daemon.h @@ -0,0 +1,34 @@ +#ifndef FSMONITOR_DAEMON_H +#define FSMONITOR_DAEMON_H + +#ifdef HAVE_FSMONITOR_DAEMON_BACKEND + +#include "cache.h" +#include "dir.h" +#include "run-command.h" +#include "simple-ipc.h" +#include "thread-utils.h" + +struct fsmonitor_batch; +struct fsmonitor_token_data; + +struct fsmonitor_daemon_backend_data; /* opaque platform-specific data */ + +struct fsmonitor_daemon_state { + pthread_t listener_thread; + pthread_mutex_t main_lock; + + struct strbuf path_worktree_watch; + struct strbuf path_gitdir_watch; + int nr_paths_watching; + + struct fsmonitor_token_data *current_token_data; + + int error_code; + struct fsmonitor_daemon_backend_data *backend_data; + + struct ipc_server_data *ipc_server_data; +}; + +#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */ +#endif /* FSMONITOR_DAEMON_H */ From patchwork Tue Mar 1 18:43:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765054 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1513C433F5 for ; Tue, 1 Mar 2022 18:44:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237057AbiCASpH (ORCPT ); Tue, 1 Mar 2022 13:45:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237035AbiCASox (ORCPT ); Tue, 1 Mar 2022 13:44:53 -0500 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D959C5D1B7 for ; Tue, 1 Mar 2022 10:43:45 -0800 (PST) Received: by mail-wm1-x32d.google.com with SMTP id i66so1821845wma.5 for ; Tue, 01 Mar 2022 10:43:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=s2EOuiBEqM7u7pum9IZt5+l8da9mgIKwm8vheBUni5E=; b=htTMEtGgmEV5L7TJwUqR63n9tXM/p/BSJ2O+wA2/dBkJW7wsug8xG8d7CDAfDYcTrT yvFtIE/CmDTmHpERGl2Dw7OY1HNCD8Q2JDy4xDEnqv6x+CCd+SFiplPPFIB7KBMuMVkX npeIy2fvgyDAP4Cj0y84cyEHSr2Ue3lMgCP0isvYHLvA5AORSlFGYsOhuTOKACK4/JLV AnBXbBLYxokJk4HDy391FeZipVmWg6bnGDc1Ch5Kli2fxWnctEOd12yDOamz3ccm1Y0w OxofkRA2YIs0l5BfDQxzV4AA2Y6Dk1u5hA1CEQMmGptNmqa47VjKyyhgKBzXUyPb0YzY JitQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=s2EOuiBEqM7u7pum9IZt5+l8da9mgIKwm8vheBUni5E=; b=76SrO7YePRC69eIrV48w3SRbHu11yPmH/txvJP6tJy2hyQ3h0vQaeGUMmIWu4vzcoj LWoxBv2uMpVctJjDNA6+gnmzJuIiorcUvQiX6x3ZMiWEN5p9bqbqNmJKkG2soo3At4FP EkJfPClyvDE8CIKbagYhHKcRz8OqPaKdmak5EeHAon4A2iGBOFxfd7NrsXeoFyLhQTwG dkRKm7vWmog53LCDZc5mg8acw2TxyEO50KLxn6U30OBRSCZmck4rXGXRguTwcroTQosx YQUYjPjhWrXiu+cXIhecbAEWQOezS+SxKSPvAeGnqz5+bQS+sheoC41PWxa89QTntRu1 ybaw== X-Gm-Message-State: AOAM530KlOaCNhT2ouyMNRjyvRDWjhlYN3MAh6PWOcD5SiikMHnjcO+f gKO+YOFjj/VBMO1rC8WFLcR9pYq7HxI= X-Google-Smtp-Source: ABdhPJwSWKkkx6AGEq8YWQ4kujujdhLaJJKW6f0Wew6gKwT696+o8Oi2PYm6teI7TSOqD3b5Z3WVUw== X-Received: by 2002:a05:600c:4202:b0:382:a5d7:9ce5 with SMTP id x2-20020a05600c420200b00382a5d79ce5mr2038077wmh.45.1646160224178; Tue, 01 Mar 2022 10:43:44 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id b1-20020a5d4d81000000b001e6993398e2sm14125775wru.75.2022.03.01.10.43.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:43 -0800 (PST) Message-Id: <8de40b0fe8b097534630cfac28fc7c84dd304463.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:13 +0000 Subject: [PATCH v6 11/30] fsmonitor--daemon: implement 'start' command Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Implement 'git fsmonitor--daemon start' command. This command starts an instance of 'git fsmonitor--daemon run' in the background using the new 'start_bg_command()' function. We avoid the fork-and-call technique on Unix systems in favor of a fork-and-exec technique. This gives us more uniform Trace2 child-* events. It also makes our usage more consistent with Windows usage. On Windows, teach 'git fsmonitor--daemon run' to optionally call 'FreeConsole()' to release handles to the inherited Win32 console (despite being passed invalid handles for stdin/out/err). Without this, command prompts and powershell terminal windows could hang in "exit" until the last background child process exited or released their Win32 console handle. (This was not seen with git-bash shells because they don't have a Win32 console attached to them.) Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 109 +++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 950614f82f6..2f721aae016 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -9,6 +9,7 @@ #include "khash.h" static const char * const builtin_fsmonitor__daemon_usage[] = { + N_("git fsmonitor--daemon start []"), N_("git fsmonitor--daemon run []"), N_("git fsmonitor--daemon stop"), N_("git fsmonitor--daemon status"), @@ -22,6 +23,9 @@ static const char * const builtin_fsmonitor__daemon_usage[] = { #define FSMONITOR__IPC_THREADS "fsmonitor.ipcthreads" static int fsmonitor__ipc_threads = 8; +#define FSMONITOR__START_TIMEOUT "fsmonitor.starttimeout" +static int fsmonitor__start_timeout_sec = 60; + #define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup" static int fsmonitor__announce_startup = 0; @@ -36,6 +40,15 @@ static int fsmonitor_config(const char *var, const char *value, void *cb) return 0; } + if (!strcmp(var, FSMONITOR__START_TIMEOUT)) { + int i = git_config_int(var, value); + if (i < 0) + return error(_("value of '%s' out of range: %d"), + FSMONITOR__START_TIMEOUT, i); + fsmonitor__start_timeout_sec = i; + return 0; + } + if (!strcmp(var, FSMONITOR__ANNOUNCE_STARTUP)) { int is_bool; int i = git_config_bool_or_int(var, value, &is_bool); @@ -250,7 +263,7 @@ done: return err; } -static int try_to_run_foreground_daemon(void) +static int try_to_run_foreground_daemon(int detach_console) { /* * Technically, we don't need to probe for an existing daemon @@ -270,17 +283,106 @@ static int try_to_run_foreground_daemon(void) fflush(stderr); } +#ifdef GIT_WINDOWS_NATIVE + if (detach_console) + FreeConsole(); +#endif + return !!fsmonitor_run_daemon(); } +static start_bg_wait_cb bg_wait_cb; + +static int bg_wait_cb(const struct child_process *cp, void *cb_data) +{ + enum ipc_active_state s = fsmonitor_ipc__get_state(); + + switch (s) { + case IPC_STATE__LISTENING: + /* child is "ready" */ + return 0; + + case IPC_STATE__NOT_LISTENING: + case IPC_STATE__PATH_NOT_FOUND: + /* give child more time */ + return 1; + + default: + case IPC_STATE__INVALID_PATH: + case IPC_STATE__OTHER_ERROR: + /* all the time in world won't help */ + return -1; + } +} + +static int try_to_start_background_daemon(void) +{ + struct child_process cp = CHILD_PROCESS_INIT; + enum start_bg_result sbgr; + + /* + * Before we try to create a background daemon process, see + * if a daemon process is already listening. This makes it + * easier for us to report an already-listening error to the + * console, since our spawn/daemon can only report the success + * of creating the background process (and not whether it + * immediately exited). + */ + if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING) + die("fsmonitor--daemon is already running '%s'", + the_repository->worktree); + + if (fsmonitor__announce_startup) { + fprintf(stderr, _("starting fsmonitor-daemon in '%s'\n"), + the_repository->worktree); + fflush(stderr); + } + + cp.git_cmd = 1; + + strvec_push(&cp.args, "fsmonitor--daemon"); + strvec_push(&cp.args, "run"); + strvec_push(&cp.args, "--detach"); + strvec_pushf(&cp.args, "--ipc-threads=%d", fsmonitor__ipc_threads); + + cp.no_stdin = 1; + cp.no_stdout = 1; + cp.no_stderr = 1; + + sbgr = start_bg_command(&cp, bg_wait_cb, NULL, + fsmonitor__start_timeout_sec); + + switch (sbgr) { + case SBGR_READY: + return 0; + + default: + case SBGR_ERROR: + case SBGR_CB_ERROR: + return error("daemon failed to start"); + + case SBGR_TIMEOUT: + return error("daemon not online yet"); + + case SBGR_DIED: + return error("daemon terminated"); + } +} + int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) { const char *subcmd; + int detach_console = 0; struct option options[] = { + OPT_BOOL(0, "detach", &detach_console, N_("detach from console")), OPT_INTEGER(0, "ipc-threads", &fsmonitor__ipc_threads, N_("use ipc worker threads")), + OPT_INTEGER(0, "start-timeout", + &fsmonitor__start_timeout_sec, + N_("max seconds to wait for background daemon startup")), + OPT_END() }; @@ -296,8 +398,11 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix) die(_("invalid 'ipc-threads' value (%d)"), fsmonitor__ipc_threads); + if (!strcmp(subcmd, "start")) + return !!try_to_start_background_daemon(); + if (!strcmp(subcmd, "run")) - return !!try_to_run_foreground_daemon(); + return !!try_to_run_foreground_daemon(detach_console); if (!strcmp(subcmd, "stop")) return !!do_as_client__send_stop(); From patchwork Tue Mar 1 18:43:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765069 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 737AAC433F5 for ; Tue, 1 Mar 2022 18:44:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237175AbiCASph (ORCPT ); Tue, 1 Mar 2022 13:45:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55092 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237058AbiCASox (ORCPT ); Tue, 1 Mar 2022 13:44:53 -0500 Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE30E5D5E6 for ; Tue, 1 Mar 2022 10:43:46 -0800 (PST) Received: by mail-wr1-x432.google.com with SMTP id b5so22003224wrr.2 for ; Tue, 01 Mar 2022 10:43:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=RT2c3XBUF0c1NpErSfda3qkboOoI55MdbTGZDgFpnAM=; b=CBGXBaEPWYYEq9U4A3a17r5F+dkujwfe/yE79CZTdHHgVQEQjL3HJl31znZMtpWXU5 FefeimKxDXsI8njWIGOJ159FkGh+IMzuthxa4d0wSoMBAtAPlJLAMa/os0X3cE+ZwVkb PmfXCDiQeYzoJzlQCX3AJ2BzLQqsa7BmNUdwOFVvnWruZtuF4DDPxQazAP9+NnFHnVF1 9xU3o95i+WVODgGQ3BuOZVznosnZLxtG2f3t05cshHQJ/J5WHYdiaEsfQrXkkdkK0nOb dA5QaGMVxl7Y3g92/HvbPKVS0PW1mLHi/FQYBEDcYSVNcPVTbT7K2WOAYkW3sBKSqHmQ AQwQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=RT2c3XBUF0c1NpErSfda3qkboOoI55MdbTGZDgFpnAM=; b=DoaL3yRiRM5isKhwRDm/7Xa54v/IL/Sjnnwf5Qk5TiVPuYc5Zj4hg3tfPfoeEOrqn5 T7NiTYOuwWLyygXo1Ts2ytumeZNKJNI3rTFUsSNp6DOppUD5iLZuuFLCsS4o06NkBbqN 5Fsm+3moVzTA3Fd4SrPnoTIGx9QYqgftWhs2qOko0yUascPuQNO6rgKcYwDLNpyteJPb mZNWgavNwOzGUwF3L6gopM8uxxsn7va9femBlW0CUVLp5XhC07c4z+JVood9QnGEgULX SviZvrwuZwrztU4H+ZM2JVz/bz09MKZKXG5mAYzNwLtbXvop3FcdfyuaU/nt6QhhwuAZ v9qA== X-Gm-Message-State: AOAM533HYQBhERO0RjuRllAUYaoU1epXdBaZvPXr3haAzcDnEPC2G84I w00CWdBArYOxad18rxl/QlG60JBULQo= X-Google-Smtp-Source: ABdhPJyBSXQiLJ+RmEtCBrEyhJcU4kj4O3hL87SDvORsmTuI12BjOkPvvoTOrxflmUih4wWIRo4Lmg== X-Received: by 2002:a5d:43cf:0:b0:1f0:2250:585d with SMTP id v15-20020a5d43cf000000b001f02250585dmr2046164wrr.194.1646160225046; Tue, 01 Mar 2022 10:43:45 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id n7-20020a5d51c7000000b001a38105483dsm14373965wrv.24.2022.03.01.10.43.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:44 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:14 +0000 Subject: [PATCH v6 12/30] fsmonitor--daemon: add pathname classification Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach fsmonitor--daemon to classify relative and absolute pathnames and decide how they should be handled. This will be used by the platform-specific backend to respond to each filesystem event. When we register for filesystem notifications on a directory, we get events for everything (recursively) in the directory. We want to report to clients changes to tracked and untracked paths within the working directory proper. We do not want to report changes within the .git directory, for example. This classification will be used in a later commit by the different backends to classify paths as events are received. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 81 ++++++++++++++++++++++++++++++++++ fsmonitor--daemon.h | 87 +++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 2f721aae016..cb126883832 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -134,6 +134,87 @@ static int handle_client(void *data, return result; } +#define FSMONITOR_COOKIE_PREFIX ".fsmonitor-daemon-" + +enum fsmonitor_path_type fsmonitor_classify_path_workdir_relative( + const char *rel) +{ + if (fspathncmp(rel, ".git", 4)) + return IS_WORKDIR_PATH; + rel += 4; + + if (!*rel) + return IS_DOT_GIT; + if (*rel != '/') + return IS_WORKDIR_PATH; /* e.g. .gitignore */ + rel++; + + if (!fspathncmp(rel, FSMONITOR_COOKIE_PREFIX, + strlen(FSMONITOR_COOKIE_PREFIX))) + return IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX; + + return IS_INSIDE_DOT_GIT; +} + +enum fsmonitor_path_type fsmonitor_classify_path_gitdir_relative( + const char *rel) +{ + if (!fspathncmp(rel, FSMONITOR_COOKIE_PREFIX, + strlen(FSMONITOR_COOKIE_PREFIX))) + return IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX; + + return IS_INSIDE_GITDIR; +} + +static enum fsmonitor_path_type try_classify_workdir_abs_path( + struct fsmonitor_daemon_state *state, + const char *path) +{ + const char *rel; + + if (fspathncmp(path, state->path_worktree_watch.buf, + state->path_worktree_watch.len)) + return IS_OUTSIDE_CONE; + + rel = path + state->path_worktree_watch.len; + + if (!*rel) + return IS_WORKDIR_PATH; /* it is the root dir exactly */ + if (*rel != '/') + return IS_OUTSIDE_CONE; + rel++; + + return fsmonitor_classify_path_workdir_relative(rel); +} + +enum fsmonitor_path_type fsmonitor_classify_path_absolute( + struct fsmonitor_daemon_state *state, + const char *path) +{ + const char *rel; + enum fsmonitor_path_type t; + + t = try_classify_workdir_abs_path(state, path); + if (state->nr_paths_watching == 1) + return t; + if (t != IS_OUTSIDE_CONE) + return t; + + if (fspathncmp(path, state->path_gitdir_watch.buf, + state->path_gitdir_watch.len)) + return IS_OUTSIDE_CONE; + + rel = path + state->path_gitdir_watch.len; + + if (!*rel) + return IS_GITDIR; /* it is the exactly */ + if (*rel != '/') + return IS_OUTSIDE_CONE; + rel++; + + return fsmonitor_classify_path_gitdir_relative(rel); +} + static void *fsm_listen__thread_proc(void *_state) { struct fsmonitor_daemon_state *state = _state; diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h index 3009c1a83de..8c3a71a48bd 100644 --- a/fsmonitor--daemon.h +++ b/fsmonitor--daemon.h @@ -30,5 +30,92 @@ struct fsmonitor_daemon_state { struct ipc_server_data *ipc_server_data; }; +/* + * Pathname classifications. + * + * The daemon classifies the pathnames that it receives from file + * system notification events into the following categories and uses + * that to decide whether clients are told about them. (And to watch + * for file system synchronization events.) + * + * The daemon only collects and reports on the set of modified paths + * within the working directory (proper). + * + * The client should only care about paths within the working + * directory proper (inside the working directory and not ".git" nor + * inside of ".git/"). That is, the client has read the index and is + * asking for a list of any paths in the working directory that have + * been modified since the last token. The client does not care about + * file system changes within the ".git/" directory (such as new loose + * objects or packfiles). So the client will only receive paths that + * are classified as IS_WORKDIR_PATH. + * + * Note that ".git" is usually a directory and is therefore inside + * the cone of the FS watch that we have on the working directory root, + * so we will also get FS events for disk activity on and within ".git/" + * that we need to respond to or filter from the client. + * + * But Git also allows ".git" to be a *file* that points to a GITDIR + * outside of the working directory. When this happens, we need to + * create FS watches on both the working directory root *and* on the + * (external) GITDIR root. (The latter is required because we put + * cookie files inside it and use them to sync with the FS event + * stream.) + * + * Note that in the context of this discussion, I'm using "GITDIR" + * to only mean an external GITDIR referenced by a ".git" file. + * + * The platform FS event backends will receive watch-specific + * relative paths (except for those OS's that always emit absolute + * paths). We use the following enum and routines to classify each + * path so that we know how to handle it. There is a slight asymmetry + * here because ".git/" is inside the working directory and the + * (external) GITDIR is not, and therefore how we handle events may + * vary slightly, so I have different enums for "IS...DOT_GIT..." and + * "IS...GITDIR...". + * + * The daemon uses the IS_DOT_GIT and IS_GITDIR internally to mean the + * exact ".git" file/directory or GITDIR directory. If the daemon + * receives a delete event for either of these paths, it will + * automatically shutdown, for example. + * + * Note that the daemon DOES NOT explicitly watch nor special case the + * index. The daemon does not read the index nor have any internal + * index-relative state, so there are no "IS...INDEX..." enum values. + */ +enum fsmonitor_path_type { + IS_WORKDIR_PATH = 0, + + IS_DOT_GIT, + IS_INSIDE_DOT_GIT, + IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX, + + IS_GITDIR, + IS_INSIDE_GITDIR, + IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX, + + IS_OUTSIDE_CONE, +}; + +/* + * Classify a pathname relative to the root of the working directory. + */ +enum fsmonitor_path_type fsmonitor_classify_path_workdir_relative( + const char *relative_path); + +/* + * Classify a pathname relative to a that is external to the + * worktree directory. + */ +enum fsmonitor_path_type fsmonitor_classify_path_gitdir_relative( + const char *relative_path); + +/* + * Classify an absolute pathname received from a filesystem event. + */ +enum fsmonitor_path_type fsmonitor_classify_path_absolute( + struct fsmonitor_daemon_state *state, + const char *path); + #endif /* HAVE_FSMONITOR_DAEMON_BACKEND */ #endif /* FSMONITOR_DAEMON_H */ From patchwork Tue Mar 1 18:43:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765068 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 651ADC433EF for ; Tue, 1 Mar 2022 18:44:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237159AbiCASpf (ORCPT ); Tue, 1 Mar 2022 13:45:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56966 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237060AbiCASox (ORCPT ); Tue, 1 Mar 2022 13:44:53 -0500 Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ADC595D5FA for ; Tue, 1 Mar 2022 10:43:47 -0800 (PST) Received: by mail-wr1-x42f.google.com with SMTP id r10so21974960wrp.3 for ; Tue, 01 Mar 2022 10:43:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=AlmY/gOlEO8HSZj05WOg2u+vIw14iQiErsBfdhO4tq4=; b=pTP5+EyUcfrqbj4xObHLNQen7u7pxkxAko2KmofNIxIznZjxdQEsW3ibRivR4SBVhW RSOiY//k2L3oWi6clde4l81sqnE6D//rGreH24BXPMj3bJjylLpS3DcOfp6FPUCloGHD esjIwNwtaDqNishoBWK31Rx0+F4+x/xkM0SAtUOq4dKn9FywQe0z7AFkcWSTbzpMS8KP uP33j2tD1OlPCCWLVBom2ailGrAVfTZAWAaK2FpqpQ4eRy3Zzuitg4ETF4CV6phKwR/R eVRrUnSsZCgZAYF+/Xw7FEdxSMw3rkVUsbvKYU2qNcs1K4eHzUHJBYHzbIReqwhfJeHQ pB6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=AlmY/gOlEO8HSZj05WOg2u+vIw14iQiErsBfdhO4tq4=; b=ZcknXNr1jmXRae7VsmLmx85vcVhz54nUOYxQZYwDas1dghF5dKKNB+hs21uF4RRJLu b5RSOcgZOCq93oIRVlNkUpJrJg5r/S33GJ3zdYILqWW36NWeuj5nJZQcH3fQBZBvXFVi hTo8qQqGRgcyMtrghn67gwSHXyTmYcmwG3jry0f0O4ummnZFGcIYkLbQPoOAWoz5yzSn CZ4D1pPgaVtpmWN56pX40d+hEv+H5ULwrfZfBTgaq0KkWm3ZmwvkomuvCTE+CHWPMVLX HUf6Ej7LFuAbs9F1ZVSCmke+IrfXB092OS/Q8+tizUD0bp4ub/47VMTrX6Yaxnd9uAcF Su6g== X-Gm-Message-State: AOAM532d1WRJrKn/JXR4sN0g54QT5fIyl2cnD+BD3JJrv1pyN2kn+Ivf RZMl99O2PVkMDF+t73xP5r/3Pra3oTk= X-Google-Smtp-Source: ABdhPJwpGkUj8YgF2KZQ90oL2KeH829x5SjPaDySlBcLHB3yTd6fWJS44JR7viDsYvrHf7M6H+g71A== X-Received: by 2002:a05:6000:186d:b0:1e8:49fc:69ce with SMTP id d13-20020a056000186d00b001e849fc69cemr20397120wri.80.1646160225898; Tue, 01 Mar 2022 10:43:45 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id q23-20020a1cf317000000b003815206a638sm3352589wmq.15.2022.03.01.10.43.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:45 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:15 +0000 Subject: [PATCH v6 13/30] fsmonitor--daemon: define token-ids Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach fsmonitor--daemon to create token-ids and define the overall token naming scheme. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 116 +++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index cb126883832..c8d1509d87d 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -106,6 +106,120 @@ static int do_as_client__status(void) } } +/* + * Requests to and from a FSMonitor Protocol V2 provider use an opaque + * "token" as a virtual timestamp. Clients can request a summary of all + * created/deleted/modified files relative to a token. In the response, + * clients receive a new token for the next (relative) request. + * + * + * Token Format + * ============ + * + * The contents of the token are private and provider-specific. + * + * For the built-in fsmonitor--daemon, we define a token as follows: + * + * "builtin" ":" ":" + * + * The "builtin" prefix is used as a namespace to avoid conflicts + * with other providers (such as Watchman). + * + * The is an arbitrary OPAQUE string, such as a GUID, + * UUID, or {timestamp,pid}. It is used to group all filesystem + * events that happened while the daemon was monitoring (and in-sync + * with the filesystem). + * + * Unlike FSMonitor Protocol V1, it is not defined as a timestamp + * and does not define less-than/greater-than relationships. + * (There are too many race conditions to rely on file system + * event timestamps.) + * + * The is a simple integer incremented whenever the + * daemon needs to make its state public. For example, if 1000 file + * system events come in, but no clients have requested the data, + * the daemon can continue to accumulate file changes in the same + * bin and does not need to advance the sequence number. However, + * as soon as a client does arrive, the daemon needs to start a new + * bin and increment the sequence number. + * + * The sequence number serves as the boundary between 2 sets + * of bins -- the older ones that the client has already seen + * and the newer ones that it hasn't. + * + * When a new is created, the is reset to + * zero. + * + * + * About Token Ids + * =============== + * + * A new token_id is created: + * + * [1] each time the daemon is started. + * + * [2] any time that the daemon must re-sync with the filesystem + * (such as when the kernel drops or we miss events on a very + * active volume). + * + * [3] in response to a client "flush" command (for dropped event + * testing). + * + * When a new token_id is created, the daemon is free to discard all + * cached filesystem events associated with any previous token_ids. + * Events associated with a non-current token_id will never be sent + * to a client. A token_id change implicitly means that the daemon + * has gap in its event history. + * + * Therefore, clients that present a token with a stale (non-current) + * token_id will always be given a trivial response. + */ +struct fsmonitor_token_data { + struct strbuf token_id; + struct fsmonitor_batch *batch_head; + struct fsmonitor_batch *batch_tail; + uint64_t client_ref_count; +}; + +static struct fsmonitor_token_data *fsmonitor_new_token_data(void) +{ + static int test_env_value = -1; + static uint64_t flush_count = 0; + struct fsmonitor_token_data *token; + + CALLOC_ARRAY(token, 1); + + strbuf_init(&token->token_id, 0); + token->batch_head = NULL; + token->batch_tail = NULL; + token->client_ref_count = 0; + + if (test_env_value < 0) + test_env_value = git_env_bool("GIT_TEST_FSMONITOR_TOKEN", 0); + + if (!test_env_value) { + struct timeval tv; + struct tm tm; + time_t secs; + + gettimeofday(&tv, NULL); + secs = tv.tv_sec; + gmtime_r(&secs, &tm); + + strbuf_addf(&token->token_id, + "%"PRIu64".%d.%4d%02d%02dT%02d%02d%02d.%06ldZ", + flush_count++, + getpid(), + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, + (long)tv.tv_usec); + } else { + strbuf_addf(&token->token_id, "test_%08x", test_env_value++); + } + + return token; +} + static ipc_server_application_cb handle_client; static int handle_client(void *data, @@ -298,7 +412,7 @@ static int fsmonitor_run_daemon(void) pthread_mutex_init(&state.main_lock, NULL); state.error_code = 0; - state.current_token_data = NULL; + state.current_token_data = fsmonitor_new_token_data(); /* Prepare to (recursively) watch the directory. */ strbuf_init(&state.path_worktree_watch, 0); From patchwork Tue Mar 1 18:43:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765055 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9C627C433F5 for ; Tue, 1 Mar 2022 18:44:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237108AbiCASpJ (ORCPT ); Tue, 1 Mar 2022 13:45:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57040 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237059AbiCASoy (ORCPT ); Tue, 1 Mar 2022 13:44:54 -0500 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 82D065D645 for ; Tue, 1 Mar 2022 10:43:48 -0800 (PST) Received: by mail-wm1-x334.google.com with SMTP id m42-20020a05600c3b2a00b00382ab337e14so600768wms.3 for ; Tue, 01 Mar 2022 10:43:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=s9ZsHzr8stBhqDrckg+BWrFd0IydVX8ZjQzZ1ZozFrI=; b=iAzFxjtPa6fYMfQ7QmdC/RjSXdzpCCil/o3JcPWEk2b5yb80PZmf4PRnI2LuMWYArd TNJTreKTNKYt4ENzJTCsCVebk7dy3DGVK59kKARab8XNHTnVEgZ42vwysRtqRGDq752e VXQ30t9RiQCfcHFoP9iD2cvFEQlm0bNXjTPK90Kgw0yHSwe+ZjFKvWkB+fVab1e6CySF cKX7aN2pYrAguHLrsqv46xUBPoxKW86Qhu6ntlxQoHgXgn3LoxSJeCS0J+XF3Xh0Oi72 o3cnmT+TJZBkAt9Tdi5mjIzq/ZszwJeBqyNeeYMe2EkDcGsoNmcQOArw2ji7Ei3fOjio 7YgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=s9ZsHzr8stBhqDrckg+BWrFd0IydVX8ZjQzZ1ZozFrI=; b=UObpX87uGXyy56S+zg6AJTqJ0dXPPEswfGrtn1eBLe7wPUozVBrJHDd4v4lX446+1M bZA1i881It//F3rqH8/K4Yets2YqDBfj0Jj6knFx34AzjMOI8mkJNt5n8dsYqaIfM+Em gDlttxa3Tio0YXFST/sjc+7GGRJL+BglKYIb3VTmUJkJDVE5NMoY1o6jGeSsUxkXJfSk IC24F8gLcB28zlncbL8a04QMdmx6gews1Tsrwe+CkrVWO5baUMN8AwrKlwsyIaMWiJkV ZfZs4hCuTuW/GpEmonCcwGbZGivHQuMsZl+lPsyU5Mr926zrgfce9Ncee1JhB6xzXgJW PCzg== X-Gm-Message-State: AOAM531H4lrTWNa7XJph4ZMq6KB9Cx+BMCDhJ3nIm9BdP+R/OFLnHOM4 1CsrI+P9UKmJHWh3e9+dpDvGA2TJysk= X-Google-Smtp-Source: ABdhPJzrtijJt41tQf2xL44rdoH9J0ucfpy2/D+b2lVs4XEEYKCr/QtsxydWfp4ee7wfYR5BdBGU6Q== X-Received: by 2002:a05:600c:3651:b0:381:8654:876f with SMTP id y17-20020a05600c365100b003818654876fmr3565209wmq.162.1646160226742; Tue, 01 Mar 2022 10:43:46 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id p2-20020a05600c418200b00380e4fa28b8sm2962435wmh.23.2022.03.01.10.43.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:46 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:16 +0000 Subject: [PATCH v6 14/30] fsmonitor--daemon: create token-based changed path cache Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach fsmonitor--daemon to build a list of changed paths and associate them with a token-id. This will be used by the platform-specific backends to accumulate changed paths in response to filesystem events. The platform-specific file system listener thread receives file system events containing one or more changed pathnames (with whatever bucketing or grouping that is convenient for the file system). These paths are accumulated (without locking) by the file system layer into a `fsmonitor_batch`. When the file system layer has drained the kernel event queue, it will "publish" them to our token queue and make them visible to concurrent client worker threads. The token layer is free to combine and/or de-dup paths within these batches for efficient presentation to clients. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 230 +++++++++++++++++++++++++++++++++++- fsmonitor--daemon.h | 40 +++++++ 2 files changed, 268 insertions(+), 2 deletions(-) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index c8d1509d87d..7c44b979035 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -181,17 +181,27 @@ struct fsmonitor_token_data { uint64_t client_ref_count; }; +struct fsmonitor_batch { + struct fsmonitor_batch *next; + uint64_t batch_seq_nr; + const char **interned_paths; + size_t nr, alloc; + time_t pinned_time; +}; + static struct fsmonitor_token_data *fsmonitor_new_token_data(void) { static int test_env_value = -1; static uint64_t flush_count = 0; struct fsmonitor_token_data *token; + struct fsmonitor_batch *batch; CALLOC_ARRAY(token, 1); + batch = fsmonitor_batch__new(); strbuf_init(&token->token_id, 0); - token->batch_head = NULL; - token->batch_tail = NULL; + token->batch_head = batch; + token->batch_tail = batch; token->client_ref_count = 0; if (test_env_value < 0) @@ -217,9 +227,143 @@ static struct fsmonitor_token_data *fsmonitor_new_token_data(void) strbuf_addf(&token->token_id, "test_%08x", test_env_value++); } + /* + * We created a new and are starting a new series + * of tokens with a zero . + * + * Since clients cannot guess our new (non test) + * they will always receive a trivial response (because of the + * mismatch on the ). The trivial response will + * tell them our new so that subsequent requests + * will be relative to our new series. (And when sending that + * response, we pin the current head of the batch list.) + * + * Even if the client correctly guesses the , their + * request of "builtin::0" asks for all changes MORE + * RECENT than batch/bin 0. + * + * This implies that it is a waste to accumulate paths in the + * initial batch/bin (because they will never be transmitted). + * + * So the daemon could be running for days and watching the + * file system, but doesn't need to actually accumulate any + * paths UNTIL we need to set a reference point for a later + * relative request. + * + * However, it is very useful for testing to always have a + * reference point set. Pin batch 0 to force early file system + * events to accumulate. + */ + if (test_env_value) + batch->pinned_time = time(NULL); + return token; } +struct fsmonitor_batch *fsmonitor_batch__new(void) +{ + struct fsmonitor_batch *batch; + + CALLOC_ARRAY(batch, 1); + + return batch; +} + +void fsmonitor_batch__free_list(struct fsmonitor_batch *batch) +{ + while (batch) { + struct fsmonitor_batch *next = batch->next; + + /* + * The actual strings within the array of this batch + * are interned, so we don't own them. We only own + * the array. + */ + free(batch->interned_paths); + free(batch); + + batch = next; + } +} + +void fsmonitor_batch__add_path(struct fsmonitor_batch *batch, + const char *path) +{ + const char *interned_path = strintern(path); + + trace_printf_key(&trace_fsmonitor, "event: %s", interned_path); + + ALLOC_GROW(batch->interned_paths, batch->nr + 1, batch->alloc); + batch->interned_paths[batch->nr++] = interned_path; +} + +static void fsmonitor_batch__combine(struct fsmonitor_batch *batch_dest, + const struct fsmonitor_batch *batch_src) +{ + size_t k; + + ALLOC_GROW(batch_dest->interned_paths, + batch_dest->nr + batch_src->nr + 1, + batch_dest->alloc); + + for (k = 0; k < batch_src->nr; k++) + batch_dest->interned_paths[batch_dest->nr++] = + batch_src->interned_paths[k]; +} + +static void fsmonitor_free_token_data(struct fsmonitor_token_data *token) +{ + if (!token) + return; + + assert(token->client_ref_count == 0); + + strbuf_release(&token->token_id); + + fsmonitor_batch__free_list(token->batch_head); + + free(token); +} + +/* + * Flush all of our cached data about the filesystem. Call this if we + * lose sync with the filesystem and miss some notification events. + * + * [1] If we are missing events, then we no longer have a complete + * history of the directory (relative to our current start token). + * We should create a new token and start fresh (as if we just + * booted up). + * + * If there are no concurrent threads reading the current token data + * series, we can free it now. Otherwise, let the last reader free + * it. + * + * Either way, the old token data series is no longer associated with + * our state data. + */ +static void with_lock__do_force_resync(struct fsmonitor_daemon_state *state) +{ + /* assert current thread holding state->main_lock */ + + struct fsmonitor_token_data *free_me = NULL; + struct fsmonitor_token_data *new_one = NULL; + + new_one = fsmonitor_new_token_data(); + + if (state->current_token_data->client_ref_count == 0) + free_me = state->current_token_data; + state->current_token_data = new_one; + + fsmonitor_free_token_data(free_me); +} + +void fsmonitor_force_resync(struct fsmonitor_daemon_state *state) +{ + pthread_mutex_lock(&state->main_lock); + with_lock__do_force_resync(state); + pthread_mutex_unlock(&state->main_lock); +} + static ipc_server_application_cb handle_client; static int handle_client(void *data, @@ -329,6 +473,81 @@ enum fsmonitor_path_type fsmonitor_classify_path_absolute( return fsmonitor_classify_path_gitdir_relative(rel); } +/* + * We try to combine small batches at the front of the batch-list to avoid + * having a long list. This hopefully makes it a little easier when we want + * to truncate and maintain the list. However, we don't want the paths array + * to just keep growing and growing with realloc, so we insert an arbitrary + * limit. + */ +#define MY_COMBINE_LIMIT (1024) + +void fsmonitor_publish(struct fsmonitor_daemon_state *state, + struct fsmonitor_batch *batch, + const struct string_list *cookie_names) +{ + if (!batch && !cookie_names->nr) + return; + + pthread_mutex_lock(&state->main_lock); + + if (batch) { + struct fsmonitor_batch *head; + + head = state->current_token_data->batch_head; + if (!head) { + BUG("token does not have batch"); + } else if (head->pinned_time) { + /* + * We cannot alter the current batch list + * because: + * + * [a] it is being transmitted to at least one + * client and the handle_client() thread has a + * ref-count, but not a lock on the batch list + * starting with this item. + * + * [b] it has been transmitted in the past to + * at least one client such that future + * requests are relative to this head batch. + * + * So, we can only prepend a new batch onto + * the front of the list. + */ + batch->batch_seq_nr = head->batch_seq_nr + 1; + batch->next = head; + state->current_token_data->batch_head = batch; + } else if (!head->batch_seq_nr) { + /* + * Batch 0 is unpinned. See the note in + * `fsmonitor_new_token_data()` about why we + * don't need to accumulate these paths. + */ + fsmonitor_batch__free_list(batch); + } else if (head->nr + batch->nr > MY_COMBINE_LIMIT) { + /* + * The head batch in the list has never been + * transmitted to a client, but folding the + * contents of the new batch onto it would + * exceed our arbitrary limit, so just prepend + * the new batch onto the list. + */ + batch->batch_seq_nr = head->batch_seq_nr + 1; + batch->next = head; + state->current_token_data->batch_head = batch; + } else { + /* + * We are free to add the paths in the given + * batch onto the end of the current head batch. + */ + fsmonitor_batch__combine(head, batch); + fsmonitor_batch__free_list(batch); + } + } + + pthread_mutex_unlock(&state->main_lock); +} + static void *fsm_listen__thread_proc(void *_state) { struct fsmonitor_daemon_state *state = _state; @@ -343,6 +562,13 @@ static void *fsm_listen__thread_proc(void *_state) fsm_listen__loop(state); + pthread_mutex_lock(&state->main_lock); + if (state->current_token_data && + state->current_token_data->client_ref_count == 0) + fsmonitor_free_token_data(state->current_token_data); + state->current_token_data = NULL; + pthread_mutex_unlock(&state->main_lock); + trace2_thread_exit(); return NULL; } diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h index 8c3a71a48bd..010fbfe60e9 100644 --- a/fsmonitor--daemon.h +++ b/fsmonitor--daemon.h @@ -12,6 +12,27 @@ struct fsmonitor_batch; struct fsmonitor_token_data; +/* + * Create a new batch of path(s). The returned batch is considered + * private and not linked into the fsmonitor daemon state. The caller + * should fill this batch with one or more paths and then publish it. + */ +struct fsmonitor_batch *fsmonitor_batch__new(void); + +/* + * Free the list of batches starting with this one. + */ +void fsmonitor_batch__free_list(struct fsmonitor_batch *batch); + +/* + * Add this path to this batch of modified files. + * + * The batch should be private and NOT (yet) linked into the fsmonitor + * daemon state and therefore not yet visible to worker threads and so + * no locking is required. + */ +void fsmonitor_batch__add_path(struct fsmonitor_batch *batch, const char *path); + struct fsmonitor_daemon_backend_data; /* opaque platform-specific data */ struct fsmonitor_daemon_state { @@ -117,5 +138,24 @@ enum fsmonitor_path_type fsmonitor_classify_path_absolute( struct fsmonitor_daemon_state *state, const char *path); +/* + * Prepend the this batch of path(s) onto the list of batches associated + * with the current token. This makes the batch visible to worker threads. + * + * The caller no longer owns the batch and must not free it. + * + * Wake up the client threads waiting on these cookies. + */ +void fsmonitor_publish(struct fsmonitor_daemon_state *state, + struct fsmonitor_batch *batch, + const struct string_list *cookie_names); + +/* + * If the platform-specific layer loses sync with the filesystem, + * it should call this to invalidate cached data and abort waiting + * threads. + */ +void fsmonitor_force_resync(struct fsmonitor_daemon_state *state); + #endif /* HAVE_FSMONITOR_DAEMON_BACKEND */ #endif /* FSMONITOR_DAEMON_H */ From patchwork Tue Mar 1 18:43:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765065 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 39B61C433FE for ; Tue, 1 Mar 2022 18:44:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237153AbiCASp3 (ORCPT ); Tue, 1 Mar 2022 13:45:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55092 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237075AbiCASoy (ORCPT ); Tue, 1 Mar 2022 13:44:54 -0500 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5CF8861A3C for ; Tue, 1 Mar 2022 10:43:49 -0800 (PST) Received: by mail-wm1-x335.google.com with SMTP id m42-20020a05600c3b2a00b00382ab337e14so600786wms.3 for ; Tue, 01 Mar 2022 10:43:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=wtNF9S9rmANvPotmjCgliX0XzOPCCgI0VnLmKRFS+PA=; b=NIwXlqivTt55cQhOcePYV6KLvrtvklw7t24YVau7iPTXdWZf1aE1wy8q6YGLQtya9T 70EEqTMPRNdUWv7HlgkDQWO3vx2V5GaeNcUVs+nZnnT7cxc63/GcAD/9IDAwyk4oSFBJ ILR/8vz/++1YPvw+4nc4MQF7TeHojwzw1cKwWOxdxqugMY9M5HZwDF4NJUuehYlT9ARH 6l7lbaG5h6AlRTlnhG2ptCSSHZ/N4MI+fk9qsxw+/1kc3i1qvXBt3mYrbmOoWrnbUpnt dcqwPxdkx6+7D5+5sYEsEwJ0SkK0AJ6BfdtWLPaRSkhrRLVBQqe1XDsPVA/Bq5Sntrus v7DA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=wtNF9S9rmANvPotmjCgliX0XzOPCCgI0VnLmKRFS+PA=; b=7n5hieJ02nDtn6zWME/fQpmn5inPtvHjpCwmJ9O6TUEXjWnLjvjBBWjccgFNgYVmNM uw6V1Nj3ro2JYRGZbdoKWUscZ0WWlT08DR8zoTQCdDH529YfQHEFxOJZtpc/nce76XhJ NfLTszmIWEavwbVgjFdodbJ8mirZhSy4gv9HnGHoGZU9HOvmM5mv92/n+jy5UcKB/ipy MQVnGWXCmtXUltYhLYwrRpvVsHdXOrUFXK7xHUiFdUy+CIx0ZHEl5438GN8BPj3lF61g mbNa3Z4cbOsn4NM1pq7ghQK26VXbjQMzJN4Z/oflwh17QrLFizC+CC95LDmjaRgVZlAd L+dw== X-Gm-Message-State: AOAM530rBGT/LSc2ebEmtMEsEXPEB5y8yQ1O5dL2WI/bTcrVhOlitMGJ 1W0+QlEmT0KdJWFQGHQsevyJqUfjetE= X-Google-Smtp-Source: ABdhPJzyUhCJLM0Htl3uF5BsWvAQpXKYaudSp7QRekYinQuRW5Y2tiu7v/FB7FFLU9UghDN1Xzs9YA== X-Received: by 2002:a05:600c:3486:b0:381:65ec:f8ed with SMTP id a6-20020a05600c348600b0038165ecf8edmr9022151wmq.68.1646160227534; Tue, 01 Mar 2022 10:43:47 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m62-20020a1c2641000000b00380d0cff5f3sm3404226wmm.8.2022.03.01.10.43.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:47 -0800 (PST) Message-Id: <6b5b3d08227df88a54084860557cc1895acb7202.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:17 +0000 Subject: [PATCH v6 15/30] compat/fsmonitor/fsm-listen-win32: implement FSMonitor backend on Windows Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach the win32 backend to register a watch on the working tree root directory (recursively). Also watch the if it is not inside the working tree. And to collect path change notifications into batches and publish. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- compat/fsmonitor/fsm-listen-win32.c | 565 ++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c index 916cbea254f..c2d11acbc1e 100644 --- a/compat/fsmonitor/fsm-listen-win32.c +++ b/compat/fsmonitor/fsm-listen-win32.c @@ -2,20 +2,585 @@ #include "config.h" #include "fsmonitor.h" #include "fsm-listen.h" +#include "fsmonitor--daemon.h" + +/* + * The documentation of ReadDirectoryChangesW() states that the maximum + * buffer size is 64K when the monitored directory is remote. + * + * Larger buffers may be used when the monitored directory is local and + * will help us receive events faster from the kernel and avoid dropped + * events. + * + * So we try to use a very large buffer and silently fallback to 64K if + * we get an error. + */ +#define MAX_RDCW_BUF_FALLBACK (65536) +#define MAX_RDCW_BUF (65536 * 8) + +struct one_watch +{ + char buffer[MAX_RDCW_BUF]; + DWORD buf_len; + DWORD count; + + struct strbuf path; + HANDLE hDir; + HANDLE hEvent; + OVERLAPPED overlapped; + + /* + * Is there an active ReadDirectoryChangesW() call pending. If so, we + * need to later call GetOverlappedResult() and possibly CancelIoEx(). + */ + BOOL is_active; +}; + +struct fsmonitor_daemon_backend_data +{ + struct one_watch *watch_worktree; + struct one_watch *watch_gitdir; + + HANDLE hEventShutdown; + + HANDLE hListener[3]; /* we don't own these handles */ +#define LISTENER_SHUTDOWN 0 +#define LISTENER_HAVE_DATA_WORKTREE 1 +#define LISTENER_HAVE_DATA_GITDIR 2 + int nr_listener_handles; +}; + +/* + * Convert the WCHAR path from the notification into UTF8 and + * then normalize it. + */ +static int normalize_path_in_utf8(FILE_NOTIFY_INFORMATION *info, + struct strbuf *normalized_path) +{ + int reserve; + int len = 0; + + strbuf_reset(normalized_path); + if (!info->FileNameLength) + goto normalize; + + /* + * Pre-reserve enough space in the UTF8 buffer for + * each Unicode WCHAR character to be mapped into a + * sequence of 2 UTF8 characters. That should let us + * avoid ERROR_INSUFFICIENT_BUFFER 99.9+% of the time. + */ + reserve = info->FileNameLength + 1; + strbuf_grow(normalized_path, reserve); + + for (;;) { + len = WideCharToMultiByte(CP_UTF8, 0, info->FileName, + info->FileNameLength / sizeof(WCHAR), + normalized_path->buf, + strbuf_avail(normalized_path) - 1, + NULL, NULL); + if (len > 0) + goto normalize; + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + error("[GLE %ld] could not convert path to UTF-8: '%.*ls'", + GetLastError(), + (int)(info->FileNameLength / sizeof(WCHAR)), + info->FileName); + return -1; + } + + strbuf_grow(normalized_path, + strbuf_avail(normalized_path) + reserve); + } + +normalize: + strbuf_setlen(normalized_path, len); + return strbuf_normalize_path(normalized_path); +} void fsm_listen__stop_async(struct fsmonitor_daemon_state *state) { + SetEvent(state->backend_data->hListener[LISTENER_SHUTDOWN]); +} + +static struct one_watch *create_watch(struct fsmonitor_daemon_state *state, + const char *path) +{ + struct one_watch *watch = NULL; + DWORD desired_access = FILE_LIST_DIRECTORY; + DWORD share_mode = + FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE; + HANDLE hDir; + wchar_t wpath[MAX_PATH]; + + if (xutftowcs_path(wpath, path) < 0) { + error(_("could not convert to wide characters: '%s'"), path); + return NULL; + } + + hDir = CreateFileW(wpath, + desired_access, share_mode, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + NULL); + if (hDir == INVALID_HANDLE_VALUE) { + error(_("[GLE %ld] could not watch '%s'"), + GetLastError(), path); + return NULL; + } + + CALLOC_ARRAY(watch, 1); + + watch->buf_len = sizeof(watch->buffer); /* assume full MAX_RDCW_BUF */ + + strbuf_init(&watch->path, 0); + strbuf_addstr(&watch->path, path); + + watch->hDir = hDir; + watch->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + return watch; +} + +static void destroy_watch(struct one_watch *watch) +{ + if (!watch) + return; + + strbuf_release(&watch->path); + if (watch->hDir != INVALID_HANDLE_VALUE) + CloseHandle(watch->hDir); + if (watch->hEvent != INVALID_HANDLE_VALUE) + CloseHandle(watch->hEvent); + + free(watch); +} + +static int start_rdcw_watch(struct fsmonitor_daemon_backend_data *data, + struct one_watch *watch) +{ + DWORD dwNotifyFilter = + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_CREATION; + + ResetEvent(watch->hEvent); + + memset(&watch->overlapped, 0, sizeof(watch->overlapped)); + watch->overlapped.hEvent = watch->hEvent; + + /* + * Queue an async call using Overlapped IO. This returns immediately. + * Our event handle will be signalled when the real result is available. + * + * The return value here just means that we successfully queued it. + * We won't know if the Read...() actually produces data until later. + */ + watch->is_active = ReadDirectoryChangesW( + watch->hDir, watch->buffer, watch->buf_len, TRUE, + dwNotifyFilter, &watch->count, &watch->overlapped, NULL); + + if (watch->is_active) + return 0; + + error("ReadDirectoryChangedW failed on '%s' [GLE %ld]", + watch->path.buf, GetLastError()); + return -1; +} + +static int recv_rdcw_watch(struct one_watch *watch) +{ + DWORD gle; + + watch->is_active = FALSE; + + /* + * The overlapped result is ready. If the Read...() was successful + * we finally receive the actual result into our buffer. + */ + if (GetOverlappedResult(watch->hDir, &watch->overlapped, &watch->count, + TRUE)) + return 0; + + gle = GetLastError(); + if (gle == ERROR_INVALID_PARAMETER && + /* + * The kernel throws an invalid parameter error when our + * buffer is too big and we are pointed at a remote + * directory (and possibly for other reasons). Quietly + * set it down and try again. + * + * See note about MAX_RDCW_BUF at the top. + */ + watch->buf_len > MAX_RDCW_BUF_FALLBACK) { + watch->buf_len = MAX_RDCW_BUF_FALLBACK; + return -2; + } + + /* + * NEEDSWORK: If an external is deleted, the above + * returns an error. I'm not sure that there's anything that + * we can do here other than failing -- the /.git + * link file would be broken anyway. We might try to check + * for that and return a better error message, but I'm not + * sure it is worth it. + */ + + error("GetOverlappedResult failed on '%s' [GLE %ld]", + watch->path.buf, gle); + return -1; +} + +static void cancel_rdcw_watch(struct one_watch *watch) +{ + DWORD count; + + if (!watch || !watch->is_active) + return; + + /* + * The calls to ReadDirectoryChangesW() and GetOverlappedResult() + * form a "pair" (my term) where we queue an IO and promise to + * hang around and wait for the kernel to give us the result. + * + * If for some reason after we queue the IO, we have to quit + * or otherwise not stick around for the second half, we must + * tell the kernel to abort the IO. This prevents the kernel + * from writing to our buffer and/or signalling our event + * after we free them. + * + * (Ask me how much fun it was to track that one down). + */ + CancelIoEx(watch->hDir, &watch->overlapped); + GetOverlappedResult(watch->hDir, &watch->overlapped, &count, TRUE); + watch->is_active = FALSE; +} + +/* + * Process filesystem events that happen anywhere (recursively) under the + * root directory. For a normal working directory, this includes + * both version controlled files and the contents of the .git/ directory. + * + * If /.git is a file, then we only see events for the file + * itself. + */ +static int process_worktree_events(struct fsmonitor_daemon_state *state) +{ + struct fsmonitor_daemon_backend_data *data = state->backend_data; + struct one_watch *watch = data->watch_worktree; + struct strbuf path = STRBUF_INIT; + struct string_list cookie_list = STRING_LIST_INIT_DUP; + struct fsmonitor_batch *batch = NULL; + const char *p = watch->buffer; + + /* + * If the kernel gets more events than will fit in the kernel + * buffer associated with our RDCW handle, it drops them and + * returns a count of zero. + * + * Yes, the call returns WITHOUT error and with length zero. + * This is the documented behavior. (My testing has confirmed + * that it also sets the last error to ERROR_NOTIFY_ENUM_DIR, + * but we do not rely on that since the function did not + * return an error and it is not documented.) + * + * (The "overflow" case is not ambiguous with the "no data" case + * because we did an INFINITE wait.) + * + * This means we have a gap in coverage. Tell the daemon layer + * to resync. + */ + if (!watch->count) { + trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel", + "overflow"); + fsmonitor_force_resync(state); + return LISTENER_HAVE_DATA_WORKTREE; + } + + /* + * On Windows, `info` contains an "array" of paths that are + * relative to the root of whichever directory handle received + * the event. + */ + for (;;) { + FILE_NOTIFY_INFORMATION *info = (void *)p; + const char *slash; + enum fsmonitor_path_type t; + + strbuf_reset(&path); + if (normalize_path_in_utf8(info, &path) == -1) + goto skip_this_path; + + t = fsmonitor_classify_path_workdir_relative(path.buf); + + switch (t) { + case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX: + /* special case cookie files within .git */ + + /* Use just the filename of the cookie file. */ + slash = find_last_dir_sep(path.buf); + string_list_append(&cookie_list, + slash ? slash + 1 : path.buf); + break; + + case IS_INSIDE_DOT_GIT: + /* ignore everything inside of "/.git/" */ + break; + + case IS_DOT_GIT: + /* "/.git" was deleted (or renamed away) */ + if ((info->Action == FILE_ACTION_REMOVED) || + (info->Action == FILE_ACTION_RENAMED_OLD_NAME)) { + trace2_data_string("fsmonitor", NULL, + "fsm-listen/dotgit", + "removed"); + goto force_shutdown; + } + break; + + case IS_WORKDIR_PATH: + /* queue normal pathname */ + if (!batch) + batch = fsmonitor_batch__new(); + fsmonitor_batch__add_path(batch, path.buf); + break; + + case IS_GITDIR: + case IS_INSIDE_GITDIR: + case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX: + default: + BUG("unexpected path classification '%d' for '%s'", + t, path.buf); + } + +skip_this_path: + if (!info->NextEntryOffset) + break; + p += info->NextEntryOffset; + } + + fsmonitor_publish(state, batch, &cookie_list); + batch = NULL; + string_list_clear(&cookie_list, 0); + strbuf_release(&path); + return LISTENER_HAVE_DATA_WORKTREE; + +force_shutdown: + fsmonitor_batch__free_list(batch); + string_list_clear(&cookie_list, 0); + strbuf_release(&path); + return LISTENER_SHUTDOWN; +} + +/* + * Process filesystem events that happened anywhere (recursively) under the + * external (such as non-primary worktrees or submodules). + * We only care about cookie files that our client threads created here. + * + * Note that we DO NOT get filesystem events on the external + * itself (it is not inside something that we are watching). In particular, + * we do not get an event if the external is deleted. + */ +static int process_gitdir_events(struct fsmonitor_daemon_state *state) +{ + struct fsmonitor_daemon_backend_data *data = state->backend_data; + struct one_watch *watch = data->watch_gitdir; + struct strbuf path = STRBUF_INIT; + struct string_list cookie_list = STRING_LIST_INIT_DUP; + const char *p = watch->buffer; + + if (!watch->count) { + trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel", + "overflow"); + fsmonitor_force_resync(state); + return LISTENER_HAVE_DATA_GITDIR; + } + + for (;;) { + FILE_NOTIFY_INFORMATION *info = (void *)p; + const char *slash; + enum fsmonitor_path_type t; + + strbuf_reset(&path); + if (normalize_path_in_utf8(info, &path) == -1) + goto skip_this_path; + + t = fsmonitor_classify_path_gitdir_relative(path.buf); + + switch (t) { + case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX: + /* special case cookie files within gitdir */ + + /* Use just the filename of the cookie file. */ + slash = find_last_dir_sep(path.buf); + string_list_append(&cookie_list, + slash ? slash + 1 : path.buf); + break; + + case IS_INSIDE_GITDIR: + goto skip_this_path; + + default: + BUG("unexpected path classification '%d' for '%s'", + t, path.buf); + } + +skip_this_path: + if (!info->NextEntryOffset) + break; + p += info->NextEntryOffset; + } + + fsmonitor_publish(state, NULL, &cookie_list); + string_list_clear(&cookie_list, 0); + strbuf_release(&path); + return LISTENER_HAVE_DATA_GITDIR; } void fsm_listen__loop(struct fsmonitor_daemon_state *state) { + struct fsmonitor_daemon_backend_data *data = state->backend_data; + DWORD dwWait; + int result; + + state->error_code = 0; + + if (start_rdcw_watch(data, data->watch_worktree) == -1) + goto force_error_stop; + + if (data->watch_gitdir && + start_rdcw_watch(data, data->watch_gitdir) == -1) + goto force_error_stop; + + for (;;) { + dwWait = WaitForMultipleObjects(data->nr_listener_handles, + data->hListener, + FALSE, INFINITE); + + if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_WORKTREE) { + result = recv_rdcw_watch(data->watch_worktree); + if (result == -1) { + /* hard error */ + goto force_error_stop; + } + if (result == -2) { + /* retryable error */ + if (start_rdcw_watch(data, data->watch_worktree) == -1) + goto force_error_stop; + continue; + } + + /* have data */ + if (process_worktree_events(state) == LISTENER_SHUTDOWN) + goto force_shutdown; + if (start_rdcw_watch(data, data->watch_worktree) == -1) + goto force_error_stop; + continue; + } + + if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_GITDIR) { + result = recv_rdcw_watch(data->watch_gitdir); + if (result == -1) { + /* hard error */ + goto force_error_stop; + } + if (result == -2) { + /* retryable error */ + if (start_rdcw_watch(data, data->watch_gitdir) == -1) + goto force_error_stop; + continue; + } + + /* have data */ + if (process_gitdir_events(state) == LISTENER_SHUTDOWN) + goto force_shutdown; + if (start_rdcw_watch(data, data->watch_gitdir) == -1) + goto force_error_stop; + continue; + } + + if (dwWait == WAIT_OBJECT_0 + LISTENER_SHUTDOWN) + goto clean_shutdown; + + error(_("could not read directory changes [GLE %ld]"), + GetLastError()); + goto force_error_stop; + } + +force_error_stop: + state->error_code = -1; + +force_shutdown: + /* + * Tell the IPC thead pool to stop (which completes the await + * in the main thread (which will also signal this thread (if + * we are still alive))). + */ + ipc_server_stop_async(state->ipc_server_data); + +clean_shutdown: + cancel_rdcw_watch(data->watch_worktree); + cancel_rdcw_watch(data->watch_gitdir); } int fsm_listen__ctor(struct fsmonitor_daemon_state *state) { + struct fsmonitor_daemon_backend_data *data; + + CALLOC_ARRAY(data, 1); + + data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL); + + data->watch_worktree = create_watch(state, + state->path_worktree_watch.buf); + if (!data->watch_worktree) + goto failed; + + if (state->nr_paths_watching > 1) { + data->watch_gitdir = create_watch(state, + state->path_gitdir_watch.buf); + if (!data->watch_gitdir) + goto failed; + } + + data->hListener[LISTENER_SHUTDOWN] = data->hEventShutdown; + data->nr_listener_handles++; + + data->hListener[LISTENER_HAVE_DATA_WORKTREE] = + data->watch_worktree->hEvent; + data->nr_listener_handles++; + + if (data->watch_gitdir) { + data->hListener[LISTENER_HAVE_DATA_GITDIR] = + data->watch_gitdir->hEvent; + data->nr_listener_handles++; + } + + state->backend_data = data; + return 0; + +failed: + CloseHandle(data->hEventShutdown); + destroy_watch(data->watch_worktree); + destroy_watch(data->watch_gitdir); + return -1; } void fsm_listen__dtor(struct fsmonitor_daemon_state *state) { + struct fsmonitor_daemon_backend_data *data; + + if (!state || !state->backend_data) + return; + + data = state->backend_data; + + CloseHandle(data->hEventShutdown); + destroy_watch(data->watch_worktree); + destroy_watch(data->watch_gitdir); + + FREE_AND_NULL(state->backend_data); } From patchwork Tue Mar 1 18:43:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765067 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EDEF9C433EF for ; Tue, 1 Mar 2022 18:44:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233221AbiCASpd (ORCPT ); Tue, 1 Mar 2022 13:45:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237042AbiCASoy (ORCPT ); Tue, 1 Mar 2022 13:44:54 -0500 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 175706516A for ; Tue, 1 Mar 2022 10:43:50 -0800 (PST) Received: by mail-wr1-x42c.google.com with SMTP id r10so21975088wrp.3 for ; Tue, 01 Mar 2022 10:43:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=CDWjf/n9UzLjzdXGySSp6qgLC/+A694jP9gMhCN6WGM=; b=DG2lkjBuylU7z65sLTb46Pkd2fzhM3VYLdVP3tcnRgQYDR2KxvdlkwnTjyJn8Eo4xU m3YL2QWDWY4xpli6gFHqhC101gYd53T/EEi5i5oPoo9xDgJ9cZVqH+506uClE5hh1nkn 2jScwbw8ybFkrURMcZJ1hM/h5DjTrV520FEYt0Cq1R1aSnhPpUWXGlFr5LCZbCmSZYua QOCgtJfHgVj2xwuZlxpV025C3LoI1M/kv/s67itZ47ddi4oq4i8JwDuKFR6vsgh5JpGR iEB3AiMDpKOuohDW8TmpOqL3eGLNXEeTe18TZUyBCVo/rt15v6r45rBIO7dB1XfytA1A kw2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=CDWjf/n9UzLjzdXGySSp6qgLC/+A694jP9gMhCN6WGM=; b=HMQS9fIesOHUlZXYEohtbMIaYoFR+IyG7A7RVPAlf+NjQTs3850FloDMfNFxFGLN2c /7/tleUI5Gy+1LjHx/1uSnxP+JfBFpn7h/umxja3FeDROC4tmJvVYVrSQlqJhug5imvi QLI1nUxJreHLlhOOtNrGnIO7+sv/KxtV7/YIyCwPC0IPyz5uMGcHhjvgz0lRo8FfckSE axbjJ9r/hBgvb3zKxVVloOTxq/xtHXbJ8lpFvylRF5GX2wS3I1bqSY9yGJkNXRR4kfdK QoerBuXUyRN1GZt5ut8+Qtrp8GDC+1XKTP1361Z1OPHdXoqxNeQetKwzHcajNznqdAnA UMzg== X-Gm-Message-State: AOAM531mWmhEnJYHaZFI6n3DGGcImUbdhCskV6Wc5tSkQpmq26gnNtuW EStWerNflj4q/EehYAxkvY5OIq4qz7k= X-Google-Smtp-Source: ABdhPJx2WHNSu4/OCblBL0cK2ApDZCbhf60FdJjQJp6NeET8+iirluaFgLqlKGFcKp94hTzGzZrvEw== X-Received: by 2002:a5d:43c2:0:b0:1ed:c331:9a96 with SMTP id v2-20020a5d43c2000000b001edc3319a96mr21766788wrr.389.1646160228405; Tue, 01 Mar 2022 10:43:48 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id l15-20020a05600c4f0f00b0037d62a899b1sm3475936wmq.6.2022.03.01.10.43.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:47 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:18 +0000 Subject: [PATCH v6 16/30] compat/fsmonitor/fsm-listen-darwin: add MacOS header files for FSEvent Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Include MacOS system declarations to allow us to use FSEvent and CoreFoundation APIs. We need different versions of the declarations for GCC vs. clang because of compiler and header file conflicts. While it is quite possible to #include Apple's CoreServices.h when compiling C source code with clang, trying to build it with GCC currently fails with this error: In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/Security.framework/Headers/AuthSession.h:32, from /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/Security.framework/Headers/Security.h:42, from /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/CoreServices.framework/Frameworks/... ...OSServices.framework/Headers/CSIdentity.h:43, from /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/CoreServices.framework/Frameworks/... ...OSServices.framework/Headers/OSServices.h:29, from /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/CoreServices.framework/Frameworks/... ...LaunchServices.framework/Headers/IconsCore.h:23, from /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/CoreServices.framework/Frameworks/... ...LaunchServices.framework/Headers/LaunchServices.h:23, from /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/CoreServices.framework/Headers/CoreServices.h:45, /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/... ...Library/Frameworks/Security.framework/Headers/Authorization.h:193:7: error: variably modified 'bytes' at file scope 193 | char bytes[kAuthorizationExternalFormLength]; | ^~~~~ The underlying reason is that GCC (rightfully) objects that an `enum` value such as `kAuthorizationExternalFormLength` is not a constant (because it is not, the preprocessor has no knowledge of it, only the actual C compiler does) and can therefore not be used to define the size of a C array. This is a known problem and tracked in GCC's bug tracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93082 In the meantime, let's not block things and go the slightly ugly route of declaring/defining the FSEvents constants, data structures and functions that we need, so that we can avoid above-mentioned issue. Let's do this _only_ for GCC, though, so that the CI/PR builds (which build both with clang and with GCC) can guarantee that we _are_ using the correct data types. Signed-off-by: Johannes Schindelin Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- compat/fsmonitor/fsm-listen-darwin.c | 96 ++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c index c84e3344ab9..f76341317dd 100644 --- a/compat/fsmonitor/fsm-listen-darwin.c +++ b/compat/fsmonitor/fsm-listen-darwin.c @@ -1,3 +1,99 @@ +#ifndef __clang__ +/* + * It is possible to #include CoreFoundation/CoreFoundation.h when compiling + * with clang, but not with GCC as of time of writing. + * + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93082 for details. + */ +typedef unsigned int FSEventStreamCreateFlags; +#define kFSEventStreamEventFlagNone 0x00000000 +#define kFSEventStreamEventFlagMustScanSubDirs 0x00000001 +#define kFSEventStreamEventFlagUserDropped 0x00000002 +#define kFSEventStreamEventFlagKernelDropped 0x00000004 +#define kFSEventStreamEventFlagEventIdsWrapped 0x00000008 +#define kFSEventStreamEventFlagHistoryDone 0x00000010 +#define kFSEventStreamEventFlagRootChanged 0x00000020 +#define kFSEventStreamEventFlagMount 0x00000040 +#define kFSEventStreamEventFlagUnmount 0x00000080 +#define kFSEventStreamEventFlagItemCreated 0x00000100 +#define kFSEventStreamEventFlagItemRemoved 0x00000200 +#define kFSEventStreamEventFlagItemInodeMetaMod 0x00000400 +#define kFSEventStreamEventFlagItemRenamed 0x00000800 +#define kFSEventStreamEventFlagItemModified 0x00001000 +#define kFSEventStreamEventFlagItemFinderInfoMod 0x00002000 +#define kFSEventStreamEventFlagItemChangeOwner 0x00004000 +#define kFSEventStreamEventFlagItemXattrMod 0x00008000 +#define kFSEventStreamEventFlagItemIsFile 0x00010000 +#define kFSEventStreamEventFlagItemIsDir 0x00020000 +#define kFSEventStreamEventFlagItemIsSymlink 0x00040000 +#define kFSEventStreamEventFlagOwnEvent 0x00080000 +#define kFSEventStreamEventFlagItemIsHardlink 0x00100000 +#define kFSEventStreamEventFlagItemIsLastHardlink 0x00200000 +#define kFSEventStreamEventFlagItemCloned 0x00400000 + +typedef struct __FSEventStream *FSEventStreamRef; +typedef const FSEventStreamRef ConstFSEventStreamRef; + +typedef unsigned int CFStringEncoding; +#define kCFStringEncodingUTF8 0x08000100 + +typedef const struct __CFString *CFStringRef; +typedef const struct __CFArray *CFArrayRef; +typedef const struct __CFRunLoop *CFRunLoopRef; + +struct FSEventStreamContext { + long long version; + void *cb_data, *retain, *release, *copy_description; +}; + +typedef struct FSEventStreamContext FSEventStreamContext; +typedef unsigned int FSEventStreamEventFlags; +#define kFSEventStreamCreateFlagNoDefer 0x02 +#define kFSEventStreamCreateFlagWatchRoot 0x04 +#define kFSEventStreamCreateFlagFileEvents 0x10 + +typedef unsigned long long FSEventStreamEventId; +#define kFSEventStreamEventIdSinceNow 0xFFFFFFFFFFFFFFFFULL + +typedef void (*FSEventStreamCallback)(ConstFSEventStreamRef streamRef, + void *context, + __SIZE_TYPE__ num_of_events, + void *event_paths, + const FSEventStreamEventFlags event_flags[], + const FSEventStreamEventId event_ids[]); +typedef double CFTimeInterval; +FSEventStreamRef FSEventStreamCreate(void *allocator, + FSEventStreamCallback callback, + FSEventStreamContext *context, + CFArrayRef paths_to_watch, + FSEventStreamEventId since_when, + CFTimeInterval latency, + FSEventStreamCreateFlags flags); +CFStringRef CFStringCreateWithCString(void *allocator, const char *string, + CFStringEncoding encoding); +CFArrayRef CFArrayCreate(void *allocator, const void **items, long long count, + void *callbacks); +void CFRunLoopRun(void); +void CFRunLoopStop(CFRunLoopRef run_loop); +CFRunLoopRef CFRunLoopGetCurrent(void); +extern CFStringRef kCFRunLoopDefaultMode; +void FSEventStreamScheduleWithRunLoop(FSEventStreamRef stream, + CFRunLoopRef run_loop, + CFStringRef run_loop_mode); +unsigned char FSEventStreamStart(FSEventStreamRef stream); +void FSEventStreamStop(FSEventStreamRef stream); +void FSEventStreamInvalidate(FSEventStreamRef stream); +void FSEventStreamRelease(FSEventStreamRef stream); +#else +/* + * Let Apple's headers declare `isalnum()` first, before + * Git's headers override it via a constant + */ +#include +#include +#include +#endif + #include "cache.h" #include "fsmonitor.h" #include "fsm-listen.h" From patchwork Tue Mar 1 18:43:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765066 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0C069C433F5 for ; Tue, 1 Mar 2022 18:44:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237155AbiCASpb (ORCPT ); Tue, 1 Mar 2022 13:45:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57080 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237088AbiCASoz (ORCPT ); Tue, 1 Mar 2022 13:44:55 -0500 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 132C665433 for ; Tue, 1 Mar 2022 10:43:51 -0800 (PST) Received: by mail-wm1-x32e.google.com with SMTP id a13-20020a05600c348d00b0038188b8bbf6so1764657wmq.0 for ; Tue, 01 Mar 2022 10:43:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=mCf+Ca1Eq79Fi9zXUbnlpDuLKRfsCLBNqTWp408Mz/w=; b=HZo2FCXp5uvYmEbeRTk42A5Xb9BAsNAIEWJ9zQJRsW8Th84eCzaAQuGcOyoMECE2L9 2w1iwyemBACstlhYLZh47blU+kkUJyPtsYHEmy9ZmZsbT94R4806Kmd2soBiv2XdPPQ+ NVfUjDJhwy+c0e/syeF0jvfS68gQODWNYw9Zhb4X7OrNkHJy8YYr56QBPq3I3WbdB5yx VXBD1o+wd3YZ3WSELtcSO2epq1OlIg+uOVoHR1eY6OwlA98jMWFMWzZJ6QuqNmsoL6S6 oT5TSK9vembatkkChZHjdvcLEgFd7/Ae9hprEX/tDtVK06PaCYtoqGTT6Rx8zZWVcxAy CIKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=mCf+Ca1Eq79Fi9zXUbnlpDuLKRfsCLBNqTWp408Mz/w=; b=UyYtz3/+c0HXs+X5nt/hV+QKtooufG/JyB2KNpccijUpSl58Etpo9owMG7m1ZBbuLi HDDAFC7fJ1EHOmpPR1VqfIBEqcxscA/Jn/HiSCC67jKztjVguA5TPPiHWq1Wc4YJERwa acBo3yWrYQ3rBJ98uuM1wDDs8gOQuIkjz5Zx5/p3hJqzdtq4xkmF0pA84EL6yn3t85f1 CX3wByR0IhN23U9xlDJZWVaWG9Xas8UohCIoMdoYnlf4XrNNHEOYd6wXlknkgRd474/o OTm0G+rdb0VPNYLkF+C6YpXigGYEwD0cXl3rqBrt49tVFyuNqR3UDIYJO5xSvHu+7M2r qFtA== X-Gm-Message-State: AOAM533nmRMuLuPy40GN3yKtbrOpO1bDeBGJ2Oqv76FcfuMO2J9J7wOL Q8uA+KVwwWtv0HTmRsETJFFO9I9Ug3Q= X-Google-Smtp-Source: ABdhPJyUT5Uy6Z3yeZfZkDrSdg3zd8/a84RymEmIudDTgU/7YWkbMuFFQ7XxjCvYU/CnxNew6n3wBQ== X-Received: by 2002:a05:600c:230a:b0:381:67e7:e207 with SMTP id 10-20020a05600c230a00b0038167e7e207mr8597180wmo.36.1646160229268; Tue, 01 Mar 2022 10:43:49 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m11-20020adff38b000000b001ef879a5930sm11058372wro.61.2022.03.01.10.43.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:48 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:19 +0000 Subject: [PATCH v6 17/30] compat/fsmonitor/fsm-listen-darwin: implement FSEvent listener on MacOS Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Implement file system event listener on MacOS using FSEvent, CoreFoundation, and CoreServices. Co-authored-by: Kevin Willford Co-authored-by: Johannes Schindelin Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- compat/fsmonitor/fsm-listen-darwin.c | 383 +++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c index f76341317dd..5c5de1ae702 100644 --- a/compat/fsmonitor/fsm-listen-darwin.c +++ b/compat/fsmonitor/fsm-listen-darwin.c @@ -97,20 +97,403 @@ void FSEventStreamRelease(FSEventStreamRef stream); #include "cache.h" #include "fsmonitor.h" #include "fsm-listen.h" +#include "fsmonitor--daemon.h" + +struct fsmonitor_daemon_backend_data +{ + CFStringRef cfsr_worktree_path; + CFStringRef cfsr_gitdir_path; + + CFArrayRef cfar_paths_to_watch; + int nr_paths_watching; + + FSEventStreamRef stream; + + CFRunLoopRef rl; + + enum shutdown_style { + SHUTDOWN_EVENT = 0, + FORCE_SHUTDOWN, + FORCE_ERROR_STOP, + } shutdown_style; + + unsigned int stream_scheduled:1; + unsigned int stream_started:1; +}; + +static void log_flags_set(const char *path, const FSEventStreamEventFlags flag) +{ + struct strbuf msg = STRBUF_INIT; + + if (flag & kFSEventStreamEventFlagMustScanSubDirs) + strbuf_addstr(&msg, "MustScanSubDirs|"); + if (flag & kFSEventStreamEventFlagUserDropped) + strbuf_addstr(&msg, "UserDropped|"); + if (flag & kFSEventStreamEventFlagKernelDropped) + strbuf_addstr(&msg, "KernelDropped|"); + if (flag & kFSEventStreamEventFlagEventIdsWrapped) + strbuf_addstr(&msg, "EventIdsWrapped|"); + if (flag & kFSEventStreamEventFlagHistoryDone) + strbuf_addstr(&msg, "HistoryDone|"); + if (flag & kFSEventStreamEventFlagRootChanged) + strbuf_addstr(&msg, "RootChanged|"); + if (flag & kFSEventStreamEventFlagMount) + strbuf_addstr(&msg, "Mount|"); + if (flag & kFSEventStreamEventFlagUnmount) + strbuf_addstr(&msg, "Unmount|"); + if (flag & kFSEventStreamEventFlagItemChangeOwner) + strbuf_addstr(&msg, "ItemChangeOwner|"); + if (flag & kFSEventStreamEventFlagItemCreated) + strbuf_addstr(&msg, "ItemCreated|"); + if (flag & kFSEventStreamEventFlagItemFinderInfoMod) + strbuf_addstr(&msg, "ItemFinderInfoMod|"); + if (flag & kFSEventStreamEventFlagItemInodeMetaMod) + strbuf_addstr(&msg, "ItemInodeMetaMod|"); + if (flag & kFSEventStreamEventFlagItemIsDir) + strbuf_addstr(&msg, "ItemIsDir|"); + if (flag & kFSEventStreamEventFlagItemIsFile) + strbuf_addstr(&msg, "ItemIsFile|"); + if (flag & kFSEventStreamEventFlagItemIsHardlink) + strbuf_addstr(&msg, "ItemIsHardlink|"); + if (flag & kFSEventStreamEventFlagItemIsLastHardlink) + strbuf_addstr(&msg, "ItemIsLastHardlink|"); + if (flag & kFSEventStreamEventFlagItemIsSymlink) + strbuf_addstr(&msg, "ItemIsSymlink|"); + if (flag & kFSEventStreamEventFlagItemModified) + strbuf_addstr(&msg, "ItemModified|"); + if (flag & kFSEventStreamEventFlagItemRemoved) + strbuf_addstr(&msg, "ItemRemoved|"); + if (flag & kFSEventStreamEventFlagItemRenamed) + strbuf_addstr(&msg, "ItemRenamed|"); + if (flag & kFSEventStreamEventFlagItemXattrMod) + strbuf_addstr(&msg, "ItemXattrMod|"); + if (flag & kFSEventStreamEventFlagOwnEvent) + strbuf_addstr(&msg, "OwnEvent|"); + if (flag & kFSEventStreamEventFlagItemCloned) + strbuf_addstr(&msg, "ItemCloned|"); + + trace_printf_key(&trace_fsmonitor, "fsevent: '%s', flags=%u %s", + path, flag, msg.buf); + + strbuf_release(&msg); +} + +static int ef_is_root_delete(const FSEventStreamEventFlags ef) +{ + return (ef & kFSEventStreamEventFlagItemIsDir && + ef & kFSEventStreamEventFlagItemRemoved); +} + +static int ef_is_root_renamed(const FSEventStreamEventFlags ef) +{ + return (ef & kFSEventStreamEventFlagItemIsDir && + ef & kFSEventStreamEventFlagItemRenamed); +} + +static int ef_is_dropped(const FSEventStreamEventFlags ef) +{ + return (ef & kFSEventStreamEventFlagMustScanSubDirs || + ef & kFSEventStreamEventFlagKernelDropped || + ef & kFSEventStreamEventFlagUserDropped); +} + +static void fsevent_callback(ConstFSEventStreamRef streamRef, + void *ctx, + size_t num_of_events, + void *event_paths, + const FSEventStreamEventFlags event_flags[], + const FSEventStreamEventId event_ids[]) +{ + struct fsmonitor_daemon_state *state = ctx; + struct fsmonitor_daemon_backend_data *data = state->backend_data; + char **paths = (char **)event_paths; + struct fsmonitor_batch *batch = NULL; + struct string_list cookie_list = STRING_LIST_INIT_DUP; + const char *path_k; + const char *slash; + int k; + struct strbuf tmp = STRBUF_INIT; + + /* + * Build a list of all filesystem changes into a private/local + * list and without holding any locks. + */ + for (k = 0; k < num_of_events; k++) { + /* + * On Mac, we receive an array of absolute paths. + */ + path_k = paths[k]; + + /* + * If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR. + * Please don't log them to Trace2. + * + * trace_printf_key(&trace_fsmonitor, "Path: '%s'", path_k); + */ + + /* + * If event[k] is marked as dropped, we assume that we have + * lost sync with the filesystem and should flush our cached + * data. We need to: + * + * [1] Abort/wake any client threads waiting for a cookie and + * flush the cached state data (the current token), and + * create a new token. + * + * [2] Discard the batch that we were locally building (since + * they are conceptually relative to the just flushed + * token). + */ + if (ef_is_dropped(event_flags[k])) { + if (trace_pass_fl(&trace_fsmonitor)) + log_flags_set(path_k, event_flags[k]); + + fsmonitor_force_resync(state); + fsmonitor_batch__free_list(batch); + string_list_clear(&cookie_list, 0); + + /* + * We assume that any events that we received + * in this callback after this dropped event + * may still be valid, so we continue rather + * than break. (And just in case there is a + * delete of ".git" hiding in there.) + */ + continue; + } + + switch (fsmonitor_classify_path_absolute(state, path_k)) { + + case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX: + case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX: + /* special case cookie files within .git or gitdir */ + + /* Use just the filename of the cookie file. */ + slash = find_last_dir_sep(path_k); + string_list_append(&cookie_list, + slash ? slash + 1 : path_k); + break; + + case IS_INSIDE_DOT_GIT: + case IS_INSIDE_GITDIR: + /* ignore all other paths inside of .git or gitdir */ + break; + + case IS_DOT_GIT: + case IS_GITDIR: + /* + * If .git directory is deleted or renamed away, + * we have to quit. + */ + if (ef_is_root_delete(event_flags[k])) { + trace_printf_key(&trace_fsmonitor, + "event: gitdir removed"); + goto force_shutdown; + } + if (ef_is_root_renamed(event_flags[k])) { + trace_printf_key(&trace_fsmonitor, + "event: gitdir renamed"); + goto force_shutdown; + } + break; + + case IS_WORKDIR_PATH: + /* try to queue normal pathnames */ + + if (trace_pass_fl(&trace_fsmonitor)) + log_flags_set(path_k, event_flags[k]); + + /* + * Because of the implicit "binning" (the + * kernel calls us at a given frequency) and + * de-duping (the kernel is free to combine + * multiple events for a given pathname), an + * individual fsevent could be marked as both + * a file and directory. Add it to the queue + * with both spellings so that the client will + * know how much to invalidate/refresh. + */ + + if (event_flags[k] & kFSEventStreamEventFlagItemIsFile) { + const char *rel = path_k + + state->path_worktree_watch.len + 1; + + if (!batch) + batch = fsmonitor_batch__new(); + fsmonitor_batch__add_path(batch, rel); + } + + if (event_flags[k] & kFSEventStreamEventFlagItemIsDir) { + const char *rel = path_k + + state->path_worktree_watch.len + 1; + + strbuf_reset(&tmp); + strbuf_addstr(&tmp, rel); + strbuf_addch(&tmp, '/'); + + if (!batch) + batch = fsmonitor_batch__new(); + fsmonitor_batch__add_path(batch, tmp.buf); + } + + break; + + case IS_OUTSIDE_CONE: + default: + trace_printf_key(&trace_fsmonitor, + "ignoring '%s'", path_k); + break; + } + } + + fsmonitor_publish(state, batch, &cookie_list); + string_list_clear(&cookie_list, 0); + strbuf_release(&tmp); + return; + +force_shutdown: + fsmonitor_batch__free_list(batch); + string_list_clear(&cookie_list, 0); + + data->shutdown_style = FORCE_SHUTDOWN; + CFRunLoopStop(data->rl); + strbuf_release(&tmp); + return; +} + +/* + * In the call to `FSEventStreamCreate()` to setup our watch, the + * `latency` argument determines the frequency of calls to our callback + * with new FS events. Too slow and events get dropped; too fast and + * we burn CPU unnecessarily. Since it is rather obscure, I don't + * think this needs to be a config setting. I've done extensive + * testing on my systems and chosen the value below. It gives good + * results and I've not seen any dropped events. + * + * With a latency of 0.1, I was seeing lots of dropped events during + * the "touch 100000" files test within t/perf/p7519, but with a + * latency of 0.001 I did not see any dropped events. So I'm going + * to assume that this is the "correct" value. + * + * https://developer.apple.com/documentation/coreservices/1443980-fseventstreamcreate + */ int fsm_listen__ctor(struct fsmonitor_daemon_state *state) { + FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagNoDefer | + kFSEventStreamCreateFlagWatchRoot | + kFSEventStreamCreateFlagFileEvents; + FSEventStreamContext ctx = { + 0, + state, + NULL, + NULL, + NULL + }; + struct fsmonitor_daemon_backend_data *data; + const void *dir_array[2]; + + CALLOC_ARRAY(data, 1); + state->backend_data = data; + + data->cfsr_worktree_path = CFStringCreateWithCString( + NULL, state->path_worktree_watch.buf, kCFStringEncodingUTF8); + dir_array[data->nr_paths_watching++] = data->cfsr_worktree_path; + + if (state->nr_paths_watching > 1) { + data->cfsr_gitdir_path = CFStringCreateWithCString( + NULL, state->path_gitdir_watch.buf, + kCFStringEncodingUTF8); + dir_array[data->nr_paths_watching++] = data->cfsr_gitdir_path; + } + + data->cfar_paths_to_watch = CFArrayCreate(NULL, dir_array, + data->nr_paths_watching, + NULL); + data->stream = FSEventStreamCreate(NULL, fsevent_callback, &ctx, + data->cfar_paths_to_watch, + kFSEventStreamEventIdSinceNow, + 0.001, flags); + if (data->stream == NULL) + goto failed; + + /* + * `data->rl` needs to be set inside the listener thread. + */ + + return 0; + +failed: + error("Unable to create FSEventStream."); + + FREE_AND_NULL(state->backend_data); return -1; } void fsm_listen__dtor(struct fsmonitor_daemon_state *state) { + struct fsmonitor_daemon_backend_data *data; + + if (!state || !state->backend_data) + return; + + data = state->backend_data; + + if (data->stream) { + if (data->stream_started) + FSEventStreamStop(data->stream); + if (data->stream_scheduled) + FSEventStreamInvalidate(data->stream); + FSEventStreamRelease(data->stream); + } + + FREE_AND_NULL(state->backend_data); } void fsm_listen__stop_async(struct fsmonitor_daemon_state *state) { + struct fsmonitor_daemon_backend_data *data; + + data = state->backend_data; + data->shutdown_style = SHUTDOWN_EVENT; + + CFRunLoopStop(data->rl); } void fsm_listen__loop(struct fsmonitor_daemon_state *state) { + struct fsmonitor_daemon_backend_data *data; + + data = state->backend_data; + + data->rl = CFRunLoopGetCurrent(); + + FSEventStreamScheduleWithRunLoop(data->stream, data->rl, kCFRunLoopDefaultMode); + data->stream_scheduled = 1; + + if (!FSEventStreamStart(data->stream)) { + error("Failed to start the FSEventStream"); + goto force_error_stop_without_loop; + } + data->stream_started = 1; + + CFRunLoopRun(); + + switch (data->shutdown_style) { + case FORCE_ERROR_STOP: + state->error_code = -1; + /* fall thru */ + case FORCE_SHUTDOWN: + ipc_server_stop_async(state->ipc_server_data); + /* fall thru */ + case SHUTDOWN_EVENT: + default: + break; + } + return; + +force_error_stop_without_loop: + state->error_code = -1; + ipc_server_stop_async(state->ipc_server_data); + return; } From patchwork Tue Mar 1 18:43:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765064 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4872EC433EF for ; Tue, 1 Mar 2022 18:44:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237151AbiCASp2 (ORCPT ); Tue, 1 Mar 2022 13:45:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57088 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237091AbiCASoz (ORCPT ); Tue, 1 Mar 2022 13:44:55 -0500 Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E5D2B2A24B for ; Tue, 1 Mar 2022 10:43:51 -0800 (PST) Received: by mail-wm1-x333.google.com with SMTP id c192so8031554wma.4 for ; Tue, 01 Mar 2022 10:43:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=RhlYIwHUBo47mOG4YPeLwxrjGp3T3Jj14AUKPUXNhbc=; b=nFytLpr8peM8e+86tHqtI9QeX5uIc6xrBiOHUObPKnKF4dKxKp0XVysoepIVf1mN3D S3mclGs5yZcx/i76/vjal+LLisAsirIT70pAEVdKjWUuC4L9dFjMA5i7nwvKA0G6BmDK 46BSxdY4HvyeIdgJAiLAtGHwBxcIgw2M6fnmZCeRSeqckrHD2rXBzlL2mKNsUf27Jl5R /5c4SUse2F007WlFiiv+vZ75TH7jOosdk+9cE3+6YHMOO//0QL04A8ViwnBbxIduyrAb FVxe5d9ZxuO5bIeYoZEcp5jRKXJbo7+aP5A5umss5tE8c2906zQ4EnDoURkyY5rjv+z4 D9qA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=RhlYIwHUBo47mOG4YPeLwxrjGp3T3Jj14AUKPUXNhbc=; b=QbeWysEa1qL5NAKJgIJATz2C2HgkAJDgq1YupAA3+l7It/UCmwM5Ea8R2W8hjvZ4U6 pKG5BZWbTrI9SJitgYSZLHag/vrlBOJpUFnSvXjXKNYHF4rwRpn91/dVfGv7slbI5i8/ Ff68IqG+Mc7IAB9RaMakQ1AYn9vtpqrMYUWE2XHZF8q86RMurCGLohlI9aZoqD4Fp562 HDppv54bU44TsbCVAq/5TQL8yUHnGvtUPurjD6qhHO0Hm6TooupIWskDCs411P6Ur11M 3lSh3FkUnSAJ8wwGds/Dl5KbPz834JQoCYM+sFYzV2+47Qah1BA6Kuzq4r+PZkRY3oBL CT8g== X-Gm-Message-State: AOAM53382oODgMko1IzXI4xDjGvJ6qrWUNEQECeUiXoKdXhrs6PctQ1i 48wo1U/9iMTbIiIZK6r6iXOz5P3czeY= X-Google-Smtp-Source: ABdhPJyrALlyS1VcXd+LzZpHO1W2RW68sjX5knFqjKSxjsAH3yEIyYyeQRIX8wW2Z5TkitKnCMCBkQ== X-Received: by 2002:a1c:a7ce:0:b0:380:eb26:f41a with SMTP id q197-20020a1ca7ce000000b00380eb26f41amr18112668wme.105.1646160230240; Tue, 01 Mar 2022 10:43:50 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id bk19-20020a0560001d9300b001a65e479d20sm13644863wrb.83.2022.03.01.10.43.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:49 -0800 (PST) Message-Id: <0896e72e2b8e23354de9d476fbda55008a11de68.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:20 +0000 Subject: [PATCH v6 18/30] fsmonitor--daemon: implement handle_client callback Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach fsmonitor--daemon to respond to IPC requests from client Git processes and respond with a list of modified pathnames relative to the provided token. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 312 +++++++++++++++++++++++++++++++++++- 1 file changed, 310 insertions(+), 2 deletions(-) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 7c44b979035..65c1ef7d4bf 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -7,6 +7,7 @@ #include "fsmonitor--daemon.h" #include "simple-ipc.h" #include "khash.h" +#include "pkt-line.h" static const char * const builtin_fsmonitor__daemon_usage[] = { N_("git fsmonitor--daemon start []"), @@ -364,6 +365,311 @@ void fsmonitor_force_resync(struct fsmonitor_daemon_state *state) pthread_mutex_unlock(&state->main_lock); } +/* + * Format an opaque token string to send to the client. + */ +static void with_lock__format_response_token( + struct strbuf *response_token, + const struct strbuf *response_token_id, + const struct fsmonitor_batch *batch) +{ + /* assert current thread holding state->main_lock */ + + strbuf_reset(response_token); + strbuf_addf(response_token, "builtin:%s:%"PRIu64, + response_token_id->buf, batch->batch_seq_nr); +} + +/* + * Parse an opaque token from the client. + * Returns -1 on error. + */ +static int fsmonitor_parse_client_token(const char *buf_token, + struct strbuf *requested_token_id, + uint64_t *seq_nr) +{ + const char *p; + char *p_end; + + strbuf_reset(requested_token_id); + *seq_nr = 0; + + if (!skip_prefix(buf_token, "builtin:", &p)) + return -1; + + while (*p && *p != ':') + strbuf_addch(requested_token_id, *p++); + if (!*p++) + return -1; + + *seq_nr = (uint64_t)strtoumax(p, &p_end, 10); + if (*p_end) + return -1; + + return 0; +} + +KHASH_INIT(str, const char *, int, 0, kh_str_hash_func, kh_str_hash_equal) + +static int do_handle_client(struct fsmonitor_daemon_state *state, + const char *command, + ipc_server_reply_cb *reply, + struct ipc_server_reply_data *reply_data) +{ + struct fsmonitor_token_data *token_data = NULL; + struct strbuf response_token = STRBUF_INIT; + struct strbuf requested_token_id = STRBUF_INIT; + struct strbuf payload = STRBUF_INIT; + uint64_t requested_oldest_seq_nr = 0; + uint64_t total_response_len = 0; + const char *p; + const struct fsmonitor_batch *batch_head; + const struct fsmonitor_batch *batch; + intmax_t count = 0, duplicates = 0; + kh_str_t *shown; + int hash_ret; + int do_trivial = 0; + int do_flush = 0; + + /* + * We expect `command` to be of the form: + * + * := quit NUL + * | flush NUL + * | NUL + * | NUL + */ + + if (!strcmp(command, "quit")) { + /* + * A client has requested over the socket/pipe that the + * daemon shutdown. + * + * Tell the IPC thread pool to shutdown (which completes + * the await in the main thread (which can stop the + * fsmonitor listener thread)). + * + * There is no reply to the client. + */ + return SIMPLE_IPC_QUIT; + + } else if (!strcmp(command, "flush")) { + /* + * Flush all of our cached data and generate a new token + * just like if we lost sync with the filesystem. + * + * Then send a trivial response using the new token. + */ + do_flush = 1; + do_trivial = 1; + + } else if (!skip_prefix(command, "builtin:", &p)) { + /* assume V1 timestamp or garbage */ + + char *p_end; + + strtoumax(command, &p_end, 10); + trace_printf_key(&trace_fsmonitor, + ((*p_end) ? + "fsmonitor: invalid command line '%s'" : + "fsmonitor: unsupported V1 protocol '%s'"), + command); + do_trivial = 1; + + } else { + /* We have "builtin:*" */ + if (fsmonitor_parse_client_token(command, &requested_token_id, + &requested_oldest_seq_nr)) { + trace_printf_key(&trace_fsmonitor, + "fsmonitor: invalid V2 protocol token '%s'", + command); + do_trivial = 1; + + } else { + /* + * We have a V2 valid token: + * "builtin::" + */ + } + } + + pthread_mutex_lock(&state->main_lock); + + if (!state->current_token_data) + BUG("fsmonitor state does not have a current token"); + + if (do_flush) + with_lock__do_force_resync(state); + + /* + * We mark the current head of the batch list as "pinned" so + * that the listener thread will treat this item as read-only + * (and prevent any more paths from being added to it) from + * now on. + */ + token_data = state->current_token_data; + batch_head = token_data->batch_head; + ((struct fsmonitor_batch *)batch_head)->pinned_time = time(NULL); + + /* + * FSMonitor Protocol V2 requires that we send a response header + * with a "new current token" and then all of the paths that changed + * since the "requested token". We send the seq_nr of the just-pinned + * head batch so that future requests from a client will be relative + * to it. + */ + with_lock__format_response_token(&response_token, + &token_data->token_id, batch_head); + + reply(reply_data, response_token.buf, response_token.len + 1); + total_response_len += response_token.len + 1; + + trace2_data_string("fsmonitor", the_repository, "response/token", + response_token.buf); + trace_printf_key(&trace_fsmonitor, "response token: %s", + response_token.buf); + + if (!do_trivial) { + if (strcmp(requested_token_id.buf, token_data->token_id.buf)) { + /* + * The client last spoke to a different daemon + * instance -OR- the daemon had to resync with + * the filesystem (and lost events), so reject. + */ + trace2_data_string("fsmonitor", the_repository, + "response/token", "different"); + do_trivial = 1; + + } else if (requested_oldest_seq_nr < + token_data->batch_tail->batch_seq_nr) { + /* + * The client wants older events than we have for + * this token_id. This means that the end of our + * batch list was truncated and we cannot give the + * client a complete snapshot relative to their + * request. + */ + trace_printf_key(&trace_fsmonitor, + "client requested truncated data"); + do_trivial = 1; + } + } + + if (do_trivial) { + pthread_mutex_unlock(&state->main_lock); + + reply(reply_data, "/", 2); + + trace2_data_intmax("fsmonitor", the_repository, + "response/trivial", 1); + + strbuf_release(&response_token); + strbuf_release(&requested_token_id); + return 0; + } + + /* + * We're going to hold onto a pointer to the current + * token-data while we walk the list of batches of files. + * During this time, we will NOT be under the lock. + * So we ref-count it. + * + * This allows the listener thread to continue prepending + * new batches of items to the token-data (which we'll ignore). + * + * AND it allows the listener thread to do a token-reset + * (and install a new `current_token_data`). + */ + token_data->client_ref_count++; + + pthread_mutex_unlock(&state->main_lock); + + /* + * The client request is relative to the token that they sent, + * so walk the batch list backwards from the current head back + * to the batch (sequence number) they named. + * + * We use khash to de-dup the list of pathnames. + * + * NEEDSWORK: each batch contains a list of interned strings, + * so we only need to do pointer comparisons here to build the + * hash table. Currently, we're still comparing the string + * values. + */ + shown = kh_init_str(); + for (batch = batch_head; + batch && batch->batch_seq_nr > requested_oldest_seq_nr; + batch = batch->next) { + size_t k; + + for (k = 0; k < batch->nr; k++) { + const char *s = batch->interned_paths[k]; + size_t s_len; + + if (kh_get_str(shown, s) != kh_end(shown)) + duplicates++; + else { + kh_put_str(shown, s, &hash_ret); + + trace_printf_key(&trace_fsmonitor, + "send[%"PRIuMAX"]: %s", + count, s); + + /* Each path gets written with a trailing NUL */ + s_len = strlen(s) + 1; + + if (payload.len + s_len >= + LARGE_PACKET_DATA_MAX) { + reply(reply_data, payload.buf, + payload.len); + total_response_len += payload.len; + strbuf_reset(&payload); + } + + strbuf_add(&payload, s, s_len); + count++; + } + } + } + + if (payload.len) { + reply(reply_data, payload.buf, payload.len); + total_response_len += payload.len; + } + + kh_release_str(shown); + + pthread_mutex_lock(&state->main_lock); + + if (token_data->client_ref_count > 0) + token_data->client_ref_count--; + + if (token_data->client_ref_count == 0) { + if (token_data != state->current_token_data) { + /* + * The listener thread did a token-reset while we were + * walking the batch list. Therefore, this token is + * stale and can be discarded completely. If we are + * the last reader thread using this token, we own + * that work. + */ + fsmonitor_free_token_data(token_data); + } + } + + pthread_mutex_unlock(&state->main_lock); + + trace2_data_intmax("fsmonitor", the_repository, "response/length", total_response_len); + trace2_data_intmax("fsmonitor", the_repository, "response/count/files", count); + trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates); + + strbuf_release(&response_token); + strbuf_release(&requested_token_id); + strbuf_release(&payload); + + return 0; +} + static ipc_server_application_cb handle_client; static int handle_client(void *data, @@ -371,7 +677,7 @@ static int handle_client(void *data, ipc_server_reply_cb *reply, struct ipc_server_reply_data *reply_data) { - /* struct fsmonitor_daemon_state *state = data; */ + struct fsmonitor_daemon_state *state = data; int result; /* @@ -382,10 +688,12 @@ static int handle_client(void *data, if (command_len != strlen(command)) BUG("FSMonitor assumes text messages"); + trace_printf_key(&trace_fsmonitor, "requested token: %s", command); + trace2_region_enter("fsmonitor", "handle_client", the_repository); trace2_data_string("fsmonitor", the_repository, "request", command); - result = 0; /* TODO Do something here. */ + result = do_handle_client(state, command, reply, reply_data); trace2_region_leave("fsmonitor", "handle_client", the_repository); From patchwork Tue Mar 1 18:43:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765063 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C0A69C433FE for ; Tue, 1 Mar 2022 18:44:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237150AbiCASp0 (ORCPT ); Tue, 1 Mar 2022 13:45:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55088 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237096AbiCASoz (ORCPT ); Tue, 1 Mar 2022 13:44:55 -0500 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ADD7965791 for ; Tue, 1 Mar 2022 10:43:52 -0800 (PST) Received: by mail-wm1-x335.google.com with SMTP id c18-20020a7bc852000000b003806ce86c6dso1776591wml.5 for ; Tue, 01 Mar 2022 10:43:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=FHMNZKs576+n2YSEBmmlnXIC91fIZibgzgB6togRe14=; b=T56Ruzc7MjHrMkNsmngczOILu3RRSmAySSJ+3NU08aVaxJuYJ3pcbUv6QKFnkfO24C mCWoL0Ak+1pbxzR1frFxmnIjvuIs2a5EssVWoUK3np8Z3dnmK2jRaEWbOtZHI3i2R4nx YMqi7oNpXeyps7sGcNFvd6FEcSl+RcN0PAC30dB7B+4lCSfFKT0FkC4Ahyh3ZevXgsfZ m43lM6Ky/lJPvAD8nlZmrSgw+8kXvOQpV50L2g20gFyAxkMPs69dZx4wZkxPXY9SArIA g7+9szhFa+OZdIKrlCOHxjeuHAlpABK0Vmf/msK8zeem5FoRgmXlxCqbzbB1vq5lLLVP ejTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=FHMNZKs576+n2YSEBmmlnXIC91fIZibgzgB6togRe14=; b=rhXIwQXCvzjZMDZgwpLfmHsCT6FNUumeuxgjCPxjZTS1z2A4dY16GpJbp4h3lHsi1P O8KWhKv5s+mf+4rt/0TQE05P2MWzMWqIyjZ9BjRhvGPW+VdY+i2n8jxxsUi0HTZ4QqJX P2Jq5CJUp5kBUthZFI4W65p6T1Scw0jiz1rfslHvwVNc6xt9T2QJRvUXFTheHN10hoMV Uc5eqaY/bAcTSia5E5DOu6aYBNwAqAy6SbYhE0DP6EHskp9H7r2FPLsIHlzs9nGgJlb0 29W56FxWK80XCksUr56jKVWpJVJOngV9+JQRjZE4/pQggG7mQoD6bsWJshnQK2AuhykF wdsw== X-Gm-Message-State: AOAM530Wwx4tJ6hjuwmMOb89/V0dePoGlmfEMFaESVuasnJMe/kZCZQq CAi+I1KqwrNnALH47CPzntsJF4V9Udg= X-Google-Smtp-Source: ABdhPJyrS1nflOQXonnf6vLBST+RB1AezxZJtoalIrRkreWZOcI7aEwWdNeWYJXC/6rwzPkO6UPplA== X-Received: by 2002:a05:600c:4e48:b0:381:83d8:54f6 with SMTP id e8-20020a05600c4e4800b0038183d854f6mr3943707wmq.18.1646160231085; Tue, 01 Mar 2022 10:43:51 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m26-20020a05600c3b1a00b003817ab146e9sm4623487wms.44.2022.03.01.10.43.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:50 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:21 +0000 Subject: [PATCH v6 19/30] help: include fsmonitor--daemon feature flag in version info Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Add the "feature: fsmonitor--daemon" message to the output of `git version --build-options`. The builtin FSMonitor is only available on certain platforms and even then only when certain Makefile flags are enabled, so print a message in the verbose version output when it is available. This can be used by test scripts for prereq testing. Granted, tests could just try `git fsmonitor--daemon status` and look for a 128 exit code or grep for a "not supported" message on stderr, but these methods are rather obscure. The main advantage is that the feature message will automatically appear in bug reports and other support requests. This concept was also used during the development of Scalar for similar reasons. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- help.c | 4 ++++ t/test-lib.sh | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/help.c b/help.c index 71444906ddf..9112a51e84b 100644 --- a/help.c +++ b/help.c @@ -12,6 +12,7 @@ #include "refs.h" #include "parse-options.h" #include "prompt.h" +#include "fsmonitor-ipc.h" struct category_description { uint32_t category; @@ -695,6 +696,9 @@ void get_version_info(struct strbuf *buf, int show_build_options) strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t)); strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH); /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ + + if (fsmonitor_ipc__is_supported()) + strbuf_addstr(buf, "feature: fsmonitor--daemon\n"); } } diff --git a/t/test-lib.sh b/t/test-lib.sh index e4716b0b867..46cd596e7f5 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1799,3 +1799,9 @@ test_lazy_prereq SHA1 ' # Tests that verify the scheduler integration must set this locally # to avoid errors. GIT_TEST_MAINT_SCHEDULER="none:exit 1" + +# Does this platform support `git fsmonitor--daemon` +# +test_lazy_prereq FSMONITOR_DAEMON ' + git version --build-options | grep "feature:" | grep "fsmonitor--daemon" +' From patchwork Tue Mar 1 18:43:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765056 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D488CC433EF for ; Tue, 1 Mar 2022 18:44:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237119AbiCASpL (ORCPT ); Tue, 1 Mar 2022 13:45:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237097AbiCASoz (ORCPT ); Tue, 1 Mar 2022 13:44:55 -0500 Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 87F216579E for ; Tue, 1 Mar 2022 10:43:53 -0800 (PST) Received: by mail-wr1-x42e.google.com with SMTP id bk29so4650397wrb.4 for ; Tue, 01 Mar 2022 10:43:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=LiVhcaCHGvMCsb+ulNn/6al8f/Ptsx7ApJ9UIEJdfOk=; b=Jr4HO8k1LxPZL5/8ANcjki9Xe2UbbNqi9qrhsjSqrVzVqtrZO/ir65wln3HFNbcKmQ EZjUtFEa6/oBLmVkv8AsWtx0SBK5UQx6uCBKkngCDiAT8cnZWvHNU/e8GNQJLTckAJ4i K0mMnBclofWFIxGL2OQLf+ticFTcxx9SeFT7Kb9R3zycdleNyCaLtxKT8c+ucO7oQHVM XErhb5zuoIIqwzIHbhazssEnHp0ZFGtYlE7/l9UQ6vHvGCv9NWlbCbTOYer+Sk1iiwQT 10MOeGdq1FropFDsbFSQBjiz9W/3lR6zun4IPicdZuPgCelbOIr/9x1w67Kw3kGXZj/l XsRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=LiVhcaCHGvMCsb+ulNn/6al8f/Ptsx7ApJ9UIEJdfOk=; b=TgRaD8MpUe4cKz13iLp5mcBpbvYUU5TtC+PXyEDhXCpsKLiSViDGTRF1jtM/8CM7JV 5Us/JwnDe8w1nf3vLsTY4CWc0RYpv9tf9e3DILSG0v2t+UFwMAQugC0HYesWslCy9ABL iEtjGDkZuteJbSub2yP7gq1GS6T9rGvl6qotqyg32zfEtCHQg7LZoBap5Ngg7o1r1adR prqFTsrWxFgfi+9WIj7qTaMt3cNkgcPM6ZnbkOopI3PMqGreeUezubhTfIj+PggETiFH JoLpPkRrtMHSG9HvDNlJ6Hzz2f0CVBTx7+KG6WpIOPxc/MsaJoD+4/J+bfn0zRK6B0qx Iz7Q== X-Gm-Message-State: AOAM5331Yfh0J46+idxWoJwo1MbL8SA/SJyOj4PuVqk5jp1CyB2+q4td SCX/iDGCLwjM4lWnvsX52gsVB6+UeE4= X-Google-Smtp-Source: ABdhPJwTm4PwI07qT859kRCLpjjqrTR0oXxCS8PIwdyf+9LDsCrbjIBNqiPTxs+OAcQSjmQfwcdHvw== X-Received: by 2002:a5d:4d87:0:b0:1ef:cf9a:2f9 with SMTP id b7-20020a5d4d87000000b001efcf9a02f9mr8454702wru.204.1646160231916; Tue, 01 Mar 2022 10:43:51 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id p11-20020adfce0b000000b001e7026150besm14567721wrn.31.2022.03.01.10.43.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:51 -0800 (PST) Message-Id: <2b563c240eb1b592e95e89400aa5d57df1bf29b8.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:22 +0000 Subject: [PATCH v6 20/30] t/helper/fsmonitor-client: create IPC client to talk to FSMonitor Daemon Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Create an IPC client to send query and flush commands to the daemon. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- Makefile | 1 + t/helper/test-fsmonitor-client.c | 121 +++++++++++++++++++++++++++++++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + 4 files changed, 124 insertions(+) create mode 100644 t/helper/test-fsmonitor-client.c diff --git a/Makefile b/Makefile index 26567d4f772..daa21bed6c3 100644 --- a/Makefile +++ b/Makefile @@ -716,6 +716,7 @@ TEST_BUILTINS_OBJS += test-dump-split-index.o TEST_BUILTINS_OBJS += test-dump-untracked-cache.o TEST_BUILTINS_OBJS += test-example-decorate.o TEST_BUILTINS_OBJS += test-fast-rebase.o +TEST_BUILTINS_OBJS += test-fsmonitor-client.o TEST_BUILTINS_OBJS += test-genrandom.o TEST_BUILTINS_OBJS += test-genzeros.o TEST_BUILTINS_OBJS += test-getcwd.o diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c new file mode 100644 index 00000000000..f7a5b3a32fa --- /dev/null +++ b/t/helper/test-fsmonitor-client.c @@ -0,0 +1,121 @@ +/* + * test-fsmonitor-client.c: client code to send commands/requests to + * a `git fsmonitor--daemon` daemon. + */ + +#include "test-tool.h" +#include "cache.h" +#include "parse-options.h" +#include "fsmonitor-ipc.h" + +#ifndef HAVE_FSMONITOR_DAEMON_BACKEND +int cmd__fsmonitor_client(int argc, const char **argv) +{ + die("fsmonitor--daemon not available on this platform"); +} +#else + +/* + * Read the `.git/index` to get the last token written to the + * FSMonitor Index Extension. + */ +static const char *get_token_from_index(void) +{ + struct index_state *istate = the_repository->index; + + if (do_read_index(istate, the_repository->index_file, 0) < 0) + die("unable to read index file"); + if (!istate->fsmonitor_last_update) + die("index file does not have fsmonitor extension"); + + return istate->fsmonitor_last_update; +} + +/* + * Send an IPC query to a `git-fsmonitor--daemon` daemon and + * ask for the changes since the given token or from the last + * token in the index extension. + * + * This will implicitly start a daemon process if necessary. The + * daemon process will persist after we exit. + */ +static int do_send_query(const char *token) +{ + struct strbuf answer = STRBUF_INIT; + int ret; + + if (!token || !*token) + token = get_token_from_index(); + + ret = fsmonitor_ipc__send_query(token, &answer); + if (ret < 0) + die(_("could not query fsmonitor--daemon")); + + write_in_full(1, answer.buf, answer.len); + strbuf_release(&answer); + + return 0; +} + +/* + * Send a "flush" command to the `git-fsmonitor--daemon` (if running) + * and tell it to flush its cache. + * + * This feature is primarily used by the test suite to simulate a loss of + * sync with the filesystem where we miss kernel events. + */ +static int do_send_flush(void) +{ + struct strbuf answer = STRBUF_INIT; + int ret; + + ret = fsmonitor_ipc__send_command("flush", &answer); + if (ret) + return ret; + + write_in_full(1, answer.buf, answer.len); + strbuf_release(&answer); + + return 0; +} + +int cmd__fsmonitor_client(int argc, const char **argv) +{ + const char *subcmd; + const char *token = NULL; + + const char * const fsmonitor_client_usage[] = { + N_("test-helper fsmonitor-client query []"), + N_("test-helper fsmonitor-client flush"), + NULL, + }; + + struct option options[] = { + OPT_STRING(0, "token", &token, N_("token"), + N_("command token to send to the server")), + OPT_END() + }; + + if (argc < 2) + usage_with_options(fsmonitor_client_usage, options); + + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(fsmonitor_client_usage, options); + + subcmd = argv[1]; + argv--; + argc++; + + argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0); + + setup_git_directory(); + + if (!strcmp(subcmd, "query")) + return !!do_send_query(token); + + if (!strcmp(subcmd, "flush")) + return !!do_send_flush(); + + die("Unhandled subcommand: '%s'", subcmd); +} +#endif diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index e6ec69cf326..0424f7adf5d 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -32,6 +32,7 @@ static struct test_cmd cmds[] = { { "dump-untracked-cache", cmd__dump_untracked_cache }, { "example-decorate", cmd__example_decorate }, { "fast-rebase", cmd__fast_rebase }, + { "fsmonitor-client", cmd__fsmonitor_client }, { "genrandom", cmd__genrandom }, { "genzeros", cmd__genzeros }, { "getcwd", cmd__getcwd }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 20756eefdda..c876e8246fb 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -23,6 +23,7 @@ int cmd__dump_untracked_cache(int argc, const char **argv); int cmd__dump_reftable(int argc, const char **argv); int cmd__example_decorate(int argc, const char **argv); int cmd__fast_rebase(int argc, const char **argv); +int cmd__fsmonitor_client(int argc, const char **argv); int cmd__genrandom(int argc, const char **argv); int cmd__genzeros(int argc, const char **argv); int cmd__getcwd(int argc, const char **argv); From patchwork Tue Mar 1 18:43:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765061 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCE27C433FE for ; Tue, 1 Mar 2022 18:44:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233257AbiCASpX (ORCPT ); Tue, 1 Mar 2022 13:45:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237106AbiCASoz (ORCPT ); Tue, 1 Mar 2022 13:44:55 -0500 Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F3A6657B4 for ; Tue, 1 Mar 2022 10:43:54 -0800 (PST) Received: by mail-wr1-x42f.google.com with SMTP id t11so953705wrm.5 for ; Tue, 01 Mar 2022 10:43:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=ODuNg15CXAlMZk9QLr/IXCBO1K/76+iTCoZ+ADCF8lQ=; b=gnetaDHc5PCZnyE4qt7P0beqd+1KcjtHrqIEYWhpi5rEiK0YWuUFnbnw+HQtnU4hge HLWFvMpsQ7T3WIXtUJoE82WmUq7hljjDEhNyFTk5Hrg+x5+GiIGGpZgZjXnf+nAGkm4C rxKWVFDVAXNCXCWAgEHafBNrHjmnGLUyiF1yCvu74PIHU5J1zT1ihxb3mC6AexD2jj29 0IMG8JdxbZsFG2NZVu1Q1hAdgiKDss1rJqbZM6lLbS/P0Pdut6QIFx6RKxDcVzpLnJOV tOhwtc1E/NajuxKmUDcoZVddAEhhoV9Fg8poM8SmQIivVyFqZuAt2tmTzPorfMkTd0sC L88g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=ODuNg15CXAlMZk9QLr/IXCBO1K/76+iTCoZ+ADCF8lQ=; b=2qF9nE8FPDVCBHmDSGUS1rJYL2580T9AXSw3GddnqfD4TVOGpo4gLodcTocc01gmq5 3mLHKl6NMOqZG/++lHwlu6FTh3tofVRMm1c/MoyS+K5shtNuWtNxmxl5LdTj7HLUoEMT BRzh5FlTV/aIAVur+OF3jmoiK+tG1/W7HL5quuyfLRtGn9LRtaTExQ6DF/urkqSxyihJ w2uK/46AbPmCYpjIHTahoKVpYq80KNXD2pHbaOJAcgCifkxb+Ar8uqK4cwbYtj4Nr7K2 MeyuSqIi+XWsQn1Jp8RyuXFOSRtvgivAwqggp3wP0dVW3ZHVcgVSJU2fIqWmE4Y9Jt5B HpfQ== X-Gm-Message-State: AOAM5315DFG9EHrcjxrhZg/TU41GKxEps3iLzP1NFo3YCYcr5OVOCel0 pPjvOoNxtBiQZFaDldUZ6TLBzvExGlk= X-Google-Smtp-Source: ABdhPJxny4ckGKLDd+42IZf6u80vJ5uU1BM+7nBJ3MqBPuBA3EGXX/DuoHx+Q6WNwRpfkmr5ze/8nA== X-Received: by 2002:a5d:52c8:0:b0:1ed:e591:be70 with SMTP id r8-20020a5d52c8000000b001ede591be70mr20355204wrv.436.1646160232771; Tue, 01 Mar 2022 10:43:52 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id t9-20020a05600c198900b0037bd5fabd10sm4135116wmq.48.2022.03.01.10.43.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:52 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:23 +0000 Subject: [PATCH v6 21/30] t7527: create test for fsmonitor--daemon Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- t/t7527-builtin-fsmonitor.sh | 511 +++++++++++++++++++++++++++++++++++ 1 file changed, 511 insertions(+) create mode 100755 t/t7527-builtin-fsmonitor.sh diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh new file mode 100755 index 00000000000..5f7b8e54233 --- /dev/null +++ b/t/t7527-builtin-fsmonitor.sh @@ -0,0 +1,511 @@ +#!/bin/sh + +test_description='built-in file system watcher' + +. ./test-lib.sh + +if ! test_have_prereq FSMONITOR_DAEMON +then + skip_all="fsmonitor--daemon is not supported on this platform" + test_done +fi + +stop_daemon_delete_repo () { + r=$1 + git -C $r fsmonitor--daemon stop >/dev/null 2>/dev/null + rm -rf $1 + return 0 +} + +start_daemon () { + case "$#" in + 1) r="-C $1";; + *) r=""; + esac + + git $r fsmonitor--daemon start || return $? + git $r fsmonitor--daemon status || return $? + + return 0 +} + +# Is a Trace2 data event present with the given catetory and key? +# We do not care what the value is. +# +have_t2_data_event () { + c=$1 + k=$2 + + grep -e '"event":"data".*"category":"'"$c"'".*"key":"'"$k"'"' +} + +test_expect_success 'explicit daemon start and stop' ' + test_when_finished "stop_daemon_delete_repo test_explicit" && + + git init test_explicit && + start_daemon test_explicit && + + git -C test_explicit fsmonitor--daemon stop && + test_must_fail git -C test_explicit fsmonitor--daemon status +' + +test_expect_success 'implicit daemon start' ' + test_when_finished "stop_daemon_delete_repo test_implicit" && + + git init test_implicit && + test_must_fail git -C test_implicit fsmonitor--daemon status && + + # query will implicitly start the daemon. + # + # for test-script simplicity, we send a V1 timestamp rather than + # a V2 token. either way, the daemon response to any query contains + # a new V2 token. (the daemon may complain that we sent a V1 request, + # but this test case is only concerned with whether the daemon was + # implicitly started.) + + GIT_TRACE2_EVENT="$(pwd)/.git/trace" \ + test-tool -C test_implicit fsmonitor-client query --token 0 >actual && + nul_to_q actual.filtered && + grep "builtin:" actual.filtered && + + # confirm that a daemon was started in the background. + # + # since the mechanism for starting the background daemon is platform + # dependent, just confirm that the foreground command received a + # response from the daemon. + + have_t2_data_event fsm_client query/response-length <.git/trace && + + git -C test_implicit fsmonitor--daemon status && + git -C test_implicit fsmonitor--daemon stop && + test_must_fail git -C test_implicit fsmonitor--daemon status +' + +test_expect_success 'implicit daemon stop (delete .git)' ' + test_when_finished "stop_daemon_delete_repo test_implicit_1" && + + git init test_implicit_1 && + + start_daemon test_implicit_1 && + + # deleting the .git directory will implicitly stop the daemon. + rm -rf test_implicit_1/.git && + + # [1] Create an empty .git directory so that the following Git + # command will stay relative to the `-C` directory. + # + # Without this, the Git command will override the requested + # -C argument and crawl out to the containing Git source tree. + # This would make the test result dependent upon whether we + # were using fsmonitor on our development worktree. + # + sleep 1 && + mkdir test_implicit_1/.git && + + test_must_fail git -C test_implicit_1 fsmonitor--daemon status +' + +test_expect_success 'implicit daemon stop (rename .git)' ' + test_when_finished "stop_daemon_delete_repo test_implicit_2" && + + git init test_implicit_2 && + + start_daemon test_implicit_2 && + + # renaming the .git directory will implicitly stop the daemon. + mv test_implicit_2/.git test_implicit_2/.xxx && + + # See [1] above. + # + sleep 1 && + mkdir test_implicit_2/.git && + + test_must_fail git -C test_implicit_2 fsmonitor--daemon status +' + +test_expect_success 'cannot start multiple daemons' ' + test_when_finished "stop_daemon_delete_repo test_multiple" && + + git init test_multiple && + + start_daemon test_multiple && + + test_must_fail git -C test_multiple fsmonitor--daemon start 2>actual && + grep "fsmonitor--daemon is already running" actual && + + git -C test_multiple fsmonitor--daemon stop && + test_must_fail git -C test_multiple fsmonitor--daemon status +' + +# These tests use the main repo in the trash directory + +test_expect_success 'setup' ' + >tracked && + >modified && + >delete && + >rename && + mkdir dir1 && + >dir1/tracked && + >dir1/modified && + >dir1/delete && + >dir1/rename && + mkdir dir2 && + >dir2/tracked && + >dir2/modified && + >dir2/delete && + >dir2/rename && + mkdir dirtorename && + >dirtorename/a && + >dirtorename/b && + + cat >.gitignore <<-\EOF && + .gitignore + expect* + actual* + EOF + + git -c core.fsmonitor=false add . && + test_tick && + git -c core.fsmonitor=false commit -m initial && + + git config core.fsmonitor true +' + +# The test already explicitly stopped (or tried to stop) the daemon. +# This is here in case something else fails first. +# +redundant_stop_daemon () { + git fsmonitor--daemon stop + return 0 +} + +test_expect_success 'update-index implicitly starts daemon' ' + test_when_finished redundant_stop_daemon && + + test_must_fail git fsmonitor--daemon status && + + GIT_TRACE2_EVENT="$(pwd)/.git/trace_implicit_1" \ + git update-index --fsmonitor && + + git fsmonitor--daemon status && + test_might_fail git fsmonitor--daemon stop && + + # Confirm that the trace2 log contains a record of the + # daemon starting. + test_subcommand git fsmonitor--daemon start <.git/trace_implicit_1 +' + +test_expect_success 'status implicitly starts daemon' ' + test_when_finished redundant_stop_daemon && + + test_must_fail git fsmonitor--daemon status && + + GIT_TRACE2_EVENT="$(pwd)/.git/trace_implicit_2" \ + git status >actual && + + git fsmonitor--daemon status && + test_might_fail git fsmonitor--daemon stop && + + # Confirm that the trace2 log contains a record of the + # daemon starting. + test_subcommand git fsmonitor--daemon start <.git/trace_implicit_2 +' + +edit_files () { + echo 1 >modified + echo 2 >dir1/modified + echo 3 >dir2/modified + >dir1/untracked +} + +delete_files () { + rm -f delete + rm -f dir1/delete + rm -f dir2/delete +} + +create_files () { + echo 1 >new + echo 2 >dir1/new + echo 3 >dir2/new +} + +rename_files () { + mv rename renamed + mv dir1/rename dir1/renamed + mv dir2/rename dir2/renamed +} + +file_to_directory () { + rm -f delete + mkdir delete + echo 1 >delete/new +} + +directory_to_file () { + rm -rf dir1 + echo 1 >dir1 +} + +verify_status () { + git status >actual && + GIT_INDEX_FILE=.git/fresh-index git read-tree master && + GIT_INDEX_FILE=.git/fresh-index git -c core.fsmonitor=false status >expect && + test_cmp expect actual && + echo HELLO AFTER && + cat .git/trace && + echo HELLO AFTER +} + +# The next few test cases confirm that our fsmonitor daemon sees each type +# of OS filesystem notification that we care about. At this layer we just +# ensure we are getting the OS notifications and do not try to confirm what +# is reported by `git status`. +# +# We run a simple query after modifying the filesystem just to introduce +# a bit of a delay so that the trace logging from the daemon has time to +# get flushed to disk. +# +# We `reset` and `clean` at the bottom of each test (and before stopping the +# daemon) because these commands might implicitly restart the daemon. + +clean_up_repo_and_stop_daemon () { + git reset --hard HEAD + git clean -fd + git fsmonitor--daemon stop + rm -f .git/trace +} + +test_expect_success 'edit some files' ' + test_when_finished clean_up_repo_and_stop_daemon && + + ( + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" && + export GIT_TRACE_FSMONITOR && + + start_daemon + ) && + + edit_files && + + test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 && + + grep "^event: dir1/modified$" .git/trace && + grep "^event: dir2/modified$" .git/trace && + grep "^event: modified$" .git/trace && + grep "^event: dir1/untracked$" .git/trace +' + +test_expect_success 'create some files' ' + test_when_finished clean_up_repo_and_stop_daemon && + + ( + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" && + export GIT_TRACE_FSMONITOR && + + start_daemon + ) && + + create_files && + + test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 && + + grep "^event: dir1/new$" .git/trace && + grep "^event: dir2/new$" .git/trace && + grep "^event: new$" .git/trace +' + +test_expect_success 'delete some files' ' + test_when_finished clean_up_repo_and_stop_daemon && + + ( + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" && + export GIT_TRACE_FSMONITOR && + + start_daemon + ) && + + delete_files && + + test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 && + + grep "^event: dir1/delete$" .git/trace && + grep "^event: dir2/delete$" .git/trace && + grep "^event: delete$" .git/trace +' + +test_expect_success 'rename some files' ' + test_when_finished clean_up_repo_and_stop_daemon && + + ( + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" && + export GIT_TRACE_FSMONITOR && + + start_daemon + ) && + + rename_files && + + test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 && + + grep "^event: dir1/rename$" .git/trace && + grep "^event: dir2/rename$" .git/trace && + grep "^event: rename$" .git/trace && + grep "^event: dir1/renamed$" .git/trace && + grep "^event: dir2/renamed$" .git/trace && + grep "^event: renamed$" .git/trace +' + +test_expect_success 'rename directory' ' + test_when_finished clean_up_repo_and_stop_daemon && + + ( + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" && + export GIT_TRACE_FSMONITOR && + + start_daemon + ) && + + mv dirtorename dirrenamed && + + test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 && + + grep "^event: dirtorename/*$" .git/trace && + grep "^event: dirrenamed/*$" .git/trace +' + +test_expect_success 'file changes to directory' ' + test_when_finished clean_up_repo_and_stop_daemon && + + ( + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" && + export GIT_TRACE_FSMONITOR && + + start_daemon + ) && + + file_to_directory && + + test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 && + + grep "^event: delete$" .git/trace && + grep "^event: delete/new$" .git/trace +' + +test_expect_success 'directory changes to a file' ' + test_when_finished clean_up_repo_and_stop_daemon && + + ( + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace" && + export GIT_TRACE_FSMONITOR && + + start_daemon + ) && + + directory_to_file && + + test-tool fsmonitor-client query --token 0 >/dev/null 2>&1 && + + grep "^event: dir1$" .git/trace +' + +# The next few test cases exercise the token-resync code. When filesystem +# drops events (because of filesystem velocity or because the daemon isn't +# polling fast enough), we need to discard the cached data (relative to the +# current token) and start collecting events under a new token. +# +# the 'test-tool fsmonitor-client flush' command can be used to send a +# "flush" message to a running daemon and ask it to do a flush/resync. + +test_expect_success 'flush cached data' ' + test_when_finished "stop_daemon_delete_repo test_flush" && + + git init test_flush && + + ( + GIT_TEST_FSMONITOR_TOKEN=true && + export GIT_TEST_FSMONITOR_TOKEN && + + GIT_TRACE_FSMONITOR="$(pwd)/.git/trace_daemon" && + export GIT_TRACE_FSMONITOR && + + start_daemon test_flush + ) && + + # The daemon should have an initial token with no events in _0 and + # then a few (probably platform-specific number of) events in _1. + # These should both have the same . + + test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_0 && + nul_to_q actual_q0 && + + touch test_flush/file_1 && + touch test_flush/file_2 && + + test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_1 && + nul_to_q actual_q1 && + + grep "file_1" actual_q1 && + + # Force a flush. This will change the , reset the , and + # flush the file data. Then create some events and ensure that the file + # again appears in the cache. It should have the new . + + test-tool -C test_flush fsmonitor-client flush >flush_0 && + nul_to_q flush_q0 && + grep "^builtin:test_00000002:0Q/Q$" flush_q0 && + + test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_2 && + nul_to_q actual_q2 && + + grep "^builtin:test_00000002:0Q$" actual_q2 && + + touch test_flush/file_3 && + + test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_3 && + nul_to_q actual_q3 && + + grep "file_3" actual_q3 +' + +# The next few test cases create repos where the .git directory is NOT +# inside the one of the working directory. That is, where .git is a file +# that points to a directory elsewhere. This happens for submodules and +# non-primary worktrees. + +test_expect_success 'setup worktree base' ' + git init wt-base && + echo 1 >wt-base/file1 && + git -C wt-base add file1 && + git -C wt-base commit -m "c1" +' + +test_expect_success 'worktree with .git file' ' + git -C wt-base worktree add ../wt-secondary && + + ( + GIT_TRACE2_PERF="$(pwd)/trace2_wt_secondary" && + export GIT_TRACE2_PERF && + + GIT_TRACE_FSMONITOR="$(pwd)/trace_wt_secondary" && + export GIT_TRACE_FSMONITOR && + + start_daemon wt-secondary + ) && + + git -C wt-secondary fsmonitor--daemon stop && + test_must_fail git -C wt-secondary fsmonitor--daemon status +' + +# NEEDSWORK: Repeat one of the "edit" tests on wt-secondary and +# confirm that we get the same events and behavior -- that is, that +# fsmonitor--daemon correctly watches BOTH the working directory and +# the external GITDIR directory and behaves the same as when ".git" +# is a directory inside the working directory. + +test_expect_success 'cleanup worktrees' ' + stop_daemon_delete_repo wt-secondary && + stop_daemon_delete_repo wt-base +' + +test_done From patchwork Tue Mar 1 18:43:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765057 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ADA4DC433EF for ; Tue, 1 Mar 2022 18:44:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237140AbiCASpO (ORCPT ); Tue, 1 Mar 2022 13:45:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237032AbiCASoz (ORCPT ); Tue, 1 Mar 2022 13:44:55 -0500 Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4495965400 for ; Tue, 1 Mar 2022 10:43:55 -0800 (PST) Received: by mail-wr1-x429.google.com with SMTP id b5so22003780wrr.2 for ; Tue, 01 Mar 2022 10:43:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=MEG3piFdmt+jIkWUnne4CEZ7uXu+O+UAM85s3uqrVgA=; b=Mh6t/WWtys/Q3w+gpeqxQEfwmwyA1i0lq6/BCStYKYIww3lnpBL3BS+9wIz2TTiL0j U1a+iXJxgr2OfnRrlAiCj33uuubVKLbPLGA7kcyPuS3ZUtYJQJmZTpPghn0Ze+XDLH5d lNGIi3yIG6By46oil36votHXf36VBsZJu8I63D3tob8LUVVR4ICHsTzE0DGZBOCCELUG dp2JAyNDj7OXsBJ+pi+79PKw0eWr3DaCq8qUr/TfUpk2N39QF4MB5y25jun2a0QtlVyW SoxlBGKwg9UfZTgV39lrk5pc4tUhzkpeYEoYHEzgXD57PkQToYlRoMpRzGM6HhgAfNdn D+3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=MEG3piFdmt+jIkWUnne4CEZ7uXu+O+UAM85s3uqrVgA=; b=U6jXcdUm7zc2JSjl5c70KvwA3IN0YTfwywz6sbQr7J1VG7Wwao9dMMWtUgjMMmhHDU lxv8wtOD3mBlWh2Bv2ehJ59ycuzlQFMcMxSLFuPzyHPB3coEfzM5ZFHWOcCcQM/+1A21 0w/DzbpGNKMl/vN6JOOXEkp3YHU8E37iypyP250Wmr3Tb7jkCb/O+x0yzyhGbIVvcReC oInUITfZbhWxIcZkacif2pAiv+1o3jV6JtyOHtj+4omVp/az7XAtvEex3kVkEtwASEIE dAaS/Q1wIoPilvQOvJUn7QcPB7l9vjEdFgoLRoZGzWrrtwzPSOMAmeqsUZ6QhRGlXXhg 3RpA== X-Gm-Message-State: AOAM531hLB4v32SjFktcqY/zAMjOgoBDZ+9Wz3dRnVc1rSH3/4rWegcl esYZ/muBuuLIyLOyTbZ4jDr4Zob4Hps= X-Google-Smtp-Source: ABdhPJw4vbp/k0CTgYo7Fj1vblrdHYXhpHP0GyY6GguN0M/KzmIA4rJE9taDpBn1/IYOxZBfC4lDkg== X-Received: by 2002:a05:6000:178e:b0:1ef:b76e:f54 with SMTP id e14-20020a056000178e00b001efb76e0f54mr9426790wrg.324.1646160233633; Tue, 01 Mar 2022 10:43:53 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id r2-20020adff702000000b001efd7eb7c37sm6418178wrp.34.2022.03.01.10.43.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:53 -0800 (PST) Message-Id: <15bd5aaff366169a22ad3fb94b412a7be38d1737.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:24 +0000 Subject: [PATCH v6 22/30] t/perf: avoid copying builtin fsmonitor files into test repo Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Do not copy any of the various fsmonitor--daemon files from the .git directory of the (GIT_PREF_REPO or GIT_PERF_LARGE_REPO) source repo into the test's trash directory. When perf tests start, they copy the contents of the source repo into the test's trash directory. If fsmonitor is running in the source repo, there may be control files, such as the IPC socket and/or fsmonitor cookie files. These should not be copied into the test repo. Unix domain sockets cannot be copied in the manner used by the test setup, so if present, the test setup fails. Cookie files are harmless, but we should avoid them. The builtin fsmonitor keeps all such control files/sockets in .git/fsmonitor--daemon*, so it is simple to exclude them. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- t/perf/perf-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index 407252bac70..932105cd12c 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -78,7 +78,7 @@ test_perf_copy_repo_contents () { for stuff in "$1"/* do case "$stuff" in - */objects|*/hooks|*/config|*/commondir|*/gitdir|*/worktrees) + */objects|*/hooks|*/config|*/commondir|*/gitdir|*/worktrees|*/fsmonitor--daemon*) ;; *) cp -R "$stuff" "$repo/.git/" || exit 1 From patchwork Tue Mar 1 18:43:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765058 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 270D5C433F5 for ; Tue, 1 Mar 2022 18:44:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237142AbiCASpP (ORCPT ); Tue, 1 Mar 2022 13:45:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56968 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237113AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 44DFB66203 for ; Tue, 1 Mar 2022 10:43:56 -0800 (PST) Received: by mail-wm1-x331.google.com with SMTP id q7-20020a7bce87000000b00382255f4ca9so1272740wmj.2 for ; Tue, 01 Mar 2022 10:43:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=ytZGPKQBsgePTFk8nBNZCqEs9yPPwA8MYf3sa3pnTvQ=; b=TB3lev3fBle3txTe4GzyvBzYCAFH0qfgFhmQPdCdSC3rsq0OfDPtbiKV28TqRLB52M uzjdmqQHxaeK5TTh9IvCPq2JXb/eTO7ku8yERTzhYsKXNlHUvqjG/FL+rUuDv60ThYTZ rZkV1xbt15Ny2rVnuJLaSqIZ000yn5h4jmArCHFCpoo9wDlRnpdl4CI76l6eZwBQZU3s HmArJft/FXA4Yk5IFT5+c3zJfD8NHlvlz4SUgy8/ygt1BrmRAI7U0nvKV7WrWXAHi8cM Wpx/KcCkONnmW63wFudLeQbR2sbCSTcI0d0iZseDdHv03mC8FCspN5Q3ViNl3CofbS/X Q25w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=ytZGPKQBsgePTFk8nBNZCqEs9yPPwA8MYf3sa3pnTvQ=; b=eBnJyBHAbKqlERsxC4SuS2RUcTDRtd0tceKUoc7qdcwV3WIqjHxcMotNAFpqafYx65 wED6fTw5hs2dYdrOKDRTgrU/y7sLQJMpSgrMEwH75EfpamgVrrWpEE+17L+CZalBedAi MgDYBgWO2ZlOQWlfn/mTo7BEsUEnrg9f7QXxO2Ns7id450e35cFRyH5bFDwgbtS60/vu faimSmjaz4RbpNzYBFCgrnwE/bUvE3en/dScWEMtWOSfo3KcTbYEY2cnSm9QWn2oK/V+ FwHeBnJjo2b9V6XEBF3FcXf6g9Vp5sfpTYvxlgBrrdTG3WTvhbwO5LX2eDBlurY3eyS3 l2zg== X-Gm-Message-State: AOAM533E/db/MfCEVojNrMAT6cfUanbZopuozowRuz+BmivBNFlFUUHY FfnLipMv3yAvQvJQDZeqycU5H21SnBE= X-Google-Smtp-Source: ABdhPJz62pY1Jf+5Kx1ze8++v/5bSKTT7etDa/L+tFncFra0XlXQ2LbcC5n/9/CfIJEokjVt17fLfw== X-Received: by 2002:a7b:c351:0:b0:381:6824:aa61 with SMTP id l17-20020a7bc351000000b003816824aa61mr8504100wmj.19.1646160234563; Tue, 01 Mar 2022 10:43:54 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id f9-20020adffcc9000000b001e9e8163a46sm20464817wrs.54.2022.03.01.10.43.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:54 -0800 (PST) Message-Id: <4cb97918d20e19cf57c69e6a2a66d289ae873a7e.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:25 +0000 Subject: [PATCH v6 23/30] t/helper/test-chmtime: skip directories on Windows Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach `test-tool.exe chmtime` to ignore errors when setting the mtime on a directory on Windows. NEEDSWORK: The Windows version of `utime()` (aka `mingw_utime()`) does not properly handle directories because it uses `_wopen()`. It should be converted to using `CreateFileW()` and backup semantics at a minimum. Since I'm already in the middle of a large patch series, I did not want to destabilize other callers of `utime()` right now. The problem has only been observed in the t/perf/p7519 test when the test repo contains an empty directory on disk. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- t/helper/test-chmtime.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c index 524b55ca496..dc28890a183 100644 --- a/t/helper/test-chmtime.c +++ b/t/helper/test-chmtime.c @@ -134,6 +134,21 @@ int cmd__chmtime(int argc, const char **argv) } if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) { +#ifdef GIT_WINDOWS_NATIVE + if (S_ISDIR(sb.st_mode)) { + /* + * NEEDSWORK: The Windows version of `utime()` + * (aka `mingw_utime()`) does not correctly + * handle directory arguments, since it uses + * `_wopen()`. Ignore it for now since this + * is just a test. + */ + fprintf(stderr, + ("Failed to modify time on directory %s. " + "Skipping\n"), argv[i]); + continue; + } +#endif fprintf(stderr, "Failed to modify time on %s: %s\n", argv[i], strerror(errno)); return 1; From patchwork Tue Mar 1 18:43:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765060 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC9A0C433F5 for ; Tue, 1 Mar 2022 18:44:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237146AbiCASpU (ORCPT ); Tue, 1 Mar 2022 13:45:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237114AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 119796620A for ; Tue, 1 Mar 2022 10:43:57 -0800 (PST) Received: by mail-wm1-x334.google.com with SMTP id p4so8030356wmg.1 for ; Tue, 01 Mar 2022 10:43:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=dYHB6VIcuLCvVwPHVF7aas3tdD7U9a/DUdka7zL2q6U=; b=N3RtWKRlbknpRwq0p4DUOmsWRJ3E2U5kDmsKkXezqtYAXLXPBX5Rk2JIRA+2vYggsS ICXnrXtZXDyOgyJhd7ah1h7lIk7EhnOqCBfQflGbjv+HziLnuRgm4RhUTVOXzV32LNxX gynlWO2RQKRa/r0I9CB1RSx/ZZuivyuqs3LokbtZ3pPf/HK1gpyylBDQOHGuwqEqdBYm eFXMsIE4ZXOiiScEA86yuuHnjGhQilcU/e1nfzfHFh1ldYxLSu8xlXvcgpRAWgSG9yuM Kbarkj+Q/YHePrzWow0nE2M2ttZJSSPa0eCjI8IIcvUqpOLypxeSzTKsJia4y2mChBga MjWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=dYHB6VIcuLCvVwPHVF7aas3tdD7U9a/DUdka7zL2q6U=; b=5rmMO4ui1Nj59HWUCM6jRfP37HpXajCkG9xbhRXNwcrx0RUuvRMJc76Y++1NWXDGMw 2yAcSJ8FguWLAAjSdWwJlMtjEbWwul3PuXfslPUYzCJay3/sd4lEECQk4jXkVBJq3fPE MtDGdOqIqzQg4h9v2HcL5Zkhb4g1cGZ4iQ8i51ea0HKwDWy/f8GPI5ygDcH/5gG8lj+4 /IgegqBoNzFLqfUR668zw2qrYFbcJUAvIab4uTdFViC1GOQQ4AfTXKwLTMKnIAR11J8b Dynay6Gqazh8XiSfmgj3YqTSoOrbzTeb5szLkw/+Gx+VRaziOuJPd8WtpuHZren6t+dD JLww== X-Gm-Message-State: AOAM5306IjFgr7mLxdQcghrMQF9PhJ8LIyXbv+v+3O/lfKbOyh2PVW/4 YToSoOXo/esdpM8OdNhTyf1HvV4/K1w= X-Google-Smtp-Source: ABdhPJzRcYIR4I3ef9O/OgFnkK2XezWVMwEYuwmeHbrvI6YXJyP0MfXns/6NLRpgEveiFlOr8uUaew== X-Received: by 2002:a1c:2644:0:b0:381:10f:503 with SMTP id m65-20020a1c2644000000b00381010f0503mr17956995wmm.188.1646160235452; Tue, 01 Mar 2022 10:43:55 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id e6-20020a056000120600b001ea9414f2c3sm14486443wrx.12.2022.03.01.10.43.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:55 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:26 +0000 Subject: [PATCH v6 24/30] t/perf/p7519: speed up test on Windows Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Change p7519 to use `test_seq` and `xargs` rather than a `for` loop to touch thousands of files. This takes minutes off of test runs on Windows because of process creation overhead. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- t/perf/p7519-fsmonitor.sh | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh index c8be58f3c76..aed7b1146b0 100755 --- a/t/perf/p7519-fsmonitor.sh +++ b/t/perf/p7519-fsmonitor.sh @@ -72,7 +72,7 @@ then fi fi -trace_start() { +trace_start () { if test -n "$GIT_PERF_7519_TRACE" then name="$1" @@ -91,13 +91,20 @@ trace_start() { fi } -trace_stop() { +trace_stop () { if test -n "$GIT_PERF_7519_TRACE" then unset GIT_TRACE2_PERF fi } +touch_files () { + n=$1 + d="$n"_files + + (cd $d ; test_seq 1 $n | xargs touch ) +} + test_expect_success "one time repo setup" ' # set untrackedCache depending on the environment if test -n "$GIT_PERF_7519_UNTRACKED_CACHE" @@ -119,10 +126,11 @@ test_expect_success "one time repo setup" ' fi && mkdir 1_file 10_files 100_files 1000_files 10000_files && - for i in $(test_seq 1 10); do touch 10_files/$i || return 1; done && - for i in $(test_seq 1 100); do touch 100_files/$i || return 1; done && - for i in $(test_seq 1 1000); do touch 1000_files/$i || return 1; done && - for i in $(test_seq 1 10000); do touch 10000_files/$i || return 1; done && + : 1_file directory should be left empty && + touch_files 10 && + touch_files 100 && + touch_files 1000 && + touch_files 10000 && git add 1_file 10_files 100_files 1000_files 10000_files && git commit -qm "Add files" && @@ -133,7 +141,7 @@ test_expect_success "one time repo setup" ' fi ' -setup_for_fsmonitor() { +setup_for_fsmonitor () { # set INTEGRATION_SCRIPT depending on the environment if test -n "$INTEGRATION_PATH" then @@ -173,7 +181,7 @@ test_perf_w_drop_caches () { test_perf "$@" } -test_fsmonitor_suite() { +test_fsmonitor_suite () { if test -n "$INTEGRATION_SCRIPT"; then DESC="fsmonitor=$(basename $INTEGRATION_SCRIPT)" else @@ -199,15 +207,15 @@ test_fsmonitor_suite() { # Update the mtimes on upto 100k files to make status think # that they are dirty. For simplicity, omit any files with - # LFs (i.e. anything that ls-files thinks it needs to dquote). - # Then fully backslash-quote the paths to capture any - # whitespace so that they pass thru xargs properly. + # LFs (i.e. anything that ls-files thinks it needs to dquote) + # and any files with whitespace so that they pass thru xargs + # properly. # test_perf_w_drop_caches "status (dirty) ($DESC)" ' git ls-files | \ head -100000 | \ grep -v \" | \ - sed '\''s/\(.\)/\\\1/g'\'' | \ + egrep -v " ." | \ xargs test-tool chmtime -300 && git status ' From patchwork Tue Mar 1 18:43:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765062 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80681C433F5 for ; Tue, 1 Mar 2022 18:44:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237106AbiCASpY (ORCPT ); Tue, 1 Mar 2022 13:45:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57080 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237116AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DAFA066213 for ; Tue, 1 Mar 2022 10:43:57 -0800 (PST) Received: by mail-wm1-x335.google.com with SMTP id a13-20020a05600c348d00b0038188b8bbf6so1764819wmq.0 for ; Tue, 01 Mar 2022 10:43:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=YFlE5oosPtaRdiA2tsjEzIscA11MI8VGLhJl8C2HPaU=; b=Q4GuNxVaH5LQB1/yaXZLQnTTD9Uye3bWJBwrvNYnW45VrCuiG2YZLgnmyjIaGr6DfD +B0pGSY0q5FuJ6dRmplIFPlU34QG9AzwSAHzaMj6nCPhZV8+Q4SFHI9nen3hp5JDrW5O CcLG0kN3ShvgeBnTGRedvrXUgpVi41RWfPZiVHML3PcxZcKhjBiN+MbpO5cFcejqKIR6 jTYIiqxK+fDHuGcFQfI923spSqXSMEOI1FiqTqrzUylrPbhzxtx7pKAaD2v3BMqiFC1T BkRuw8vM+aUBOldseyXUj8a8o+BlHaw/zhgKsKTJt9c7p3ICU6KGgIjIPX0fS0BOyyVd zBiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=YFlE5oosPtaRdiA2tsjEzIscA11MI8VGLhJl8C2HPaU=; b=6s1m55rlhP1Eih3Iuf42TjJOLny+xNjdg1ikoOEANviC/1mk7QNhGeAxebdCFHvcBC i2FYQ0FmPmox9/5eWhptZqD74y3GYPkr9NvpJrmCtjQQsgpWDUmzVKKgIFwfkCrEThBD NoLM3cOh2NqH1nr0/468z8bYb1NH7eg1rX6tjjpFsfsR0IGHC0p5ydIvUIChat/XOkuc r5lE6zwDG0Rq+uR2r2o0VhoOSxsGhqXn4Zm5WmSiAnK/H+QZJF1gKQ59tiFhtmnK4Jx3 k98/CzJ0aIWk53tF4qaWpJBTRKsOKa5ZpiDOdjOknQ3awqJSJ8uxvxrVN//zS+LHRybL D5AQ== X-Gm-Message-State: AOAM532GJPPIEciw5TYefShSF9kD4LZ1JczBOCfPHjt7pVH550EV5NQ0 IghasbtNHKz+up559JGnTCqxBJnfmNg= X-Google-Smtp-Source: ABdhPJwHkZNQA3Tt7HuqmQHB0swuzjHykEeb44SRE2NoLHRbpuSjlwoZaSuwliEK9URdj3qsYc79CA== X-Received: by 2002:a05:600c:1c1c:b0:381:45b4:3f69 with SMTP id j28-20020a05600c1c1c00b0038145b43f69mr13169778wms.86.1646160236261; Tue, 01 Mar 2022 10:43:56 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id p5-20020a05600c358500b0038167e239a2sm4017646wmq.19.2022.03.01.10.43.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:55 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:27 +0000 Subject: [PATCH v6 25/30] t/perf/p7519: add fsmonitor--daemon test cases Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Repeat all of the fsmonitor perf tests using `git fsmonitor--daemon` and the "Simple IPC" interface. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- t/perf/p7519-fsmonitor.sh | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh index aed7b1146b0..a1c552129cc 100755 --- a/t/perf/p7519-fsmonitor.sh +++ b/t/perf/p7519-fsmonitor.sh @@ -182,7 +182,10 @@ test_perf_w_drop_caches () { } test_fsmonitor_suite () { - if test -n "$INTEGRATION_SCRIPT"; then + if test -n "$USE_FSMONITOR_DAEMON" + then + DESC="builtin fsmonitor--daemon" + elif test -n "$INTEGRATION_SCRIPT"; then DESC="fsmonitor=$(basename $INTEGRATION_SCRIPT)" else DESC="fsmonitor=disabled" @@ -293,4 +296,28 @@ test_expect_success "setup without fsmonitor" ' test_fsmonitor_suite trace_stop +# +# Run a full set of perf tests using the built-in fsmonitor--daemon. +# It does not use the Hook API, so it has a different setup. +# Explicitly start the daemon here and before we start client commands +# so that we can later add custom tracing. +# +if test_have_prereq FSMONITOR_DAEMON +then + USE_FSMONITOR_DAEMON=t + + trace_start fsmonitor--daemon--server + git fsmonitor--daemon start + + trace_start fsmonitor--daemon--client + + git config core.fsmonitor true + git update-index --fsmonitor + + test_fsmonitor_suite + + git fsmonitor--daemon stop + trace_stop +fi + test_done From patchwork Tue Mar 1 18:43:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765059 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3F985C433F5 for ; Tue, 1 Mar 2022 18:44:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237144AbiCASpR (ORCPT ); Tue, 1 Mar 2022 13:45:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237115AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 957786622D for ; Tue, 1 Mar 2022 10:43:58 -0800 (PST) Received: by mail-wr1-x42d.google.com with SMTP id u1so21923080wrg.11 for ; Tue, 01 Mar 2022 10:43:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=eGVqXr10YN37Ri5pZmcpjgcOL550mL38kfNfCfBeJaY=; b=CvBLZB60iT9pN3xH8cXKwOYM1whtcBLlAP7Jcd0DdFitagi3HQOQzCivoXXZO9eXxF lJw6JRETncqVfGWVAJdi8zbtu7gIyJsX6WUd1+05Cztq3jCX6yg8foIZvolZhrKPHGzq qTBgrbJpBjIHzAYGlY4y+n5Dg14hJ/Kpzbhsv2cQy5kqSQLIscsAkt9M+C06REZGyE5U DXClMIFgCnfetcwWs83o3Vp6SiC8QVHFudoTndxLmGsGctM4gOIzeSfpC0vp2BO8j5Q3 s4nL8sqeL7Ln7xHbgwMxszgR2xLFzz+rGY7EkqxXSPh7bWo1F1AQ+GrfppbTqlBHBgbH xEiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=eGVqXr10YN37Ri5pZmcpjgcOL550mL38kfNfCfBeJaY=; b=vy5sCdgPm/jTqH+0tUeLAu/C0sghVUik9+7PVMWOvyAbrcYTEMlf71tMatLcibm/xZ lm0jLfn0nARns5l7WqS/NqhSkZx0sr2QJuwKn6XCZglmesjzCJQUz/eIHiUnK6ReibsS HrA36IAFZ0iPumrdY4yKIIbdz+D3/SCHC9Pa0sdstL3SO2oa1JGDSzh7H372EBvXNuDN EnyiPotGna+OympkyYst3Fv1fseW8LBvvl0s6chBTOBsxXeRUJEm97c/5afZ3UuESJGQ mqe9I5mZkGWOmHiG0n88NDCtUVMZ1ZP6C8cE7Pu7artnE+H64YraOsACWgU7ON5y2DTn mUFg== X-Gm-Message-State: AOAM530KSjnIIXUGEL78wbwJPsAykXFYcqbv2ElnBgCmkcN4FIU6+HTd XspMPWWTaPFavkUYR0AaZlKDd+1rU9Q= X-Google-Smtp-Source: ABdhPJyYC5BlDEHlpa51XFNxFdW6KXXSGa4i0wwhR7zT+rQSCiNf2PIoApieO/N42+H4pPfrb6xi7A== X-Received: by 2002:a05:6000:1888:b0:1e7:cd21:c24f with SMTP id a8-20020a056000188800b001e7cd21c24fmr20520276wri.308.1646160237003; Tue, 01 Mar 2022 10:43:57 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v12-20020a5d4a4c000000b001e68ba61747sm14431957wrs.16.2022.03.01.10.43.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:56 -0800 (PST) Message-Id: <64a5b7416702c8bec948a1c3e289e18f9b6f87d5.1646160212.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:28 +0000 Subject: [PATCH v6 26/30] fsmonitor--daemon: periodically truncate list of modified files Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach fsmonitor--daemon to periodically truncate the list of modified files to save some memory. Clients will ask for the set of changes relative to a token that they found in the FSMN index extension in the index. (This token is like a point in time, but different). Clients will then update the index to contain the response token (so that subsequent commands will be relative to this new token). Therefore, the daemon can gradually truncate the in-memory list of changed paths as they become obsolete (older than the previous token). Since we may have multiple clients making concurrent requests with a skew of tokens and clients may be racing to the talk to the daemon, we lazily truncate the list. We introduce a 5 minute delay and truncate batches 5 minutes after they are considered obsolete. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 88 +++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 65c1ef7d4bf..6ca4f5959e6 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -312,6 +312,75 @@ static void fsmonitor_batch__combine(struct fsmonitor_batch *batch_dest, batch_src->interned_paths[k]; } +/* + * To keep the batch list from growing unbounded in response to filesystem + * activity, we try to truncate old batches from the end of the list as + * they become irrelevant. + * + * We assume that the .git/index will be updated with the most recent token + * any time the index is updated. And future commands will only ask for + * recent changes *since* that new token. So as tokens advance into the + * future, older batch items will never be requested/needed. So we can + * truncate them without loss of functionality. + * + * However, multiple commands may be talking to the daemon concurrently + * or perform a slow command, so a little "token skew" is possible. + * Therefore, we want this to be a little bit lazy and have a generous + * delay. + * + * The current reader thread walked backwards in time from `token->batch_head` + * back to `batch_marker` somewhere in the middle of the batch list. + * + * Let's walk backwards in time from that marker an arbitrary delay + * and truncate the list there. Note that these timestamps are completely + * artificial (based on when we pinned the batch item) and not on any + * filesystem activity. + * + * Return the obsolete portion of the list after we have removed it from + * the official list so that the caller can free it after leaving the lock. + */ +#define MY_TIME_DELAY_SECONDS (5 * 60) /* seconds */ + +static struct fsmonitor_batch *with_lock__truncate_old_batches( + struct fsmonitor_daemon_state *state, + const struct fsmonitor_batch *batch_marker) +{ + /* assert current thread holding state->main_lock */ + + const struct fsmonitor_batch *batch; + struct fsmonitor_batch *remainder; + + if (!batch_marker) + return NULL; + + trace_printf_key(&trace_fsmonitor, "Truncate: mark (%"PRIu64",%"PRIu64")", + batch_marker->batch_seq_nr, + (uint64_t)batch_marker->pinned_time); + + for (batch = batch_marker; batch; batch = batch->next) { + time_t t; + + if (!batch->pinned_time) /* an overflow batch */ + continue; + + t = batch->pinned_time + MY_TIME_DELAY_SECONDS; + if (t > batch_marker->pinned_time) /* too close to marker */ + continue; + + goto truncate_past_here; + } + + return NULL; + +truncate_past_here: + state->current_token_data->batch_tail = (struct fsmonitor_batch *)batch; + + remainder = ((struct fsmonitor_batch *)batch)->next; + ((struct fsmonitor_batch *)batch)->next = NULL; + + return remainder; +} + static void fsmonitor_free_token_data(struct fsmonitor_token_data *token) { if (!token) @@ -425,6 +494,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state, const char *p; const struct fsmonitor_batch *batch_head; const struct fsmonitor_batch *batch; + struct fsmonitor_batch *remainder = NULL; intmax_t count = 0, duplicates = 0; kh_str_t *shown; int hash_ret; @@ -654,11 +724,29 @@ static int do_handle_client(struct fsmonitor_daemon_state *state, * that work. */ fsmonitor_free_token_data(token_data); + } else if (batch) { + /* + * We are holding the lock and are the only + * reader of the ref-counted portion of the + * list, so we get the honor of seeing if the + * list can be truncated to save memory. + * + * The main loop did not walk to the end of the + * list, so this batch is the first item in the + * batch-list that is older than the requested + * end-point sequence number. See if the tail + * end of the list is obsolete. + */ + remainder = with_lock__truncate_old_batches(state, + batch); } } pthread_mutex_unlock(&state->main_lock); + if (remainder) + fsmonitor_batch__free_list(remainder); + trace2_data_intmax("fsmonitor", the_repository, "response/length", total_response_len); trace2_data_intmax("fsmonitor", the_repository, "response/count/files", count); trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates); From patchwork Tue Mar 1 18:43:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765070 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E7B7C433FE for ; Tue, 1 Mar 2022 18:45:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237176AbiCASpj (ORCPT ); Tue, 1 Mar 2022 13:45:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55116 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237121AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 787E566239 for ; Tue, 1 Mar 2022 10:43:59 -0800 (PST) Received: by mail-wr1-x432.google.com with SMTP id u1so21923145wrg.11 for ; Tue, 01 Mar 2022 10:43:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=zzXV5huITbYS749z5WfXe0ozYRylHviForeQT7QzxDw=; b=MvLbD8ulTYQO0nwUaCs3oBWGaN7zQRYCih+cQ68bKGTMIHF2uUFa1rwqBKSBNh/gqe zb6c/LWY7g4mS50W8FGEt7Mqz5E24Ace9HImNa7JkpfZk3f84L05JIYGaSDH7S+YNFtC ENzgcIXmVBVT4GVQ1WwXDPUA5GOBCOa1wwekK5tqUHbsZxNAiLOTwi0WC7tEcRhMqQ6g KHcHLtf5Wxtqxenb+s7+RUAX22hmcFglJT+KWjMXXaypnUxkXVQPgEDDhlOz1PX3btTp Ko7gSuYDFMcViNWe2Ja7oMqAzenTKY/T3a70owdkJEAs7wztQGAORnOFG+cfZ/Blt8/N xDPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=zzXV5huITbYS749z5WfXe0ozYRylHviForeQT7QzxDw=; b=Ow784K2a1qCXLeDtL21Dc+0l9/xPSjhvdhmUE1ryzkyhXeKp30LDzMJNGWW4YB1lqz w6vHR1DLQU8C58N54kvfLbyT+Cjm46QJyZ8qT55WwPRvUcZ0WDGOJFingEFXHle6Tnq9 UaUc+U73+/RsN+Y2m0iW0lWX0jx7//a0N6D0NkYGnyTQpghkBqQD8R6uaiQ7t3FsCsbG duhKr2TthdGsvOsKIj/V4KTm/f5TdMqfIfVic/hwBKMLKvjRC02tPTsamziTjNtpmFxB AQ8HMScgKwkUK3uYJurEsVxlA7Zzd0++vvQxAsMQZlyuszrEU7aXGgY67EyAqcin2ufh BEzQ== X-Gm-Message-State: AOAM5336GhylwzhCGntTKe3gPq9ZJgYcBpTViLeoMCdN46ElneDoqsSa UmuqPeVfinP0673HWEPD3NtMnD9CEE8= X-Google-Smtp-Source: ABdhPJz97QWKfO0MzidDQ02olDGkS6F6gY3WsZMEEsA4zrm/M2ThvNVnGYqZ0R2DKCVLZps53Ynaeg== X-Received: by 2002:a05:6000:549:b0:1ee:d3fa:78b2 with SMTP id b9-20020a056000054900b001eed3fa78b2mr18835269wrf.91.1646160237799; Tue, 01 Mar 2022 10:43:57 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id k13-20020a7bc40d000000b00381890032dfsm2633962wmi.1.2022.03.01.10.43.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:57 -0800 (PST) Message-Id: <5b06eb5d0e60c7d23987d915609c07364e4f7372.1646160213.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:29 +0000 Subject: [PATCH v6 27/30] fsmonitor--daemon: use a cookie file to sync with file system Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Teach fsmonitor--daemon client threads to create a cookie file inside the .git directory and then wait until FS events for the cookie are observed by the FS listener thread. This helps address the racy nature of file system events by blocking the client response until the kernel has drained any event backlog. This is especially important on MacOS where kernel events are only issued with a limited frequency. See the `latency` argument of `FSeventStreamCreate()`. The kernel only signals every `latency` seconds, but does not guarantee that the kernel queue is completely drained, so we may have to wait more than one interval. If we increase the latency, the system is more likely to drop events. We avoid these issues by having each client thread create a unique cookie file and then wait until it is seen in the event stream. Co-authored-by: Kevin Willford Co-authored-by: Johannes Schindelin Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/fsmonitor--daemon.c | 230 +++++++++++++++++++++++++++++++++++- fsmonitor--daemon.h | 5 + 2 files changed, 234 insertions(+), 1 deletion(-) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 6ca4f5959e6..97ca2a356e5 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -107,6 +107,155 @@ static int do_as_client__status(void) } } +enum fsmonitor_cookie_item_result { + FCIR_ERROR = -1, /* could not create cookie file ? */ + FCIR_INIT = 0, + FCIR_SEEN, + FCIR_ABORT, +}; + +struct fsmonitor_cookie_item { + struct hashmap_entry entry; + const char *name; + enum fsmonitor_cookie_item_result result; +}; + +static int cookies_cmp(const void *data, const struct hashmap_entry *he1, + const struct hashmap_entry *he2, const void *keydata) +{ + const struct fsmonitor_cookie_item *a = + container_of(he1, const struct fsmonitor_cookie_item, entry); + const struct fsmonitor_cookie_item *b = + container_of(he2, const struct fsmonitor_cookie_item, entry); + + return strcmp(a->name, keydata ? keydata : b->name); +} + +static enum fsmonitor_cookie_item_result with_lock__wait_for_cookie( + struct fsmonitor_daemon_state *state) +{ + /* assert current thread holding state->main_lock */ + + int fd; + struct fsmonitor_cookie_item *cookie; + struct strbuf cookie_pathname = STRBUF_INIT; + struct strbuf cookie_filename = STRBUF_INIT; + enum fsmonitor_cookie_item_result result; + int my_cookie_seq; + + CALLOC_ARRAY(cookie, 1); + + my_cookie_seq = state->cookie_seq++; + + strbuf_addf(&cookie_filename, "%i-%i", getpid(), my_cookie_seq); + + strbuf_addbuf(&cookie_pathname, &state->path_cookie_prefix); + strbuf_addbuf(&cookie_pathname, &cookie_filename); + + cookie->name = strbuf_detach(&cookie_filename, NULL); + cookie->result = FCIR_INIT; + hashmap_entry_init(&cookie->entry, strhash(cookie->name)); + + hashmap_add(&state->cookies, &cookie->entry); + + trace_printf_key(&trace_fsmonitor, "cookie-wait: '%s' '%s'", + cookie->name, cookie_pathname.buf); + + /* + * Create the cookie file on disk and then wait for a notification + * that the listener thread has seen it. + */ + fd = open(cookie_pathname.buf, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + close(fd); + unlink(cookie_pathname.buf); + + /* + * Technically, this is an infinite wait (well, unless another + * thread sends us an abort). I'd like to change this to + * use `pthread_cond_timedwait()` and return an error/timeout + * and let the caller do the trivial response thing, but we + * don't have that routine in our thread-utils. + * + * After extensive beta testing I'm not really worried about + * this. Also note that the above open() and unlink() calls + * will cause at least two FS events on that path, so the odds + * of getting stuck are pretty slim. + */ + while (cookie->result == FCIR_INIT) + pthread_cond_wait(&state->cookies_cond, + &state->main_lock); + } else { + error_errno(_("could not create fsmonitor cookie '%s'"), + cookie->name); + + cookie->result = FCIR_ERROR; + } + + hashmap_remove(&state->cookies, &cookie->entry, NULL); + + result = cookie->result; + + free((char*)cookie->name); + free(cookie); + strbuf_release(&cookie_pathname); + + return result; +} + +/* + * Mark these cookies as _SEEN and wake up the corresponding client threads. + */ +static void with_lock__mark_cookies_seen(struct fsmonitor_daemon_state *state, + const struct string_list *cookie_names) +{ + /* assert current thread holding state->main_lock */ + + int k; + int nr_seen = 0; + + for (k = 0; k < cookie_names->nr; k++) { + struct fsmonitor_cookie_item key; + struct fsmonitor_cookie_item *cookie; + + key.name = cookie_names->items[k].string; + hashmap_entry_init(&key.entry, strhash(key.name)); + + cookie = hashmap_get_entry(&state->cookies, &key, entry, NULL); + if (cookie) { + trace_printf_key(&trace_fsmonitor, "cookie-seen: '%s'", + cookie->name); + cookie->result = FCIR_SEEN; + nr_seen++; + } + } + + if (nr_seen) + pthread_cond_broadcast(&state->cookies_cond); +} + +/* + * Set _ABORT on all pending cookies and wake up all client threads. + */ +static void with_lock__abort_all_cookies(struct fsmonitor_daemon_state *state) +{ + /* assert current thread holding state->main_lock */ + + struct hashmap_iter iter; + struct fsmonitor_cookie_item *cookie; + int nr_aborted = 0; + + hashmap_for_each_entry(&state->cookies, &iter, cookie, entry) { + trace_printf_key(&trace_fsmonitor, "cookie-abort: '%s'", + cookie->name); + cookie->result = FCIR_ABORT; + nr_aborted++; + } + + if (nr_aborted) + pthread_cond_broadcast(&state->cookies_cond); +} + /* * Requests to and from a FSMonitor Protocol V2 provider use an opaque * "token" as a virtual timestamp. Clients can request a summary of all @@ -404,6 +553,9 @@ static void fsmonitor_free_token_data(struct fsmonitor_token_data *token) * We should create a new token and start fresh (as if we just * booted up). * + * [2] Some of those lost events may have been for cookie files. We + * should assume the worst and abort them rather letting them starve. + * * If there are no concurrent threads reading the current token data * series, we can free it now. Otherwise, let the last reader free * it. @@ -425,6 +577,8 @@ static void with_lock__do_force_resync(struct fsmonitor_daemon_state *state) state->current_token_data = new_one; fsmonitor_free_token_data(free_me); + + with_lock__abort_all_cookies(state); } void fsmonitor_force_resync(struct fsmonitor_daemon_state *state) @@ -500,6 +654,8 @@ static int do_handle_client(struct fsmonitor_daemon_state *state, int hash_ret; int do_trivial = 0; int do_flush = 0; + int do_cookie = 0; + enum fsmonitor_cookie_item_result cookie_result; /* * We expect `command` to be of the form: @@ -560,6 +716,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state, * We have a V2 valid token: * "builtin::" */ + do_cookie = 1; } } @@ -568,6 +725,30 @@ static int do_handle_client(struct fsmonitor_daemon_state *state, if (!state->current_token_data) BUG("fsmonitor state does not have a current token"); + /* + * Write a cookie file inside the directory being watched in + * an effort to flush out existing filesystem events that we + * actually care about. Suspend this client thread until we + * see the filesystem events for this cookie file. + * + * Creating the cookie lets us guarantee that our FS listener + * thread has drained the kernel queue and we are caught up + * with the kernel. + * + * If we cannot create the cookie (or otherwise guarantee that + * we are caught up), we send a trivial response. We have to + * assume that there might be some very, very recent activity + * on the FS still in flight. + */ + if (do_cookie) { + cookie_result = with_lock__wait_for_cookie(state); + if (cookie_result != FCIR_SEEN) { + error(_("fsmonitor: cookie_result '%d' != SEEN"), + cookie_result); + do_trivial = 1; + } + } + if (do_flush) with_lock__do_force_resync(state); @@ -788,7 +969,9 @@ static int handle_client(void *data, return result; } -#define FSMONITOR_COOKIE_PREFIX ".fsmonitor-daemon-" +#define FSMONITOR_DIR "fsmonitor--daemon" +#define FSMONITOR_COOKIE_DIR "cookies" +#define FSMONITOR_COOKIE_PREFIX (FSMONITOR_DIR "/" FSMONITOR_COOKIE_DIR "/") enum fsmonitor_path_type fsmonitor_classify_path_workdir_relative( const char *rel) @@ -941,6 +1124,9 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state, } } + if (cookie_names->nr) + with_lock__mark_cookies_seen(state, cookie_names); + pthread_mutex_unlock(&state->main_lock); } @@ -1032,7 +1218,9 @@ static int fsmonitor_run_daemon(void) memset(&state, 0, sizeof(state)); + hashmap_init(&state.cookies, cookies_cmp, NULL, 0); pthread_mutex_init(&state.main_lock, NULL); + pthread_cond_init(&state.cookies_cond, NULL); state.error_code = 0; state.current_token_data = fsmonitor_new_token_data(); @@ -1057,6 +1245,44 @@ static int fsmonitor_run_daemon(void) state.nr_paths_watching = 2; } + /* + * We will write filesystem syncing cookie files into + * ///-. + * + * The extra layers of subdirectories here keep us from + * changing the mtime on ".git/" or ".git/foo/" when we create + * or delete cookie files. + * + * There have been problems with some IDEs that do a + * non-recursive watch of the ".git/" directory and run a + * series of commands any time something happens. + * + * For example, if we place our cookie files directly in + * ".git/" or ".git/foo/" then a `git status` (or similar + * command) from the IDE will cause a cookie file to be + * created in one of those dirs. This causes the mtime of + * those dirs to change. This triggers the IDE's watch + * notification. This triggers the IDE to run those commands + * again. And the process repeats and the machine never goes + * idle. + * + * Adding the extra layers of subdirectories prevents the + * mtime of ".git/" and ".git/foo" from changing when a + * cookie file is created. + */ + strbuf_init(&state.path_cookie_prefix, 0); + strbuf_addbuf(&state.path_cookie_prefix, &state.path_gitdir_watch); + + strbuf_addch(&state.path_cookie_prefix, '/'); + strbuf_addstr(&state.path_cookie_prefix, FSMONITOR_DIR); + mkdir(state.path_cookie_prefix.buf, 0777); + + strbuf_addch(&state.path_cookie_prefix, '/'); + strbuf_addstr(&state.path_cookie_prefix, FSMONITOR_COOKIE_DIR); + mkdir(state.path_cookie_prefix.buf, 0777); + + strbuf_addch(&state.path_cookie_prefix, '/'); + /* * Confirm that we can create platform-specific resources for the * filesystem listener before we bother starting all the threads. @@ -1069,6 +1295,7 @@ static int fsmonitor_run_daemon(void) err = fsmonitor_run_daemon_1(&state); done: + pthread_cond_destroy(&state.cookies_cond); pthread_mutex_destroy(&state.main_lock); fsm_listen__dtor(&state); @@ -1076,6 +1303,7 @@ done: strbuf_release(&state.path_worktree_watch); strbuf_release(&state.path_gitdir_watch); + strbuf_release(&state.path_cookie_prefix); return err; } diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h index 010fbfe60e9..bd09fffc176 100644 --- a/fsmonitor--daemon.h +++ b/fsmonitor--daemon.h @@ -45,6 +45,11 @@ struct fsmonitor_daemon_state { struct fsmonitor_token_data *current_token_data; + struct strbuf path_cookie_prefix; + pthread_cond_t cookies_cond; + int cookie_seq; + struct hashmap cookies; + int error_code; struct fsmonitor_daemon_backend_data *backend_data; From patchwork Tue Mar 1 18:43:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765071 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D8DEC433F5 for ; Tue, 1 Mar 2022 18:45:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237178AbiCASpk (ORCPT ); Tue, 1 Mar 2022 13:45:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57270 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237124AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 466666660D for ; Tue, 1 Mar 2022 10:44:00 -0800 (PST) Received: by mail-wr1-x430.google.com with SMTP id p9so21921197wra.12 for ; Tue, 01 Mar 2022 10:44:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=OqCROC5s98+c4tM5gHnUYLicOFeDXUaj+atK5YqejLE=; b=po1zAQslS0pjbi4Z1uWFCSIH1h11/sQ5nNYt/8He9+WdNajUP+SF0uQrfkgtLzhG9i n4i41rEX4085ACligHLkDhTNLPTay7TrYZ6SMm/LC1PIxwWJ2DWju+1RVosVT7imtsWD Ix6Ai8P4w1ZhjtSFedrO0n2BpWc0UQ77bbIXkujLCbKsndBZ3taSMrahMbK2rarkQeI1 f0oyJFtGfGenWFpoxI1Gs+OT/wNzt9PHUClOMGSckHOb4/8oDhIXl7khrF7KJywZxpeT 83tAHqmzAhqEjaZOu6Vm3pS/gcR8IWOXxtKRgtcnmxZddK241xrR07bV8aH7PuhPq2NM 1rKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=OqCROC5s98+c4tM5gHnUYLicOFeDXUaj+atK5YqejLE=; b=eq5YtIkmp2/ZOr0sps6y7YPiFnl53Fyy6mHQFUk21nff3CA7vr6rmAdLzYTqNt8tvl 63ojHRWRfMw/s0zglEJ+fG9XmuDzqa3q18H8GCfHutF+xgCUFZSCItZiDROOkqp93bRk a75eqfK+0DsDGYaW+6xOpn3eGbd4ZJY9FuWY+GKSQyDIOSs11Dy1lAyvgA7JlD7Lzt8G +sutCdwBmDFATKFVeznbyiZYQInhrBi5kkrX7WN/XbY97oRHyHEmXnTiIhluuGEQx6Nr NeFS9C+WkkpH/5HcFvq484VDId7p6HOHzLo92hIPh8WJPAYCXzPynrZRGTyIH5FKxNto shZQ== X-Gm-Message-State: AOAM532s7/BZPxjqxPgP+4BBoYvMXDUlCHWM2cHTwgj+DVLfmib96mP3 o0jV1MJtmgFK4hUzIPefu3+a2qTUrnw= X-Google-Smtp-Source: ABdhPJz6VyGSKP3CNB6OYC9JZTzEShZE4c5T2Jx5sbfuHyodF2yuVkwf9fmsdlqxmcKT4hFmlliA8g== X-Received: by 2002:a5d:50d2:0:b0:1f0:2348:4331 with SMTP id f18-20020a5d50d2000000b001f023484331mr1607913wrt.19.1646160238628; Tue, 01 Mar 2022 10:43:58 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id g6-20020a05600c4ec600b0037bf934bca3sm4102682wmq.17.2022.03.01.10.43.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:58 -0800 (PST) Message-Id: <1fd5439de0353a10240fac123d64109d8ddf00cd.1646160213.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:30 +0000 Subject: [PATCH v6 28/30] fsmonitor: force update index after large responses Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Measure the time taken to apply the FSMonitor query result to the index and the untracked-cache. Set the `FSMONITOR_CHANGED` bit on `istate->cache_changed` when FSMonitor returns a very large repsonse to ensure that the index is written to disk. Normally, when the FSMonitor response includes a tracked file, the index is always updated. Similarly, the index might be updated when the response alters the untracked-cache (when enabled). However, in cases where neither of those cause the index to be considered changed, the FSMonitor response is wasted. Subsequent Git commands will make requests with the same token and receive the same response. If that response is very large, performance may suffer. It would be more efficient to force update the index now (and the token in the index extension) in order to reduce the size of the response received by future commands. This was observed on Windows after a large checkout. On Windows, the kernel emits events for the files that are changed as they are changed. However, it might delay events for the containing directories until the system is more idle (or someone scans the directory (so it seems)). The first status following a checkout would get the list of files. The subsequent status commands would get the list of directories as the events trickled out. But they would never catch up because the token was not advanced because the index wasn't updated. This list of directories caused `wt_status_collect_untracked()` to unnecessarily spend time actually scanning them during each command. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- fsmonitor.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/fsmonitor.c b/fsmonitor.c index a38b5710eb3..292a6742b4f 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -219,6 +219,43 @@ static void fsmonitor_refresh_callback(struct index_state *istate, char *name) untracked_cache_invalidate_path(istate, name, 0); } +/* + * The number of pathnames that we need to receive from FSMonitor + * before we force the index to be updated. + * + * Note that any pathname within the set of received paths MAY cause + * cache-entry or istate flag bits to be updated and thus cause the + * index to be updated on disk. + * + * However, the response may contain many paths (such as ignored + * paths) that will not update any flag bits. And thus not force the + * index to be updated. (This is fine and normal.) It also means + * that the token will not be updated in the FSMonitor index + * extension. So the next Git command will find the same token in the + * index, make the same token-relative request, and receive the same + * response (plus any newly changed paths). If this response is large + * (and continues to grow), performance could be impacted. + * + * For example, if the user runs a build and it writes 100K object + * files but doesn't modify any source files, the index would not need + * to be updated. The FSMonitor response (after the build and + * relative to a pre-build token) might be 5MB. Each subsequent Git + * command will receive that same 100K/5MB response until something + * causes the index to be updated. And `refresh_fsmonitor()` will + * have to iterate over those 100K paths each time. + * + * Performance could be improved if we optionally force update the + * index after a very large response and get an updated token into + * the FSMonitor index extension. This should allow subsequent + * commands to get smaller and more current responses. + * + * The value chosen here does not need to be precise. The index + * will be updated automatically the first time the user touches + * a tracked file and causes a command like `git status` to + * update an mtime to be updated and/or set a flag bit. + */ +static int fsmonitor_force_update_threshold = 100; + void refresh_fsmonitor(struct index_state *istate) { struct strbuf query_result = STRBUF_INIT; @@ -362,25 +399,39 @@ apply_results: * information and that we should consider everything * invalid. We call this a trivial response. */ + trace2_region_enter("fsmonitor", "apply_results", istate->repo); + if (query_success && !is_trivial) { /* * Mark all pathnames returned by the monitor as dirty. * * This updates both the cache-entries and the untracked-cache. */ + int count = 0; + buf = query_result.buf; for (i = bol; i < query_result.len; i++) { if (buf[i] != '\0') continue; fsmonitor_refresh_callback(istate, buf + bol); bol = i + 1; + count++; } - if (bol < query_result.len) + if (bol < query_result.len) { fsmonitor_refresh_callback(istate, buf + bol); + count++; + } /* Now mark the untracked cache for fsmonitor usage */ if (istate->untracked) istate->untracked->use_fsmonitor = 1; + + if (count > fsmonitor_force_update_threshold) + istate->cache_changed |= FSMONITOR_CHANGED; + + trace2_data_intmax("fsmonitor", istate->repo, "apply_count", + count); + } else { /* * We failed to get a response or received a trivial response, @@ -409,6 +460,8 @@ apply_results: if (istate->untracked) istate->untracked->use_fsmonitor = 0; } + trace2_region_leave("fsmonitor", "apply_results", istate->repo); + strbuf_release(&query_result); /* Now that we've updated istate, save the last_update_token */ From patchwork Tue Mar 1 18:43:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765073 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C127DC433F5 for ; Tue, 1 Mar 2022 18:45:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237035AbiCASpo (ORCPT ); Tue, 1 Mar 2022 13:45:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57050 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237133AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 20D3D6661E for ; Tue, 1 Mar 2022 10:44:01 -0800 (PST) Received: by mail-wr1-x431.google.com with SMTP id ay10so4108836wrb.6 for ; Tue, 01 Mar 2022 10:44:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=eB3v/8E8+3K2F4p78oh14iDjR5lnR3MP13qtVVjU7W4=; b=j2teBM5Y6jQ0lOTO6zhREOdtqXkXQE3+AUfl/YjTdjZa7BOOgz2OrMUbA5dGwmohFl lwkC1rIHZQvESBJ5gn/34OMicqZVIUuTs7QJZq7eSWP4Y0UaJ/q1Ozo4ZGDSBylSekj1 1/prGEzXPZqx9ryHmz2LOavVnB+gPjUV24GAGgDn1cSiHNZnjXi/1VlbuZtJZ7LwWvxT YyrvRcrsEmcAr4pqt1gBFWY4so/4P6WzaIesuH8koSaNJyvfvPYRvUpKoTVxMegy0nX1 13g7vyII91cqcznyT8FnI1uc6Zeb+sEK9HJ8u5GvTEJ2pE4HDgcVVW8CMs9f9l91dyRH nzKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=eB3v/8E8+3K2F4p78oh14iDjR5lnR3MP13qtVVjU7W4=; b=s5YDMD8dUdzpqxRKXeMgAeay6s4s5okqhr4RHeQozkMCft905A7NIoXith5rcKluka bXguq03cJoGxFD8sCHNwi1QKkVnrQTxpTCZ1XMBxU57GoIJmRE6rgLcJ2nx2VK1ozrKV Er+Nr0UWXDFCgEBHE8ZklnTvSnmmNdC53WysRog3J5K4KGZb3cuZZBACAFG9uEgtGb/G Rsvg/aejkTI4ZbpgPV+9tRRSpI4dEYRqZb3oKEvNwEheKvfEOpHpA0/2S2Jp7bnq1rqS 7Ch+6rstli95rLHtomi1ccRif7X5PVgzWCFp5zJhNqwQDd1wZaVMyc7AQGTAZycFQtmM RjyA== X-Gm-Message-State: AOAM531nT/l853soI0UIacKoclWSzc8S5+ZDrG+3QQmigBCBnTJos4sZ 9k8bABWx/N97o2bvHw8kgYKreXYjCqY= X-Google-Smtp-Source: ABdhPJzF8AWwoicPoSsaHvMlFugu/huy8br+ydTJ6paQx7tICC948mIgWwf50M6Xom0uCnEZ+K7KSw== X-Received: by 2002:a5d:4dca:0:b0:1f0:2543:e10e with SMTP id f10-20020a5d4dca000000b001f02543e10emr520911wru.60.1646160239565; Tue, 01 Mar 2022 10:43:59 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id f18-20020a05600c155200b003816bac83f6sm3703039wmg.27.2022.03.01.10.43.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:59 -0800 (PST) Message-Id: <6fc1430285ff814ef972ad3f3128f09e751cdb1a.1646160213.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:31 +0000 Subject: [PATCH v6 29/30] t7527: test status with untracked-cache and fsmonitor--daemon Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Create 2x2 test matrix with the untracked-cache and fsmonitor--daemon features and a series of edits and verify that status output is identical. Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- t/t7527-builtin-fsmonitor.sh | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh index 5f7b8e54233..0ccbfb9616f 100755 --- a/t/t7527-builtin-fsmonitor.sh +++ b/t/t7527-builtin-fsmonitor.sh @@ -162,6 +162,8 @@ test_expect_success 'setup' ' .gitignore expect* actual* + flush* + trace* EOF git -c core.fsmonitor=false add . && @@ -508,4 +510,95 @@ test_expect_success 'cleanup worktrees' ' stop_daemon_delete_repo wt-base ' +# The next few tests perform arbitrary/contrived file operations and +# confirm that status is correct. That is, that the data (or lack of +# data) from fsmonitor doesn't cause incorrect results. And doesn't +# cause incorrect results when the untracked-cache is enabled. + +test_lazy_prereq UNTRACKED_CACHE ' + git update-index --test-untracked-cache +' + +test_expect_success 'Matrix: setup for untracked-cache,fsmonitor matrix' ' + test_unconfig core.fsmonitor && + git update-index --no-fsmonitor && + test_might_fail git fsmonitor--daemon stop +' + +matrix_clean_up_repo () { + git reset --hard HEAD && + git clean -fd +} + +matrix_try () { + uc=$1 + fsm=$2 + fn=$3 + + test_expect_success "Matrix[uc:$uc][fsm:$fsm] $fn" ' + matrix_clean_up_repo && + $fn && + if test $uc = false && test $fsm = false + then + git status --porcelain=v1 >.git/expect.$fn + else + git status --porcelain=v1 >.git/actual.$fn && + test_cmp .git/expect.$fn .git/actual.$fn + fi + ' +} + +uc_values="false" +test_have_prereq UNTRACKED_CACHE && uc_values="false true" +for uc_val in $uc_values +do + if test $uc_val = false + then + test_expect_success "Matrix[uc:$uc_val] disable untracked cache" ' + git config core.untrackedcache false && + git update-index --no-untracked-cache + ' + else + test_expect_success "Matrix[uc:$uc_val] enable untracked cache" ' + git config core.untrackedcache true && + git update-index --untracked-cache + ' + fi + + fsm_values="false true" + for fsm_val in $fsm_values + do + if test $fsm_val = false + then + test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] disable fsmonitor" ' + test_unconfig core.fsmonitor && + git update-index --no-fsmonitor && + test_might_fail git fsmonitor--daemon stop + ' + else + test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] enable fsmonitor" ' + git config core.fsmonitor true && + git fsmonitor--daemon start && + git update-index --fsmonitor + ' + fi + + matrix_try $uc_val $fsm_val edit_files + matrix_try $uc_val $fsm_val delete_files + matrix_try $uc_val $fsm_val create_files + matrix_try $uc_val $fsm_val rename_files + matrix_try $uc_val $fsm_val file_to_directory + matrix_try $uc_val $fsm_val directory_to_file + + if test $fsm_val = true + then + test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] disable fsmonitor at end" ' + test_unconfig core.fsmonitor && + git update-index --no-fsmonitor && + test_might_fail git fsmonitor--daemon stop + ' + fi + done +done + test_done From patchwork Tue Mar 1 18:43:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Hostetler X-Patchwork-Id: 12765072 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 35B4AC4332F for ; Tue, 1 Mar 2022 18:45:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237180AbiCASpl (ORCPT ); Tue, 1 Mar 2022 13:45:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55094 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237132AbiCASo5 (ORCPT ); Tue, 1 Mar 2022 13:44:57 -0500 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E40C366620 for ; Tue, 1 Mar 2022 10:44:01 -0800 (PST) Received: by mail-wm1-x32a.google.com with SMTP id p4so8030482wmg.1 for ; Tue, 01 Mar 2022 10:44:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=brC2wcOdkQh4a308InYtzfFjo3H8sjFwU5wYnZr4Ujk=; b=nF3Hmb/PbITKhBASpLZGWbL6ddOFJ44o26Z/yVkSkcHI95nY4oeM8Wg/8K7A17fR16 g0pb3k14XLNGowLzK4cKpziqWw6iss1GjOtbDcIb5wmShiqbdFDh3KW33xslzDBmc0yY LMOk4ebkwnmm3aguCQOnIElXuBa7F1A9yaydZTTD+e2SbtdSC0io4bXoA4AhQIvpIz7s tjFvZ9n/LZsusHNoWQxQteE20LsNwvn1r3FThZk5cfmacA3CcFBngqC9Vmh02trvqwCC OHT3NcTk7qhR+GtKFioG1X/A2hsYFCsjiOH2lRO8K/thqhxfoIIBStumrCxAOuONWhVO +5QQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=brC2wcOdkQh4a308InYtzfFjo3H8sjFwU5wYnZr4Ujk=; b=i8QteqTjzrJIqD3avS1lSL7dsXorOsW93BBWNdIBbtfMu1P+V6VnDGNwPeCrYqpfFX 7XVis5Z9g3NqODowDJDPBtLmwqIyAH7/uV+CbguF1dXc7+0hURsyub7jd8xaH335GUVc v82eibpIGgkDFg53KS9SqpEuOrrAhwE72MedgOUh5B0PUd854wEcZL6BX0MPDGw7cW5x pOh/6DXOck67RabENLKR44tC8O9b7W8X/7LDH2NGOdjzTQN9bLjoD6pGVvnApmgMqD+i sBheOTLrKezAJWIKnNdF5KOPnaBbprPzvTwNFv8+3lZw2D16jFFyTAQzSXN5ekPJuleY kTEw== X-Gm-Message-State: AOAM53059LegZpbVR90KqObOKfvaaVY4VJlTiXlVtQrTpJQGZZQQ0Kd6 BXe+3MUWZTQgOLr/ZTTBQuIzmEl+6pg= X-Google-Smtp-Source: ABdhPJxNG/OVfA30nQ9qGzh1Ebk1zTUY2HuNoJXMnttTn7HPPNacNNYWeR9u+uStYRXRC0vJeJdzAg== X-Received: by 2002:a05:600c:42d6:b0:380:ed47:43e8 with SMTP id j22-20020a05600c42d600b00380ed4743e8mr17969261wme.61.1646160240303; Tue, 01 Mar 2022 10:44:00 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id 6-20020a05600c230600b0038115c73362sm3257353wmo.12.2022.03.01.10.43.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 10:43:59 -0800 (PST) Message-Id: In-Reply-To: References: Date: Tue, 01 Mar 2022 18:43:32 +0000 Subject: [PATCH v6 30/30] update-index: convert fsmonitor warnings to advise Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Bagas Sanjaya , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Jeff Hostetler , Eric Sunshine , Johannes Schindelin , Tao Klerks , Jeff Hostetler , Jeff Hostetler Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jeff Hostetler From: Jeff Hostetler Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- builtin/update-index.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin/update-index.c b/builtin/update-index.c index 876112abb21..d335f1ac72a 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -1238,18 +1238,18 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (fsmonitor > 0) { enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r); if (fsm_mode == FSMONITOR_MODE_DISABLED) { - warning(_("core.fsmonitor is unset; " - "set it if you really want to " - "enable fsmonitor")); + advise(_("core.fsmonitor is unset; " + "set it if you really want to " + "enable fsmonitor")); } add_fsmonitor(&the_index); report(_("fsmonitor enabled")); } else if (!fsmonitor) { enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r); if (fsm_mode > FSMONITOR_MODE_DISABLED) - warning(_("core.fsmonitor is set; " - "remove it if you really want to " - "disable fsmonitor")); + advise(_("core.fsmonitor is set; " + "remove it if you really want to " + "disable fsmonitor")); remove_fsmonitor(&the_index); report(_("fsmonitor disabled")); }