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