@@ -7101,6 +7101,201 @@ INSTANTIATE_TEST_SUITE_P(
71017101 ));
71027102#endif
71037103
7104+ class DeferredReplayTest : public DeferredWriteTest {
7105+ };
7106+
7107+ TEST_P (DeferredReplayTest, DeferredReplay) {
7108+ const bool print = false ;
7109+ deferred_test_t t = GetParam ();
7110+ SetVal (g_conf (), " bdev_block_size" , stringify (t.bdev_block_size ).c_str ());
7111+ SetVal (g_conf (), " bluestore_min_alloc_size" , stringify (t.min_alloc_size ).c_str ());
7112+ SetVal (g_conf (), " bluestore_max_blob_size" , stringify (t.max_blob_size ).c_str ());
7113+ SetVal (g_conf (), " bluestore_prefer_deferred_size" , stringify (t.prefer_deferred_size ).c_str ());
7114+ // forbid periodic deferred ops submission to keep them pending
7115+ // until umount.
7116+ SetVal (g_conf (), " bluestore_max_defer_interval" , " 0" );
7117+ g_conf ().apply_changes (nullptr );
7118+ DeferredSetup ();
7119+
7120+ int r;
7121+ coll_t cid;
7122+ const PerfCounters* logger = store->get_perf_counters ();
7123+ ObjectStore::CollectionHandle ch = store->create_new_collection (cid);
7124+ {
7125+ ObjectStore::Transaction t;
7126+ t.create_collection (cid, 0 );
7127+ r = queue_transaction (store, ch, std::move (t));
7128+ ASSERT_EQ (r, 0 );
7129+ }
7130+ {
7131+ auto offset = offsets[0 ];
7132+ auto length = lengths[0 ];
7133+ std::string hname = fmt::format (" test-{}-{}" , offset, length);
7134+ ghobject_t hoid (hobject_t (hname, " " , CEPH_NOSNAP, 0 , -1 , " " ));
7135+ {
7136+ ObjectStore::Transaction t;
7137+ t.touch (cid, hoid);
7138+ r = queue_transaction (store, ch, std::move (t));
7139+ ASSERT_EQ (r, 0 );
7140+ }
7141+ if (print)
7142+ std::cout << hname << std::endl;
7143+
7144+ auto w_new = logger->get (l_bluestore_write_new);
7145+ auto i_deferred_w = logger->get (l_bluestore_issued_deferred_writes);
7146+ {
7147+ C_SaferCond c;
7148+ ObjectStore::Transaction t;
7149+ bufferlist bl;
7150+ bl.append (std::string (length, ' x' ));
7151+ t.write (cid, hoid, offset, bl.length (), bl,
7152+ CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7153+ t.register_on_commit (&c);
7154+ r = queue_transaction (store, ch, std::move (t));
7155+ ASSERT_EQ (r, 0 );
7156+ c.wait ();
7157+ }
7158+ uint32_t first_db = offset / t.bdev_block_size ;
7159+ uint32_t last_db = (offset + length - 1 ) / t.bdev_block_size ;
7160+
7161+ uint32_t write_size = (last_db - first_db + 1 ) * t.bdev_block_size ;
7162+ if (write_size < t.prefer_deferred_size ) {
7163+ // expect no direct writes
7164+ ASSERT_EQ (w_new, logger->get (l_bluestore_write_new));
7165+ ASSERT_EQ (i_deferred_w + 1 , logger->get (l_bluestore_issued_deferred_writes));
7166+ ASSERT_EQ (0 , logger->get (l_bluestore_submitted_deferred_writes));
7167+ }
7168+ }
7169+ auto cct = store->cct ;
7170+ // disable DB txc commits during umount,
7171+ // hence deferred op(s) aren't fully committed and
7172+ // are left pending in DB.
7173+ //
7174+ SetVal (g_conf (), " bluestore_debug_omit_kv_commit" , " true" );
7175+ g_conf ().apply_changes (nullptr );
7176+ store->umount ();
7177+ SetVal (g_conf (), " bluestore_debug_omit_kv_commit" , " false" );
7178+ g_conf ().apply_changes (nullptr );
7179+ store = ObjectStore::create (cct,
7180+ get_type (),
7181+ get_data_dir (),
7182+ " store_test_temp_journal" );
7183+ store->mount ();
7184+ logger = store->get_perf_counters ();
7185+ // mount performs deferred ops replay and submits pending ones,
7186+ // hence we get a submitted deferred write.
7187+ ASSERT_EQ (1 , logger->get (l_bluestore_submitted_deferred_writes));
7188+ }
7189+
7190+
7191+ TEST_P (DeferredReplayTest, DeferredReplayInReadOnly) {
7192+ const bool print = false ;
7193+ deferred_test_t t = GetParam ();
7194+ SetVal (g_conf (), " bdev_block_size" , stringify (t.bdev_block_size ).c_str ());
7195+ SetVal (g_conf (), " bluestore_min_alloc_size" , stringify (t.min_alloc_size ).c_str ());
7196+ SetVal (g_conf (), " bluestore_max_blob_size" , stringify (t.max_blob_size ).c_str ());
7197+ SetVal (g_conf (), " bluestore_prefer_deferred_size" , stringify (t.prefer_deferred_size ).c_str ());
7198+ // forbid periodic deferred ops submission to keep them pending
7199+ // until umount.
7200+ SetVal (g_conf (), " bluestore_max_defer_interval" , " 0" );
7201+ g_conf ().apply_changes (nullptr );
7202+ DeferredSetup ();
7203+
7204+ int r;
7205+ coll_t cid;
7206+ const PerfCounters* logger = store->get_perf_counters ();
7207+ ObjectStore::CollectionHandle ch = store->create_new_collection (cid);
7208+ {
7209+ ObjectStore::Transaction t;
7210+ t.create_collection (cid, 0 );
7211+ r = queue_transaction (store, ch, std::move (t));
7212+ ASSERT_EQ (r, 0 );
7213+ }
7214+ {
7215+ auto offset = offsets[0 ];
7216+ auto length = lengths[0 ];
7217+ std::string hname = fmt::format (" test-{}-{}" , offset, length);
7218+ ghobject_t hoid (hobject_t (hname, " " , CEPH_NOSNAP, 0 , -1 , " " ));
7219+ {
7220+ ObjectStore::Transaction t;
7221+ t.touch (cid, hoid);
7222+ r = queue_transaction (store, ch, std::move (t));
7223+ ASSERT_EQ (r, 0 );
7224+ }
7225+ if (print)
7226+ std::cout << hname << std::endl;
7227+
7228+ auto w_new = logger->get (l_bluestore_write_new);
7229+ auto i_deferred_w = logger->get (l_bluestore_issued_deferred_writes);
7230+ {
7231+ C_SaferCond c;
7232+ ObjectStore::Transaction t;
7233+ bufferlist bl;
7234+ bl.append (std::string (length, ' x' ));
7235+ t.write (cid, hoid, offset, bl.length (), bl,
7236+ CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7237+ t.register_on_commit (&c);
7238+ r = queue_transaction (store, ch, std::move (t));
7239+ ASSERT_EQ (r, 0 );
7240+ c.wait ();
7241+ }
7242+ uint32_t first_db = offset / t.bdev_block_size ;
7243+ uint32_t last_db = (offset + length - 1 ) / t.bdev_block_size ;
7244+
7245+ uint32_t write_size = (last_db - first_db + 1 ) * t.bdev_block_size ;
7246+ if (write_size < t.prefer_deferred_size ) {
7247+ // expect no direct writes
7248+ ASSERT_EQ (w_new, logger->get (l_bluestore_write_new));
7249+ ASSERT_EQ (i_deferred_w + 1 , logger->get (l_bluestore_issued_deferred_writes));
7250+ ASSERT_EQ (0 , logger->get (l_bluestore_submitted_deferred_writes));
7251+ }
7252+ }
7253+ auto cct = store->cct ;
7254+ // disable DB txc commits during umount,
7255+ // hence deferred op(s) aren't fully committed and
7256+ // kept in DB.
7257+ //
7258+ SetVal (g_conf (), " bluestore_debug_omit_kv_commit" , " true" );
7259+ g_conf ().apply_changes (nullptr );
7260+ store->umount ();
7261+ SetVal (g_conf (), " bluestore_debug_omit_kv_commit" , " false" );
7262+ g_conf ().apply_changes (nullptr );
7263+ store = ObjectStore::create (cct,
7264+ get_type (),
7265+ get_data_dir (),
7266+ " store_test_temp_journal" );
7267+ store->mount_readonly ();
7268+ logger = store->get_perf_counters ();
7269+ // make sure we don't inherit old perf counters from the previous mount
7270+ ASSERT_EQ (0 , logger->get (l_bluestore_issued_deferred_writes));
7271+ // mount_readonly performs deferred ops replay and submits pending ones,
7272+ // hence we get a submitted deferred write.
7273+ // Deferred op isn't removed though - will see that on the next mount.
7274+ ASSERT_EQ (1 , logger->get (l_bluestore_submitted_deferred_writes));
7275+
7276+ store->umount_readonly ();
7277+ store = ObjectStore::create (cct,
7278+ get_type (),
7279+ get_data_dir (),
7280+ " store_test_temp_journal" );
7281+ store->mount ();
7282+ logger = store->get_perf_counters ();
7283+ // mount performs deferred ops replay and submits pending ones,
7284+ // preceding mount_readonly left deferred op pending, although applied it.
7285+ // Hence we get a submitted deferred write once again.
7286+ ASSERT_EQ (1 , logger->get (l_bluestore_submitted_deferred_writes));
7287+ }
7288+
7289+ #if defined(WITH_BLUESTORE)
7290+ INSTANTIATE_TEST_SUITE_P (
7291+ BlueStore,
7292+ DeferredReplayTest,
7293+ ::testing::Values (
7294+ // bdev alloc blob deferred
7295+ deferred_test_t {4 * 1024 , 4 * 1024 , 16 * 1024 , 32 * 1024 }
7296+ ));
7297+ #endif
7298+
71047299void doMany4KWritesTest (ObjectStore* store,
71057300 unsigned max_objects,
71067301 unsigned max_ops,
0 commit comments