#include <boost/random/uniform_int.hpp>
#include <boost/random/binomial_distribution.hpp>
#include <gtest/gtest.h>
+#include <fmt/format.h>
#include "os/ObjectStore.h"
#include "os/filestore/FileStore.h"
#endif
"kstore"));
+struct deferred_test_t {
+ uint32_t bdev_block_size;
+ uint32_t min_alloc_size;
+ uint32_t max_blob_size;
+ uint32_t prefer_deferred_size;
+};
+
+void PrintTo(const deferred_test_t& t, ::std::ostream* os)
+{
+ *os << t.bdev_block_size << "/" << t.min_alloc_size << "/"
+ << t.max_blob_size << "/" << t.prefer_deferred_size;
+}
+
+class DeferredWriteTest : public StoreTestFixture,
+ public ::testing::WithParamInterface<deferred_test_t> {
+public:
+ DeferredWriteTest()
+ : StoreTestFixture("bluestore")
+ {}
+ void SetUp() override {
+ //do nothing
+ }
+protected:
+ void DeferredSetup() {
+ StoreTestFixture::SetUp();
+ }
+public:
+ std::vector<uint32_t> offsets = {0, 3000, 4096, 20000, 32768, 65000, 65536, 80000, 128 * 1024};
+ std::vector<uint32_t> lengths = {1, 1000, 4096, 12000, 32768, 30000, 80000, 128 * 1024};
+};
+
+TEST_P(DeferredWriteTest, NewData) {
+ const bool print = false;
+ deferred_test_t t = GetParam();
+ SetVal(g_conf(), "bdev_block_size", stringify(t.bdev_block_size).c_str());
+ SetVal(g_conf(), "bluestore_min_alloc_size", stringify(t.min_alloc_size).c_str());
+ SetVal(g_conf(), "bluestore_max_blob_size", stringify(t.max_blob_size).c_str());
+ SetVal(g_conf(), "bluestore_prefer_deferred_size", stringify(t.prefer_deferred_size).c_str());
+ g_conf().apply_changes(nullptr);
+ DeferredSetup();
+
+ int r;
+ coll_t cid;
+ const PerfCounters* logger = store->get_perf_counters();
+ ObjectStore::CollectionHandle ch = store->create_new_collection(cid);
+ {
+ ObjectStore::Transaction t;
+ t.create_collection(cid, 0);
+ r = queue_transaction(store, ch, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+ {
+ for (auto offset:offsets) {
+ for (auto length:lengths) {
+ std::string hname = fmt::format("test-{}-{}", offset, length);
+ ghobject_t hoid(hobject_t(hname, "", CEPH_NOSNAP, 0, -1, ""));
+ {
+ ObjectStore::Transaction t;
+ t.touch(cid, hoid);
+ r = queue_transaction(store, ch, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+ if (print)
+ std::cout << hname << std::endl;
+
+ auto w_new = logger->get(l_bluestore_write_new);
+ auto w_big_deferred = logger->get(l_bluestore_write_big_deferred);
+ auto i_deferred_w = logger->get(l_bluestore_write_deferred);
+ {
+ ObjectStore::Transaction t;
+ bufferlist bl;
+ bl.append(std::string(length, 'x'));
+ t.write(cid, hoid, offset, bl.length(), bl,
+ CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
+ r = queue_transaction(store, ch, std::move(t));
+ ASSERT_EQ(r, 0);
+ }
+ uint32_t first_db = offset / t.bdev_block_size;
+ uint32_t last_db = (offset + length - 1) / t.bdev_block_size;
+
+ uint32_t write_size = (last_db - first_db + 1) * t.bdev_block_size;
+ if (write_size < t.prefer_deferred_size) {
+ // expect no direct writes
+ ASSERT_EQ(w_new , logger->get(l_bluestore_write_new));
+ } else {
+ // expect no deferred
+ ASSERT_EQ(w_big_deferred , logger->get(l_bluestore_write_big_deferred));
+ ASSERT_EQ(i_deferred_w , logger->get(l_bluestore_write_deferred));
+ }
+ }
+ }
+ }
+}
+
+#if defined(WITH_BLUESTORE)
+INSTANTIATE_TEST_SUITE_P(
+ BlueStore,
+ DeferredWriteTest,
+ ::testing::Values(
+ // bdev alloc blob deferred
+ deferred_test_t{4 * 1024, 4 * 1024, 16 * 1024, 32 * 1024},
+ deferred_test_t{4 * 1024, 16 * 1024, 64 * 1024, 64 * 1024},
+ deferred_test_t{4 * 1024, 64 * 1024, 64 * 1024, 4 * 1024},
+ deferred_test_t{4 * 1024, 4 * 1024, 64 * 1024, 0 * 1024},
+ deferred_test_t{4 * 1024, 16 * 1024, 32 * 1024, 32 * 1024},
+ deferred_test_t{4 * 1024, 16 * 1024, 64 * 1024, 128 * 1024}
+ ));
+#endif
+
void doMany4KWritesTest(boost::scoped_ptr<ObjectStore>& store,
unsigned max_objects,
unsigned max_ops,