summaryrefslogtreecommitdiffstats
path: root/src/test/rgw/test_log_backing.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/rgw/test_log_backing.cc')
-rw-r--r--src/test/rgw/test_log_backing.cc367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/test/rgw/test_log_backing.cc b/src/test/rgw/test_log_backing.cc
new file mode 100644
index 000000000..c67debb9f
--- /dev/null
+++ b/src/test/rgw/test_log_backing.cc
@@ -0,0 +1,367 @@
+// -*- 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) 2019 Red Hat, Inc.
+ *
+ * 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 "rgw_log_backing.h"
+
+#include <cerrno>
+#include <iostream>
+#include <string_view>
+
+#undef FMT_HEADER_ONLY
+#define FMT_HEADER_ONLY 1
+#include <fmt/format.h>
+
+#include "include/types.h"
+#include "include/rados/librados.hpp"
+
+#include "test/librados/test_cxx.h"
+#include "global/global_context.h"
+
+#include "cls/log/cls_log_client.h"
+
+#include "rgw/rgw_tools.h"
+#include "rgw/cls_fifo_legacy.h"
+
+#include "gtest/gtest.h"
+
+namespace lr = librados;
+namespace cb = ceph::buffer;
+namespace fifo = rados::cls::fifo;
+namespace RCf = rgw::cls::fifo;
+
+auto cct = new CephContext(CEPH_ENTITY_TYPE_CLIENT);
+const DoutPrefix dp(cct, 1, "test log backing: ");
+
+class LogBacking : public testing::Test {
+protected:
+ static constexpr int SHARDS = 3;
+ const std::string pool_name = get_temp_pool_name();
+ lr::Rados rados;
+ lr::IoCtx ioctx;
+ lr::Rados rados2;
+ lr::IoCtx ioctx2;
+
+ void SetUp() override {
+ ASSERT_EQ("", create_one_pool_pp(pool_name, rados));
+ ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx));
+ connect_cluster_pp(rados2);
+ ASSERT_EQ(0, rados2.ioctx_create(pool_name.c_str(), ioctx2));
+ }
+ void TearDown() override {
+ destroy_one_pool_pp(pool_name, rados);
+ }
+
+ std::string get_oid(uint64_t gen_id, int i) const {
+ return (gen_id > 0 ?
+ fmt::format("shard@G{}.{}", gen_id, i) :
+ fmt::format("shard.{}", i));
+ }
+
+ void make_omap() {
+ for (int i = 0; i < SHARDS; ++i) {
+ using ceph::encode;
+ lr::ObjectWriteOperation op;
+ cb::list bl;
+ encode(i, bl);
+ cls_log_add(op, ceph_clock_now(), {}, "meow", bl);
+ auto r = rgw_rados_operate(&dp, ioctx, get_oid(0, i), &op, null_yield);
+ ASSERT_GE(r, 0);
+ }
+ }
+
+ void add_omap(int i) {
+ using ceph::encode;
+ lr::ObjectWriteOperation op;
+ cb::list bl;
+ encode(i, bl);
+ cls_log_add(op, ceph_clock_now(), {}, "meow", bl);
+ auto r = rgw_rados_operate(&dp, ioctx, get_oid(0, i), &op, null_yield);
+ ASSERT_GE(r, 0);
+ }
+
+ void empty_omap() {
+ for (int i = 0; i < SHARDS; ++i) {
+ auto oid = get_oid(0, i);
+ std::string to_marker;
+ {
+ lr::ObjectReadOperation op;
+ std::list<cls_log_entry> entries;
+ bool truncated = false;
+ cls_log_list(op, {}, {}, {}, 1, entries, &to_marker, &truncated);
+ auto r = rgw_rados_operate(&dp, ioctx, oid, &op, nullptr, null_yield);
+ ASSERT_GE(r, 0);
+ ASSERT_FALSE(entries.empty());
+ }
+ {
+ lr::ObjectWriteOperation op;
+ cls_log_trim(op, {}, {}, {}, to_marker);
+ auto r = rgw_rados_operate(&dp, ioctx, oid, &op, null_yield);
+ ASSERT_GE(r, 0);
+ }
+ {
+ lr::ObjectReadOperation op;
+ std::list<cls_log_entry> entries;
+ bool truncated = false;
+ cls_log_list(op, {}, {}, {}, 1, entries, &to_marker, &truncated);
+ auto r = rgw_rados_operate(&dp, ioctx, oid, &op, nullptr, null_yield);
+ ASSERT_GE(r, 0);
+ ASSERT_TRUE(entries.empty());
+ }
+ }
+ }
+
+ void make_fifo()
+ {
+ for (int i = 0; i < SHARDS; ++i) {
+ std::unique_ptr<RCf::FIFO> fifo;
+ auto r = RCf::FIFO::create(&dp, ioctx, get_oid(0, i), &fifo, null_yield);
+ ASSERT_EQ(0, r);
+ ASSERT_TRUE(fifo);
+ }
+ }
+
+ void add_fifo(int i)
+ {
+ using ceph::encode;
+ std::unique_ptr<RCf::FIFO> fifo;
+ auto r = RCf::FIFO::open(&dp, ioctx, get_oid(0, i), &fifo, null_yield);
+ ASSERT_GE(0, r);
+ ASSERT_TRUE(fifo);
+ cb::list bl;
+ encode(i, bl);
+ r = fifo->push(&dp, bl, null_yield);
+ ASSERT_GE(0, r);
+ }
+
+ void assert_empty() {
+ std::vector<lr::ObjectItem> result;
+ lr::ObjectCursor next;
+ auto r = ioctx.object_list(ioctx.object_list_begin(), ioctx.object_list_end(),
+ 100, {}, &result, &next);
+ ASSERT_GE(r, 0);
+ ASSERT_TRUE(result.empty());
+ }
+};
+
+TEST_F(LogBacking, TestOmap)
+{
+ make_omap();
+ auto stat = log_backing_type(&dp, ioctx, log_type::fifo, SHARDS,
+ [this](int shard){ return get_oid(0, shard); },
+ null_yield);
+ ASSERT_EQ(log_type::omap, *stat);
+}
+
+TEST_F(LogBacking, TestOmapEmpty)
+{
+ auto stat = log_backing_type(&dp, ioctx, log_type::omap, SHARDS,
+ [this](int shard){ return get_oid(0, shard); },
+ null_yield);
+ ASSERT_EQ(log_type::omap, *stat);
+}
+
+TEST_F(LogBacking, TestFIFO)
+{
+ make_fifo();
+ auto stat = log_backing_type(&dp, ioctx, log_type::fifo, SHARDS,
+ [this](int shard){ return get_oid(0, shard); },
+ null_yield);
+ ASSERT_EQ(log_type::fifo, *stat);
+}
+
+TEST_F(LogBacking, TestFIFOEmpty)
+{
+ auto stat = log_backing_type(&dp, ioctx, log_type::fifo, SHARDS,
+ [this](int shard){ return get_oid(0, shard); },
+ null_yield);
+ ASSERT_EQ(log_type::fifo, *stat);
+}
+
+TEST(CursorGen, RoundTrip) {
+ const auto pcurs = "fded"sv;
+ {
+ auto gc = gencursor(0, pcurs);
+ ASSERT_EQ(pcurs, gc);
+ auto [gen, cursor] = cursorgen(gc);
+ ASSERT_EQ(0, gen);
+ ASSERT_EQ(pcurs, cursor);
+ }
+ {
+ auto gc = gencursor(53, pcurs);
+ ASSERT_NE(pcurs, gc);
+ auto [gen, cursor] = cursorgen(gc);
+ ASSERT_EQ(53, gen);
+ ASSERT_EQ(pcurs, cursor);
+ }
+}
+
+class generations final : public logback_generations {
+public:
+
+ entries_t got_entries;
+ std::optional<uint64_t> tail;
+
+ using logback_generations::logback_generations;
+
+ bs::error_code handle_init(entries_t e) noexcept {
+ got_entries = e;
+ return {};
+ }
+
+ bs::error_code handle_new_gens(entries_t e) noexcept {
+ got_entries = e;
+ return {};
+ }
+
+ bs::error_code handle_empty_to(uint64_t new_tail) noexcept {
+ tail = new_tail;
+ return {};
+ }
+};
+
+TEST_F(LogBacking, GenerationSingle)
+{
+ auto lgr = logback_generations::init<generations>(
+ &dp, ioctx, "foobar", [this](uint64_t gen_id, int shard) {
+ return get_oid(gen_id, shard);
+ }, SHARDS, log_type::fifo, null_yield);
+ ASSERT_TRUE(lgr);
+
+ auto lg = std::move(*lgr);
+
+ ASSERT_EQ(0, lg->got_entries.begin()->first);
+
+ ASSERT_EQ(0, lg->got_entries[0].gen_id);
+ ASSERT_EQ(log_type::fifo, lg->got_entries[0].type);
+ ASSERT_FALSE(lg->got_entries[0].pruned);
+
+ auto ec = lg->empty_to(&dp, 0, null_yield);
+ ASSERT_TRUE(ec);
+
+ lg.reset();
+
+ lg = *logback_generations::init<generations>(
+ &dp, ioctx, "foobar", [this](uint64_t gen_id, int shard) {
+ return get_oid(gen_id, shard);
+ }, SHARDS, log_type::fifo, null_yield);
+
+ ASSERT_EQ(0, lg->got_entries.begin()->first);
+
+ ASSERT_EQ(0, lg->got_entries[0].gen_id);
+ ASSERT_EQ(log_type::fifo, lg->got_entries[0].type);
+ ASSERT_FALSE(lg->got_entries[0].pruned);
+
+ lg->got_entries.clear();
+
+ ec = lg->new_backing(&dp, log_type::omap, null_yield);
+ ASSERT_FALSE(ec);
+
+ ASSERT_EQ(1, lg->got_entries.size());
+ ASSERT_EQ(1, lg->got_entries[1].gen_id);
+ ASSERT_EQ(log_type::omap, lg->got_entries[1].type);
+ ASSERT_FALSE(lg->got_entries[1].pruned);
+
+ lg.reset();
+
+ lg = *logback_generations::init<generations>(
+ &dp, ioctx, "foobar", [this](uint64_t gen_id, int shard) {
+ return get_oid(gen_id, shard);
+ }, SHARDS, log_type::fifo, null_yield);
+
+ ASSERT_EQ(2, lg->got_entries.size());
+ ASSERT_EQ(0, lg->got_entries[0].gen_id);
+ ASSERT_EQ(log_type::fifo, lg->got_entries[0].type);
+ ASSERT_FALSE(lg->got_entries[0].pruned);
+
+ ASSERT_EQ(1, lg->got_entries[1].gen_id);
+ ASSERT_EQ(log_type::omap, lg->got_entries[1].type);
+ ASSERT_FALSE(lg->got_entries[1].pruned);
+
+ ec = lg->empty_to(&dp, 0, null_yield);
+ ASSERT_FALSE(ec);
+
+ ASSERT_EQ(0, *lg->tail);
+
+ lg.reset();
+
+ lg = *logback_generations::init<generations>(
+ &dp, ioctx, "foobar", [this](uint64_t gen_id, int shard) {
+ return get_oid(gen_id, shard);
+ }, SHARDS, log_type::fifo, null_yield);
+
+ ASSERT_EQ(1, lg->got_entries.size());
+ ASSERT_EQ(1, lg->got_entries[1].gen_id);
+ ASSERT_EQ(log_type::omap, lg->got_entries[1].type);
+ ASSERT_FALSE(lg->got_entries[1].pruned);
+}
+
+TEST_F(LogBacking, GenerationWN)
+{
+ auto lg1 = *logback_generations::init<generations>(
+ &dp, ioctx, "foobar", [this](uint64_t gen_id, int shard) {
+ return get_oid(gen_id, shard);
+ }, SHARDS, log_type::fifo, null_yield);
+
+ auto ec = lg1->new_backing(&dp, log_type::omap, null_yield);
+ ASSERT_FALSE(ec);
+
+ ASSERT_EQ(1, lg1->got_entries.size());
+ ASSERT_EQ(1, lg1->got_entries[1].gen_id);
+ ASSERT_EQ(log_type::omap, lg1->got_entries[1].type);
+ ASSERT_FALSE(lg1->got_entries[1].pruned);
+
+ lg1->got_entries.clear();
+
+ auto lg2 = *logback_generations::init<generations>(
+ &dp, ioctx2, "foobar", [this](uint64_t gen_id, int shard) {
+ return get_oid(gen_id, shard);
+ }, SHARDS, log_type::fifo, null_yield);
+
+ ASSERT_EQ(2, lg2->got_entries.size());
+
+ ASSERT_EQ(0, lg2->got_entries[0].gen_id);
+ ASSERT_EQ(log_type::fifo, lg2->got_entries[0].type);
+ ASSERT_FALSE(lg2->got_entries[0].pruned);
+
+ ASSERT_EQ(1, lg2->got_entries[1].gen_id);
+ ASSERT_EQ(log_type::omap, lg2->got_entries[1].type);
+ ASSERT_FALSE(lg2->got_entries[1].pruned);
+
+ lg2->got_entries.clear();
+
+ ec = lg1->new_backing(&dp, log_type::fifo, null_yield);
+ ASSERT_FALSE(ec);
+
+ ASSERT_EQ(1, lg1->got_entries.size());
+ ASSERT_EQ(2, lg1->got_entries[2].gen_id);
+ ASSERT_EQ(log_type::fifo, lg1->got_entries[2].type);
+ ASSERT_FALSE(lg1->got_entries[2].pruned);
+
+ ASSERT_EQ(1, lg2->got_entries.size());
+ ASSERT_EQ(2, lg2->got_entries[2].gen_id);
+ ASSERT_EQ(log_type::fifo, lg2->got_entries[2].type);
+ ASSERT_FALSE(lg2->got_entries[2].pruned);
+
+ lg1->got_entries.clear();
+ lg2->got_entries.clear();
+
+ ec = lg2->empty_to(&dp, 1, null_yield);
+ ASSERT_FALSE(ec);
+
+ ASSERT_EQ(1, *lg1->tail);
+ ASSERT_EQ(1, *lg2->tail);
+
+ lg1->tail.reset();
+ lg2->tail.reset();
+}