diff options
author | Amitay Isaacs <amitay@gmail.com> | 2015-11-10 16:00:07 +1100 |
---|---|---|
committer | Martin Schwenke <martins@samba.org> | 2016-07-22 06:50:21 +0200 |
commit | 388fa2c9b87fddd1ae7345f1f3ee119e16105f14 (patch) | |
tree | 84c47a4eefbf7ffe94404d7ef382fd559cdfcac0 /ctdb | |
parent | 5fe216aa3eeead696c5c9e5d1deeea2cfff226e9 (diff) | |
download | samba-388fa2c9b87fddd1ae7345f1f3ee119e16105f14.tar.gz |
ctdb-tests: Replace ctdb_bench with message_ring using new client API
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
Diffstat (limited to 'ctdb')
-rwxr-xr-x | ctdb/tests/simple/51_ctdb_bench.sh | 2 | ||||
-rw-r--r-- | ctdb/tests/src/ctdb_bench.c | 292 | ||||
-rw-r--r-- | ctdb/tests/src/message_ring.c | 362 | ||||
-rwxr-xr-x | ctdb/wscript | 4 |
4 files changed, 365 insertions, 295 deletions
diff --git a/ctdb/tests/simple/51_ctdb_bench.sh b/ctdb/tests/simple/51_ctdb_bench.sh index ed39286f553..b8d6e5a2a3a 100755 --- a/ctdb/tests/simple/51_ctdb_bench.sh +++ b/ctdb/tests/simple/51_ctdb_bench.sh @@ -38,7 +38,7 @@ try_command_on_node 0 "$CTDB listnodes" num_nodes=$(echo "$out" | wc -l) echo "Running ctdb_bench on all $num_nodes nodes." -try_command_on_node -v -p all $CTDB_TEST_WRAPPER $VALGRIND ctdb_bench -n $num_nodes +try_command_on_node -v -p all $CTDB_TEST_WRAPPER $VALGRIND message_ring -n $num_nodes # Get the last line of output. while read line ; do diff --git a/ctdb/tests/src/ctdb_bench.c b/ctdb/tests/src/ctdb_bench.c deleted file mode 100644 index 32438f5c101..00000000000 --- a/ctdb/tests/src/ctdb_bench.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - simple ctdb benchmark - - Copyright (C) Andrew Tridgell 2006 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "replace.h" -#include "system/filesys.h" -#include "system/network.h" - -#include <popt.h> -#include <talloc.h> -#include <tevent.h> - -#include "lib/util/time.h" -#include "lib/util/debug.h" - -#include "ctdb_private.h" -#include "ctdb_client.h" - -#include "common/cmdline.h" -#include "common/common.h" -#include "common/logging.h" - -static struct timeval tp1,tp2; - -static void start_timer(void) -{ - gettimeofday(&tp1,NULL); -} - -static double end_timer(void) -{ - gettimeofday(&tp2,NULL); - return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - - (tp1.tv_sec + (tp1.tv_usec*1.0e-6)); -} - - -static int timelimit = 10; -static int num_records = 10; -static int num_nodes; - -enum my_functions {FUNC_INCR=1, FUNC_FETCH=2}; - -/* - ctdb call function to increment an integer -*/ -static int incr_func(struct ctdb_call_info *call) -{ - if (call->record_data.dsize == 0) { - call->new_data = talloc(call, TDB_DATA); - if (call->new_data == NULL) { - return ENOMEM; - } - call->new_data->dptr = talloc_size(call, 4); - call->new_data->dsize = 4; - *(uint32_t *)call->new_data->dptr = 0; - } else { - call->new_data = &call->record_data; - } - (*(uint32_t *)call->new_data->dptr)++; - return 0; -} - -/* - ctdb call function to fetch a record -*/ -static int fetch_func(struct ctdb_call_info *call) -{ - call->reply_data = &call->record_data; - return 0; -} - - -struct bench_data { - struct ctdb_context *ctdb; - struct tevent_context *ev; - int msg_count; - int msg_plus, msg_minus; -}; - -/* - handler for messages in bench_ring() -*/ -static void ring_message_handler(uint64_t srvid, TDB_DATA data, - void *private_data) -{ - struct bench_data *bdata = talloc_get_type_abort( - private_data, struct bench_data); - int incr = *(int *)data.dptr; - int dest; - - bdata->msg_count++; - dest = (ctdb_get_pnn(bdata->ctdb) + num_nodes + incr) % num_nodes; - ctdb_client_send_message(bdata->ctdb, dest, srvid, data); - if (incr == 1) { - bdata->msg_plus++; - } else { - bdata->msg_minus++; - } -} - - -static void send_start_messages(struct ctdb_context *ctdb, int incr) -{ - /* two messages are injected into the ring, moving - in opposite directions */ - int dest; - TDB_DATA data; - - data.dptr = (uint8_t *)&incr; - data.dsize = sizeof(incr); - - dest = (ctdb_get_pnn(ctdb) + num_nodes + incr) % num_nodes; - ctdb_client_send_message(ctdb, dest, 0, data); -} - -static void each_second(struct tevent_context *ev, struct tevent_timer *te, - struct timeval t, void *private_data) -{ - struct bench_data *bdata = talloc_get_type_abort( - private_data, struct bench_data); - - /* we kickstart the ring into action by inserting messages from node - with pnn 0. - it may happen that some other node does not yet have ctdb_bench - running in which case the ring is broken and the messages are lost. - if so, once every second try again to restart the ring - */ - if (bdata->msg_plus == 0) { -// printf("no messages recevied, try again to kickstart the ring in forward direction...\n"); - send_start_messages(bdata->ctdb, 1); - } - if (bdata->msg_minus == 0) { -// printf("no messages recevied, try again to kickstart the ring in reverse direction...\n"); - send_start_messages(bdata->ctdb, -1); - } - tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0), - each_second, bdata); -} - -static void dummy_event(struct tevent_context *ev, struct tevent_timer *te, - struct timeval t, void *private_data) -{ - struct bench_data *bdata = talloc_get_type_abort( - private_data, struct bench_data); - - tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0), - dummy_event, bdata); -} - -/* - benchmark sending messages in a ring around the nodes -*/ -static void bench_ring(struct bench_data *bdata) -{ - int pnn = ctdb_get_pnn(bdata->ctdb); - - if (pnn == 0) { - tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0), - each_second, bdata); - } else { - tevent_add_timer(bdata->ev, bdata, timeval_current_ofs(1, 0), - dummy_event, bdata); - } - - start_timer(); - while (end_timer() < timelimit) { - if (pnn == 0 && bdata->msg_count % 10000 == 0 && end_timer() > 0) { - printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\r", - bdata->msg_count/end_timer(), - bdata->msg_plus, bdata->msg_minus); - fflush(stdout); - } - tevent_loop_once(bdata->ev); - } - - printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\n", - bdata->msg_count/end_timer(), - bdata->msg_plus, bdata->msg_minus); -} - -/* - main program -*/ -int main(int argc, const char *argv[]) -{ - struct ctdb_context *ctdb; - struct ctdb_db_context *ctdb_db; - - struct poptOption popt_options[] = { - POPT_AUTOHELP - POPT_CTDB_CMDLINE - { "timelimit", 't', POPT_ARG_INT, &timelimit, 0, "timelimit", "integer" }, - { "num-records", 'r', POPT_ARG_INT, &num_records, 0, "num_records", "integer" }, - { NULL, 'n', POPT_ARG_INT, &num_nodes, 0, "num_nodes", "integer" }, - POPT_TABLEEND - }; - int opt; - const char **extra_argv; - int extra_argc = 0; - int ret; - poptContext pc; - struct tevent_context *ev; - struct bench_data *bdata; - - pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); - - while ((opt = poptGetNextOpt(pc)) != -1) { - switch (opt) { - default: - fprintf(stderr, "Invalid option %s: %s\n", - poptBadOption(pc, 0), poptStrerror(opt)); - exit(1); - } - } - - /* setup the remaining options for the main program to use */ - extra_argv = poptGetArgs(pc); - if (extra_argv) { - extra_argv++; - while (extra_argv[extra_argc]) extra_argc++; - } - - if (num_nodes == 0) { - printf("You must specify the number of nodes\n"); - exit(1); - } - - ev = tevent_context_init(NULL); - - /* initialise ctdb */ - ctdb = ctdb_cmdline_client(ev, timeval_current_ofs(3, 0)); - if (ctdb == NULL) { - exit(1); - } - - /* attach to a specific database */ - ctdb_db = ctdb_attach(ctdb, timeval_current_ofs(2, 0), "test.tdb", - false, 0); - if (!ctdb_db) { - printf("ctdb_attach failed - %s\n", ctdb_errstr(ctdb)); - exit(1); - } - - /* setup a ctdb call function */ - ret = ctdb_set_call(ctdb_db, incr_func, FUNC_INCR); - if (ret != 0) { - DEBUG(DEBUG_DEBUG,("ctdb_set_call() failed, ignoring return code %d\n", ret)); - } - ret = ctdb_set_call(ctdb_db, fetch_func, FUNC_FETCH); - if (ret != 0) { - DEBUG(DEBUG_DEBUG,("ctdb_set_call() failed, ignoring return code %d\n", ret)); - } - - bdata = talloc_zero(ctdb, struct bench_data); - if (bdata == NULL) { - goto error; - } - bdata->ctdb = ctdb; - bdata->ev = ev; - - if (ctdb_client_set_message_handler(ctdb, 0, ring_message_handler, bdata)) - goto error; - - printf("Waiting for cluster\n"); - while (1) { - uint32_t recmode=1; - ctdb_ctrl_getrecmode(ctdb, ctdb, timeval_zero(), CTDB_CURRENT_NODE, &recmode); - if (recmode == 0) break; - tevent_loop_once(ev); - } - - bench_ring(bdata); - -error: - return 0; -} diff --git a/ctdb/tests/src/message_ring.c b/ctdb/tests/src/message_ring.c new file mode 100644 index 00000000000..bd95a280d85 --- /dev/null +++ b/ctdb/tests/src/message_ring.c @@ -0,0 +1,362 @@ +/* + simple ctdb benchmark - send messages in a ring around cluster + + Copyright (C) Amitay Isaacs 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/network.h" + +#include "lib/util/time.h" +#include "lib/util/tevent_unix.h" + +#include "client/client.h" +#include "tests/src/test_options.h" +#include "tests/src/cluster_wait.h" + +#define MSG_ID_BENCH 0 + +struct message_ring_state { + struct tevent_context *ev; + struct ctdb_client_context *client; + int num_nodes; + int timelimit; + int msg_count; + int msg_plus, msg_minus; + struct timeval start_time; +}; + +static void message_ring_wait(struct tevent_req *subreq); +static void message_ring_start(struct tevent_req *subreq); +static void message_ring_each_second(struct tevent_req *subreq); +static void message_ring_msg_sent(struct tevent_req *subreq); +static void message_ring_msg_handler(uint64_t srvid, TDB_DATA data, + void *private_data); +static void message_ring_finish(struct tevent_req *subreq); + +static struct tevent_req *message_ring_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdb_client_context *client, + int num_nodes, int timelimit) +{ + struct tevent_req *req, *subreq; + struct message_ring_state *state; + + req = tevent_req_create(mem_ctx, &state, struct message_ring_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->client = client; + state->num_nodes = num_nodes; + state->timelimit = timelimit; + + subreq = ctdb_client_set_message_handler_send( + state, state->ev, state->client, + MSG_ID_BENCH, + message_ring_msg_handler, req); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, message_ring_wait, req); + + return req; +} + +static void message_ring_wait(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct message_ring_state *state = tevent_req_data( + req, struct message_ring_state); + bool status; + int ret; + + status = ctdb_client_set_message_handler_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + subreq = cluster_wait_send(state, state->ev, state->client, + state->num_nodes); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, message_ring_start, req); +} + +static void message_ring_start(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct message_ring_state *state = tevent_req_data( + req, struct message_ring_state); + bool status; + int ret; + + status = cluster_wait_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + state->start_time = tevent_timeval_current(); + + if (ctdb_client_pnn(state->client) == 0) { + subreq = tevent_wakeup_send(state, state->ev, + tevent_timeval_current_ofs(1, 0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, message_ring_each_second, req); + } + + subreq = tevent_wakeup_send(state, state->ev, + tevent_timeval_current_ofs( + state->timelimit, 0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, message_ring_finish, req); +} + +static uint32_t next_node(struct ctdb_client_context *client, + int num_nodes, int incr) +{ + return (ctdb_client_pnn(client) + num_nodes + incr) % num_nodes; +} + +static void message_ring_each_second(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct message_ring_state *state = tevent_req_data( + req, struct message_ring_state); + struct ctdb_req_message msg; + uint32_t pnn; + int incr; + bool status; + + status = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, EIO); + return; + } + + pnn = ctdb_client_pnn(state->client); + if (pnn == 0) { + double t; + + t = timeval_elapsed(&state->start_time); + printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\r", + state->msg_count / t, + state->msg_plus, state->msg_minus); + fflush(stdout); + } + + if (state->msg_plus == 0) { + incr = 1; + + msg.srvid = 0; + msg.data.data.dptr = (uint8_t *)&incr; + msg.data.data.dsize = sizeof(incr); + + pnn = next_node(state->client, state->num_nodes, incr); + + subreq = ctdb_client_message_send(state, state->ev, + state->client, pnn, &msg); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, message_ring_msg_sent, req); + } + + if (state->msg_minus == 0) { + incr = -1; + + msg.srvid = 0; + msg.data.data.dptr = (uint8_t *)&incr; + msg.data.data.dsize = sizeof(incr); + + pnn = next_node(state->client, state->num_nodes, incr); + + subreq = ctdb_client_message_send(state, state->ev, + state->client, pnn, &msg); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, message_ring_msg_sent, req); + } + + subreq = tevent_wakeup_send(state, state->ev, + tevent_timeval_current_ofs(1, 0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, message_ring_each_second, req); +} + +static void message_ring_msg_sent(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + bool status; + int ret; + + status = ctdb_client_message_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + } +} + +static void message_ring_msg_handler(uint64_t srvid, TDB_DATA data, + void *private_data) +{ + struct tevent_req *req = talloc_get_type_abort( + private_data, struct tevent_req); + struct message_ring_state *state = tevent_req_data( + req, struct message_ring_state); + struct ctdb_req_message msg; + struct tevent_req *subreq; + int incr; + uint32_t pnn; + + if (srvid != MSG_ID_BENCH) { + return; + } + + if (data.dsize != sizeof(int)) { + return; + } + incr = *(int *)data.dptr; + + state->msg_count += 1; + if (incr == 1) { + state->msg_plus += 1; + } else { + state->msg_minus += 1; + } + + pnn = next_node(state->client, state->num_nodes, incr); + + msg.srvid = srvid; + msg.data.data = data; + + subreq = ctdb_client_message_send(state, state->ev, state->client, + pnn, &msg); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, message_ring_msg_sent, req); +} + +static void message_ring_finish(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct message_ring_state *state = tevent_req_data( + req, struct message_ring_state); + bool status; + double t; + + status = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, EIO); + return; + } + + t = timeval_elapsed(&state->start_time); + + printf("Ring: %.2f msgs/sec (+ve=%d -ve=%d)\n", + state->msg_count / t, state->msg_plus, state->msg_minus); + + tevent_req_done(req); +} + +static bool message_ring_recv(struct tevent_req *req) +{ + int ret; + + if (tevent_req_is_unix_error(req, &ret)) { + return false; + } + return true; +} + +int main(int argc, const char *argv[]) +{ + const struct test_options *opts; + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct ctdb_client_context *client; + struct tevent_req *req; + int ret; + bool status; + + status = process_options_basic(argc, argv, &opts); + if (! status) { + exit(1); + } + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + fprintf(stderr, "Memory allocation error\n"); + exit(1); + } + + ev = tevent_context_init(mem_ctx); + if (ev == NULL) { + fprintf(stderr, "Memory allocation error\n"); + exit(1); + } + + ret = ctdb_client_init(mem_ctx, ev, opts->socket, &client); + if (ret != 0) { + fprintf(stderr, "Failed to initialize client, %s\n", + strerror(ret)); + exit(1); + } + + if (! ctdb_recovery_wait(ev, client)) { + fprintf(stderr, "Failed to wait for recovery\n"); + exit(1); + } + + req = message_ring_send(mem_ctx, ev, client, + opts->num_nodes, opts->timelimit); + if (req == NULL) { + fprintf(stderr, "Memory allocation error\n"); + exit(1); + } + + tevent_req_poll(req, ev); + + status = message_ring_recv(req); + if (! status) { + fprintf(stderr, "message ring test failed\n"); + exit(1); + } + + talloc_free(mem_ctx); + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index 25ba19ccb8d..3b8af4d913a 100755 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -677,7 +677,6 @@ def build(bld): # Test binaries ctdb_tests = [ 'rb_test', - 'ctdb_bench', 'ctdb_fetch', 'ctdb_fetch_one', 'ctdb_fetch_readonly_once', @@ -710,7 +709,8 @@ def build(bld): deps='replace popt talloc tevent tdb') ctdb_tests = [ - 'g_lock_loop' + 'g_lock_loop', + 'message_ring' ] for target in ctdb_tests: |