]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fsmonitor--daemon: define token-ids
authorJeff Hostetler <jeffhost@microsoft.com>
Fri, 25 Mar 2022 18:02:56 +0000 (18:02 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 25 Mar 2022 23:04:16 +0000 (16:04 -0700)
Teach fsmonitor--daemon to create token-ids and define the
overall token naming scheme.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fsmonitor--daemon.c

index 1ce00b7c1505106b1ac832e736217c7e0382c8b5..1c7c156288d6aed6244788d873524e48137f2d38 100644 (file)
@@ -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" ":" <token_id> ":" <sequence_nr>
+ *
+ * The "builtin" prefix is used as a namespace to avoid conflicts
+ * with other providers (such as Watchman).
+ *
+ * The <token_id> 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 <sequence_nr> 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 <token_id> is created, the <sequence_nr> 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 <worktree-root> directory. */
        strbuf_init(&state.path_worktree_watch, 0);