]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "test/crimson/gtest_seastar.h" | |
5 | #include "test/crimson/seastore/transaction_manager_test_state.h" | |
6 | ||
7 | #include "crimson/os/seastore/onode.h" | |
8 | #include "crimson/os/seastore/object_data_handler.h" | |
9 | ||
10 | using namespace crimson; | |
11 | using namespace crimson::os; | |
12 | using namespace crimson::os::seastore; | |
13 | ||
14 | #define MAX_OBJECT_SIZE (16<<20) | |
15 | #define DEFAULT_OBJECT_DATA_RESERVATION (16<<20) | |
16 | #define DEFAULT_OBJECT_METADATA_RESERVATION (16<<20) | |
17 | ||
18 | namespace { | |
19 | [[maybe_unused]] seastar::logger& logger() { | |
20 | return crimson::get_logger(ceph_subsys_test); | |
21 | } | |
22 | } | |
23 | ||
24 | class TestOnode final : public Onode { | |
25 | onode_layout_t layout; | |
26 | bool dirty = false; | |
27 | ||
28 | public: | |
29 | TestOnode(uint32_t ddr, uint32_t dmr) : Onode(ddr, dmr) {} | |
30 | const onode_layout_t &get_layout() const final { | |
31 | return layout; | |
32 | } | |
33 | onode_layout_t &get_mutable_layout(Transaction &t) final { | |
34 | dirty = true; | |
35 | return layout; | |
36 | } | |
aee94f69 TL |
37 | bool is_alive() const { |
38 | return true; | |
39 | } | |
20effc67 TL |
40 | bool is_dirty() const { return dirty; } |
41 | laddr_t get_hint() const final {return L_ADDR_MIN; } | |
42 | ~TestOnode() final = default; | |
43 | }; | |
44 | ||
45 | struct object_data_handler_test_t: | |
46 | public seastar_test_suite_t, | |
47 | TMTestState { | |
48 | OnodeRef onode; | |
49 | ||
50 | bufferptr known_contents; | |
51 | extent_len_t size = 0; | |
52 | ||
53 | object_data_handler_test_t() {} | |
54 | ||
55 | void write(Transaction &t, objaddr_t offset, extent_len_t len, char fill) { | |
56 | ceph_assert(offset + len <= known_contents.length()); | |
57 | size = std::max<extent_len_t>(size, offset + len); | |
58 | memset( | |
59 | known_contents.c_str() + offset, | |
60 | fill, | |
61 | len); | |
62 | bufferlist bl; | |
63 | bl.append( | |
64 | bufferptr( | |
65 | known_contents, | |
66 | offset, | |
67 | len)); | |
68 | with_trans_intr(t, [&](auto &t) { | |
69 | return ObjectDataHandler(MAX_OBJECT_SIZE).write( | |
70 | ObjectDataHandler::context_t{ | |
71 | *tm, | |
72 | t, | |
73 | *onode, | |
74 | }, | |
75 | offset, | |
76 | bl); | |
77 | }).unsafe_get0(); | |
78 | } | |
79 | void write(objaddr_t offset, extent_len_t len, char fill) { | |
80 | auto t = create_mutate_transaction(); | |
81 | write(*t, offset, len, fill); | |
82 | return submit_transaction(std::move(t)); | |
83 | } | |
84 | ||
85 | void truncate(Transaction &t, objaddr_t offset) { | |
86 | if (size > offset) { | |
87 | memset( | |
88 | known_contents.c_str() + offset, | |
89 | 0, | |
90 | size - offset); | |
91 | with_trans_intr(t, [&](auto &t) { | |
92 | return ObjectDataHandler(MAX_OBJECT_SIZE).truncate( | |
93 | ObjectDataHandler::context_t{ | |
94 | *tm, | |
95 | t, | |
96 | *onode | |
97 | }, | |
98 | offset); | |
99 | }).unsafe_get0(); | |
100 | } | |
101 | size = offset; | |
102 | } | |
103 | void truncate(objaddr_t offset) { | |
104 | auto t = create_mutate_transaction(); | |
105 | truncate(*t, offset); | |
106 | return submit_transaction(std::move(t)); | |
107 | } | |
108 | ||
109 | void read(Transaction &t, objaddr_t offset, extent_len_t len) { | |
110 | bufferlist bl = with_trans_intr(t, [&](auto &t) { | |
111 | return ObjectDataHandler(MAX_OBJECT_SIZE).read( | |
112 | ObjectDataHandler::context_t{ | |
113 | *tm, | |
114 | t, | |
115 | *onode | |
116 | }, | |
117 | offset, | |
118 | len); | |
119 | }).unsafe_get0(); | |
120 | bufferlist known; | |
121 | known.append( | |
122 | bufferptr( | |
123 | known_contents, | |
124 | offset, | |
125 | len)); | |
126 | EXPECT_EQ(bl.length(), known.length()); | |
127 | EXPECT_EQ(bl, known); | |
128 | } | |
129 | void read(objaddr_t offset, extent_len_t len) { | |
130 | auto t = create_read_transaction(); | |
131 | read(*t, offset, len); | |
132 | } | |
133 | void read_near(objaddr_t offset, extent_len_t len, extent_len_t fuzz) { | |
134 | auto fuzzes = std::vector<int32_t>{-1 * (int32_t)fuzz, 0, (int32_t)fuzz}; | |
135 | for (auto left_fuzz : fuzzes) { | |
136 | for (auto right_fuzz : fuzzes) { | |
137 | read(offset + left_fuzz, len - left_fuzz + right_fuzz); | |
138 | } | |
139 | } | |
140 | } | |
1e59de90 TL |
141 | std::list<LBAMappingRef> get_mappings(objaddr_t offset, extent_len_t length) { |
142 | auto t = create_mutate_transaction(); | |
143 | auto ret = with_trans_intr(*t, [&](auto &t) { | |
144 | return tm->get_pins(t, offset, length); | |
145 | }).unsafe_get0(); | |
146 | return ret; | |
147 | } | |
20effc67 TL |
148 | |
149 | seastar::future<> set_up_fut() final { | |
150 | onode = new TestOnode( | |
151 | DEFAULT_OBJECT_DATA_RESERVATION, | |
152 | DEFAULT_OBJECT_METADATA_RESERVATION); | |
153 | known_contents = buffer::create(4<<20 /* 4MB */); | |
154 | memset(known_contents.c_str(), 0, known_contents.length()); | |
155 | size = 0; | |
156 | return tm_setup(); | |
157 | } | |
158 | ||
159 | seastar::future<> tear_down_fut() final { | |
160 | onode.reset(); | |
161 | size = 0; | |
162 | return tm_teardown(); | |
163 | } | |
164 | }; | |
165 | ||
aee94f69 | 166 | TEST_P(object_data_handler_test_t, single_write) |
20effc67 TL |
167 | { |
168 | run_async([this] { | |
169 | write(1<<20, 8<<10, 'c'); | |
170 | ||
171 | read_near(1<<20, 8<<10, 1); | |
172 | read_near(1<<20, 8<<10, 512); | |
173 | }); | |
174 | } | |
175 | ||
aee94f69 | 176 | TEST_P(object_data_handler_test_t, multi_write) |
20effc67 TL |
177 | { |
178 | run_async([this] { | |
179 | write((1<<20) - (4<<10), 4<<10, 'a'); | |
180 | write(1<<20, 4<<10, 'b'); | |
181 | write((1<<20) + (4<<10), 4<<10, 'c'); | |
182 | ||
183 | read_near(1<<20, 4<<10, 1); | |
184 | read_near(1<<20, 4<<10, 512); | |
185 | ||
186 | read_near((1<<20)-(4<<10), 12<<10, 1); | |
187 | read_near((1<<20)-(4<<10), 12<<10, 512); | |
188 | }); | |
189 | } | |
190 | ||
aee94f69 | 191 | TEST_P(object_data_handler_test_t, write_hole) |
20effc67 TL |
192 | { |
193 | run_async([this] { | |
194 | write((1<<20) - (4<<10), 4<<10, 'a'); | |
195 | // hole at 1<<20 | |
196 | write((1<<20) + (4<<10), 4<<10, 'c'); | |
197 | ||
198 | read_near(1<<20, 4<<10, 1); | |
199 | read_near(1<<20, 4<<10, 512); | |
200 | ||
201 | read_near((1<<20)-(4<<10), 12<<10, 1); | |
202 | read_near((1<<20)-(4<<10), 12<<10, 512); | |
203 | }); | |
204 | } | |
205 | ||
aee94f69 | 206 | TEST_P(object_data_handler_test_t, overwrite_single) |
20effc67 TL |
207 | { |
208 | run_async([this] { | |
209 | write((1<<20), 4<<10, 'a'); | |
210 | write((1<<20), 4<<10, 'c'); | |
211 | ||
212 | read_near(1<<20, 4<<10, 1); | |
213 | read_near(1<<20, 4<<10, 512); | |
214 | }); | |
215 | } | |
216 | ||
aee94f69 | 217 | TEST_P(object_data_handler_test_t, overwrite_double) |
20effc67 TL |
218 | { |
219 | run_async([this] { | |
220 | write((1<<20), 4<<10, 'a'); | |
221 | write((1<<20)+(4<<10), 4<<10, 'c'); | |
222 | write((1<<20), 8<<10, 'b'); | |
223 | ||
224 | read_near(1<<20, 8<<10, 1); | |
225 | read_near(1<<20, 8<<10, 512); | |
226 | ||
227 | read_near(1<<20, 4<<10, 1); | |
228 | read_near(1<<20, 4<<10, 512); | |
229 | ||
230 | read_near((1<<20) + (4<<10), 4<<10, 1); | |
231 | read_near((1<<20) + (4<<10), 4<<10, 512); | |
232 | }); | |
233 | } | |
234 | ||
aee94f69 | 235 | TEST_P(object_data_handler_test_t, overwrite_partial) |
20effc67 TL |
236 | { |
237 | run_async([this] { | |
238 | write((1<<20), 12<<10, 'a'); | |
239 | read_near(1<<20, 12<<10, 1); | |
240 | ||
241 | write((1<<20)+(8<<10), 4<<10, 'b'); | |
242 | read_near(1<<20, 12<<10, 1); | |
243 | ||
244 | write((1<<20)+(4<<10), 4<<10, 'c'); | |
245 | read_near(1<<20, 12<<10, 1); | |
246 | ||
247 | write((1<<20), 4<<10, 'd'); | |
248 | ||
249 | read_near(1<<20, 12<<10, 1); | |
250 | read_near(1<<20, 12<<10, 512); | |
251 | ||
252 | read_near(1<<20, 4<<10, 1); | |
253 | read_near(1<<20, 4<<10, 512); | |
254 | ||
255 | read_near((1<<20) + (4<<10), 4<<10, 1); | |
256 | read_near((1<<20) + (4<<10), 4<<10, 512); | |
257 | }); | |
258 | } | |
259 | ||
aee94f69 | 260 | TEST_P(object_data_handler_test_t, unaligned_write) |
20effc67 TL |
261 | { |
262 | run_async([this] { | |
263 | objaddr_t base = 1<<20; | |
264 | write(base, (4<<10)+(1<<10), 'a'); | |
265 | read_near(base-(4<<10), 12<<10, 512); | |
266 | ||
267 | base = (1<<20) + (64<<10); | |
268 | write(base+(1<<10), (4<<10)+(1<<10), 'b'); | |
269 | read_near(base-(4<<10), 12<<10, 512); | |
270 | ||
271 | base = (1<<20) + (128<<10); | |
272 | write(base-(1<<10), (4<<10)+(2<<20), 'c'); | |
273 | read_near(base-(4<<10), 12<<10, 512); | |
274 | }); | |
275 | } | |
276 | ||
aee94f69 | 277 | TEST_P(object_data_handler_test_t, unaligned_overwrite) |
20effc67 TL |
278 | { |
279 | run_async([this] { | |
280 | objaddr_t base = 1<<20; | |
281 | write(base, (128<<10) + (16<<10), 'x'); | |
282 | ||
283 | write(base, (4<<10)+(1<<10), 'a'); | |
284 | read_near(base-(4<<10), 12<<10, 2<<10); | |
285 | ||
286 | base = (1<<20) + (64<<10); | |
287 | write(base+(1<<10), (4<<10)+(1<<10), 'b'); | |
288 | read_near(base-(4<<10), 12<<10, 2<<10); | |
289 | ||
290 | base = (1<<20) + (128<<10); | |
291 | write(base-(1<<10), (4<<10)+(2<<20), 'c'); | |
292 | read_near(base-(4<<10), 12<<10, 2<<10); | |
293 | ||
294 | read(base, (128<<10) + (16<<10)); | |
295 | }); | |
296 | } | |
297 | ||
aee94f69 | 298 | TEST_P(object_data_handler_test_t, truncate) |
20effc67 TL |
299 | { |
300 | run_async([this] { | |
301 | objaddr_t base = 1<<20; | |
302 | write(base, 8<<10, 'a'); | |
303 | write(base+(8<<10), 8<<10, 'b'); | |
304 | write(base+(16<<10), 8<<10, 'c'); | |
305 | ||
306 | truncate(base + (32<<10)); | |
307 | read(base, 64<<10); | |
308 | ||
309 | truncate(base + (24<<10)); | |
310 | read(base, 64<<10); | |
311 | ||
312 | truncate(base + (12<<10)); | |
313 | read(base, 64<<10); | |
314 | ||
315 | truncate(base - (12<<10)); | |
316 | read(base, 64<<10); | |
317 | }); | |
318 | } | |
1e59de90 | 319 | |
aee94f69 | 320 | TEST_P(object_data_handler_test_t, no_split) { |
1e59de90 TL |
321 | run_async([this] { |
322 | write(0, 8<<10, 'x'); | |
323 | write(0, 8<<10, 'a'); | |
324 | ||
325 | auto pins = get_mappings(0, 8<<10); | |
326 | EXPECT_EQ(pins.size(), 1); | |
327 | ||
328 | read(0, 8<<10); | |
329 | }); | |
330 | } | |
331 | ||
aee94f69 | 332 | TEST_P(object_data_handler_test_t, split_left) { |
1e59de90 TL |
333 | run_async([this] { |
334 | write(0, 128<<10, 'x'); | |
335 | ||
336 | write(64<<10, 60<<10, 'a'); | |
337 | ||
338 | auto pins = get_mappings(0, 128<<10); | |
339 | EXPECT_EQ(pins.size(), 2); | |
340 | ||
341 | size_t res[2] = {0, 64<<10}; | |
342 | auto base = pins.front()->get_key(); | |
343 | int i = 0; | |
344 | for (auto &pin : pins) { | |
345 | EXPECT_EQ(pin->get_key() - base, res[i]); | |
346 | i++; | |
347 | } | |
348 | read(0, 128<<10); | |
349 | }); | |
350 | } | |
351 | ||
aee94f69 | 352 | TEST_P(object_data_handler_test_t, split_right) { |
1e59de90 TL |
353 | run_async([this] { |
354 | write(0, 128<<10, 'x'); | |
355 | write(4<<10, 60<<10, 'a'); | |
356 | ||
357 | auto pins = get_mappings(0, 128<<10); | |
358 | EXPECT_EQ(pins.size(), 2); | |
359 | ||
360 | size_t res[2] = {0, 64<<10}; | |
361 | auto base = pins.front()->get_key(); | |
362 | int i = 0; | |
363 | for (auto &pin : pins) { | |
364 | EXPECT_EQ(pin->get_key() - base, res[i]); | |
365 | i++; | |
366 | } | |
367 | read(0, 128<<10); | |
368 | }); | |
369 | } | |
aee94f69 | 370 | TEST_P(object_data_handler_test_t, split_left_right) { |
1e59de90 TL |
371 | run_async([this] { |
372 | write(0, 128<<10, 'x'); | |
373 | write(48<<10, 32<<10, 'a'); | |
374 | ||
375 | auto pins = get_mappings(0, 128<<10); | |
376 | EXPECT_EQ(pins.size(), 3); | |
377 | ||
378 | size_t res[3] = {0, 48<<10, 80<<10}; | |
379 | auto base = pins.front()->get_key(); | |
380 | int i = 0; | |
381 | for (auto &pin : pins) { | |
382 | EXPECT_EQ(pin->get_key() - base, res[i]); | |
383 | i++; | |
384 | } | |
385 | }); | |
386 | } | |
aee94f69 | 387 | TEST_P(object_data_handler_test_t, multiple_split) { |
1e59de90 TL |
388 | run_async([this] { |
389 | write(0, 128<<10, 'x'); | |
390 | ||
391 | auto t = create_mutate_transaction(); | |
392 | // normal split | |
393 | write(*t, 120<<10, 4<<10, 'a'); | |
394 | // not aligned right | |
395 | write(*t, 4<<10, 5<<10, 'b'); | |
396 | // split right extent of last split result | |
397 | write(*t, 32<<10, 4<<10, 'c'); | |
398 | // non aligned overwrite | |
399 | write(*t, 13<<10, 4<<10, 'd'); | |
400 | ||
401 | write(*t, 64<<10, 32<<10, 'e'); | |
402 | // not split right | |
403 | write(*t, 60<<10, 8<<10, 'f'); | |
404 | ||
405 | submit_transaction(std::move(t)); | |
406 | ||
407 | auto pins = get_mappings(0, 128<<10); | |
408 | EXPECT_EQ(pins.size(), 10); | |
409 | ||
410 | size_t res[10] = {0, 4<<10, 12<<10, 20<<10, 32<<10, | |
411 | 36<<10, 60<<10, 96<<10, 120<<10, 124<<10}; | |
412 | auto base = pins.front()->get_key(); | |
413 | int i = 0; | |
414 | for (auto &pin : pins) { | |
415 | EXPECT_EQ(pin->get_key() - base, res[i]); | |
416 | i++; | |
417 | } | |
418 | read(0, 128<<10); | |
419 | }); | |
420 | } | |
aee94f69 TL |
421 | |
422 | INSTANTIATE_TEST_SUITE_P( | |
423 | object_data_handler_test, | |
424 | object_data_handler_test_t, | |
425 | ::testing::Values ( | |
426 | "segmented", | |
427 | "circularbounded" | |
428 | ) | |
429 | ); | |
430 | ||
431 |