ctdb-tests: Fix CID 1364525 (Argument cannot be negative)
[samba.git] / ctdb / tests / src / fetch_readonly_loop.c
1 /*
2    simple ctdb benchmark
3
4    Copyright (C) Amitay Isaacs  2015
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/network.h"
22
23 #include "lib/util/tevent_unix.h"
24
25 #include "client/client.h"
26 #include "tests/src/test_options.h"
27 #include "tests/src/cluster_wait.h"
28
29 #define TESTDB  "fetch_readonly_loop.tdb"
30 #define TESTKEY "testkey"
31
32 struct fetch_loop_state {
33         struct tevent_context *ev;
34         struct ctdb_client_context *client;
35         struct ctdb_db_context *ctdb_db;
36         int num_nodes;
37         int timelimit;
38         TDB_DATA key;
39         int locks_count;
40 };
41
42 static void fetch_loop_start(struct tevent_req *subreq);
43 static void fetch_loop_next(struct tevent_req *subreq);
44 static void fetch_loop_each_second(struct tevent_req *subreq);
45 static void fetch_loop_finish(struct tevent_req *subreq);
46
47 static struct tevent_req *fetch_loop_send(TALLOC_CTX *mem_ctx,
48                                           struct tevent_context *ev,
49                                           struct ctdb_client_context *client,
50                                           struct ctdb_db_context *ctdb_db,
51                                           int num_nodes, int timelimit)
52 {
53         struct tevent_req *req, *subreq;
54         struct fetch_loop_state *state;
55
56         req = tevent_req_create(mem_ctx, &state, struct fetch_loop_state);
57         if (req == NULL) {
58                 return NULL;
59         }
60
61         state->ev = ev;
62         state->client = client;
63         state->ctdb_db = ctdb_db;
64         state->num_nodes = num_nodes;
65         state->timelimit = timelimit;
66         state->key.dptr = discard_const(TESTKEY);
67         state->key.dsize = strlen(TESTKEY);
68
69         subreq = cluster_wait_send(state, state->ev, state->client,
70                                    state->num_nodes);
71         if (tevent_req_nomem(subreq, req)) {
72                 return tevent_req_post(req, ev);
73         }
74         tevent_req_set_callback(subreq, fetch_loop_start, req);
75
76         return req;
77 }
78
79 static void fetch_loop_start(struct tevent_req *subreq)
80 {
81         struct tevent_req *req = tevent_req_callback_data(
82                 subreq, struct tevent_req);
83         struct fetch_loop_state *state = tevent_req_data(
84                 req, struct fetch_loop_state);
85         bool status;
86         int ret;
87
88         status = cluster_wait_recv(subreq, &ret);
89         TALLOC_FREE(subreq);
90         if (! status) {
91                 tevent_req_error(req, ret);
92                 return;
93         }
94
95         subreq = ctdb_fetch_lock_send(state, state->ev, state->client,
96                                       state->ctdb_db, state->key, true);
97         if (tevent_req_nomem(subreq, req)) {
98                 return;
99         }
100         tevent_req_set_callback(subreq, fetch_loop_next, req);
101
102         if (ctdb_client_pnn(state->client) == 0) {
103                 subreq = tevent_wakeup_send(state, state->ev,
104                                             tevent_timeval_current_ofs(1, 0));
105                 if (tevent_req_nomem(subreq, req)) {
106                         return;
107                 }
108                 tevent_req_set_callback(subreq, fetch_loop_each_second, req);
109         }
110
111         subreq = tevent_wakeup_send(state, state->ev,
112                                     tevent_timeval_current_ofs(
113                                             state->timelimit, 0));
114         if (tevent_req_nomem(subreq, req)) {
115                 return;
116         }
117         tevent_req_set_callback(subreq, fetch_loop_finish, req);
118 }
119
120 static void fetch_loop_next(struct tevent_req *subreq)
121 {
122         struct tevent_req *req = tevent_req_callback_data(
123                 subreq, struct tevent_req);
124         struct fetch_loop_state *state = tevent_req_data(
125                 req, struct fetch_loop_state);
126         struct ctdb_record_handle *h;
127         int ret;
128
129         h = ctdb_fetch_lock_recv(subreq, NULL, state, NULL, &ret);
130         TALLOC_FREE(subreq);
131         if (h == NULL) {
132                 tevent_req_error(req, ret);
133                 return;
134         }
135
136         state->locks_count += 1;
137         talloc_free(h);
138
139         subreq = ctdb_fetch_lock_send(state, state->ev, state->client,
140                                       state->ctdb_db, state->key, true);
141         if (tevent_req_nomem(subreq, req)) {
142                 return;
143         }
144         tevent_req_set_callback(subreq, fetch_loop_next, req);
145 }
146
147 static void fetch_loop_each_second(struct tevent_req *subreq)
148 {
149         struct tevent_req *req = tevent_req_callback_data(
150                 subreq, struct tevent_req);
151         struct fetch_loop_state *state = tevent_req_data(
152                 req, struct fetch_loop_state);
153         bool status;
154
155         status = tevent_wakeup_recv(subreq);
156         TALLOC_FREE(subreq);
157         if (! status) {
158                 tevent_req_error(req, EIO);
159                 return;
160         }
161
162         printf("Locks:%d\r", state->locks_count);
163         fflush(stdout);
164
165         subreq = tevent_wakeup_send(state, state->ev,
166                                     tevent_timeval_current_ofs(1, 0));
167         if (tevent_req_nomem(subreq, req)) {
168                 return;
169         }
170         tevent_req_set_callback(subreq, fetch_loop_each_second, req);
171 }
172
173 static void fetch_loop_finish(struct tevent_req *subreq)
174 {
175         struct tevent_req *req = tevent_req_callback_data(
176                 subreq, struct tevent_req);
177         struct fetch_loop_state *state = tevent_req_data(
178                 req, struct fetch_loop_state);
179         bool status;
180
181         status = tevent_wakeup_recv(subreq);
182         TALLOC_FREE(subreq);
183         if (! status) {
184                 tevent_req_error(req, EIO);
185                 return;
186         }
187
188         printf("Locks:%d\n", state->locks_count);
189
190         tevent_req_done(req);
191 }
192
193 static bool fetch_loop_recv(struct tevent_req *req, int *perr)
194 {
195         int err;
196
197         if (tevent_req_is_unix_error(req, &err)) {
198                 if (perr != NULL) {
199                         *perr = err;
200                 }
201                 return false;
202         }
203         return true;
204 }
205
206 int main(int argc, const char *argv[])
207 {
208         const struct test_options *opts;
209         TALLOC_CTX *mem_ctx;
210         struct tevent_context *ev;
211         struct ctdb_client_context *client;
212         struct ctdb_db_context *ctdb_db;
213         struct tevent_req *req;
214         int ret;
215         bool status;
216
217         status = process_options_basic(argc, argv, &opts);
218         if (! status) {
219                 exit(1);
220         }
221
222         mem_ctx = talloc_new(NULL);
223         if (mem_ctx == NULL) {
224                 fprintf(stderr, "Memory allocation error\n");
225                 exit(1);
226         }
227
228         ev = tevent_context_init(mem_ctx);
229         if (ev == NULL) {
230                 fprintf(stderr, "Memory allocation error\n");
231                 exit(1);
232         }
233
234         ret = ctdb_client_init(mem_ctx, ev, opts->socket, &client);
235         if (ret != 0) {
236                 fprintf(stderr, "Failed to initialize client, ret=%d\n", ret);
237                 exit(1);
238         }
239
240         if (! ctdb_recovery_wait(ev, client)) {
241                 fprintf(stderr, "Memory allocation error\n");
242                 exit(1);
243         }
244
245         ret = ctdb_attach(ev, client, tevent_timeval_zero(), TESTDB, 0,
246                           &ctdb_db);
247         if (ret != 0) {
248                 fprintf(stderr, "Failed to attach to DB %s\n", TESTDB);
249                 exit(1);
250         }
251
252         req = fetch_loop_send(mem_ctx, ev, client, ctdb_db,
253                                opts->num_nodes, opts->timelimit);
254         if (req == NULL) {
255                 fprintf(stderr, "Memory allocation error\n");
256                 exit(1);
257         }
258
259         tevent_req_poll(req, ev);
260
261         status = fetch_loop_recv(req, &ret);
262         if (! status) {
263                 fprintf(stderr, "fetch readonly loop test failed\n");
264                 exit(1);
265         }
266
267         talloc_free(mem_ctx);
268         return 0;
269 }