From a32bc89436421563a155350678b22ae648371a54 Mon Sep 17 00:00:00 2001 From: Colin Patrick McCabe Date: Wed, 13 Jul 2011 15:11:44 -0700 Subject: [PATCH] Create rados_delete_pools_parallel test * add rados_delete_pools_parallel test * change RETURN_IF_NOT_VAL -> RETURN1_IF_NOT_VAL. We want to return a non-zero error code when the value is something we don't expect, even if that unexpected value is 0. * st_rados_list_objects: add option to ignore list errors (for the deletion test) Signed-off-by: Colin McCabe --- src/.gitignore | 1 + src/Makefile.am | 14 ++ .../system/rados_delete_pools_parallel.cc | 149 ++++++++++++++++++ src/test/system/rados_list_parallel.cc | 48 +++--- src/test/system/rados_open_pools_parallel.cc | 16 +- src/test/system/st_rados_create_pool.cc | 10 +- src/test/system/st_rados_list_objects.cc | 18 ++- src/test/system/st_rados_list_objects.h | 4 +- src/test/system/systest_runnable.h | 8 +- 9 files changed, 221 insertions(+), 47 deletions(-) create mode 100644 src/test/system/rados_delete_pools_parallel.cc diff --git a/src/.gitignore b/src/.gitignore index 17779dd7cee1c..bdcddef8d0b6b 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -90,3 +90,4 @@ ceph.conf massif.out.* rados_list_parallel rados_open_pools_parallel +rados_delete_pools_parallel diff --git a/src/Makefile.am b/src/Makefile.am index cb9f631aa2c5b..42e393a22b44b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -396,6 +396,20 @@ rados_open_pools_parallel_SOURCES = \ rados_open_pools_parallel_LDADD = libsystest.la librados.la bin_DEBUGPROGRAMS += rados_open_pools_parallel +rados_list_parallel_SOURCES = \ + test/system/rados_list_parallel.cc \ + test/system/st_rados_create_pool.cc \ + test/system/st_rados_list_objects.cc +rados_list_parallel_LDADD = libsystest.la librados.la +bin_DEBUGPROGRAMS += rados_list_parallel + +rados_delete_pools_parallel_SOURCES = \ + test/system/rados_delete_pools_parallel.cc \ + test/system/st_rados_create_pool.cc \ + test/system/st_rados_list_objects.cc +rados_delete_pools_parallel_LDADD = libsystest.la librados.la +bin_DEBUGPROGRAMS += rados_delete_pools_parallel + ## unit tests # target to build but not run the unit tests diff --git a/src/test/system/rados_delete_pools_parallel.cc b/src/test/system/rados_delete_pools_parallel.cc new file mode 100644 index 0000000000000..ccc6bb1265981 --- /dev/null +++ b/src/test/system/rados_delete_pools_parallel.cc @@ -0,0 +1,149 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* +* Ceph - scalable distributed file system +* +* Copyright (C) 2011 New Dream Network +* +* This is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License version 2.1, as published by the Free Software +* Foundation. See file COPYING. +* +*/ + +#include "cross_process_sem.h" +#include "include/rados/librados.h" +#include "st_rados_create_pool.h" +#include "st_rados_list_objects.h" +#include "systest_runnable.h" +#include "systest_settings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::ostringstream; +using std::string; +using std::vector; + +static int g_num_objects = 50; + +/* + * rados_delete_pools_parallel + * + * This tests creation and deletion races. + * + * EXPECT: * can delete a pool while another user is using it + * * operations on pools return error codes after the pools + * are deleted + * + * DO NOT EXPECT * hangs, crashes + */ +class StRadosDeletePool : public SysTestRunnable +{ +public: + StRadosDeletePool(int argc, const char **argv, + CrossProcessSem *pool_setup_sem, CrossProcessSem *delete_pool_sem, + const std::string &pool_name) + : SysTestRunnable(argc, argv), + m_pool_setup_sem(pool_setup_sem), m_delete_pool_sem(delete_pool_sem), + m_pool_name(pool_name) + { + } + + ~StRadosDeletePool() + { + } + + int run() + { + rados_t cl; + RETURN1_IF_NONZERO(rados_create(&cl, NULL)); + rados_conf_parse_argv(cl, m_argc, m_argv); + RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); + RETURN1_IF_NONZERO(rados_connect(cl)); + m_pool_setup_sem->wait(); + m_pool_setup_sem->post(); + + rados_ioctx_t io_ctx; + RETURN1_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, m_pool_name.c_str())); + RETURN1_IF_NONZERO(rados_ioctx_create(cl, m_pool_name.c_str(), &io_ctx)); + rados_ioctx_destroy(io_ctx); + rados_pool_delete(cl, m_pool_name.c_str()); + if (m_delete_pool_sem) + m_delete_pool_sem->post(); + rados_shutdown(cl); + return 0; + } + +private: + CrossProcessSem *m_pool_setup_sem; + CrossProcessSem *m_delete_pool_sem; + std::string m_pool_name; +}; + +const char *get_id_str() +{ + return "main"; +} + +int main(int argc, const char **argv) +{ + const char *num_objects = getenv("NUM_OBJECTS"); + if (num_objects) { + g_num_objects = atoi(num_objects); + if (g_num_objects == 0) + return 100; + } + + CrossProcessSem *pool_setup_sem = NULL; + RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); + CrossProcessSem *delete_pool_sem = NULL; + RETURN1_IF_NONZERO(CrossProcessSem::create(0, &delete_pool_sem)); + + // first test: create a pool, then delete that pool + { + StRadosCreatePool r1(argc, argv, pool_setup_sem, NULL, 50); + StRadosDeletePool r2(argc, argv, pool_setup_sem, NULL, "foo"); + vector < SysTestRunnable* > vec; + vec.push_back(&r1); + vec.push_back(&r2); + std::string error = SysTestRunnable::run_until_finished(vec); + if (!error.empty()) { + printf("test1: got error: %s\n", error.c_str()); + return EXIT_FAILURE; + } + } + + // second test: create a pool, the list objects in that pool while it's + // being deleted. + RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); + RETURN1_IF_NONZERO(delete_pool_sem->reinit(0)); + { + StRadosCreatePool r1(argc, argv, pool_setup_sem, NULL, g_num_objects); + StRadosDeletePool r2(argc, argv, + pool_setup_sem, delete_pool_sem, "foo"); + StRadosListObjects r3(argc, argv, true, g_num_objects / 2, + pool_setup_sem, delete_pool_sem); + vector < SysTestRunnable* > vec; + vec.push_back(&r1); + vec.push_back(&r2); + vec.push_back(&r3); + std::string error = SysTestRunnable::run_until_finished(vec); + if (!error.empty()) { + printf("test2: got error: %s\n", error.c_str()); + return EXIT_FAILURE; + } + } + + printf("******* SUCCESS **********\n"); + return EXIT_SUCCESS; +} diff --git a/src/test/system/rados_list_parallel.cc b/src/test/system/rados_list_parallel.cc index 369939ef41266..be2e8a2163cc7 100644 --- a/src/test/system/rados_list_parallel.cc +++ b/src/test/system/rados_list_parallel.cc @@ -56,19 +56,19 @@ public: { int ret; rados_t cl; - RETURN_IF_NONZERO(rados_create(&cl, NULL)); + RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); - RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL)); + RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); - RETURN_IF_NONZERO(rados_connect(cl)); + RETURN1_IF_NONZERO(rados_connect(cl)); pool_setup_sem->wait(); pool_setup_sem->post(); rados_ioctx_t io_ctx; - RETURN_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); - RETURN_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); + RETURN1_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); + RETURN1_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); std::map to_delete; for (int i = 0; i < g_num_objects; ++i) { @@ -132,19 +132,19 @@ public: { int ret; rados_t cl; - RETURN_IF_NONZERO(rados_create(&cl, NULL)); + RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); - RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL)); + RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); - RETURN_IF_NONZERO(rados_connect(cl)); + RETURN1_IF_NONZERO(rados_connect(cl)); pool_setup_sem->wait(); pool_setup_sem->post(); rados_ioctx_t io_ctx; - RETURN_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); - RETURN_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); + RETURN1_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); + RETURN1_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); std::map to_add; for (int i = 0; i < g_num_objects; ++i) { @@ -209,15 +209,16 @@ int main(int argc, const char **argv) return 100; } - RETURN_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); - RETURN_IF_NONZERO(CrossProcessSem::create(1, &modify_sem)); + RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); + RETURN1_IF_NONZERO(CrossProcessSem::create(1, &modify_sem)); std::string error; // Test 1... list objects { StRadosCreatePool r1(argc, argv, pool_setup_sem, NULL, g_num_objects); - StRadosListObjects r2(argc, argv, g_num_objects, pool_setup_sem, modify_sem); + StRadosListObjects r2(argc, argv, false, g_num_objects, + pool_setup_sem, modify_sem); vector < SysTestRunnable* > vec; vec.push_back(&r1); vec.push_back(&r2); @@ -229,11 +230,12 @@ int main(int argc, const char **argv) } // Test 2... list objects while they're being deleted - RETURN_IF_NONZERO(pool_setup_sem->reinit(0)); - RETURN_IF_NONZERO(modify_sem->reinit(0)); + RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); + RETURN1_IF_NONZERO(modify_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, pool_setup_sem, NULL, g_num_objects); - StRadosListObjects r2(argc, argv, g_num_objects, pool_setup_sem, modify_sem); + StRadosListObjects r2(argc, argv, false, g_num_objects / 2, + pool_setup_sem, modify_sem); RadosDeleteObjectsR r3(argc, argv); vector < SysTestRunnable* > vec; vec.push_back(&r1); @@ -247,11 +249,12 @@ int main(int argc, const char **argv) } // Test 3... list objects while others are being added - RETURN_IF_NONZERO(pool_setup_sem->reinit(0)); - RETURN_IF_NONZERO(modify_sem->reinit(0)); + RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); + RETURN1_IF_NONZERO(modify_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, pool_setup_sem, NULL, g_num_objects); - StRadosListObjects r2(argc, argv, g_num_objects, pool_setup_sem, modify_sem); + StRadosListObjects r2(argc, argv, false, g_num_objects / 2, + pool_setup_sem, modify_sem); RadosAddObjectsR r3(argc, argv, "obj2"); vector < SysTestRunnable* > vec; vec.push_back(&r1); @@ -265,11 +268,12 @@ int main(int argc, const char **argv) } // Test 4... list objects while others are being added and deleted - RETURN_IF_NONZERO(pool_setup_sem->reinit(0)); - RETURN_IF_NONZERO(modify_sem->reinit(0)); + RETURN1_IF_NONZERO(pool_setup_sem->reinit(0)); + RETURN1_IF_NONZERO(modify_sem->reinit(0)); { StRadosCreatePool r1(argc, argv, pool_setup_sem, NULL, g_num_objects); - StRadosListObjects r2(argc, argv, g_num_objects, pool_setup_sem, modify_sem); + StRadosListObjects r2(argc, argv, false, g_num_objects / 2, + pool_setup_sem, modify_sem); RadosAddObjectsR r3(argc, argv, "obj2"); RadosAddObjectsR r4(argc, argv, "obj3"); RadosDeleteObjectsR r5(argc, argv); diff --git a/src/test/system/rados_open_pools_parallel.cc b/src/test/system/rados_open_pools_parallel.cc index aee95a210844c..a02662d723b20 100644 --- a/src/test/system/rados_open_pools_parallel.cc +++ b/src/test/system/rados_open_pools_parallel.cc @@ -62,21 +62,21 @@ public: int run() { rados_t cl; - RETURN_IF_NONZERO(rados_create(&cl, NULL)); + RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); - RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL)); - RETURN_IF_NONZERO(rados_connect(cl)); + RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); + RETURN1_IF_NONZERO(rados_connect(cl)); if (m_pool_setup_sem) m_pool_setup_sem->wait(); printf("%s: rados_pool_create.\n", get_id_str()); - RETURN_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); + RETURN1_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); rados_ioctx_t io_ctx; printf("%s: rados_ioctx_create.\n", get_id_str()); - RETURN_IF_NOT_VAL(0, rados_ioctx_create(cl, "foo", &io_ctx)); + RETURN1_IF_NOT_VAL(0, rados_ioctx_create(cl, "foo", &io_ctx)); if (m_open_pool_sem) m_open_pool_sem->post(); rados_ioctx_destroy(io_ctx); @@ -99,7 +99,7 @@ int main(int argc, const char **argv) // first test: create a pool, shut down the client, access that // pool in a different process. CrossProcessSem *pool_setup_sem = NULL; - RETURN_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); + RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem)); StRadosCreatePool r1(argc, argv, pool_setup_sem, NULL, 50); StRadosOpenPool r2(argc, argv, pool_setup_sem, NULL); vector < SysTestRunnable* > vec; @@ -114,9 +114,9 @@ int main(int argc, const char **argv) // second test: create a pool, access that // pool in a different process, THEN shut down the first client. CrossProcessSem *pool_setup_sem2 = NULL; - RETURN_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem2)); + RETURN1_IF_NONZERO(CrossProcessSem::create(0, &pool_setup_sem2)); CrossProcessSem *open_pool_sem2 = NULL; - RETURN_IF_NONZERO(CrossProcessSem::create(0, &open_pool_sem2)); + RETURN1_IF_NONZERO(CrossProcessSem::create(0, &open_pool_sem2)); StRadosCreatePool r3(argc, argv, pool_setup_sem2, open_pool_sem2, 50); StRadosOpenPool r4(argc, argv, pool_setup_sem2, open_pool_sem2); vector < SysTestRunnable* > vec2; diff --git a/src/test/system/st_rados_create_pool.cc b/src/test/system/st_rados_create_pool.cc index 4bced3ce9acaf..a56c0d668c531 100644 --- a/src/test/system/st_rados_create_pool.cc +++ b/src/test/system/st_rados_create_pool.cc @@ -57,22 +57,22 @@ int StRadosCreatePool:: run() { rados_t cl; - RETURN_IF_NONZERO(rados_create(&cl, NULL)); + RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); rados_conf_parse_argv(cl, m_argc, m_argv); - RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL)); + RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); std::string log_name = SysTestSettings::inst().get_log_name(get_id_str()); if (!log_name.empty()) rados_conf_set(cl, "log_file", log_name.c_str()); - RETURN_IF_NONZERO(rados_connect(cl)); + RETURN1_IF_NONZERO(rados_connect(cl)); int ret = rados_pool_delete(cl, "foo"); if (!((ret == 0) || (ret == -ENOENT))) { printf("%s: rados_pool_delete error %d\n", get_id_str(), ret); return ret; } - RETURN_IF_NONZERO(rados_pool_create(cl, "foo")); + RETURN1_IF_NONZERO(rados_pool_create(cl, "foo")); rados_ioctx_t io_ctx; - RETURN_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); + RETURN1_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); for (int i = 0; i < m_num_objects; ++i) { char oid[128]; diff --git a/src/test/system/st_rados_list_objects.cc b/src/test/system/st_rados_list_objects.cc index 41ba15dde00bb..1c124e7167a58 100644 --- a/src/test/system/st_rados_list_objects.cc +++ b/src/test/system/st_rados_list_objects.cc @@ -28,9 +28,11 @@ using std::ostringstream; StRadosListObjects:: -StRadosListObjects(int argc, const char **argv, int midway_cnt, +StRadosListObjects(int argc, const char **argv, + bool accept_list_errors, int midway_cnt, CrossProcessSem *pool_setup_sem, CrossProcessSem *midway_sem) : SysTestRunnable(argc, argv), + m_accept_list_errors(accept_list_errors), m_midway_cnt(midway_cnt), m_pool_setup_sem(pool_setup_sem), m_midway_sem(midway_sem) @@ -46,28 +48,30 @@ int StRadosListObjects:: run() { rados_t cl; - RETURN_IF_NONZERO(rados_create(&cl, NULL)); + RETURN1_IF_NONZERO(rados_create(&cl, NULL)); rados_conf_parse_argv(cl, m_argc, m_argv); - RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL)); - RETURN_IF_NONZERO(rados_connect(cl)); + RETURN1_IF_NONZERO(rados_conf_read_file(cl, NULL)); + RETURN1_IF_NONZERO(rados_connect(cl)); m_pool_setup_sem->wait(); m_pool_setup_sem->post(); rados_ioctx_t io_ctx; - RETURN_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); - RETURN_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); + RETURN1_IF_NOT_VAL(-EEXIST, rados_pool_create(cl, "foo")); + RETURN1_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx)); int ret, saw = 0; const char *obj_name; rados_list_ctx_t h; printf("%s: listing objects.\n", get_id_str()); - RETURN_IF_NONZERO(rados_objects_list_open(io_ctx, &h)); + RETURN1_IF_NONZERO(rados_objects_list_open(io_ctx, &h)); while (true) { ret = rados_objects_list_next(h, &obj_name); if (ret == -ENOENT) { break; } else if (ret != 0) { + if (m_accept_list_errors) + break; printf("%s: rados_objects_list_next error: %d\n", get_id_str(), ret); return ret; } diff --git a/src/test/system/st_rados_list_objects.h b/src/test/system/st_rados_list_objects.h index ded99a9b34c20..e57bdf1d1a209 100644 --- a/src/test/system/st_rados_list_objects.h +++ b/src/test/system/st_rados_list_objects.h @@ -32,11 +32,13 @@ class StRadosListObjects : public SysTestRunnable { public: static std::string get_random_buf(int sz); - StRadosListObjects(int argc, const char **argv, int midway_cnt, + StRadosListObjects(int argc, const char **argv, bool accept_list_errors, + int midway_cnt, CrossProcessSem *pool_setup_sem, CrossProcessSem *midway_sem); ~StRadosListObjects(); virtual int run(); private: + bool m_accept_list_errors; int m_midway_cnt; CrossProcessSem *m_pool_setup_sem; CrossProcessSem *m_midway_sem; diff --git a/src/test/system/systest_runnable.h b/src/test/system/systest_runnable.h index 8962152c1205b..8fb59f4c68d37 100644 --- a/src/test/system/systest_runnable.h +++ b/src/test/system/systest_runnable.h @@ -20,18 +20,18 @@ #include #include -#define RETURN_IF_NOT_VAL(expected, expr) \ +#define RETURN1_IF_NOT_VAL(expected, expr) \ do {\ int _rinv_ret = expr;\ if (_rinv_ret != expected) {\ printf("%s: file %s, line %d: expected %d, got %d\n",\ get_id_str(), __FILE__, __LINE__, expected, _rinv_ret);\ - return _rinv_ret;\ + return 1; \ }\ } while(0); -#define RETURN_IF_NONZERO(expr) \ - RETURN_IF_NOT_VAL(0, expr) +#define RETURN1_IF_NONZERO(expr) \ + RETURN1_IF_NOT_VAL(0, expr) extern void* systest_runnable_pthread_helper(void *arg); -- 2.39.5