@@ -106,6 +106,120 @@ static int do_as_client__status(void)
106106 }
107107}
108108
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+
109223static ipc_server_application_cb handle_client ;
110224
111225static int handle_client (void * data ,
@@ -298,7 +412,7 @@ static int fsmonitor_run_daemon(void)
298412
299413 pthread_mutex_init (& state .main_lock , NULL );
300414 state .error_code = 0 ;
301- state .current_token_data = NULL ;
415+ state .current_token_data = fsmonitor_new_token_data () ;
302416
303417 /* Prepare to (recursively) watch the <worktree-root> directory. */
304418 strbuf_init (& state .path_worktree_watch , 0 );
0 commit comments