]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: Add more legacy -> per PG upgrade tests
authorAdam Kupczyk <akupczyk@redhat.com>
Sat, 13 Nov 2021 09:41:14 +0000 (10:41 +0100)
committerNeha Ojha <nojha@redhat.com>
Fri, 19 Nov 2021 19:31:30 +0000 (19:31 +0000)
Signed-off-by: Adam Kupczyk <akupczyk@redhat.com>
(cherry picked from commit 0d13d64e0543ffbb95cbb0a2b00843ee0ec98331)

 Conflicts:
src/test/objectstore/store_test.cc

src/test/objectstore/store_test.cc

index c3926a3bf4a43e6527c8e9b41aee36074b58316f..970c0cf2ae474bcae8038937d8a523e75aa94203 100644 (file)
@@ -255,6 +255,139 @@ protected:
 
 };
 
+class StoreTestOmapUpgrade : public StoreTestDeferredSetup {
+protected:
+  void StartDeferred() {
+    DeferredSetup();
+  }
+
+public:
+  struct generator {
+    double r = 3.6;
+    double x = 0.5;
+    double operator()(){
+      double v = x;
+      x = r * x * (1 - x);
+      return v;
+    }
+  };
+
+  std::string generate_monotonic_name(uint32_t SUM, uint32_t i, double r, double x)
+  {
+    generator gen{r, x};
+    //std::cout << "r=" << r << " x=" << x << std::endl;
+    std::string s;
+    while (SUM > 1) {
+      uint32_t lo = 0;
+      uint32_t hi = 1 + gen() * 10;
+      uint32_t start = ('z' - 'a' + 1 - hi) * gen();
+      while (hi - lo > 0) {
+       uint32_t mid = (lo + hi + 1 + (SUM&1)) / 2; // round up or down, depending on SUM
+       //      std::cout << "SUM=" << SUM << " x=" << gen.x << std::endl;
+       uint32_t mid_val = gen() * (SUM - 1) + 1;
+       // LEFT  = lo  .. mid - 1
+       // RIGHT = mid .. hi
+       //      std::cout << "lo=" << lo << " hi=" << hi << " mid=" << mid
+       //      << " SUM=" << SUM << " i=" << i << " x=" << gen.x << " mid_val=" << mid_val << std::endl;
+       if (i < mid_val) {
+         hi = mid - 1;
+         SUM = mid_val;
+       } else {
+         lo = mid;
+         SUM = SUM - mid_val;
+         i = i - mid_val;
+       }
+      }
+      //std::cout << "lo=" << lo << " hi=" << hi
+      //             << " SUM=" << SUM << " i=" << i << std::endl;
+
+      s.push_back('a' + lo  + start); // to keep alphabetic order
+      uint32_t cnt = gen() * 8;
+      for (uint32_t j = 0; j < cnt; j++) {
+       s.push_back('a' + ('z' - 'a' + 1) * gen());
+      }
+      s.push_back('.');
+    }
+    return s;
+  }
+
+  std::string gen_string(size_t size, generator& gen) {
+    std::string s;
+    for (size_t i = 0; i < size; i++) {
+      s.push_back('a' + ('z' - 'a' + 1 ) * gen());
+    }
+    return s;
+  }
+
+  void make_omap_data(size_t object_count,
+                     int64_t poolid,
+                     coll_t cid) {
+    int r;
+    ObjectStore::CollectionHandle ch = store->open_collection(cid);
+    for (size_t o = 0; o < object_count; o++)
+    {
+      ObjectStore::Transaction t;
+      std::string oid = generate_monotonic_name(object_count, o, 3.71, 0.5);
+      ghobject_t hoid(hobject_t(oid, "", CEPH_NOSNAP, 0, poolid, ""));
+      t.touch(cid, hoid);
+      generator gen{3.85 + 0.1 * o / object_count, 1 - double(o) / object_count};
+
+      map<string, bufferlist> start_set;
+      size_t omap_count = 1 + gen() * 20;
+      bool do_omap_header = gen() > 0.5;
+      if (do_omap_header) {
+       bufferlist header;
+       header.append(gen_string(50, gen));
+       t.omap_setheader(cid, hoid, header);
+      }
+      for (size_t i = 0; i < omap_count; i++) {
+       std::string name = generate_monotonic_name(omap_count, i, 3.66 + 0.22 * o / object_count, 0.5);
+       bufferlist val;
+       val.append(gen_string(100, gen));
+       start_set.emplace(name, val);
+      }
+      t.omap_setkeys(cid, hoid, start_set);
+      r = queue_transaction(store, ch, std::move(t));
+      ASSERT_EQ(r, 0);
+    }
+  }
+
+  void check_omap_data(size_t object_count,
+                      int64_t poolid,
+                      coll_t cid) {
+    int r;
+    ObjectStore::CollectionHandle ch = store->open_collection(cid);
+
+    for (size_t o = 0; o < object_count; o++)
+    {
+      ObjectStore::Transaction t;
+      std::string oid = generate_monotonic_name(object_count, o, 3.71, 0.5);
+      ghobject_t hoid(hobject_t(oid, "", CEPH_NOSNAP, 0, poolid, ""));
+      generator gen{3.85 + 0.1 * o / object_count, 1 - double(o) / object_count};
+
+      bufferlist omap_header;
+      map<string, bufferlist> omap_set;
+      r = store->omap_get(ch, hoid, &omap_header, &omap_set);
+      ASSERT_EQ(r, 0);
+      size_t omap_count = 1 + gen() * 20;
+      bool do_omap_header = gen() > 0.5;
+      if (do_omap_header) {
+       std::string header_str = gen_string(50, gen);
+       ASSERT_EQ(header_str, omap_header.to_str());
+      }
+      auto it = omap_set.begin();
+      for (size_t i = 0; i < omap_count; i++) {
+       ASSERT_TRUE(it != omap_set.end());
+       std::string name = generate_monotonic_name(omap_count, i, 3.66 + 0.22 * o / object_count, 0.5);
+       std::string val_gen = gen_string(100, gen);
+       ASSERT_EQ(it->first, name);
+       ASSERT_EQ(it->second.to_str(), val_gen);
+       ++it;
+      }
+    }
+  }
+};
+
 TEST_P(StoreTest, collect_metadata) {
   map<string,string> pm;
   store->collect_metadata(&pm);
@@ -6678,7 +6811,20 @@ INSTANTIATE_TEST_SUITE_P(
 #endif
     "kstore"));
 
