1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/crimson/gtest_seastar.h"
8 #include "crimson/common/log.h"
9 #include "crimson/os/seastore/random_block_manager/nvme_manager.h"
10 #include "crimson/os/seastore/random_block_manager/nvmedevice.h"
11 #include "test/crimson/seastore/transaction_manager_test_state.h"
13 using namespace crimson
;
14 using namespace crimson::os
;
15 using namespace crimson::os::seastore
;
18 [[maybe_unused
]] seastar::logger
& logger() {
19 return crimson::get_logger(ceph_subsys_test
);
23 constexpr uint64_t DEFAULT_TEST_SIZE
= 1 << 20;
24 constexpr uint64_t DEFAULT_BLOCK_SIZE
= 4096;
27 public seastar_test_suite_t
, TMTestState
{
28 std::unique_ptr
<NVMeManager
> rbm_manager
;
29 std::unique_ptr
<nvme_device::NVMeBlockDevice
> device
;
31 struct rbm_transaction
{
32 void add_rbm_allocated_blocks(rbm_alloc_delta_t
&d
) {
33 allocated_blocks
.push_back(d
);
35 void clear_rbm_allocated_blocks() {
36 if (!allocated_blocks
.empty()) {
37 allocated_blocks
.clear();
40 const auto &get_rbm_allocated_blocks() {
41 return allocated_blocks
;
43 std::vector
<rbm_alloc_delta_t
> allocated_blocks
;
46 std::default_random_engine generator
;
48 const uint64_t block_size
= DEFAULT_BLOCK_SIZE
;
50 RandomBlockManager::mkfs_config_t config
;
53 rbm_test_t() = default;
55 seastar::future
<> set_up_fut() final
{
56 device
.reset(new nvme_device::TestMemory(DEFAULT_TEST_SIZE
));
57 rbm_manager
.reset(new NVMeManager(device
.get(), std::string()));
58 config
.start
= paddr_t::make_seg_paddr(0, 0, 0);
59 config
.end
= paddr_t::make_seg_paddr(0, 0, DEFAULT_TEST_SIZE
);
60 config
.block_size
= DEFAULT_BLOCK_SIZE
;
61 config
.total_size
= DEFAULT_TEST_SIZE
;
65 seastar::future
<> tear_down_fut() final
{
72 return rbm_manager
->mkfs(config
).unsafe_get0();
75 auto read_rbm_header() {
76 blk_paddr_t addr
= convert_paddr_to_blk_paddr(
79 config
.blocks_per_segment
);
80 return rbm_manager
->read_rbm_header(addr
).unsafe_get0();
84 return rbm_manager
->open("", config
.start
).unsafe_get0();
87 auto write(uint64_t addr
, bufferptr
&ptr
) {
88 return rbm_manager
->write(addr
, ptr
).unsafe_get0();
91 auto read(uint64_t addr
, bufferptr
&ptr
) {
92 return rbm_manager
->read(addr
, ptr
).unsafe_get0();
95 auto create_rbm_transaction() {
96 return std::make_unique
<rbm_transaction
>();
99 auto alloc_extent(rbm_transaction
&t
, size_t size
) {
100 auto tt
= create_mutate_transaction(); // dummy transaction
101 auto extent
= rbm_manager
->find_free_block(*tt
, size
).unsafe_get0();
102 if (!extent
.empty()) {
103 rbm_alloc_delta_t alloc_info
;
104 for (auto p
: extent
) {
105 paddr_t paddr
= convert_blk_paddr_to_paddr(
106 p
.first
* block_size
,
108 config
.blocks_per_segment
,
110 size_t len
= p
.second
* block_size
;
111 alloc_info
.alloc_blk_ranges
.push_back(std::make_pair(paddr
, len
));
112 alloc_info
.op
= rbm_alloc_delta_t::op_types_t::SET
;
114 t
.add_rbm_allocated_blocks(alloc_info
);
118 void free_extent(rbm_transaction
&t
, interval_set
<blk_id_t
> range
) {
119 for (auto [off
, len
] : range
) {
120 logger().debug("free_extent: start {} len {}", off
* DEFAULT_BLOCK_SIZE
,
121 len
* DEFAULT_BLOCK_SIZE
);
122 rbm_manager
->add_free_extent(t
.allocated_blocks
, off
* DEFAULT_BLOCK_SIZE
,
123 len
* DEFAULT_BLOCK_SIZE
);
127 interval_set
<blk_id_t
> get_allocated_blk_ids(rbm_transaction
&t
) {
128 auto allocated_blocks
= t
.get_rbm_allocated_blocks();
129 interval_set
<blk_id_t
> alloc_ids
;
130 for (auto p
: allocated_blocks
) {
131 for (auto b
: p
.alloc_blk_ranges
) {
133 convert_paddr_to_blk_paddr(
136 config
.blocks_per_segment
);
137 alloc_ids
.insert(addr
/ block_size
, b
.second
/ block_size
);
140 logger().debug(" get allocated blockid {}", alloc_ids
);
144 bool check_ids_are_allocated(interval_set
<blk_id_t
> &ids
, bool allocated
= true) {
147 for (blk_id_t id
= r
.first
; id
< r
.first
+ r
.second
; id
++) {
148 auto addr
= rbm_manager
->get_start_block_alloc_area() +
149 (id
/ rbm_manager
->max_block_by_bitmap_block())
150 * DEFAULT_BLOCK_SIZE
;
151 logger().debug(" addr {} id {} ", addr
, id
);
152 auto bp
= bufferptr(ceph::buffer::create_page_aligned(DEFAULT_BLOCK_SIZE
));
153 rbm_manager
->read(addr
, bp
).unsafe_get0();
154 rbm_bitmap_block_t
b_block(DEFAULT_BLOCK_SIZE
);
157 auto b_bl
= bl
.cbegin();
158 decode(b_block
, b_bl
);
159 if (!b_block
.is_allocated(id
% rbm_manager
->max_block_by_bitmap_block())) {
160 logger().debug(" block id {} is not allocated", id
);
166 logger().debug(" block id {} allocated", id
);
177 auto complete_allocation(rbm_transaction
&t
) {
178 auto alloc_blocks
= t
.get_rbm_allocated_blocks();
179 return rbm_manager
->sync_allocation(alloc_blocks
).unsafe_get0();
182 bufferptr
generate_extent(size_t blocks
) {
183 std::uniform_int_distribution
<char> distribution(
184 std::numeric_limits
<char>::min(),
185 std::numeric_limits
<char>::max()
187 char contents
= distribution(generator
);
188 return buffer::ptr(buffer::create(blocks
* block_size
, contents
));
193 TEST_F(rbm_test_t
, mkfs_test
)
198 auto super
= read_rbm_header();
200 super
.block_size
== DEFAULT_BLOCK_SIZE
&&
201 super
.end
== DEFAULT_TEST_SIZE
&&
202 super
.start_alloc_area
== DEFAULT_BLOCK_SIZE
&&
203 super
.free_block_count
== DEFAULT_TEST_SIZE
/ DEFAULT_BLOCK_SIZE
- 2 &&
204 super
.alloc_area_size
== DEFAULT_BLOCK_SIZE
210 TEST_F(rbm_test_t
, open_test
)
215 auto content
= generate_extent(1);
220 auto bp
= bufferptr(ceph::buffer::create_page_aligned(DEFAULT_BLOCK_SIZE
));
228 block
.append(content
);
230 bl
.begin().crc32c(bl
.length(), 1),
231 block
.begin().crc32c(block
.length(), 1));
236 TEST_F(rbm_test_t
, block_alloc_test
)
241 auto t
= create_rbm_transaction();
242 alloc_extent(*t
, DEFAULT_BLOCK_SIZE
);
243 auto alloc_ids
= get_allocated_blk_ids(*t
);
244 complete_allocation(*t
);
245 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
247 auto t2
= create_rbm_transaction();
248 alloc_extent(*t2
, DEFAULT_BLOCK_SIZE
* 3);
249 alloc_ids
= get_allocated_blk_ids(*t2
);
250 complete_allocation(*t2
);
251 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
255 TEST_F(rbm_test_t
, block_alloc_free_test
)
260 auto t
= create_rbm_transaction();
261 alloc_extent(*t
, DEFAULT_BLOCK_SIZE
);
262 auto alloc_ids
= get_allocated_blk_ids(*t
);
263 free_extent(*t
, alloc_ids
);
264 complete_allocation(*t
);
265 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
, false));
267 auto t2
= create_rbm_transaction();
268 alloc_extent(*t2
, DEFAULT_BLOCK_SIZE
* 4);
269 alloc_ids
= get_allocated_blk_ids(*t2
);
270 free_extent(*t2
, alloc_ids
);
271 complete_allocation(*t2
);
272 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
, false));
274 auto t3
= create_rbm_transaction();
275 alloc_extent(*t3
, DEFAULT_BLOCK_SIZE
* 8);
276 alloc_ids
= get_allocated_blk_ids(*t3
);
277 complete_allocation(*t3
);
278 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
280 auto t4
= create_rbm_transaction();
281 free_extent(*t4
, alloc_ids
);
282 complete_allocation(*t4
);
283 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
, false));
287 TEST_F(rbm_test_t
, many_block_alloc
)
290 config
.start
= paddr_t::make_seg_paddr(0, 0, 0);
291 config
.end
= paddr_t::make_seg_paddr(0, 0, DEFAULT_TEST_SIZE
* 1024);
292 config
.block_size
= DEFAULT_BLOCK_SIZE
;
293 config
.total_size
= DEFAULT_TEST_SIZE
* 1024;
296 auto max
= rbm_manager
->max_block_by_bitmap_block();
297 rbm_manager
->rbm_sync_block_bitmap_by_range(max
+ 10, max
+ 14, bitmap_op_types_t::ALL_SET
).unsafe_get0();
298 interval_set
<blk_id_t
> alloc_ids
;
299 alloc_ids
.insert(max
+ 12, 2);
300 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
302 alloc_ids
.insert(max
+ 10, 4);
303 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
304 rbm_manager
->rbm_sync_block_bitmap_by_range(max
+ 10, max
+ 14, bitmap_op_types_t::ALL_CLEAR
).unsafe_get0();
305 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
, false));
306 rbm_manager
->rbm_sync_block_bitmap_by_range(max
+ 10, max
+ max
+ 10, bitmap_op_types_t::ALL_SET
).unsafe_get0();
308 alloc_ids
.insert(max
+ 10000, 10);
309 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
311 alloc_ids
.insert(max
+ max
, 10);
312 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
313 rbm_manager
->rbm_sync_block_bitmap_by_range(max
, max
* 3, bitmap_op_types_t::ALL_SET
).unsafe_get0();
315 alloc_ids
.insert(max
* 3 - 1, 1);
316 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
318 alloc_ids
.insert(max
* 3, 1);
319 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
321 alloc_ids
.insert(max
, 1);
322 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
323 rbm_manager
->rbm_sync_block_bitmap_by_range(max
, max
* 6, bitmap_op_types_t::ALL_SET
).unsafe_get0();
325 alloc_ids
.insert(max
* 5, 10);
326 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
328 alloc_ids
.insert(max
* 6, 1);
329 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
));
330 rbm_manager
->rbm_sync_block_bitmap_by_range(max
, max
* 6, bitmap_op_types_t::ALL_CLEAR
).unsafe_get0();
332 alloc_ids
.insert(max
* 3, 10);
333 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
, false));
335 alloc_ids
.insert(max
* 5, 10);
336 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
, false));
338 alloc_ids
.insert(max
* 6, 1);
339 ASSERT_TRUE(check_ids_are_allocated(alloc_ids
, false));
343 TEST_F(rbm_test_t
, check_free_blocks
)
348 rbm_manager
->rbm_sync_block_bitmap_by_range(10, 12, bitmap_op_types_t::ALL_SET
).unsafe_get0();
349 rbm_manager
->check_bitmap_blocks().unsafe_get0();
350 ASSERT_TRUE(rbm_manager
->get_free_blocks() == DEFAULT_TEST_SIZE
/DEFAULT_BLOCK_SIZE
- 5);
351 auto free
= rbm_manager
->get_free_blocks();
352 interval_set
<blk_id_t
> alloc_ids
;
353 auto t
= create_rbm_transaction();
354 alloc_extent(*t
, DEFAULT_BLOCK_SIZE
* 4);
355 alloc_ids
= get_allocated_blk_ids(*t
);
356 complete_allocation(*t
);
357 ASSERT_TRUE(rbm_manager
->get_free_blocks() == free
- 4);
359 free
= rbm_manager
->get_free_blocks();
360 auto t2
= create_rbm_transaction();
361 free_extent(*t2
, alloc_ids
);
362 complete_allocation(*t2
);
363 ASSERT_TRUE(rbm_manager
->get_free_blocks() == free
+ 4);