lib_LTLIBRARIES += libhadoopcephfs.la
endif
+## System tests
+libsystest_la_SOURCES = \
+ test/system/systest_runnable.cc \
+ test/system/systest_settings.cc
+libsystest_la_LIBADD = libglobal.la
+noinst_LTLIBRARIES += libsystest.la
+
+rados_list_parallel_SOURCES = test/system/rados_list_parallel.cc
+rados_list_parallel_LDADD = libsystest.la librados.la
+bin_DEBUGPROGRAMS += rados_list_parallel
+
## unit tests
# target to build but not run the unit tests
tools/gui_resources.h\
test/osd/RadosModel.h\
global/pidfile.h\
- common/sync_filesystem.h
+ common/sync_filesystem.h \
+ test/system/systest_runnable.h \
+ test/system/systest_settings.h
all_sources = $(cmon_SOURCES) $(ceph_SOURCES) $(cephfs_SOURCES) $(librados_config_SOURCES) $(cauthtool_SOURCES) $(monmaptool_SOURCES) \
$(crushtool_SOURCES) $(osdmaptool_SOURCES) $(cconf_SOURCES) $(mount_ceph_SOURCES) $(cmds_SOURCES) \
--- /dev/null
+// -*- 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) 2004-2006 Sage Weil <sage@newdream.net>
+*
+* 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 "include/rados/librados.h"
+#include "systest_runnable.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <sstream>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <time.h>
+#include <vector>
+
+using std::ostringstream;
+using std::string;
+using std::vector;
+
+static const int RLP_NUM_OBJECTS = 50; //16384;
+static const int RLP_OBJECT_SZ_MAX = 256;
+
+static std::string get_random_buf(void)
+{
+ ostringstream oss;
+ int size = rand() % RLP_OBJECT_SZ_MAX; // yep, it's not very random
+ for (int i = 0; i < size; ++i) {
+ oss << ".";
+ }
+ return oss.str();
+}
+
+sem_t pool_setup_sem;
+sem_t modify_sem;
+
+class RadosCreateBigPoolR : public SysTestRunnable
+{
+public:
+ RadosCreateBigPoolR()
+ : SysTestRunnable()
+ {
+ }
+
+ ~RadosCreateBigPoolR()
+ {
+ }
+
+ int run(void)
+ {
+ rados_t cl;
+ RETURN_IF_NONZERO(rados_create(&cl, NULL));
+ RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL));
+ RETURN_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"));
+ rados_ioctx_t io_ctx;
+ RETURN_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx));
+
+ for (int i = 0; i < RLP_NUM_OBJECTS; ++i) {
+ char oid[128];
+ snprintf(oid, sizeof(oid), "%d.obj", i);
+ std::string buf(get_random_buf());
+ ret = rados_write(io_ctx, oid, buf.c_str(), buf.size(), 0);
+ if (ret < static_cast<int>(buf.size())) {
+ printf("%s: rados_write error %d\n", get_id_str(), ret);
+ return ret;
+ }
+ }
+ sem_post(&pool_setup_sem);
+ sem_post(&pool_setup_sem);
+ rados_ioctx_destroy(cl);
+ return 0;
+ }
+};
+
+class RadosListObjectsR : public SysTestRunnable
+{
+public:
+ RadosListObjectsR()
+ : SysTestRunnable()
+ {
+ }
+
+ ~RadosListObjectsR()
+ {
+ }
+
+ int run(void)
+ {
+ rados_t cl;
+ RETURN_IF_NONZERO(rados_create(&cl, NULL));
+ RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL));
+ RETURN_IF_NONZERO(rados_connect(cl));
+ sem_wait(&pool_setup_sem);
+
+ rados_ioctx_t io_ctx;
+ RETURN_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx));
+
+ int ret, saw = 0;
+ const char *obj_name;
+ char tmp[RLP_OBJECT_SZ_MAX];
+ rados_list_ctx_t h;
+ RETURN_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) {
+ printf("%s: rados_objects_list_next error: %d\n", get_id_str(), ret);
+ return ret;
+ }
+ int len = strlen(obj_name);
+ if (len > RLP_OBJECT_SZ_MAX)
+ len = RLP_OBJECT_SZ_MAX;
+ memcpy(tmp, obj_name, strlen(obj_name));
+ ++saw;
+ if (saw == RLP_NUM_OBJECTS / 2)
+ sem_wait(&modify_sem);
+ }
+ rados_objects_list_close(h);
+
+ printf("%s: saw %d objects\n", get_id_str(), saw);
+
+ rados_ioctx_destroy(cl);
+
+ return 0;
+ }
+};
+
+class RadosModifyPoolR : public SysTestRunnable
+{
+public:
+ RadosModifyPoolR()
+ : SysTestRunnable()
+ {
+ }
+
+ ~RadosModifyPoolR()
+ {
+ }
+
+ int run(void)
+ {
+ int ret;
+ rados_t cl;
+ RETURN_IF_NONZERO(rados_create(&cl, NULL));
+ RETURN_IF_NONZERO(rados_conf_read_file(cl, NULL));
+ RETURN_IF_NONZERO(rados_connect(cl));
+ sem_wait(&pool_setup_sem);
+
+ rados_ioctx_t io_ctx;
+ RETURN_IF_NONZERO(rados_ioctx_create(cl, "foo", &io_ctx));
+
+ std::vector <std::string> to_delete;
+ for (int i = 0; i < RLP_NUM_OBJECTS; ++i) {
+ char oid[128];
+ snprintf(oid, sizeof(oid), "%d.obj", i);
+ to_delete.push_back(oid);
+ }
+
+ int removed = 0;
+ while (true) {
+ if (to_delete.empty())
+ break;
+ int r = rand() % to_delete.size();
+ std::string oid(to_delete[r]);
+ ret = rados_remove(io_ctx, oid.c_str());
+ if (ret != 0) {
+ printf("%s: rados_remove(%s) failed with error %d\n",
+ get_id_str(), oid.c_str(), ret);
+ return ret;
+ }
+ ++removed;
+ if (removed == RLP_NUM_OBJECTS / 2)
+ sem_post(&modify_sem);
+ }
+
+ printf("%s: removed %d objects\n", get_id_str(), removed);
+
+ rados_ioctx_destroy(cl);
+
+ return 0;
+ }
+};
+
+int main(int argc, const char **argv)
+{
+ sem_init(&pool_setup_sem, 1, 0);
+ sem_init(&modify_sem, 1, 0);
+
+ RadosCreateBigPoolR r1;
+ RadosListObjectsR r2;
+ RadosModifyPoolR r3;
+ 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("got error: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
+
+ printf("******* SUCCESS **********\n");
+ return EXIT_SUCCESS;
+}
--- /dev/null
+// -*- 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 "include/atomic.h"
+#include "systest_runnable.h"
+#include "systest_settings.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <sstream>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <vector>
+
+using std::ostringstream;
+using std::string;
+
+static pid_t do_gettid(void)
+{
+ return static_cast < pid_t >(syscall(SYS_gettid));
+}
+
+ceph::atomic_t m_highest_id(0);
+
+SysTestRunnable::
+SysTestRunnable()
+{
+ m_started = false;
+ m_id = m_highest_id.inc();
+ memset(&m_pthread, 0, sizeof(m_pthread));
+ m_pid = 0;
+ update_id_str(false);
+}
+
+SysTestRunnable::
+~SysTestRunnable()
+{
+}
+
+const char* SysTestRunnable::
+get_id_str(void) const
+{
+ return m_id_str;
+}
+
+int SysTestRunnable::
+start()
+{
+ if (m_started) {
+ return -EDOM;
+ }
+ bool use_threads = SysTestSettings::inst().use_threads();
+ if (use_threads) {
+ int ret = pthread_create(&m_pthread, NULL, systest_runnable_pthread_helper,
+ static_cast<void*>(this));
+ if (ret)
+ return ret;
+ m_started = true;
+ return 0;
+ }
+ else {
+ // TODO: implement
+ // m_pid = ???
+ return -ENOTSUP;
+ }
+}
+
+std::string SysTestRunnable::
+join()
+{
+ if (!m_started) {
+ return "SysTestRunnable was never started.";
+ }
+ bool use_threads = SysTestSettings::inst().use_threads();
+ if (use_threads) {
+ void *ptrretval;
+ int ret = pthread_join(m_pthread, &ptrretval);
+ if (ret) {
+ ostringstream oss;
+ oss << "pthread_join failed with error " << ret;
+ return oss.str();
+ }
+ int retval = (int)(uintptr_t)ptrretval;
+ if (retval != 0) {
+ ostringstream oss;
+ oss << "ERROR " << retval;
+ return oss.str();
+ }
+ return "";
+ }
+ else {
+ // TODO: implement
+ // m_pid = ???
+ return "processes not supported yet";
+ }
+}
+
+void SysTestRunnable::
+update_id_str(bool started)
+{
+ bool use_threads = SysTestSettings::inst().use_threads();
+ char extra[128];
+ extra[0] = '\0';
+
+ if (started) {
+ if (use_threads)
+ snprintf(extra, sizeof(extra), " [%d]", do_gettid());
+ else
+ snprintf(extra, sizeof(extra), " [%d]", getpid());
+ }
+ if (use_threads)
+ snprintf(m_id_str, SysTestRunnable::ID_STR_SZ, "thread %d%s", m_id, extra);
+ else
+ snprintf(m_id_str, SysTestRunnable::ID_STR_SZ, "process %d%s", m_id, extra);
+}
+
+std::string SysTestRunnable::
+run_until_finished(std::vector < SysTestRunnable * > &runnables)
+{
+ int ret, index = 0;
+ for (std::vector < SysTestRunnable * >::const_iterator r = runnables.begin();
+ r != runnables.end(); ++r) {
+ ret = (*r)->start();
+ if (ret) {
+ ostringstream oss;
+ oss << "run_until_finished: got error " << ret
+ << " when starting runnable " << index;
+ return oss.str();
+ }
+ ++index;
+ }
+
+ for (std::vector < SysTestRunnable * >::const_iterator r = runnables.begin();
+ r != runnables.end(); ++r) {
+ std::string rstr = (*r)->join();
+ if (!rstr.empty()) {
+ ostringstream oss;
+ oss << "run_until_finished: runnable " << (*r)->get_id_str()
+ << ": got error " << rstr;
+ return oss.str();
+ }
+ }
+ return "";
+}
+
+void *systest_runnable_pthread_helper(void *arg)
+{
+ SysTestRunnable *st = static_cast < SysTestRunnable * >(arg);
+ st->update_id_str(true);
+ int ret = st->run();
+ return (void*)(uintptr_t)ret;
+}
--- /dev/null
+// -*- 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.
+ *
+ */
+
+#ifndef CEPH_SYSTEM_TEST_H
+#define CEPH_SYSTEM_TEST_H
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+#define RETURN_IF_NOT_VAL(expected, expr) \
+ do {\
+ int _rinv_ret = expr;\
+ if (_rinv_ret) {\
+ printf("%s: file %s, line %d: expected %d, got %d",\
+ get_id_str(), __FILE__, __LINE__, expected, _rinv_ret);\
+ return _rinv_ret;\
+ }\
+ } while(0);
+
+#define RETURN_IF_NONZERO(expr) \
+ RETURN_IF_NOT_VAL(0, expr)
+
+extern void* systest_runnable_pthread_helper(void *arg);
+
+/* Represents a single test thread / process.
+ *
+ * Inherit from this class and implement the test body in run().
+*/
+class SysTestRunnable
+{
+public:
+ static const int ID_STR_SZ = 128;
+
+ SysTestRunnable();
+ virtual ~SysTestRunnable();
+
+ /* Returns 0 on success; error code otherwise. */
+ virtual int run(void) = 0;
+
+ /* Return a string identifying the runnable. */
+ const char* get_id_str(void) const;
+
+ /* Start the Runnable */
+ int start();
+
+ /* Wait until the Runnable is finished. Returns an error string on failure. */
+ std::string join();
+
+ /* Starts a bunch of SystemTestRunnables and waits until they're done.
+ *
+ * Returns an error string on failure. */
+ static std::string run_until_finished(std::vector < SysTestRunnable * >&
+ runnables);
+
+private:
+ void update_id_str(bool started);
+
+ friend void* systest_runnable_pthread_helper(void *arg);
+
+ bool m_started;
+ int m_id;
+ pthread_t m_pthread;
+ int m_pid;
+ char m_id_str[ID_STR_SZ];
+};
+
+#endif
--- /dev/null
+// -*- 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 "systest_settings.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+
+pthread_mutex_t g_system_test_settings_lock = PTHREAD_MUTEX_INITIALIZER;
+
+SysTestSettings& SysTestSettings::
+inst()
+{
+ pthread_mutex_lock(&g_system_test_settings_lock);
+ if (!m_inst)
+ m_inst = new SysTestSettings();
+ pthread_mutex_unlock(&g_system_test_settings_lock);
+ return *m_inst;
+}
+
+bool SysTestSettings::
+use_threads() const
+{
+ return m_use_threads;
+}
+
+SysTestSettings* SysTestSettings::
+m_inst = NULL;
+
+SysTestSettings::
+SysTestSettings()
+{
+ m_use_threads = !!getenv("USE_THREADS");
+}
+
+SysTestSettings::
+~SysTestSettings()
+{
+}
--- /dev/null
+// -*- 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.
+ *
+ */
+
+#ifndef CEPH_SYSTEM_TEST_SETTINGS_H
+#define CEPH_SYSTEM_TEST_SETTINGS_H
+
+/* Singleton with settings grabbed from environment variables */
+class SysTestSettings
+{
+public:
+ static SysTestSettings& inst();
+ bool use_threads() const;
+private:
+ static SysTestSettings* m_inst;
+ SysTestSettings();
+ ~SysTestSettings();
+
+ bool m_use_threads;
+};
+
+#endif