]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
test/crimson/seastore/test_transaction_manager: add random overwrite test
authorSamuel Just <sjust@redhat.com>
Thu, 20 Aug 2020 21:17:31 +0000 (14:17 -0700)
committerSamuel Just <sjust@redhat.com>
Fri, 25 Sep 2020 19:51:47 +0000 (12:51 -0700)
Also improves replay() by recycling all structures except for the
segment_manager.

Signed-off-by: Samuel Just <sjust@redhat.com>
src/test/crimson/seastore/test_block.h
src/test/crimson/seastore/test_transaction_manager.cc

index e105ccec7533bd5a344b38747212a3bc724d393b..44ec65a2375161a2fc7518b617bdb1c36a088fc7 100644 (file)
@@ -126,20 +126,19 @@ struct test_block_mutator_t {
   offset_distribution = std::uniform_int_distribution<uint16_t>(
     0, TestBlock::SIZE - 1);
 
-  std::default_random_engine generator = std::default_random_engine(0);
-
   std::uniform_int_distribution<uint16_t> length_distribution(uint16_t offset) {
     return std::uniform_int_distribution<uint16_t>(
       0, TestBlock::SIZE - offset - 1);
   }
 
 
-  void mutate(TestBlock &block) {
-    auto offset = offset_distribution(generator);
+  template <typename generator_t>
+  void mutate(TestBlock &block, generator_t &gen) {
+    auto offset = offset_distribution(gen);
     block.set_contents(
-      contents_distribution(generator),
+      contents_distribution(gen),
       offset,
-      length_distribution(offset)(generator));
+      length_distribution(offset)(gen));
   }
 };
 
index e0e72be8a99af7f330e887487ffc62cf92ff2e27..843618fb303cbff3cb0f93a6ea10ae2f967753fe 100644 (file)
@@ -1,6 +1,8 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
+#include <random>
+
 #include "test/crimson/gtest_seastar.h"
 
 #include "crimson/os/seastore/segment_cleaner.h"
