diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/test/librados/aio.cc | |
parent | Initial commit. (diff) | |
download | ceph-upstream/16.2.11+ds.tar.xz ceph-upstream/16.2.11+ds.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/test/librados/aio.cc | 1642 |
1 files changed, 1642 insertions, 0 deletions
diff --git a/src/test/librados/aio.cc b/src/test/librados/aio.cc new file mode 100644 index 000000000..2ffff1c34 --- /dev/null +++ b/src/test/librados/aio.cc @@ -0,0 +1,1642 @@ +#include <errno.h> +#include <fcntl.h> +#include <string> +#include <sstream> +#include <utility> +#include <boost/scoped_ptr.hpp> + +#include "include/err.h" +#include "include/rados/librados.h" +#include "include/types.h" +#include "include/stringify.h" +#include "include/scope_guard.h" + +#include "common/errno.h" + +#include "gtest/gtest.h" + +#include "test.h" + +using std::ostringstream; + +class AioTestData +{ +public: + AioTestData() + : m_cluster(NULL), + m_ioctx(NULL), + m_init(false) + { + } + + ~AioTestData() + { + if (m_init) { + rados_ioctx_destroy(m_ioctx); + destroy_one_pool(m_pool_name, &m_cluster); + } + } + + std::string init() + { + int ret; + m_pool_name = get_temp_pool_name(); + std::string err = create_one_pool(m_pool_name, &m_cluster); + if (!err.empty()) { + ostringstream oss; + oss << "create_one_pool(" << m_pool_name << ") failed: error " << err; + return oss.str(); + } + ret = rados_ioctx_create(m_cluster, m_pool_name.c_str(), &m_ioctx); + if (ret) { + destroy_one_pool(m_pool_name, &m_cluster); + ostringstream oss; + oss << "rados_ioctx_create failed: error " << ret; + return oss.str(); + } + m_init = true; + return ""; + } + + rados_t m_cluster; + rados_ioctx_t m_ioctx; + std::string m_pool_name; + bool m_init; +}; + +TEST(LibRadosAio, TooBig) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(-E2BIG, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, UINT_MAX, 0)); + ASSERT_EQ(-E2BIG, rados_aio_write_full(test_data.m_ioctx, "foo", + my_completion, buf, UINT_MAX)); + ASSERT_EQ(-E2BIG, rados_aio_append(test_data.m_ioctx, "foo", + my_completion, buf, UINT_MAX)); + rados_aio_release(my_completion); +} + +TEST(LibRadosAio, SimpleWrite) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + auto sg = make_scope_guard([&] { rados_aio_release(my_completion); }); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + + rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + auto sg2 = make_scope_guard([&] { rados_aio_release(my_completion2); }); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion2, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); +} + +TEST(LibRadosAio, WaitForSafe) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + rados_aio_release(my_completion); +} + +TEST(LibRadosAio, RoundTrip) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[256]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAio, RoundTrip2) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAio, RoundTrip3) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + + rados_write_op_t op1 = rados_create_write_op(); + rados_write_op_write(op1, buf, sizeof(buf), 0); + rados_write_op_set_alloc_hint2(op1, 0, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); + ASSERT_EQ(0, rados_aio_write_op_operate(op1, test_data.m_ioctx, my_completion, + "foo", NULL, 0)); + rados_release_write_op(op1); + + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + rados_aio_release(my_completion); + + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + + rados_read_op_t op2 = rados_create_read_op(); + rados_read_op_read(op2, 0, sizeof(buf2), buf2, NULL, NULL); + rados_read_op_set_flags(op2, LIBRADOS_OP_FLAG_FADVISE_NOCACHE | + LIBRADOS_OP_FLAG_FADVISE_RANDOM); + ceph_le32 init_value = init_le32(-1); + ceph_le32 checksum[2]; + rados_read_op_checksum(op2, LIBRADOS_CHECKSUM_TYPE_CRC32C, + reinterpret_cast<char *>(&init_value), + sizeof(init_value), 0, 0, 0, + reinterpret_cast<char *>(&checksum), + sizeof(checksum), NULL); + ASSERT_EQ(0, rados_aio_read_op_operate(op2, test_data.m_ioctx, my_completion2, + "foo", 0)); + rados_release_read_op(op2); + + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion2); + + bufferlist bl; + bl.append(buf, sizeof(buf)); + ASSERT_EQ(1U, checksum[0]); + ASSERT_EQ(bl.crc32c(-1), checksum[1]); +} + +TEST(LibRadosAio, RoundTripAppend) { + AioTestData test_data; + rados_completion_t my_completion, my_completion2, my_completion3; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0xdd, sizeof(buf2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + char buf3[sizeof(buf) + sizeof(buf2)]; + memset(buf3, 0, sizeof(buf3)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion3, buf3, sizeof(buf3), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ((int)sizeof(buf3), rados_aio_get_return_value(my_completion3)); + ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); + ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} + +TEST(LibRadosAio, RemoveTest) { + char buf[128]; + char buf2[sizeof(buf)]; + rados_completion_t my_completion; + AioTestData test_data; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + memset(buf, 0xaa, sizeof(buf)); + ASSERT_EQ(0, rados_append(test_data.m_ioctx, "foo", buf, sizeof(buf))); + ASSERT_EQ(0, rados_aio_remove(test_data.m_ioctx, "foo", my_completion)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + memset(buf2, 0, sizeof(buf2)); + ASSERT_EQ(-ENOENT, rados_read(test_data.m_ioctx, "foo", buf2, sizeof(buf2), 0)); + rados_aio_release(my_completion); +} + +TEST(LibRadosAio, XattrsRoundTrip) { + char buf[128]; + char attr1[] = "attr1"; + char attr1_buf[] = "foo bar baz"; + // append + AioTestData test_data; + ASSERT_EQ("", test_data.init()); + memset(buf, 0xaa, sizeof(buf)); + ASSERT_EQ(0, rados_append(test_data.m_ioctx, "foo", buf, sizeof(buf))); + // async getxattr + rados_completion_t my_completion; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + ASSERT_EQ(0, rados_aio_getxattr(test_data.m_ioctx, "foo", my_completion, attr1, buf, sizeof(buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(-ENODATA, rados_aio_get_return_value(my_completion)); + rados_aio_release(my_completion); + // async setxattr + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_setxattr(test_data.m_ioctx, "foo", my_completion2, attr1, attr1_buf, sizeof(attr1_buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + rados_aio_release(my_completion2); + // async getxattr + rados_completion_t my_completion3; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_getxattr(test_data.m_ioctx, "foo", my_completion3, attr1, buf, sizeof(buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ((int)sizeof(attr1_buf), rados_aio_get_return_value(my_completion3)); + rados_aio_release(my_completion3); + // check content of attribute + ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf))); +} + +TEST(LibRadosAio, RmXattr) { + char buf[128]; + char attr1[] = "attr1"; + char attr1_buf[] = "foo bar baz"; + // append + memset(buf, 0xaa, sizeof(buf)); + AioTestData test_data; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_append(test_data.m_ioctx, "foo", buf, sizeof(buf))); + // async setxattr + rados_completion_t my_completion; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + ASSERT_EQ(0, rados_aio_setxattr(test_data.m_ioctx, "foo", my_completion, attr1, attr1_buf, sizeof(attr1_buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + rados_aio_release(my_completion); + // async rmxattr + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_rmxattr(test_data.m_ioctx, "foo", my_completion2, attr1)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + rados_aio_release(my_completion2); + // async getxattr after deletion + rados_completion_t my_completion3; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_getxattr(test_data.m_ioctx, "foo", my_completion3, attr1, buf, sizeof(buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ(-ENODATA, rados_aio_get_return_value(my_completion3)); + rados_aio_release(my_completion3); + // Test rmxattr on a removed object + char buf2[128]; + char attr2[] = "attr2"; + char attr2_buf[] = "foo bar baz"; + memset(buf2, 0xbb, sizeof(buf2)); + ASSERT_EQ(0, rados_write(test_data.m_ioctx, "foo_rmxattr", buf2, sizeof(buf2), 0)); + // asynx setxattr + rados_completion_t my_completion4; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion4)); + ASSERT_EQ(0, rados_aio_setxattr(test_data.m_ioctx, "foo_rmxattr", my_completion4, attr2, attr2_buf, sizeof(attr2_buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion4)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion4)); + rados_aio_release(my_completion4); + // remove object + ASSERT_EQ(0, rados_remove(test_data.m_ioctx, "foo_rmxattr")); + // async rmxattr on non existing object + rados_completion_t my_completion5; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion5)); + ASSERT_EQ(0, rados_aio_rmxattr(test_data.m_ioctx, "foo_rmxattr", my_completion5, attr2)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion5)); + } + ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion5)); + rados_aio_release(my_completion5); +} + +TEST(LibRadosAio, XattrIter) { + AioTestData test_data; + ASSERT_EQ("", test_data.init()); + // Create an object with 2 attributes + char buf[128]; + char attr1[] = "attr1"; + char attr1_buf[] = "foo bar baz"; + char attr2[] = "attr2"; + char attr2_buf[256]; + for (size_t j = 0; j < sizeof(attr2_buf); ++j) { + attr2_buf[j] = j % 0xff; + } + memset(buf, 0xaa, sizeof(buf)); + ASSERT_EQ(0, rados_append(test_data.m_ioctx, "foo", buf, sizeof(buf))); + ASSERT_EQ(0, rados_setxattr(test_data.m_ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf))); + ASSERT_EQ(0, rados_setxattr(test_data.m_ioctx, "foo", attr2, attr2_buf, sizeof(attr2_buf))); + // call async version of getxattrs and wait for completion + rados_completion_t my_completion; + ASSERT_EQ(0, rados_aio_create_completion2((void*)&test_data, + nullptr, &my_completion)); + rados_xattrs_iter_t iter; + ASSERT_EQ(0, rados_aio_getxattrs(test_data.m_ioctx, "foo", my_completion, &iter)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + // loop over attributes + int num_seen = 0; + while (true) { + const char *name; + const char *val; + size_t len; + ASSERT_EQ(0, rados_getxattrs_next(iter, &name, &val, &len)); + if (name == NULL) { + break; + } + ASSERT_LT(num_seen, 2); + if ((strcmp(name, attr1) == 0) && (val != NULL) && (memcmp(val, attr1_buf, len) == 0)) { + num_seen++; + continue; + } + else if ((strcmp(name, attr2) == 0) && (val != NULL) && (memcmp(val, attr2_buf, len) == 0)) { + num_seen++; + continue; + } + else { + ASSERT_EQ(0, 1); + } + } + rados_getxattrs_end(iter); +} + +TEST(LibRadosAio, IsComplete) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + + // Busy-wait until the AIO completes. + // Normally we wouldn't do this, but we want to test rados_aio_is_complete. + while (true) { + int is_complete = rados_aio_is_complete(my_completion2); + if (is_complete) + break; + } + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAio, IsSafe) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + + // Busy-wait until the AIO completes. + // Normally we wouldn't do this, but we want to test rados_aio_is_safe. + while (true) { + int is_safe = rados_aio_is_safe(my_completion); + if (is_safe) + break; + } + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAio, ReturnValue) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "nonexistent", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion)); + rados_aio_release(my_completion); +} + +TEST(LibRadosAio, Flush) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xee, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + ASSERT_EQ(0, rados_aio_flush(test_data.m_ioctx)); + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAio, FlushAsync) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + rados_completion_t flush_completion; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, nullptr, &flush_completion)); + char buf[128]; + memset(buf, 0xee, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + ASSERT_EQ(0, rados_aio_flush_async(test_data.m_ioctx, flush_completion)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(flush_completion)); + } + ASSERT_EQ(1, rados_aio_is_complete(my_completion)); + ASSERT_EQ(1, rados_aio_is_complete(flush_completion)); + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(flush_completion); +} + +TEST(LibRadosAio, RoundTripWriteFull) { + AioTestData test_data; + rados_completion_t my_completion, my_completion2, my_completion3; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[64]; + memset(buf2, 0xdd, sizeof(buf2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_write_full(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + char buf3[sizeof(buf) + sizeof(buf2)]; + memset(buf3, 0, sizeof(buf3)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion3, buf3, sizeof(buf3), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion3)); + ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} + +TEST(LibRadosAio, RoundTripWriteSame) { + AioTestData test_data; + rados_completion_t my_completion, my_completion2, my_completion3; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char full[128]; + memset(full, 0xcc, sizeof(full)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, full, sizeof(full), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + /* write the same buf four times */ + char buf[32]; + size_t ws_write_len = sizeof(full); + memset(buf, 0xdd, sizeof(buf)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_writesame(test_data.m_ioctx, "foo", + my_completion2, buf, sizeof(buf), + ws_write_len, 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion3, full, sizeof(full), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ((int)sizeof(full), rados_aio_get_return_value(my_completion3)); + for (char *cmp = full; cmp < full + sizeof(full); cmp += sizeof(buf)) { + ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf))); + } + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} + +TEST(LibRadosAio, SimpleStat) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + uint64_t psize; + time_t pmtime; + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion2, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(sizeof(buf), psize); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAio, SimpleStatNS) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); + char buf2[64]; + memset(buf2, 0xbb, sizeof(buf2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + uint64_t psize; + time_t pmtime; + rados_completion_t my_completion2; + rados_ioctx_set_namespace(test_data.m_ioctx, ""); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion2, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(sizeof(buf), psize); + + rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); + rados_completion_t my_completion3; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion3, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); + ASSERT_EQ(sizeof(buf2), psize); + + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} + +TEST(LibRadosAio, StatRemove) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + uint64_t psize; + time_t pmtime; + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion2, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(sizeof(buf), psize); + rados_completion_t my_completion3; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_remove(test_data.m_ioctx, "foo", my_completion3)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); + uint64_t psize2; + time_t pmtime2; + rados_completion_t my_completion4; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion4)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion4, &psize2, &pmtime2)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion4)); + } + ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion4)); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); + rados_aio_release(my_completion4); +} + +TEST(LibRadosAio, ExecuteClass) { + AioTestData test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + } + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + char out[128]; + ASSERT_EQ(0, rados_aio_exec(test_data.m_ioctx, "foo", my_completion2, + "hello", "say_hello", NULL, 0, out, sizeof(out))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(13, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, strncmp("Hello, world!", out, 13)); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +using std::string; +using std::map; +using std::set; + +TEST(LibRadosAio, MultiWrite) { + AioTestData test_data; + rados_completion_t my_completion, my_completion2, my_completion3; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + + char buf2[64]; + memset(buf2, 0xdd, sizeof(buf2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), sizeof(buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + + char buf3[(sizeof(buf) + sizeof(buf2)) * 3]; + memset(buf3, 0, sizeof(buf3)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion3, buf3, sizeof(buf3), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)), rados_aio_get_return_value(my_completion3)); + ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); + ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} + +TEST(LibRadosAio, AioUnlock) { + AioTestData test_data; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_lock_exclusive(test_data.m_ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); + rados_completion_t my_completion; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + ASSERT_EQ(0, rados_aio_unlock(test_data.m_ioctx, "foo", "TestLock", "Cookie", my_completion)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + ASSERT_EQ(0, rados_lock_exclusive(test_data.m_ioctx, "foo", "TestLock", "Cookie", "", NULL, 0)); +} + +// EC test cases +class AioTestDataEC +{ +public: + AioTestDataEC() + : m_cluster(NULL), + m_ioctx(NULL), + m_init(false) + { + } + + ~AioTestDataEC() + { + if (m_init) { + rados_ioctx_destroy(m_ioctx); + destroy_one_ec_pool(m_pool_name, &m_cluster); + } + } + + std::string init() + { + int ret; + m_pool_name = get_temp_pool_name(); + std::string err = create_one_ec_pool(m_pool_name, &m_cluster); + if (!err.empty()) { + ostringstream oss; + oss << "create_one_ec_pool(" << m_pool_name << ") failed: error " << err; + return oss.str(); + } + ret = rados_ioctx_create(m_cluster, m_pool_name.c_str(), &m_ioctx); + if (ret) { + destroy_one_ec_pool(m_pool_name, &m_cluster); + ostringstream oss; + oss << "rados_ioctx_create failed: error " << ret; + return oss.str(); + } + m_init = true; + return ""; + } + + rados_t m_cluster; + rados_ioctx_t m_ioctx; + std::string m_pool_name; + bool m_init; +}; + +TEST(LibRadosAioEC, SimpleWrite) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + auto sg = make_scope_guard([&] { rados_aio_release(my_completion); }); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + + rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + auto sg2 = make_scope_guard([&] { rados_aio_release(my_completion2); }); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion2, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); +} + +TEST(LibRadosAioEC, WaitForComplete) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + rados_aio_release(my_completion); +} + +TEST(LibRadosAioEC, RoundTrip) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[256]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAioEC, RoundTrip2) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAioEC, RoundTripAppend) { + AioTestDataEC test_data; + rados_completion_t my_completion, my_completion2, my_completion3, my_completion4; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + int requires; + ASSERT_EQ(0, rados_ioctx_pool_requires_alignment2(test_data.m_ioctx, &requires)); + ASSERT_NE(0, requires); + uint64_t alignment; + ASSERT_EQ(0, rados_ioctx_pool_required_alignment2(test_data.m_ioctx, &alignment)); + ASSERT_NE(0U, alignment); + + int bsize = alignment; + char *buf = (char *)new char[bsize]; + memset(buf, 0xcc, bsize); + ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", + my_completion, buf, bsize)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + + int hbsize = bsize / 2; + char *buf2 = (char *)new char[hbsize]; + memset(buf2, 0xdd, hbsize); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", + my_completion2, buf2, hbsize)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_append(test_data.m_ioctx, "foo", + my_completion3, buf2, hbsize)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + EXPECT_EQ(-EOPNOTSUPP, rados_aio_get_return_value(my_completion3)); + + int tbsize = bsize + hbsize; + char *buf3 = (char *)new char[tbsize]; + memset(buf3, 0, tbsize); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion4)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion4, buf3, bsize * 3, 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion4)); + } + ASSERT_EQ(tbsize, rados_aio_get_return_value(my_completion4)); + ASSERT_EQ(0, memcmp(buf3, buf, bsize)); + ASSERT_EQ(0, memcmp(buf3 + bsize, buf2, hbsize)); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); + rados_aio_release(my_completion4); + delete[] buf; + delete[] buf2; + delete[] buf3; +} + +TEST(LibRadosAioEC, IsComplete) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + + // Busy-wait until the AIO completes. + // Normally we wouldn't do this, but we want to test rados_aio_is_complete. + while (true) { + int is_complete = rados_aio_is_complete(my_completion2); + if (is_complete) + break; + } + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAioEC, IsSafe) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + + // Busy-wait until the AIO completes. + // Normally we wouldn't do this, but we want to test rados_aio_is_safe. + while (true) { + int is_safe = rados_aio_is_safe(my_completion); + if (is_safe) + break; + } + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAioEC, ReturnValue) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "nonexistent", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion)); + rados_aio_release(my_completion); +} + +TEST(LibRadosAioEC, Flush) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xee, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + ASSERT_EQ(0, rados_aio_flush(test_data.m_ioctx)); + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAioEC, FlushAsync) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + rados_completion_t flush_completion; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, nullptr, &flush_completion)); + char buf[128]; + memset(buf, 0xee, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + ASSERT_EQ(0, rados_aio_flush_async(test_data.m_ioctx, flush_completion)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(flush_completion)); + } + ASSERT_EQ(1, rados_aio_is_complete(my_completion)); + ASSERT_EQ(1, rados_aio_is_complete(flush_completion)); + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[128]; + memset(buf2, 0, sizeof(buf2)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(flush_completion); +} + +TEST(LibRadosAioEC, RoundTripWriteFull) { + AioTestDataEC test_data; + rados_completion_t my_completion, my_completion2, my_completion3; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + char buf2[64]; + memset(buf2, 0xdd, sizeof(buf2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_write_full(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + char buf3[sizeof(buf) + sizeof(buf2)]; + memset(buf3, 0, sizeof(buf3)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion3, buf3, sizeof(buf3), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ((int)sizeof(buf2), rados_aio_get_return_value(my_completion3)); + ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} + +TEST(LibRadosAioEC, SimpleStat) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + uint64_t psize; + time_t pmtime; + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion2, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(sizeof(buf), psize); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + + +TEST(LibRadosAioEC, SimpleStatNS) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); + char buf2[64]; + memset(buf2, 0xbb, sizeof(buf2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf2, sizeof(buf2), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + uint64_t psize; + time_t pmtime; + rados_completion_t my_completion2; + rados_ioctx_set_namespace(test_data.m_ioctx, ""); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion2, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(sizeof(buf), psize); + + rados_ioctx_set_namespace(test_data.m_ioctx, "nspace"); + rados_completion_t my_completion3; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion3, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); + ASSERT_EQ(sizeof(buf2), psize); + + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} + +TEST(LibRadosAioEC, StatRemove) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + uint64_t psize; + time_t pmtime; + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion2, &psize, &pmtime)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(sizeof(buf), psize); + rados_completion_t my_completion3; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_remove(test_data.m_ioctx, "foo", my_completion3)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion3)); + uint64_t psize2; + time_t pmtime2; + rados_completion_t my_completion4; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion4)); + ASSERT_EQ(0, rados_aio_stat(test_data.m_ioctx, "foo", + my_completion4, &psize2, &pmtime2)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion4)); + } + ASSERT_EQ(-ENOENT, rados_aio_get_return_value(my_completion4)); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); + rados_aio_release(my_completion4); +} + +TEST(LibRadosAioEC, ExecuteClass) { + AioTestDataEC test_data; + rados_completion_t my_completion; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + rados_completion_t my_completion2; + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + char out[128]; + ASSERT_EQ(0, rados_aio_exec(test_data.m_ioctx, "foo", my_completion2, + "hello", "say_hello", NULL, 0, out, sizeof(out))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(13, rados_aio_get_return_value(my_completion2)); + ASSERT_EQ(0, strncmp("Hello, world!", out, 13)); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); +} + +TEST(LibRadosAioEC, MultiWrite) { + AioTestDataEC test_data; + rados_completion_t my_completion, my_completion2, my_completion3; + ASSERT_EQ("", test_data.init()); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion)); + char buf[128]; + memset(buf, 0xcc, sizeof(buf)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion, buf, sizeof(buf), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion)); + } + ASSERT_EQ(0, rados_aio_get_return_value(my_completion)); + + char buf2[64]; + memset(buf2, 0xdd, sizeof(buf2)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion2)); + ASSERT_EQ(0, rados_aio_write(test_data.m_ioctx, "foo", + my_completion2, buf2, sizeof(buf2), sizeof(buf))); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2)); + } + ASSERT_EQ(-EOPNOTSUPP, rados_aio_get_return_value(my_completion2)); + + char buf3[(sizeof(buf) + sizeof(buf2)) * 3]; + memset(buf3, 0, sizeof(buf3)); + ASSERT_EQ(0, rados_aio_create_completion2(nullptr, + nullptr, &my_completion3)); + ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo", + my_completion3, buf3, sizeof(buf3), 0)); + { + TestAlarm alarm; + ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion3)); + } + ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion3)); + ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf))); + rados_aio_release(my_completion); + rados_aio_release(my_completion2); + rados_aio_release(my_completion3); +} |