]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: add WriteLogMap test cases
authorYuan Lu <yuan.y.lu@intel.com>
Tue, 14 Apr 2020 07:45:45 +0000 (15:45 +0800)
committerYuan Lu <yuan.y.lu@intel.com>
Sun, 26 Apr 2020 02:55:50 +0000 (10:55 +0800)
Signed-off-by: Peterson, Scott <scott.d.peterson@intel.com>
Signed-off-by: Li, Xiaoyan <xiaoyan.li@intel.com>
Signed-off-by: Lu, Yuan <yuan.y.lu@intel.com>
Signed-off-by: Chamarthy, Mahati <mahati.chamarthy@intel.com>
src/test/librbd/CMakeLists.txt
src/test/librbd/cache/rwl/test_WriteLogMap.cc [new file with mode: 0644]

index f1179f4f6648b7602929d4881556c1d86af67890..c219660200dfce2bf64ca9173364f684e03254d4 100644 (file)
@@ -119,7 +119,8 @@ set(unittest_librbd_srcs
 if(WITH_RBD_RWL)
    set(unittest_librbd_srcs
      ${unittest_librbd_srcs}
-     cache/test_mock_ReplicatedWriteLog.cc)
+     cache/test_mock_ReplicatedWriteLog.cc
+     cache/rwl/test_WriteLogMap.cc)
 endif(WITH_RBD_RWL)
 
 add_executable(unittest_librbd
diff --git a/src/test/librbd/cache/rwl/test_WriteLogMap.cc b/src/test/librbd/cache/rwl/test_WriteLogMap.cc
new file mode 100644 (file)
index 0000000..1fc2cfd
--- /dev/null
@@ -0,0 +1,336 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/librbd/test_fixture.h"
+#include "test/librbd/test_support.h"
+
+#include "librbd/cache/rwl/LogMap.cc"
+
+void register_test_write_log_map() {
+}
+
+namespace librbd {
+namespace cache {
+namespace rwl {
+
+struct TestLogEntry {
+  uint64_t image_offset_bytes;
+  uint64_t write_bytes;
+  uint32_t referring_map_entries = 0;
+  TestLogEntry(const uint64_t image_offset_bytes, const uint64_t write_bytes)
+    : image_offset_bytes(image_offset_bytes), write_bytes(write_bytes) {
+  }
+  uint64_t get_offset_bytes() {
+    return image_offset_bytes;
+  }
+  uint64_t get_write_bytes() {
+    return write_bytes;
+  }
+  BlockExtent block_extent() {
+    return BlockExtent(image_offset_bytes, image_offset_bytes + write_bytes);
+  }
+  uint32_t get_map_ref() {
+    return referring_map_entries;
+  }
+  void inc_map_ref() {
+    referring_map_entries++;
+  }
+  void dec_map_ref() {
+    referring_map_entries--;
+  }
+  friend std::ostream &operator<<(std::ostream &os,
+                                  const TestLogEntry &entry) {
+    os << "referring_map_entries=" << entry.referring_map_entries << ", "
+       << "image_offset_bytes=" << entry.image_offset_bytes << ", "
+       << "write_bytes=" << entry.write_bytes;
+    return os;
+  };
+};
+
+typedef std::list<std::shared_ptr<TestLogEntry>> TestLogEntries;
+typedef LogMapEntry<TestLogEntry> TestMapEntry;
+typedef LogMapEntries<TestLogEntry> TestLogMapEntries;
+typedef LogMap<TestLogEntry> TestLogMap;
+
+class TestWriteLogMap : public TestFixture {
+public:
+  void SetUp() override {
+    TestFixture::SetUp();
+    m_cct = reinterpret_cast<CephContext*>(m_ioctx.cct());
+  }
+
+  CephContext *m_cct;
+};
+
+TEST_F(TestWriteLogMap, Simple) {
+  TestLogEntries es;
+  TestLogMapEntries lme;
+  TestLogMap  map(m_cct);
+
+  /* LogEntry takes offset, length, in bytes */
+  auto e1 = make_shared<TestLogEntry>(4, 8);
+  TestLogEntry *e1_ptr = e1.get();
+  ASSERT_EQ(4, e1_ptr->get_offset_bytes());
+  ASSERT_EQ(8, e1_ptr->get_write_bytes());
+  map.add_log_entry(e1);
+
+  /* BlockExtent takes first, last, in blocks */
+  TestLogMapEntries found0 = map.find_map_entries(BlockExtent(0, 100));
+  int numfound = found0.size();
+  /* Written range includes the single write above */
+  ASSERT_EQ(1, numfound);
+  ASSERT_EQ(e1, found0.front().log_entry);
+
+  /* Nothing before that */
+  found0 = map.find_map_entries(BlockExtent(0, 3));
+  numfound = found0.size();
+  ASSERT_EQ(0, numfound);
+
+  /* Nothing after that */
+  found0 = map.find_map_entries(BlockExtent(12, 99));
+  numfound = found0.size();
+  ASSERT_EQ(0, numfound);
+
+  /* 4-11 will be e1 */
+  for (int i=4; i<12; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(1, numfound);
+    ASSERT_EQ(e1, found0.front().log_entry);
+  }
+
+  map.remove_log_entry(e1);
+  /* Nothing should be found */
+  for (int i=4; i<12; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(0, numfound);
+  }
+}
+
+TEST_F(TestWriteLogMap, OverlapFront) {
+  TestLogMap map(m_cct);
+
+  auto e0 = make_shared<TestLogEntry>(4, 8);
+  map.add_log_entry(e0);
+  /* replaces block 4-7 of e0 */
+  auto e1 = make_shared<TestLogEntry>(0, 8);
+  map.add_log_entry(e1);
+
+  /* Written range includes the two writes above */
+  TestLogMapEntries found0 = map.find_map_entries(BlockExtent(0, 100));
+  int numfound = found0.size();
+  ASSERT_EQ(2, numfound);
+  ASSERT_EQ(e1, found0.front().log_entry);
+  ASSERT_EQ(0, found0.front().block_extent.block_start);
+  ASSERT_EQ(8, found0.front().block_extent.block_end);
+  found0.pop_front();
+  ASSERT_EQ(e0, found0.front().log_entry);
+  ASSERT_EQ(8, found0.front().block_extent.block_start);
+  ASSERT_EQ(12, found0.front().block_extent.block_end);
+
+  /* 0-7 will be e1 */
+  for (int i=0; i<8; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(1, numfound);
+    ASSERT_EQ(e1, found0.front().log_entry);
+  }
+
+  /* 8-11 will be e0 */
+  for (int i=8; i<12; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(1, numfound);
+    ASSERT_EQ(e0, found0.front().log_entry);
+  }
+}
+
+TEST_F(TestWriteLogMap, OverlapBack) {
+  TestLogMap map(m_cct);
+
+  auto e0 = make_shared<TestLogEntry>(0, 8);
+  map.add_log_entry(e0);
+  /* replaces block 4-7 of e0 */
+  auto e1 = make_shared<TestLogEntry>(4, 8);
+  map.add_log_entry(e1);
+
+  /* Written range includes the two writes above */
+  TestLogMapEntries found0 = map.find_map_entries(BlockExtent(0, 100));
+  int numfound = found0.size();
+  ASSERT_EQ(2, numfound);
+  ASSERT_EQ(e0, found0.front().log_entry);
+  ASSERT_EQ(0, found0.front().block_extent.block_start);
+  ASSERT_EQ(4, found0.front().block_extent.block_end);
+  found0.pop_front();
+  ASSERT_EQ(e1, found0.front().log_entry);
+  ASSERT_EQ(4, found0.front().block_extent.block_start);
+  ASSERT_EQ(12, found0.front().block_extent.block_end);
+
+  /* 0-3 will be e0 */
+  for (int i=0; i<4; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(1, numfound);
+    ASSERT_EQ(e0, found0.front().log_entry);
+  }
+
+  /* 4-11 will be e1 */
+  for (int i=4; i<12; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(1, numfound);
+    ASSERT_EQ(e1, found0.front().log_entry);
+  }
+
+  map.remove_log_entry(e0);
+
+  /* 0-3 will find nothing */
+  for (int i=0; i<4; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(0, numfound);
+  }
+
+  /* 4-11 will still be e1 */
+  for (int i=4; i<12; i++) {
+    TestLogMapEntries found0 = map.find_map_entries(BlockExtent(i, i + 1));
+    int numfound = found0.size();
+    ASSERT_EQ(1, numfound);
+    ASSERT_EQ(e1, found0.front().log_entry);
+  }
+
+}
+
+TEST_F(TestWriteLogMap, OverlapMiddle) {
+  TestLogMap map(m_cct);
+
+  auto e0 = make_shared<TestLogEntry>(0, 1);
+  map.add_log_entry(e0);
+
+  TestLogMapEntries found0 = map.find_map_entries(BlockExtent(0, 1));
+  int numfound = found0.size();
+  ASSERT_EQ(1, numfound);
+  ASSERT_EQ(e0, found0.front().log_entry);
+  TestLogEntries entries = map.find_log_entries(BlockExtent(0, 1));
+  int entriesfound = entries.size();
+  ASSERT_EQ(1, entriesfound);
+  ASSERT_EQ(e0, entries.front());
+
+  auto e1 = make_shared<TestLogEntry>(1, 1);
+  map.add_log_entry(e1);
+
+  found0 = map.find_map_entries(BlockExtent(1, 2));
+  numfound = found0.size();
+  ASSERT_EQ(1, numfound);
+  ASSERT_EQ(e1, found0.front().log_entry);
+  entries = map.find_log_entries(BlockExtent(1, 2));
+  entriesfound = entries.size();
+  ASSERT_EQ(1, entriesfound);
+  ASSERT_EQ(e1, entries.front());
+
+  auto e2 = make_shared<TestLogEntry>(2, 1);
+  map.add_log_entry(e2);
+
+  found0 = map.find_map_entries(BlockExtent(2, 3));
+  numfound = found0.size();
+  ASSERT_EQ(1, numfound);
+  ASSERT_EQ(e2, found0.front().log_entry);
+  entries = map.find_log_entries(BlockExtent(2, 3));
+  entriesfound = entries.size();
+  ASSERT_EQ(1, entriesfound);
+  ASSERT_EQ(e2, entries.front());
+
+  /* replaces e1 */
+  auto e3 = make_shared<TestLogEntry>(1, 1);
+  map.add_log_entry(e3);
+
+  found0 = map.find_map_entries(BlockExtent(1, 2));
+  numfound = found0.size();
+  ASSERT_EQ(1, numfound);
+  ASSERT_EQ(e3, found0.front().log_entry);
+  entries = map.find_log_entries(BlockExtent(1, 2));
+  entriesfound = entries.size();
+  ASSERT_EQ(1, entriesfound);
+  ASSERT_EQ(e3, entries.front());
+
+  found0 = map.find_map_entries(BlockExtent(0, 100));
+  numfound = found0.size();
+  ASSERT_EQ(3, numfound);
+  ASSERT_EQ(e0, found0.front().log_entry);
+  found0.pop_front();
+  ASSERT_EQ(e3, found0.front().log_entry);
+  found0.pop_front();
+  ASSERT_EQ(e2, found0.front().log_entry);
+  entries = map.find_log_entries(BlockExtent(0, 100));
+  entriesfound = entries.size();
+  ASSERT_EQ(3, entriesfound);
+  ASSERT_EQ(e0, entries.front());
+  entries.pop_front();
+  ASSERT_EQ(e3, entries.front());
+  entries.pop_front();
+  ASSERT_EQ(e2, entries.front());
+
+  entries.clear();
+  entries.emplace_back(e0);
+  entries.emplace_back(e1);
+  map.remove_log_entries(entries);
+
+  found0 = map.find_map_entries(BlockExtent(0, 100));
+  numfound = found0.size();
+  ASSERT_EQ(2, numfound);
+  ASSERT_EQ(e3, found0.front().log_entry);
+  found0.pop_front();
+  ASSERT_EQ(e2, found0.front().log_entry);
+}
+
+TEST_F(TestWriteLogMap, OverlapSplit) {
+  TestLogMap map(m_cct);
+
+  auto e0 = make_shared<TestLogEntry>(0, 8);
+  map.add_log_entry(e0);
+
+  /* Splits e0 at 1 */
+  auto e1 = make_shared<TestLogEntry>(1, 1);
+  map.add_log_entry(e1);
+
+  /* Splits e0 again at 4 */
+  auto e2 = make_shared<TestLogEntry>(4, 2);
+  map.add_log_entry(e2);
+
+  /* Replaces one block of e2, and one of e0 */
+  auto e3 = make_shared<TestLogEntry>(5, 2);
+  map.add_log_entry(e3);
+
+  /* Expecting: 0:e0, 1:e1, 2..3:e0, 4:e2, 5..6:e3, 7:e0 */
+  TestLogMapEntries found0 = map.find_map_entries(BlockExtent(0, 100));
+  int numfound = found0.size();
+  ASSERT_EQ(6, numfound);
+  ASSERT_EQ(e0, found0.front().log_entry);
+  ASSERT_EQ(0, found0.front().block_extent.block_start);
+  ASSERT_EQ(1, found0.front().block_extent.block_end);
+  found0.pop_front();
+  ASSERT_EQ(e1, found0.front().log_entry);
+  ASSERT_EQ(1, found0.front().block_extent.block_start);
+  ASSERT_EQ(2, found0.front().block_extent.block_end);
+  found0.pop_front();
+  ASSERT_EQ(e0, found0.front().log_entry);
+  ASSERT_EQ(2, found0.front().block_extent.block_start);
+  ASSERT_EQ(4, found0.front().block_extent.block_end);
+  found0.pop_front();
+  ASSERT_EQ(e2, found0.front().log_entry);
+  ASSERT_EQ(4, found0.front().block_extent.block_start);
+  ASSERT_EQ(5, found0.front().block_extent.block_end);
+  found0.pop_front();
+  ASSERT_EQ(e3, found0.front().log_entry);
+  ASSERT_EQ(5, found0.front().block_extent.block_start);
+  ASSERT_EQ(7, found0.front().block_extent.block_end);
+  found0.pop_front();
+  ASSERT_EQ(e0, found0.front().log_entry);
+  ASSERT_EQ(7, found0.front().block_extent.block_start);
+  ASSERT_EQ(8, found0.front().block_extent.block_end);
+}
+
+} // namespace rwl
+} // namespace cache
+} // namespace librbd