From: Volker Lendecke Date: Thu, 12 Mar 2020 15:20:50 +0000 (+0100) Subject: torture3: Test ctdb_req_send/recv X-Git-Tag: ldb-2.2.0~858 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7a7d56c5624cd8c711f0ae8619ed07f6bae8982c;p=thirdparty%2Fsamba.git torture3: Test ctdb_req_send/recv Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 6bc45daee6a..03ffc995114 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -1067,6 +1067,7 @@ for test in CLUSTERED_TESTS: planclusteredmembertestsuite(test, "$PREFIX") CLUSTERED_LOCAL_TESTS = [ + "ctdbd-conn1", "local-dbwrap-ctdb1" ] @@ -1080,4 +1081,4 @@ for t in CLUSTERED_LOCAL_TESTS: '""', '""', smbtorture3, - ""]) + "-N 1000 -o 2000"]) diff --git a/source3/torture/proto.h b/source3/torture/proto.h index 7f4c922d83d..21966356ff9 100644 --- a/source3/torture/proto.h +++ b/source3/torture/proto.h @@ -145,5 +145,6 @@ bool run_local_namemap_cache1(int dummy); bool run_local_idmap_cache1(int dummy); bool run_hidenewfiles(int dummy); bool run_readdir_timestamp(int dummy); +bool run_ctdbd_conn1(int dummy); #endif /* __TORTURE_H__ */ diff --git a/source3/torture/test_ctdbd_conn.c b/source3/torture/test_ctdbd_conn.c new file mode 100644 index 00000000000..124a334b55d --- /dev/null +++ b/source3/torture/test_ctdbd_conn.c @@ -0,0 +1,312 @@ +/* + * Unix SMB/CIFS implementation. + * Test async ctdb_req_send/recv + * Copyright (C) Volker Lendecke 2020 + * + * 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 . + */ + +#include "includes.h" +#include "torture/proto.h" +#include "ctdbd_conn.h" +#include "lib/cluster_support.h" +#include "ctdb/include/ctdb_protocol.h" +#include "lib/util/tevent_unix.h" + +extern int torture_nprocs; +extern int torture_numops; + +struct ctdb_echo_state { + struct ctdb_req_control_old req; + struct iovec iov[2]; + TDB_DATA echodata; +}; + +static void ctdb_echo_done(struct tevent_req *subreq); + +static struct tevent_req *ctdb_echo_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdbd_connection *conn, + uint32_t delay) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct ctdb_echo_state *state = NULL; + struct ctdb_req_header *hdr = NULL; + uint32_t datalen; + + req = tevent_req_create( + mem_ctx, &state, struct ctdb_echo_state); + if (req == NULL) { + return NULL; + } + + hdr = &state->req.hdr; + ctdbd_prep_hdr_next_reqid(conn, hdr); + hdr->operation = CTDB_REQ_CONTROL; + state->req.opcode = CTDB_CONTROL_ECHO_DATA; + + state->iov[0] = (struct iovec) { + .iov_base = &state->req, + .iov_len = offsetof(struct ctdb_req_control_old, data), + }; + + datalen = generate_random() % 1024; + + state->echodata.dptr = talloc_array(state, uint8_t, datalen+8); + if (tevent_req_nomem(state->echodata.dptr, req)) { + return tevent_req_post(req, ev); + } + state->echodata.dsize = talloc_get_size(state->echodata.dptr); + generate_random_buffer( + state->echodata.dptr, state->echodata.dsize); + + memcpy(state->echodata.dptr, &delay, sizeof(delay)); + memcpy(state->echodata.dptr+4, &datalen, sizeof(datalen)); + + state->req.datalen = state->echodata.dsize; + + state->iov[1] = (struct iovec) { + .iov_base = state->echodata.dptr, + .iov_len = state->echodata.dsize, + }; + + hdr->length = + offsetof(struct ctdb_req_control_old, data) + + state->req.datalen; + + subreq = ctdbd_req_send( + state, ev, conn, state->iov, ARRAY_SIZE(state->iov)); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_echo_done, req); + + return req; +} + +static void ctdb_echo_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_echo_state *state = tevent_req_data( + req, struct ctdb_echo_state); + struct ctdb_req_header *hdr = NULL; + struct ctdb_reply_control_old *reply = NULL; + int cmp, ret; + + ret = ctdbd_req_recv(subreq, state, &hdr); + TALLOC_FREE(subreq); + if (tevent_req_error(req, ret)) { + printf("ctdbd_req_recv(%"PRIu32") returned %d (%s)\n", + state->req.hdr.reqid, + ret, + strerror(ret)); + return; + } + if (hdr->operation != CTDB_REPLY_CONTROL) { + printf("Expected CTDB_REPLY_CONTROL, got %"PRIu32"\n", + hdr->operation); + tevent_req_error(req, EIO); + return; + } + reply = (struct ctdb_reply_control_old *)hdr; + if (reply->status != 0) { + printf("reply->status = %"PRIi32"\n", reply->status); + tevent_req_error(req, EIO); + return; + } + if (reply->datalen != state->req.datalen) { + printf("state->echodata.dsize=%zu datalen=%"PRIu32"\n", + state->echodata.dsize, + reply->datalen); + tevent_req_error(req, EIO); + return; + } + cmp = memcmp(reply->data, + state->echodata.dptr, + state->echodata.dsize); + if (cmp != 0) { + printf("data mismatch\n"); + tevent_req_error(req, EIO); + return; + } + TALLOC_FREE(reply); + tevent_req_done(req); +} + +static int ctdb_echo_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_unix(req); +} + +struct ctdb_ping_flood_state { + struct tevent_context *ev; + struct ctdbd_connection *conn; + size_t num_running; + bool done; +}; + +static void ctdb_ping_flood_next(struct tevent_req *subreq); +static void ctdb_ping_flood_done(struct tevent_req *subreq); + +static struct tevent_req *ctdb_ping_flood_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ctdbd_connection *conn, + size_t num_parallel, + unsigned usecs) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct ctdb_ping_flood_state *state = NULL; + size_t i; + + req = tevent_req_create( + mem_ctx, &state, struct ctdb_ping_flood_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->conn = conn; + + for (i=0; iev, + state->conn, + generate_random() % 10); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_ping_flood_next, req); + } + state->num_running = num_parallel; + + subreq = tevent_wakeup_send( + state, + ev, + tevent_timeval_current_ofs(0, usecs)); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_ping_flood_done, req); + + return req; +} + +static void ctdb_ping_flood_next(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_ping_flood_state *state = tevent_req_data( + req, struct ctdb_ping_flood_state); + int ret; + + ret = ctdb_echo_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_error(req, ret)) { + return; + } + state->num_running -= 1; + + if (state->done) { + if (state->num_running == 0) { + tevent_req_done(req); + } + return; + } + + subreq = ctdb_echo_send( + state, + state->ev, + state->conn, + generate_random() % 10); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, ctdb_ping_flood_next, req); + state->num_running += 1; +} + +static void ctdb_ping_flood_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_ping_flood_state *state = tevent_req_data( + req, struct ctdb_ping_flood_state); + bool ok; + + ok = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + tevent_req_oom(req); + return; + } + state->done = true; +} + +static int ctdb_ping_flood_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_unix(req); +} + +bool run_ctdbd_conn1(int dummy) +{ + struct ctdbd_connection *conn = NULL; + struct tevent_context *ev = NULL; + struct tevent_req *req = NULL; + int ret; + bool ok; + bool result = false; + + ev = samba_tevent_context_init(talloc_tos()); + if (ev == NULL) { + printf("samba_tevent_context_init failed\n"); + goto done; + } + + ret = ctdbd_init_async_connection( + ev, lp_ctdbd_socket(), 0, &conn); + if (ret != 0) { + printf("ctdbd_init_async_connection failed: %s\n", + strerror(ret)); + goto done; + } + + req = ctdb_ping_flood_send( + ev, ev, conn, torture_nprocs, torture_numops * 1000); + if (req == NULL) { + printf("ctdb_ping_flood_send failed\n"); + goto done; + } + + ok = tevent_req_poll_unix(req, ev, &ret); + if (!ok) { + printf("tevent_req_poll_unix failed: %s\n", + strerror(ret)); + goto done; + } + + ret = ctdb_ping_flood_recv(req); + TALLOC_FREE(req); + if (ret != 0) { + printf("ctdb_ping_flood failed: %s\n", strerror(ret)); + goto done; + } + + result = true; +done: + TALLOC_FREE(conn); + return result; +} diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 96de663de8d..b7c0dd3f73d 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -14995,6 +14995,12 @@ static struct { .name = "hide-new-files-timeout", .fn = run_hidenewfiles, }, +#ifdef CLUSTER_SUPPORT + { + .name = "ctdbd-conn1", + .fn = run_ctdbd_conn1, + }, +#endif { .name = "readdir-timestamp", .fn = run_readdir_timestamp, diff --git a/source3/wscript_build b/source3/wscript_build index 9f038c3554d..93e58a4c9f0 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1181,6 +1181,11 @@ bld.SAMBA3_BINARY('locktest2', ''', for_selftest=True) +TORTURE3_ADDITIONAL_SOURCE="" + +if bld.env.with_ctdb: + TORTURE3_ADDITIONAL_SOURCE += ' torture/test_ctdbd_conn.c' + bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3, source=''' torture/torture.c @@ -1221,7 +1226,7 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3, torture/test_idmap_cache.c torture/test_hidenewfiles.c torture/test_readdir_timestamp.c - ''', + ''' + TORTURE3_ADDITIONAL_SOURCE, deps=''' talloc smbconf