@@ -47,31 +49,57 @@ std::ostream &operator<<(std::ostream &lhs, const test_extent_record_t &rhs) {
 
 struct transaction_manager_test_t : public seastar_test_suite_t {
   std::unique_ptr<SegmentManager> segment_manager;
-  SegmentCleaner segment_cleaner;
-  Journal journal;
-  Cache cache;
+  std::unique_ptr<SegmentCleaner> segment_cleaner;
+  std::unique_ptr<Journal> journal;
+  std::unique_ptr<Cache> cache;
   LBAManagerRef lba_manager;
-  TransactionManager tm;
+  std::unique_ptr<TransactionManager> tm;
+
+  std::random_device rd;
+  std::mt19937 gen;
 
   transaction_manager_test_t()
     : segment_manager(create_ephemeral(segment_manager::DEFAULT_TEST_EPHEMERAL)),
-      segment_cleaner(
-       SegmentCleaner::config_t::default_from_segment_manager(
-         *segment_manager)),
-      journal(*segment_manager),
-      cache(*segment_manager),
-      lba_manager(
-       lba_manager::create_lba_manager(*segment_manager, cache)),
-      tm(*segment_manager, segment_cleaner, journal, cache, *lba_manager) {
-    journal.set_segment_provider(&segment_cleaner);
-    segment_cleaner.set_extent_callback(&tm);
+      gen(rd()) {
+    init();
+  }
+
+  void init() {
+    segment_cleaner = std::make_unique<SegmentCleaner>(
+      SegmentCleaner::config_t::default_from_segment_manager(
+       *segment_manager));
+    journal = std::make_unique<Journal>(*segment_manager);
+    cache = std::make_unique<Cache>(*segment_manager);
+    lba_manager = lba_manager::create_lba_manager(*segment_manager, *cache);
+    tm = std::make_unique<TransactionManager>(
+      *segment_manager, *segment_cleaner, *journal, *cache, *lba_manager);
+
+    journal->set_segment_provider(&*segment_cleaner);
+    segment_cleaner->set_extent_callback(&*tm);
+  }
+
+  void destroy() {
+    tm.reset();
+    lba_manager.reset();
+    cache.reset();
+    journal.reset();
+    segment_cleaner.reset();
+  }
+
+  laddr_t get_random_laddr(size_t block_size, laddr_t limit) {
+    return block_size *
+      std::uniform_int_distribution<>(0, (limit / block_size) - 1)(gen);
+  }
+
+  char get_random_contents() {
+    return static_cast<char>(std::uniform_int_distribution<>(0, 255)(gen));
   }
 
   seastar::future<> set_up_fut() final {
     return segment_manager->init().safe_then([this] {
-      return tm.mkfs();
+      return tm->mkfs();
     }).safe_then([this] {
-      return tm.mount();
+      return tm->mount();
     }).handle_error(
       crimson::ct_error::all_same_way([] {
        ASSERT_FALSE("Unable to mount");
@@ -80,7 +108,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
   }
 
   seastar::future<> tear_down_fut() final {
-    return tm.close(
+    return tm->close(
     ).handle_error(
       crimson::ct_error::all_same_way([] {
        ASSERT_FALSE("Unable to close");
@@ -135,7 +163,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
   };
 
   test_transaction_t create_transaction() {
-    return { tm.create_transaction(), test_mappings };
+    return { tm->create_transaction(), test_mappings };
   }
 
   TestBlockRef alloc_extent(
@@ -143,7 +171,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
     laddr_t hint,
     extent_len_t len,
     char contents) {
-    auto extent = tm.alloc_extent<TestBlock>(
+    auto extent = tm->alloc_extent<TestBlock>(
       *(t.t),
       hint,
       len).unsafe_get0();
@@ -154,9 +182,24 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
     return extent;
   }
 
+  TestBlockRef alloc_extent(
+    test_transaction_t &t,
+    laddr_t hint,
+    extent_len_t len) {
+    return alloc_extent(
+      t,
+      hint,
+      len,
+      get_random_contents());
+  }
+
   void replay() {
-    tm.close().unsafe_get();
-    tm.mount().unsafe_get();
+    tm->close().unsafe_get();
+    auto next = segment_cleaner->get_next();
+    destroy();
+    init();
+    segment_cleaner->set_next(next);
+    tm->mount().unsafe_get();
   }
 
   void check_mappings() {
@@ -171,7 +214,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
     ceph_assert(t.mappings.count(addr));
     ceph_assert(t.mappings[addr].desc.len == len);
 
-    auto ret_list = tm.read_extents<TestBlock>(
+    auto ret_list = tm->read_extents<TestBlock>(
       *t.t, addr, len
     ).unsafe_get0();
     EXPECT_EQ(ret_list.size(), 1);
@@ -188,10 +231,10 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
     TestBlockRef ref) {
     ceph_assert(t.mappings.count(ref->get_laddr()));
     ceph_assert(t.mappings[ref->get_laddr()].desc.len == ref->get_length());
-    auto ext = tm.get_mutable_extent(*t.t, ref)->cast<TestBlock>();
+    auto ext = tm->get_mutable_extent(*t.t, ref)->cast<TestBlock>();
     EXPECT_EQ(ext->get_laddr(), ref->get_laddr());
     EXPECT_EQ(ext->get_desc(), ref->get_desc());
-    mutator.mutate(*ext);
+    mutator.mutate(*ext, gen);
     t.mappings[ext->get_laddr()].update(ext->get_desc());
     return ext;
   }
@@ -199,7 +242,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
   void inc_ref(test_transaction_t &t, laddr_t offset) {
     ceph_assert(t.mappings.count(offset));
     ceph_assert(t.mappings[offset].refcount > 0);
-    auto refcnt = tm.inc_ref(*t.t, offset).unsafe_get0();
+    auto refcnt = tm->inc_ref(*t.t, offset).unsafe_get0();
     t.mappings[offset].refcount++;
     EXPECT_EQ(refcnt, t.mappings[offset].refcount);
   }
@@ -207,7 +250,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
   void dec_ref(test_transaction_t &t, laddr_t offset) {
     ceph_assert(t.mappings.count(offset));
     ceph_assert(t.mappings[offset].refcount > 0);
-    auto refcnt = tm.dec_ref(*t.t, offset).unsafe_get0();
+    auto refcnt = tm->dec_ref(*t.t, offset).unsafe_get0();
     t.mappings[offset].refcount--;
     EXPECT_EQ(refcnt, t.mappings[offset].refcount);
     if (t.mappings[offset].refcount == 0) {
@@ -224,7 +267,7 @@ struct transaction_manager_test_t : public seastar_test_suite_t {
   }
 
   void submit_transaction(test_transaction_t t) {
-    tm.submit_transaction(std::move(t.t)).unsafe_get();
+    tm->submit_transaction(std::move(t.t)).unsafe_get();
     test_mappings = t.mappings;
   }
 };
@@ -382,3 +425,46 @@ TEST_F(transaction_manager_test_t, cause_lba_split)
     check_mappings();
   });
 }
+
+TEST_F(transaction_manager_test_t, random_writes)
+{
+  constexpr size_t TOTAL = 4<<20;
+  constexpr size_t BSIZE = 4<<10;
+  constexpr size_t PADDING_SIZE = 256<<10;
+  constexpr size_t BLOCKS = TOTAL / BSIZE;
+  run_async([this] {
+    for (unsigned i = 0; i < BLOCKS; ++i) {
+      auto t = create_transaction();
+      auto extent = alloc_extent(
+       t,
+       i * BSIZE,
+       BSIZE);
+      ASSERT_EQ(i * BSIZE, extent->get_laddr());
+      submit_transaction(std::move(t));
+    }
+
+    for (unsigned i = 0; i < 5; ++i) {
+      for (unsigned j = 0; j < 50; ++j) {
+       auto t = create_transaction();
+       for (unsigned k = 0; k < 2; ++k) {
+         auto ext = get_extent(
+           t,
+           get_random_laddr(BSIZE, TOTAL),
+           BSIZE);
+         auto mut = mutate_extent(t, ext);
+         // pad out transaction
+         auto padding = alloc_extent(
+           t,
+           TOTAL + (k * PADDING_SIZE),
+           PADDING_SIZE);
+         dec_ref(t, padding->get_laddr());
+       }
+       submit_transaction(std::move(t));
+      }
+      replay();
+      logger().debug("random_writes: checking");
+      check_mappings();
+      logger().debug("random_writes: done replaying/checking");
+    }
+  });
+}