]>
git.ipfire.org Git - thirdparty/git.git/blob - t/helper/test-fsmonitor-client.c
2 * test-fsmonitor-client.c: client code to send commands/requests to
3 * a `git fsmonitor--daemon` daemon.
7 #include "parse-options.h"
8 #include "fsmonitor-ipc.h"
9 #include "read-cache-ll.h"
10 #include "repository.h"
12 #include "thread-utils.h"
15 #ifndef HAVE_FSMONITOR_DAEMON_BACKEND
16 int cmd__fsmonitor_client(int argc UNUSED
, const char **argv UNUSED
)
18 die("fsmonitor--daemon not available on this platform");
23 * Read the `.git/index` to get the last token written to the
24 * FSMonitor Index Extension.
26 static const char *get_token_from_index(void)
28 struct index_state
*istate
= the_repository
->index
;
30 if (do_read_index(istate
, the_repository
->index_file
, 0) < 0)
31 die("unable to read index file");
32 if (!istate
->fsmonitor_last_update
)
33 die("index file does not have fsmonitor extension");
35 return istate
->fsmonitor_last_update
;
39 * Send an IPC query to a `git-fsmonitor--daemon` daemon and
40 * ask for the changes since the given token or from the last
41 * token in the index extension.
43 * This will implicitly start a daemon process if necessary. The
44 * daemon process will persist after we exit.
46 static int do_send_query(const char *token
)
48 struct strbuf answer
= STRBUF_INIT
;
51 if (!token
|| !*token
)
52 token
= get_token_from_index();
54 ret
= fsmonitor_ipc__send_query(token
, &answer
);
56 die("could not query fsmonitor--daemon");
58 write_in_full(1, answer
.buf
, answer
.len
);
59 strbuf_release(&answer
);
65 * Send a "flush" command to the `git-fsmonitor--daemon` (if running)
66 * and tell it to flush its cache.
68 * This feature is primarily used by the test suite to simulate a loss of
69 * sync with the filesystem where we miss kernel events.
71 static int do_send_flush(void)
73 struct strbuf answer
= STRBUF_INIT
;
76 ret
= fsmonitor_ipc__send_command("flush", &answer
);
80 write_in_full(1, answer
.buf
, answer
.len
);
81 strbuf_release(&answer
);
86 struct hammer_thread_data
98 static void *hammer_thread_proc(void *_hammer_thread_data
)
100 struct hammer_thread_data
*data
= _hammer_thread_data
;
101 struct strbuf answer
= STRBUF_INIT
;
105 trace2_thread_start("hammer");
107 for (k
= 0; k
< data
->nr_requests
; k
++) {
108 strbuf_reset(&answer
);
110 ret
= fsmonitor_ipc__send_query(data
->token
, &answer
);
114 data
->sum_successful
++;
117 strbuf_release(&answer
);
118 trace2_thread_exit();
123 * Start a pool of client threads that will each send a series of
124 * commands to the daemon.
126 * The goal is to overload the daemon with a sustained series of
127 * concurrent requests.
129 static int do_hammer(const char *token
, int nr_threads
, int nr_requests
)
131 struct hammer_thread_data
*data
= NULL
;
133 int sum_join_errors
= 0;
134 int sum_commands
= 0;
137 if (!token
|| !*token
)
138 token
= get_token_from_index();
144 CALLOC_ARRAY(data
, nr_threads
);
146 for (k
= 0; k
< nr_threads
; k
++) {
147 struct hammer_thread_data
*p
= &data
[k
];
149 p
->nr_requests
= nr_requests
;
152 if (pthread_create(&p
->pthread_id
, NULL
, hammer_thread_proc
, p
)) {
153 warning("failed to create thread[%d] skipping remainder", k
);
159 for (k
= 0; k
< nr_threads
; k
++) {
160 struct hammer_thread_data
*p
= &data
[k
];
162 if (pthread_join(p
->pthread_id
, NULL
))
164 sum_commands
+= p
->sum_successful
;
165 sum_errors
+= p
->sum_errors
;
168 fprintf(stderr
, "HAMMER: [threads %d][requests %d] [ok %d][err %d][join %d]\n",
169 nr_threads
, nr_requests
, sum_commands
, sum_errors
, sum_join_errors
);
174 * Return an error if any of the _send_query requests failed.
175 * We don't care about thread create/join errors.
177 return sum_errors
> 0;
180 int cmd__fsmonitor_client(int argc
, const char **argv
)
183 const char *token
= NULL
;
187 const char * const fsmonitor_client_usage
[] = {
188 "test-tool fsmonitor-client query [<token>]",
189 "test-tool fsmonitor-client flush",
190 "test-tool fsmonitor-client hammer [<token>] [<threads>] [<requests>]",
194 struct option options
[] = {
195 OPT_STRING(0, "token", &token
, "token",
196 "command token to send to the server"),
198 OPT_INTEGER(0, "threads", &nr_threads
, "number of client threads"),
199 OPT_INTEGER(0, "requests", &nr_requests
, "number of requests per thread"),
204 argc
= parse_options(argc
, argv
, NULL
, options
, fsmonitor_client_usage
, 0);
207 usage_with_options(fsmonitor_client_usage
, options
);
211 setup_git_directory();
213 if (!strcmp(subcmd
, "query"))
214 return !!do_send_query(token
);
216 if (!strcmp(subcmd
, "flush"))
217 return !!do_send_flush();
219 if (!strcmp(subcmd
, "hammer"))
220 return !!do_hammer(token
, nr_threads
, nr_requests
);
222 die("Unhandled subcommand: '%s'", subcmd
);