4 Copyright (C) Amitay Isaacs 2015
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.
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.
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/>.
21 #include "system/network.h"
23 #include "lib/util/tevent_unix.h"
25 #include "client/client.h"
26 #include "tests/src/test_options.h"
27 #include "tests/src/cluster_wait.h"
29 #define TESTDB "fetch_readonly_loop.tdb"
30 #define TESTKEY "testkey"
32 struct fetch_loop_state
{
33 struct tevent_context
*ev
;
34 struct ctdb_client_context
*client
;
35 struct ctdb_db_context
*ctdb_db
;
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
);
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
)
53 struct tevent_req
*req
, *subreq
;
54 struct fetch_loop_state
*state
;
56 req
= tevent_req_create(mem_ctx
, &state
, struct fetch_loop_state
);
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
);
69 subreq
= cluster_wait_send(state
, state
->ev
, state
->client
,
71 if (tevent_req_nomem(subreq
, req
)) {
72 return tevent_req_post(req
, ev
);
74 tevent_req_set_callback(subreq
, fetch_loop_start
, req
);
79 static void fetch_loop_start(struct tevent_req
*subreq
)
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
);
88 status
= cluster_wait_recv(subreq
, &ret
);
91 tevent_req_error(req
, ret
);
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
)) {
100 tevent_req_set_callback(subreq
, fetch_loop_next
, req
);
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
)) {
108 tevent_req_set_callback(subreq
, fetch_loop_each_second
, req
);
111 subreq
= tevent_wakeup_send(state
, state
->ev
,
112 tevent_timeval_current_ofs(
113 state
->timelimit
, 0));
114 if (tevent_req_nomem(subreq
, req
)) {
117 tevent_req_set_callback(subreq
, fetch_loop_finish
, req
);
120 static void fetch_loop_next(struct tevent_req
*subreq
)
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
;
129 h
= ctdb_fetch_lock_recv(subreq
, NULL
, state
, NULL
, &ret
);
132 tevent_req_error(req
, ret
);
136 state
->locks_count
+= 1;
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
)) {
144 tevent_req_set_callback(subreq
, fetch_loop_next
, req
);
147 static void fetch_loop_each_second(struct tevent_req
*subreq
)
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
);
155 status
= tevent_wakeup_recv(subreq
);
158 tevent_req_error(req
, EIO
);
162 printf("Locks:%d\r", state
->locks_count
);
165 subreq
= tevent_wakeup_send(state
, state
->ev
,
166 tevent_timeval_current_ofs(1, 0));
167 if (tevent_req_nomem(subreq
, req
)) {
170 tevent_req_set_callback(subreq
, fetch_loop_each_second
, req
);
173 static void fetch_loop_finish(struct tevent_req
*subreq
)
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
);
181 status
= tevent_wakeup_recv(subreq
);
184 tevent_req_error(req
, EIO
);
188 printf("Locks:%d\n", state
->locks_count
);
190 tevent_req_done(req
);
193 static bool fetch_loop_recv(struct tevent_req
*req
, int *perr
)
197 if (tevent_req_is_unix_error(req
, &err
)) {
206 int main(int argc
, const char *argv
[])
208 const struct test_options
*opts
;
210 struct tevent_context
*ev
;
211 struct ctdb_client_context
*client
;
212 struct ctdb_db_context
*ctdb_db
;
213 struct tevent_req
*req
;
217 status
= process_options_basic(argc
, argv
, &opts
);
222 mem_ctx
= talloc_new(NULL
);
223 if (mem_ctx
== NULL
) {
224 fprintf(stderr
, "Memory allocation error\n");
228 ev
= tevent_context_init(mem_ctx
);
230 fprintf(stderr
, "Memory allocation error\n");
234 ret
= ctdb_client_init(mem_ctx
, ev
, opts
->socket
, &client
);
236 fprintf(stderr
, "Failed to initialize client, ret=%d\n", ret
);
240 if (! ctdb_recovery_wait(ev
, client
)) {
241 fprintf(stderr
, "Memory allocation error\n");
245 ret
= ctdb_attach(ev
, client
, tevent_timeval_zero(), TESTDB
, 0,
248 fprintf(stderr
, "Failed to attach to DB %s\n", TESTDB
);
252 req
= fetch_loop_send(mem_ctx
, ev
, client
, ctdb_db
,
253 opts
->num_nodes
, opts
->timelimit
);
255 fprintf(stderr
, "Memory allocation error\n");
259 tevent_req_poll(req
, ev
);
261 status
= fetch_loop_recv(req
, &ret
);
263 fprintf(stderr
, "fetch readonly loop test failed\n");
267 talloc_free(mem_ctx
);