fsmonitor--daemon: define token-ids
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>
Jeff Hostetler committed
Mar 25, 2022 at 18:02 UTC
aeef767a4155f55233338928f705a3e9986fe2bf
1 file changed
+115
-1
builtin/fsmonitor--daemon.c
+115
-1
@@ -106,6 +106,120 @@ static int do_as_client__status(void)
106
}
107
}
108
109
+/*
110
+ * Requests to and from a FSMonitor Protocol V2 provider use an opaque
111
+ * "token" as a virtual timestamp. Clients can request a summary of all
112
+ * created/deleted/modified files relative to a token. In the response,
113
+ * clients receive a new token for the next (relative) request.
114
+ *
115
+ *
116
+ * Token Format
117
+ * ============
118
+ *
119
+ * The contents of the token are private and provider-specific.
120
+ *
121
+ * For the built-in fsmonitor--daemon, we define a token as follows:
122
+ *
123
+ * "builtin" ":" <token_id> ":" <sequence_nr>
124
+ *
125
+ * The "builtin" prefix is used as a namespace to avoid conflicts
126
+ * with other providers (such as Watchman).
127
+ *
128
+ * The <token_id> is an arbitrary OPAQUE string, such as a GUID,
129
+ * UUID, or {timestamp,pid}. It is used to group all filesystem
130
+ * events that happened while the daemon was monitoring (and in-sync
131
+ * with the filesystem).
132
+ *
133
+ * Unlike FSMonitor Protocol V1, it is not defined as a timestamp
134
+ * and does not define less-than/greater-than relationships.
135
+ * (There are too many race conditions to rely on file system
136
+ * event timestamps.)
137
+ *
138
+ * The <sequence_nr> is a simple integer incremented whenever the
139
+ * daemon needs to make its state public. For example, if 1000 file
140
+ * system events come in, but no clients have requested the data,
141
+ * the daemon can continue to accumulate file changes in the same
142
+ * bin and does not need to advance the sequence number. However,
143
+ * as soon as a client does arrive, the daemon needs to start a new
144
+ * bin and increment the sequence number.
145
+ *
146
+ * The sequence number serves as the boundary between 2 sets
147
+ * of bins -- the older ones that the client has already seen
148
+ * and the newer ones that it hasn't.
149
+ *
150
+ * When a new <token_id> is created, the <sequence_nr> is reset to
151
+ * zero.
152
+ *
153
+ *
154
+ * About Token Ids
155
+ * ===============
156
+ *
157
+ * A new token_id is created:
158
+ *
159
+ * [1] each time the daemon is started.
160
+ *
161
+ * [2] any time that the daemon must re-sync with the filesystem
162
+ * (such as when the kernel drops or we miss events on a very
163
+ * active volume).
164
+ *
165
+ * [3] in response to a client "flush" command (for dropped event
166
+ * testing).
167
+ *
168
+ * When a new token_id is created, the daemon is free to discard all
169
+ * cached filesystem events associated with any previous token_ids.
170
+ * Events associated with a non-current token_id will never be sent
171
+ * to a client. A token_id change implicitly means that the daemon
172
+ * has gap in its event history.
173
+ *
174
+ * Therefore, clients that present a token with a stale (non-current)
175
+ * token_id will always be given a trivial response.
176
+ */
177
+struct fsmonitor_token_data {
178
+ struct strbuf token_id;
179
+ struct fsmonitor_batch *batch_head;
180
+ struct fsmonitor_batch *batch_tail;
181
+ uint64_t client_ref_count;
182
+};
183
+
184
+static struct fsmonitor_token_data *fsmonitor_new_token_data(void)
185
+{
186
+ static int test_env_value = -1;
187
+ static uint64_t flush_count = 0;
188
+ struct fsmonitor_token_data *token;
189
+
190
+ CALLOC_ARRAY(token, 1);
191
+
192
+ strbuf_init(&token->token_id, 0);
193
+ token->batch_head = NULL;
194
+ token->batch_tail = NULL;
195
+ token->client_ref_count = 0;
196
+
197
+ if (test_env_value < 0)
198
+ test_env_value = git_env_bool("GIT_TEST_FSMONITOR_TOKEN", 0);
199
+
200
+ if (!test_env_value) {
201
+ struct timeval tv;
202
+ struct tm tm;
203
+ time_t secs;
204
+
205
+ gettimeofday(&tv, NULL);
206
+ secs = tv.tv_sec;
207
+ gmtime_r(&secs, &tm);
208
+
209
+ strbuf_addf(&token->token_id,
210
+ "%"PRIu64".%d.%4d%02d%02dT%02d%02d%02d.%06ldZ",
211
+ flush_count++,
212
+ getpid(),
213
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
214
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
215
+ (long)tv.tv_usec);
216
+ } else {
217
+ strbuf_addf(&token->token_id, "test_%08x", test_env_value++);
218
+ }
219
+
220
+ return token;
221
+}
222
+
223
static ipc_server_application_cb handle_client;
224
225
static int handle_client(void *data,
@@ -298,7 +412,7 @@ static int fsmonitor_run_daemon(void)
412
413
pthread_mutex_init(&state.main_lock, NULL);
414
state.error_code = 0;
301
- state.current_token_data = NULL;
415
+ state.current_token_data = fsmonitor_new_token_data();
416
417
/* Prepare to (recursively) watch the <worktree-root> directory. */
418
strbuf_init(&state.path_worktree_watch, 0);