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"
5 #include "test/crimson/seastore/transaction_manager_test_state.h"
7 #include "crimson/os/seastore/onode.h"
8 #include "crimson/os/seastore/object_data_handler.h"
10 using namespace crimson
;
11 using namespace crimson::os
;
12 using namespace crimson::os::seastore
;
14 #define MAX_OBJECT_SIZE (16<<20)
15 #define DEFAULT_OBJECT_DATA_RESERVATION (16<<20)
16 #define DEFAULT_OBJECT_METADATA_RESERVATION (16<<20)
19 [[maybe_unused
]] seastar::logger
& logger() {
20 return crimson::get_logger(ceph_subsys_test
);
24 class TestOnode final
: public Onode
{
25 onode_layout_t layout
;
29 TestOnode(uint32_t ddr
, uint32_t dmr
) : Onode(ddr
, dmr
) {}
30 const onode_layout_t
&get_layout() const final
{
33 onode_layout_t
&get_mutable_layout(Transaction
&t
) final
{
37 bool is_dirty() const { return dirty
; }
38 laddr_t
get_hint() const final
{return L_ADDR_MIN
; }
39 ~TestOnode() final
= default;
42 struct object_data_handler_test_t
:
43 public seastar_test_suite_t
,
47 bufferptr known_contents
;
48 extent_len_t size
= 0;
50 object_data_handler_test_t() {}
52 void write(Transaction
&t
, objaddr_t offset
, extent_len_t len
, char fill
) {
53 ceph_assert(offset
+ len
<= known_contents
.length());
54 size
= std::max
<extent_len_t
>(size
, offset
+ len
);
56 known_contents
.c_str() + offset
,
65 with_trans_intr(t
, [&](auto &t
) {
66 return ObjectDataHandler(MAX_OBJECT_SIZE
).write(
67 ObjectDataHandler::context_t
{
76 void write(objaddr_t offset
, extent_len_t len
, char fill
) {
77 auto t
= create_mutate_transaction();
78 write(*t
, offset
, len
, fill
);
79 return submit_transaction(std::move(t
));
82 void truncate(Transaction
&t
, objaddr_t offset
) {
85 known_contents
.c_str() + offset
,
88 with_trans_intr(t
, [&](auto &t
) {
89 return ObjectDataHandler(MAX_OBJECT_SIZE
).truncate(
90 ObjectDataHandler::context_t
{
100 void truncate(objaddr_t offset
) {
101 auto t
= create_mutate_transaction();
102 truncate(*t
, offset
);
103 return submit_transaction(std::move(t
));
106 void read(Transaction
&t
, objaddr_t offset
, extent_len_t len
) {
107 bufferlist bl
= with_trans_intr(t
, [&](auto &t
) {
108 return ObjectDataHandler(MAX_OBJECT_SIZE
).read(
109 ObjectDataHandler::context_t
{
123 EXPECT_EQ(bl
.length(), known
.length());
124 EXPECT_EQ(bl
, known
);
126 void read(objaddr_t offset
, extent_len_t len
) {
127 auto t
= create_read_transaction();
128 read(*t
, offset
, len
);
130 void read_near(objaddr_t offset
, extent_len_t len
, extent_len_t fuzz
) {
131 auto fuzzes
= std::vector
<int32_t>{-1 * (int32_t)fuzz
, 0, (int32_t)fuzz
};
132 for (auto left_fuzz
: fuzzes
) {
133 for (auto right_fuzz
: fuzzes
) {
134 read(offset
+ left_fuzz
, len
- left_fuzz
+ right_fuzz
);
138 std::list
<LBAMappingRef
> get_mappings(objaddr_t offset
, extent_len_t length
) {
139 auto t
= create_mutate_transaction();
140 auto ret
= with_trans_intr(*t
, [&](auto &t
) {
141 return tm
->get_pins(t
, offset
, length
);
146 seastar::future
<> set_up_fut() final
{
147 onode
= new TestOnode(
148 DEFAULT_OBJECT_DATA_RESERVATION
,
149 DEFAULT_OBJECT_METADATA_RESERVATION
);
150 known_contents
= buffer::create(4<<20 /* 4MB */);
151 memset(known_contents
.c_str(), 0, known_contents
.length());
156 seastar::future
<> tear_down_fut() final
{
159 return tm_teardown();
163 TEST_F(object_data_handler_test_t
, single_write
)
166 write(1<<20, 8<<10, 'c');
168 read_near(1<<20, 8<<10, 1);
169 read_near(1<<20, 8<<10, 512);
173 TEST_F(object_data_handler_test_t
, multi_write
)
176 write((1<<20) - (4<<10), 4<<10, 'a');
177 write(1<<20, 4<<10, 'b');
178 write((1<<20) + (4<<10), 4<<10, 'c');
180 read_near(1<<20, 4<<10, 1);
181 read_near(1<<20, 4<<10, 512);
183 read_near((1<<20)-(4<<10), 12<<10, 1);
184 read_near((1<<20)-(4<<10), 12<<10, 512);
188 TEST_F(object_data_handler_test_t
, write_hole
)
191 write((1<<20) - (4<<10), 4<<10, 'a');
193 write((1<<20) + (4<<10), 4<<10, 'c');
195 read_near(1<<20, 4<<10, 1);
196 read_near(1<<20, 4<<10, 512);
198 read_near((1<<20)-(4<<10), 12<<10, 1);
199 read_near((1<<20)-(4<<10), 12<<10, 512);
203 TEST_F(object_data_handler_test_t
, overwrite_single
)
206 write((1<<20), 4<<10, 'a');
207 write((1<<20), 4<<10, 'c');
209 read_near(1<<20, 4<<10, 1);
210 read_near(1<<20, 4<<10, 512);
214 TEST_F(object_data_handler_test_t
, overwrite_double
)
217 write((1<<20), 4<<10, 'a');
218 write((1<<20)+(4<<10), 4<<10, 'c');
219 write((1<<20), 8<<10, 'b');
221 read_near(1<<20, 8<<10, 1);
222 read_near(1<<20, 8<<10, 512);
224 read_near(1<<20, 4<<10, 1);
225 read_near(1<<20, 4<<10, 512);
227 read_near((1<<20) + (4<<10), 4<<10, 1);
228 read_near((1<<20) + (4<<10), 4<<10, 512);
232 TEST_F(object_data_handler_test_t
, overwrite_partial
)
235 write((1<<20), 12<<10, 'a');
236 read_near(1<<20, 12<<10, 1);
238 write((1<<20)+(8<<10), 4<<10, 'b');
239 read_near(1<<20, 12<<10, 1);
241 write((1<<20)+(4<<10), 4<<10, 'c');
242 read_near(1<<20, 12<<10, 1);
244 write((1<<20), 4<<10, 'd');
246 read_near(1<<20, 12<<10, 1);
247 read_near(1<<20, 12<<10, 512);
249 read_near(1<<20, 4<<10, 1);
250 read_near(1<<20, 4<<10, 512);
252 read_near((1<<20) + (4<<10), 4<<10, 1);
253 read_near((1<<20) + (4<<10), 4<<10, 512);
257 TEST_F(object_data_handler_test_t
, unaligned_write
)
260 objaddr_t base
= 1<<20;
261 write(base
, (4<<10)+(1<<10), 'a');
262 read_near(base
-(4<<10), 12<<10, 512);
264 base
= (1<<20) + (64<<10);
265 write(base
+(1<<10), (4<<10)+(1<<10), 'b');
266 read_near(base
-(4<<10), 12<<10, 512);
268 base
= (1<<20) + (128<<10);
269 write(base
-(1<<10), (4<<10)+(2<<20), 'c');
270 read_near(base
-(4<<10), 12<<10, 512);
274 TEST_F(object_data_handler_test_t
, unaligned_overwrite
)
277 objaddr_t base
= 1<<20;
278 write(base
, (128<<10) + (16<<10), 'x');
280 write(base
, (4<<10)+(1<<10), 'a');
281 read_near(base
-(4<<10), 12<<10, 2<<10);
283 base
= (1<<20) + (64<<10);
284 write(base
+(1<<10), (4<<10)+(1<<10), 'b');
285 read_near(base
-(4<<10), 12<<10, 2<<10);
287 base
= (1<<20) + (128<<10);
288 write(base
-(1<<10), (4<<10)+(2<<20), 'c');
289 read_near(base
-(4<<10), 12<<10, 2<<10);
291 read(base
, (128<<10) + (16<<10));
295 TEST_F(object_data_handler_test_t
, truncate
)
298 objaddr_t base
= 1<<20;
299 write(base
, 8<<10, 'a');
300 write(base
+(8<<10), 8<<10, 'b');
301 write(base
+(16<<10), 8<<10, 'c');
303 truncate(base
+ (32<<10));
306 truncate(base
+ (24<<10));
309 truncate(base
+ (12<<10));
312 truncate(base
- (12<<10));
317 TEST_F(object_data_handler_test_t
, no_split
) {
319 write(0, 8<<10, 'x');
320 write(0, 8<<10, 'a');
322 auto pins
= get_mappings(0, 8<<10);
323 EXPECT_EQ(pins
.size(), 1);
329 TEST_F(object_data_handler_test_t
, split_left
) {
331 write(0, 128<<10, 'x');
333 write(64<<10, 60<<10, 'a');
335 auto pins
= get_mappings(0, 128<<10);
336 EXPECT_EQ(pins
.size(), 2);
338 size_t res
[2] = {0, 64<<10};
339 auto base
= pins
.front()->get_key();
341 for (auto &pin
: pins
) {
342 EXPECT_EQ(pin
->get_key() - base
, res
[i
]);
349 TEST_F(object_data_handler_test_t
, split_right
) {
351 write(0, 128<<10, 'x');
352 write(4<<10, 60<<10, 'a');
354 auto pins
= get_mappings(0, 128<<10);
355 EXPECT_EQ(pins
.size(), 2);
357 size_t res
[2] = {0, 64<<10};
358 auto base
= pins
.front()->get_key();
360 for (auto &pin
: pins
) {
361 EXPECT_EQ(pin
->get_key() - base
, res
[i
]);
367 TEST_F(object_data_handler_test_t
, split_left_right
) {
369 write(0, 128<<10, 'x');
370 write(48<<10, 32<<10, 'a');
372 auto pins
= get_mappings(0, 128<<10);
373 EXPECT_EQ(pins
.size(), 3);
375 size_t res
[3] = {0, 48<<10, 80<<10};
376 auto base
= pins
.front()->get_key();
378 for (auto &pin
: pins
) {
379 EXPECT_EQ(pin
->get_key() - base
, res
[i
]);
384 TEST_F(object_data_handler_test_t
, multiple_split
) {
386 write(0, 128<<10, 'x');
388 auto t
= create_mutate_transaction();
390 write(*t
, 120<<10, 4<<10, 'a');
392 write(*t
, 4<<10, 5<<10, 'b');
393 // split right extent of last split result
394 write(*t
, 32<<10, 4<<10, 'c');
395 // non aligned overwrite
396 write(*t
, 13<<10, 4<<10, 'd');
398 write(*t
, 64<<10, 32<<10, 'e');
400 write(*t
, 60<<10, 8<<10, 'f');
402 submit_transaction(std::move(t
));
404 auto pins
= get_mappings(0, 128<<10);
405 EXPECT_EQ(pins
.size(), 10);
407 size_t res
[10] = {0, 4<<10, 12<<10, 20<<10, 32<<10,
408 36<<10, 60<<10, 96<<10, 120<<10, 124<<10};
409 auto base
= pins
.front()->get_key();
411 for (auto &pin
: pins
) {
412 EXPECT_EQ(pin
->get_key() - base
, res
[i
]);