1 /* 2 simple ctdb benchmark for g_lock operations 3 4 Copyright (C) Amitay Isaacs 2016 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 #include "lib/util/debug.h" 25 26 #include "protocol/protocol_api.h" 27 #include "client/client.h" 28 #include "tests/src/test_options.h" 29 #include "tests/src/cluster_wait.h" 30 31 #define TESTKEY "testkey" 32 33 struct glock_loop_state { 34 struct tevent_context *ev; 35 struct ctdb_client_context *client; next_node(struct ctdb_client_context * client,uint32_t num_nodes)36 struct ctdb_db_context *db; 37 int num_nodes; 38 int timelimit; 39 uint32_t pnn; 40 uint32_t counter; 41 struct ctdb_server_id sid; 42 const char *key; 43 }; 44 45 static void glock_loop_start(struct tevent_req *subreq); 46 static void glock_loop_locked(struct tevent_req *subreq); 47 static void glock_loop_unlocked(struct tevent_req *subreq); 48 static void glock_loop_finish(struct tevent_req *subreq); 49 50 static struct tevent_req *glock_loop_send( 51 TALLOC_CTX *mem_ctx, 52 struct tevent_context *ev, 53 struct ctdb_client_context *client, 54 struct ctdb_db_context *db, 55 int num_nodes, int timelimit) 56 { 57 struct tevent_req *req, *subreq; 58 struct glock_loop_state *state; 59 60 req = tevent_req_create(mem_ctx, &state, 61 struct glock_loop_state); fetch_ring_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct ctdb_client_context * client,struct ctdb_db_context * ctdb_db,uint32_t num_nodes,int timelimit,int interactive)62 if (req == NULL) { 63 return NULL; 64 } 65 66 state->ev = ev; 67 state->client = client; 68 state->db = db; 69 state->num_nodes = num_nodes; 70 state->timelimit = timelimit; 71 state->pnn = ctdb_client_pnn(client); 72 state->counter = 0; 73 state->sid = ctdb_client_get_server_id(client, 1); 74 state->key = TESTKEY; 75 76 subreq = cluster_wait_send(state, state->ev, state->client, 77 state->num_nodes); 78 if (tevent_req_nomem(subreq, req)) { 79 return tevent_req_post(req, ev); 80 } 81 tevent_req_set_callback(subreq, glock_loop_start, req); 82 83 return req; 84 } 85 86 static void glock_loop_start(struct tevent_req *subreq) 87 { 88 struct tevent_req *req = tevent_req_callback_data( 89 subreq, struct tevent_req); 90 struct glock_loop_state *state = tevent_req_data( 91 req, struct glock_loop_state); 92 bool status; 93 int ret; 94 95 status = cluster_wait_recv(subreq, &ret); 96 TALLOC_FREE(subreq); fetch_ring_msg_handler(uint64_t srvid,TDB_DATA data,void * private_data)97 if (! status) { 98 tevent_req_error(req, ret); 99 return; 100 } 101 102 subreq = ctdb_g_lock_lock_send(state, state->ev, state->client, 103 state->db, state->key, &state->sid, 104 false); 105 if (tevent_req_nomem(subreq, req)) { 106 return; 107 } 108 tevent_req_set_callback(subreq, glock_loop_locked, req); 109 110 subreq = tevent_wakeup_send(state, state->ev, 111 tevent_timeval_current_ofs( 112 state->timelimit, 0)); 113 if (tevent_req_nomem(subreq, req)) { 114 return; 115 } fetch_ring_wait(struct tevent_req * subreq)116 tevent_req_set_callback(subreq, glock_loop_finish, req); 117 } 118 119 static void glock_loop_locked(struct tevent_req *subreq) 120 { 121 struct tevent_req *req = tevent_req_callback_data( 122 subreq, struct tevent_req); 123 struct glock_loop_state *state = tevent_req_data( 124 req, struct glock_loop_state); 125 int ret; 126 bool status; 127 128 status = ctdb_g_lock_lock_recv(subreq, &ret); 129 TALLOC_FREE(subreq); 130 if (! status) { 131 fprintf(stderr, "g_lock_lock failed\n"); 132 tevent_req_error(req, ret); 133 return; 134 } 135 136 state->counter += 1; 137 138 subreq = ctdb_g_lock_unlock_send(state, state->ev, state->client, 139 state->db, state->key, state->sid); fetch_ring_start(struct tevent_req * subreq)140 if (tevent_req_nomem(subreq, req)) { 141 return; 142 } 143 tevent_req_set_callback(subreq, glock_loop_unlocked, req); 144 } 145 146 static void glock_loop_unlocked(struct tevent_req *subreq) 147 { 148 struct tevent_req *req = tevent_req_callback_data( 149 subreq, struct tevent_req); 150 struct glock_loop_state *state = tevent_req_data( 151 req, struct glock_loop_state); 152 int ret; 153 bool status; 154 155 status = ctdb_g_lock_unlock_recv(subreq, &ret); 156 TALLOC_FREE(subreq); 157 if (! status) { 158 fprintf(stderr, "g_lock_unlock failed\n"); 159 tevent_req_error(req, ret); 160 return; 161 } 162 163 subreq = ctdb_g_lock_lock_send(state, state->ev, state->client, 164 state->db, state->key, &state->sid, 165 false); 166 if (tevent_req_nomem(subreq, req)) { 167 return; 168 } 169 tevent_req_set_callback(subreq, glock_loop_locked, req); 170 } 171 172 static void glock_loop_finish(struct tevent_req *subreq) 173 { 174 struct tevent_req *req = tevent_req_callback_data( 175 subreq, struct tevent_req); 176 struct glock_loop_state *state = tevent_req_data( 177 req, struct glock_loop_state); fetch_ring_update(struct tevent_req * subreq)178 bool status; 179 180 status = tevent_wakeup_recv(subreq); 181 TALLOC_FREE(subreq); 182 if (! status) { 183 tevent_req_error(req, EIO); 184 return; 185 } 186 187 printf("PNN:%u counter:%u\n", state->pnn, state->counter); 188 189 tevent_req_done(req); 190 } 191 192 static bool glock_loop_recv(struct tevent_req *req, int *perr) 193 { 194 int err; 195 196 if (tevent_req_is_unix_error(req, &err)) { 197 if (perr != NULL) { 198 *perr = err; 199 } 200 return false; 201 } 202 return true; 203 } 204 205 int main(int argc, const char *argv[]) 206 { 207 const struct test_options *opts; 208 TALLOC_CTX *mem_ctx; 209 struct tevent_context *ev; 210 struct ctdb_client_context *client; 211 struct ctdb_db_context *ctdb_db; 212 struct tevent_req *req; 213 int ret; 214 bool status; 215 216 setup_logging("glock_loop", DEBUG_STDERR); 217 218 status = process_options_basic(argc, argv, &opts); 219 if (! status) { 220 exit(1); 221 } 222 223 mem_ctx = talloc_new(NULL); 224 if (mem_ctx == NULL) { 225 fprintf(stderr, "Memory allocation error\n"); 226 exit(1); 227 } 228 229 ev = tevent_context_init(mem_ctx); 230 if (ev == NULL) { 231 fprintf(stderr, "Memory allocation error\n"); 232 exit(1); 233 } 234 235 ret = ctdb_client_init(mem_ctx, ev, opts->socket, &client); 236 if (ret != 0) { 237 fprintf(stderr, "Failed to initialize client, ret=%d\n", ret); 238 exit(1); 239 } 240 241 if (! ctdb_recovery_wait(ev, client)) { fetch_ring_msg_sent(struct tevent_req * subreq)242 fprintf(stderr, "Memory allocation error\n"); 243 exit(1); 244 } 245 246 ret = ctdb_attach(ev, client, tevent_timeval_zero(), "g_lock.tdb", 247 0, &ctdb_db); 248 if (ret != 0) { 249 fprintf(stderr, "Failed to attach to g_lock.tdb\n"); 250 exit(1); 251 } 252 253 req = glock_loop_send(mem_ctx, ev, client, ctdb_db, 254 opts->num_nodes, opts->timelimit); 255 if (req == NULL) { fetch_ring_finish(struct tevent_req * subreq)256 fprintf(stderr, "Memory allocation error\n"); 257 exit(1); 258 } 259 260 tevent_req_poll(req, ev); 261 262 status = glock_loop_recv(req, &ret); 263 if (! status) { 264 fprintf(stderr, "g_lock loop test failed\n"); 265 exit(1); 266 } 267 268 talloc_free(mem_ctx); 269 return 0; 270 } 271