-void doMany4KWritesTest(boost::scoped_ptr<ObjectStore>& store,
+// Note: instantiate all stores to preserve store numbering order only
+INSTANTIATE_TEST_SUITE_P(
+  ObjectStore,
+  StoreTestOmapUpgrade,
+  ::testing::Values(
+    "memstore",
+    "filestore",
+#if defined(WITH_BLUESTORE)
+    "bluestore",
+#endif
+    "kstore"));
+
+//void doMany4KWritesTest(boost::scoped_ptr<ObjectStore>& store,
+void doMany4KWritesTest(ObjectStore* store,
                         unsigned max_objects,
                         unsigned max_ops,
                         unsigned max_object_size,
@@ -9454,14 +9600,14 @@ TEST_P(StoreTestSpecificAUSize, Ticket45195Repro) {
   ASSERT_EQ(r, 0x10000);
 }
 
-TEST_P(StoreTestSpecificAUSize, OmapUpgradeTest) {
+TEST_P(StoreTestOmapUpgrade, WithOmapHeader) {
   if (string(GetParam()) != "bluestore")
     return;
 
   SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
   g_conf().apply_changes(nullptr);
 
-  StartDeferred(0x1000);
+  StartDeferred();
   int64_t poolid = 11;
   coll_t cid(spg_t(pg_t(1, poolid), shard_id_t::NO_SHARD));
   ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, poolid, ""));
@@ -9588,6 +9734,131 @@ TEST_P(StoreTestSpecificAUSize, BluefsWriteInNoWalDiskEnvTest) {
   }
 }
 
+TEST_P(StoreTestOmapUpgrade, NoOmapHeader) {
+  if (string(GetParam()) != "bluestore")
+    return;
+
+  SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
+  g_conf().apply_changes(nullptr);
+
+  StartDeferred();
+  int64_t poolid = 11;
+  coll_t cid(spg_t(pg_t(1, poolid), shard_id_t::NO_SHARD));
+  ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, poolid, ""));
+  auto ch = store->create_new_collection(cid);
+  int r;
+  {
+    ObjectStore::Transaction t;
+    t.create_collection(cid, 0);
+    r = queue_transaction(store, ch, std::move(t));
+    ASSERT_EQ(r, 0);
+  }
+
+  map<string, bufferlist> attrs;
+  {
+    ObjectStore::Transaction t;
+    t.touch(cid, hoid);
+    map<string, bufferlist> start_set;
+    bufferlist bl;
+    bl.append(string("value"));
+    start_set.emplace(string("key1"), bl);
+    t.omap_setkeys(cid, hoid, start_set);
+    r = queue_transaction(store, ch, std::move(t));
+  }
+  {
+    map<string,bufferlist> res;
+    bufferlist h;
+    r = store->omap_get(ch, hoid, &h, &res);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ(h.length(), 0);
+    ASSERT_EQ(res.size(), 1);
+    ASSERT_EQ(res.begin()->first, "key1");
+  }
+  store->umount();
+  ASSERT_EQ(store->fsck(false), 0);
+  SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
+  SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
+  g_conf().apply_changes(nullptr);
+  ASSERT_EQ(store->fsck(false), 2);
+  ASSERT_EQ(store->quick_fix(), 0);
+  store->mount();
+  ch = store->open_collection(cid);
+  {
+    map<string,bufferlist> res;
+    bufferlist h;
+    r = store->omap_get(ch, hoid, &h, &res);
+    ASSERT_EQ(r, 0);
+    ASSERT_EQ(res.size(), 1);
+    ASSERT_EQ(res.begin()->first, "key1");
+  }
+  {
+    ObjectStore::Transaction t;
+    t.remove(cid, hoid);
+    t.remove_collection(cid);
+    r = queue_transaction(store, ch, std::move(t));
+    ASSERT_EQ(r, 0);
+  }
+}
+
+TEST_P(StoreTestOmapUpgrade, LargeLegacyToPG) {
+  if (string(GetParam()) != "bluestore")
+    return;
+
+  SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
+  g_conf().apply_changes(nullptr);
+
+  int64_t poolid;
+  coll_t cid;
+  ghobject_t hoid;
+  ObjectStore::CollectionHandle ch;
+  StartDeferred();
+  poolid = 11;
+  cid = coll_t(spg_t(pg_t(1, poolid), shard_id_t::NO_SHARD));
+  ch = store->create_new_collection(cid);
+  int r;
+  {
+    ObjectStore::Transaction t;
+    t.create_collection(cid, 0);
+    r = queue_transaction(store, ch, std::move(t));
+    ASSERT_EQ(r, 0);
+  }
+  //ASSERT_EQ(false, g_conf().get_val<bool>("bluestore_debug_inject_upgrade_bug53062"));
+  map<string, bufferlist> attrs;
+  bufferlist expected_header;
+  expected_header.append("this is a header");
+
+  size_t object_count = 1000;
+  make_omap_data(object_count, poolid, cid);
+  //checking just written data
+  check_omap_data(object_count, poolid, cid);
+
+  store->umount();
+  ASSERT_EQ(store->fsck(false), 0);
+  SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
+  SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
+  g_conf().apply_changes(nullptr);
+  ASSERT_EQ(store->fsck(false), 1001);
+  ASSERT_EQ(store->quick_fix(), 0);
+  store->mount();
+  ch = store->open_collection(cid);
+
+  //checking quick_fix() data
+  check_omap_data(object_count, poolid, cid);
+
+  {
+    ObjectStore::Transaction t;
+    for (size_t o = 0; o < object_count; o++)
+    {
+      std::string oid = generate_monotonic_name(object_count, o, 3.71, 0.5);
+      ghobject_t hoid(hobject_t(oid, "", CEPH_NOSNAP, 0, poolid, ""));
+      t.remove(cid, hoid);
+    }
+    t.remove_collection(cid);
+    r = queue_transaction(store, ch, std::move(t));
+    ASSERT_EQ(r, 0);
+  }
+}
+
 #endif  // WITH_BLUESTORE
 
 int main(int argc, char **argv) {