#include "crimson/common/utility.h"
#include "include/ceph_assert.h"
+class transaction_manager_test_t;
+
namespace crimson::interruptible {
template <typename, typename>
protected:
using base_t::get_exception;
+ friend class ::transaction_manager_test_t;
public:
using errorator_type = ::crimson::errorator<AllowedErrors...>;
using promise_type = seastar::promise<ValueT>;
auto unsafe_get0() {
return seastar::future<ValueT>::get0();
}
+ void unsafe_wait() {
+ seastar::future<ValueT>::wait();
+ }
template <class FuncT>
_future finally(FuncT &&func) {
virtual std::size_t get_reclaim_size_per_cycle() const = 0;
+#ifdef UNIT_TESTS_BUILT
+ virtual void prefill_fragmented_devices() {}
+#endif
+
// test only
virtual bool check_usage() = 0;
return 0;
}
+#ifdef UNIT_TESTS_BUILT
+ void prefill_fragmented_devices() final {
+ LOG_PREFIX(RBMCleaner::prefill_fragmented_devices);
+ SUBDEBUG(seastore_cleaner, "");
+ auto rbs = rb_group->get_rb_managers();
+ for (auto p : rbs) {
+ p->prefill_fragmented_device();
+ }
+ }
+#endif
+
RandomBlockManager* get_rbm(paddr_t paddr) {
auto rbs = rb_group->get_rb_managers();
for (auto p : rbs) {
virtual bool can_inplace_rewrite(Transaction& t,
CachedExtentRef extent) = 0;
+
+#ifdef UNIT_TESTS_BUILT
+ virtual void prefill_fragmented_devices() {}
+#endif
};
using ExtentOolWriterRef = std::unique_ptr<ExtentOolWriter>;
return crimson::os::seastore::can_inplace_rewrite(extent->get_type());
}
+#ifdef UNIT_TESTS_BUILT
+ void prefill_fragmented_devices() final {
+ LOG_PREFIX(RandomBlockOolWriter::prefill_fragmented_devices);
+ SUBDEBUG(seastore_epm, "");
+ return rb_cleaner->prefill_fragmented_devices();
+ }
+#endif
private:
alloc_write_iertr::future<> do_write(
Transaction& t,
return allocs;
}
+#ifdef UNIT_TESTS_BUILT
+ void prefill_fragmented_devices() {
+ LOG_PREFIX(ExtentPlacementManager::prefill_fragmented_devices);
+ SUBDEBUG(seastore_epm, "");
+ for (auto &writer : writer_refs) {
+ writer->prefill_fragmented_devices();
+ }
+ }
+#endif
+
/**
* dispatch_result_t
*
virtual rbm_extent_state_t get_extent_state(paddr_t addr, size_t size) = 0;
virtual size_t get_journal_size() const = 0;
virtual ~RandomBlockManager() {}
+#ifdef UNIT_TESTS_BUILT
+ virtual void prefill_fragmented_device() = 0;
+#endif
};
using RandomBlockManagerRef = std::unique_ptr<RandomBlockManager>;
std::move(bptr));
}
+#ifdef UNIT_TESTS_BUILT
+void BlockRBManager::prefill_fragmented_device()
+{
+ LOG_PREFIX(BlockRBManager::prefill_fragmented_device);
+ // the first 2 blocks must be allocated to lba root
+ // and backref root during mkfs
+ for (size_t block = get_block_size() * 2;
+ block <= get_size() - get_block_size() * 2;
+ block += get_block_size() * 2) {
+ DEBUG("marking {}~{} used",
+ get_start_rbm_addr() + block,
+ get_block_size());
+ allocator->mark_extent_used(
+ get_start_rbm_addr() + block,
+ get_block_size());
+ }
+}
+#endif
+
std::ostream &operator<<(std::ostream &out, const rbm_metadata_header_t &header)
{
out << " rbm_metadata_header_t(size=" << header.size
return device->get_journal_size();
}
+#ifdef UNIT_TESTS_BUILT
+ void prefill_fragmented_device() final;
+#endif
+
private:
/*
* this contains the number of bitmap blocks, free blocks and
return extent;
}
+ std::vector<TestBlockRef> alloc_extents(
+ test_transaction_t &t,
+ laddr_t hint,
+ extent_len_t len,
+ char contents) {
+ auto extents = with_trans_intr(*(t.t), [&](auto& trans) {
+ return tm->alloc_data_extents<TestBlock>(trans, hint, len);
+ }).unsafe_get0();
+ size_t length = 0;
+ for (auto &extent : extents) {
+ extent->set_contents(contents);
+ length += extent->get_length();
+ EXPECT_FALSE(test_mappings.contains(extent->get_laddr(), t.mapping_delta));
+ test_mappings.alloced(hint, *extent, t.mapping_delta);
+ }
+ EXPECT_EQ(len, length);
+ return extents;
+ }
+
+ void alloc_extents_deemed_fail(
+ test_transaction_t &t,
+ laddr_t hint,
+ extent_len_t len,
+ char contents)
+ {
+ std::cout << __func__ << std::endl;
+ auto fut = with_trans_intr(*(t.t), [&](auto& trans) {
+ return tm->alloc_data_extents<TestBlock>(trans, hint, len);
+ });
+ fut.unsafe_wait();
+ assert(fut.failed());
+ (void)fut.get_exception();
+ }
+
TestBlockRef alloc_extent(
test_transaction_t &t,
laddr_t hint,
tm_multi_tier_device_test_t() : transaction_manager_test_t(1, 2) {}
};
+struct tm_random_block_device_test_t :
+ public transaction_manager_test_t {
+
+ tm_random_block_device_test_t() : transaction_manager_test_t(1, 0) {}
+};
+
+TEST_P(tm_random_block_device_test_t, scatter_allocation)
+{
+ run_async([this] {
+ constexpr laddr_t ADDR = 0xFF * 4096;
+ epm->prefill_fragmented_devices();
+ auto t = create_transaction();
+ for (int i = 0; i < 1991; i++) {
+ auto extents = alloc_extents(t, ADDR + i * 16384, 16384, 'a');
+ std::cout << "num of extents: " << extents.size() << std::endl;
+ }
+ alloc_extents_deemed_fail(t, ADDR + 1991 * 16384, 16384, 'a');
+ check_mappings(t);
+ check();
+ submit_transaction(std::move(t));
+ check();
+ });
+}
+
TEST_P(tm_single_device_test_t, basic)
{
constexpr laddr_t SIZE = 4096;
"segmented"
)
);
+
+INSTANTIATE_TEST_SUITE_P(
+ transaction_manager_test,
+ tm_random_block_device_test_t,
+ ::testing::Values (
+ "circularbounded"
+ )
+);