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/debug.h"
24 #include "lib/util/tevent_unix.h"
25
26 #include "client/client.h"
27 #include "tests/src/test_options.h"
28 #include "tests/src/cluster_wait.h"
29
30 struct fetch_loop_state {
31 struct tevent_context *ev;
32 struct ctdb_client_context *client;
33 struct ctdb_db_context *ctdb_db;
34 int timelimit;
35 TDB_DATA key;
36 int locks_count;
37 };
38
39 static void fetch_loop_next(struct tevent_req *subreq);
40
fetch_loop_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct ctdb_client_context * client,struct ctdb_db_context * ctdb_db,const char * keystr,int timelimit)41 static struct tevent_req *fetch_loop_send(TALLOC_CTX *mem_ctx,
42 struct tevent_context *ev,
43 struct ctdb_client_context *client,
44 struct ctdb_db_context *ctdb_db,
45 const char *keystr,
46 int timelimit)
47 {
48 struct tevent_req *req, *subreq;
49 struct fetch_loop_state *state;
50
51 req = tevent_req_create(mem_ctx, &state, struct fetch_loop_state);
52 if (req == NULL) {
53 return NULL;
54 }
55
56 state->ev = ev;
57 state->client = client;
58 state->ctdb_db = ctdb_db;
59 state->timelimit = timelimit;
60 state->key.dptr = discard_const(keystr);
61 state->key.dsize = strlen(keystr);
62
63 subreq = ctdb_fetch_lock_send(state, ev, client, ctdb_db,
64 state->key, false);
65 if (tevent_req_nomem(subreq, req)) {
66 return tevent_req_post(req, ev);
67 }
68 tevent_req_set_callback(subreq, fetch_loop_next, req);
69
70 return req;
71 }
72
fetch_loop_next(struct tevent_req * subreq)73 static void fetch_loop_next(struct tevent_req *subreq)
74 {
75 struct tevent_req *req = tevent_req_callback_data(
76 subreq, struct tevent_req);
77 struct fetch_loop_state *state = tevent_req_data(
78 req, struct fetch_loop_state);
79 struct ctdb_record_handle *h;
80 TDB_DATA data;
81 int ret;
82
83 h = ctdb_fetch_lock_recv(subreq, NULL, state, &data, &ret);
84 TALLOC_FREE(subreq);
85 if (h == NULL) {
86 tevent_req_error(req, ret);
87 return;
88 }
89
90 if (data.dsize == sizeof(uint32_t)) {
91 state->locks_count = *(uint32_t *)data.dptr;
92 }
93 TALLOC_FREE(data.dptr);
94
95 state->locks_count += 1;
96 data.dsize = sizeof(uint32_t);
97 data.dptr = (uint8_t *)&state->locks_count;
98
99 ret = ctdb_store_record(h, data);
100 if (ret != 0) {
101 talloc_free(h);
102 tevent_req_error(req, ret);
103 return;
104 }
105
106 talloc_free(h);
107
108 subreq = ctdb_fetch_lock_send(state, state->ev, state->client,
109 state->ctdb_db, state->key, false);
110 if (tevent_req_nomem(subreq, req)) {
111 return;
112 }
113 tevent_req_set_callback(subreq, fetch_loop_next, req);
114 }
115
fetch_loop_recv(struct tevent_req * req,int * perr)116 static bool fetch_loop_recv(struct tevent_req *req, int *perr)
117 {
118 int err;
119
120 if (tevent_req_is_unix_error(req, &err)) {
121 if (perr != NULL) {
122 *perr = err;
123 }
124 return false;
125 }
126 return true;
127 }
128
129 static struct tevent_req *global_req;
130
alarm_handler(int sig)131 static void alarm_handler(int sig)
132 {
133 struct fetch_loop_state *state = tevent_req_data(
134 global_req, struct fetch_loop_state);
135 static int time_passed = 0;
136
137 time_passed += 1;
138
139 printf("Locks:%d\n", state->locks_count);
140 fflush(stdout);
141
142 if (time_passed >= state->timelimit) {
143 tevent_req_done(global_req);
144 }
145
146 alarm(1);
147 }
148
main(int argc,const char * argv[])149 int main(int argc, const char *argv[])
150 {
151 const struct test_options *opts;
152 TALLOC_CTX *mem_ctx;
153 struct tevent_context *ev;
154 struct ctdb_client_context *client;
155 struct ctdb_db_context *ctdb_db;
156 int ret;
157 bool status;
158
159 setup_logging("fetch_loop_key", DEBUG_STDERR);
160
161 status = process_options_database(argc, argv, &opts);
162 if (! status) {
163 exit(1);
164 }
165
166 mem_ctx = talloc_new(NULL);
167 if (mem_ctx == NULL) {
168 fprintf(stderr, "Memory allocation error\n");
169 exit(1);
170 }
171
172 ev = tevent_context_init(mem_ctx);
173 if (ev == NULL) {
174 fprintf(stderr, "Memory allocation error\n");
175 exit(1);
176 }
177
178 ret = ctdb_client_init(mem_ctx, ev, opts->socket, &client);
179 if (ret != 0) {
180 fprintf(stderr, "Failed to initialize client, %s\n",
181 strerror(ret));
182 exit(1);
183 }
184
185 if (! ctdb_recovery_wait(ev, client)) {
186 fprintf(stderr, "Memory allocation error\n");
187 exit(1);
188 }
189
190 ret = ctdb_attach(ev, client, tevent_timeval_zero(), opts->dbname, 0,
191 &ctdb_db);
192 if (ret != 0) {
193 fprintf(stderr, "Failed to attach to DB %s\n", opts->dbname);
194 exit(1);
195 }
196
197 global_req = fetch_loop_send(mem_ctx, ev, client, ctdb_db,
198 opts->keystr, opts->timelimit);
199 if (global_req == NULL) {
200 fprintf(stderr, "Memory allocation error\n");
201 exit(1);
202 }
203
204 signal(SIGALRM, alarm_handler);
205 alarm(1);
206
207 tevent_req_poll(global_req, ev);
208
209 status = fetch_loop_recv(global_req, &ret);
210 if (! status) {
211 fprintf(stderr, "fetch loop test failed\n");
212 exit(1);
213 }
214
215 talloc_free(mem_ctx);
216 return 0;
217 }
218