]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/crimson/seastore/test_object_data_handler.cc
add stop-gap to fix compat with CPUs not supporting SSE 4.1
[ceph.git] / ceph / src / test / crimson / seastore / test_object_data_handler.cc
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 }
37 bool is_dirty() const { return dirty; }
38 laddr_t get_hint() const final {return L_ADDR_MIN; }
39 ~TestOnode() final = default;
40 };
41
42 struct object_data_handler_test_t:
43 public seastar_test_suite_t,
44 TMTestState {
45 OnodeRef onode;
46
47 bufferptr known_contents;
48 extent_len_t size = 0;
49
50 object_data_handler_test_t() {}
51
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);
55 memset(
56 known_contents.c_str() + offset,
57 fill,
58 len);
59 bufferlist bl;
60 bl.append(
61 bufferptr(
62 known_contents,
63 offset,
64 len));
65 with_trans_intr(t, [&](auto &t) {
66 return ObjectDataHandler(MAX_OBJECT_SIZE).write(
67 ObjectDataHandler::context_t{
68 *tm,
69 t,
70 *onode,
71 },
72 offset,
73 bl);
74 }).unsafe_get0();
75 }
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));
80 }
81
82 void truncate(Transaction &t, objaddr_t offset) {
83 if (size > offset) {
84 memset(
85 known_contents.c_str() + offset,
86 0,
87 size - offset);
88 with_trans_intr(t, [&](auto &t) {
89 return ObjectDataHandler(MAX_OBJECT_SIZE).truncate(
90 ObjectDataHandler::context_t{
91 *tm,
92 t,
93 *onode
94 },
95 offset);
96 }).unsafe_get0();
97 }
98 size = offset;
99 }
100 void truncate(objaddr_t offset) {
101 auto t = create_mutate_transaction();
102 truncate(*t, offset);
103 return submit_transaction(std::move(t));
104 }
105
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{
110 *tm,
111 t,
112 *onode
113 },
114 offset,
115 len);
116 }).unsafe_get0();
117 bufferlist known;
118 known.append(
119 bufferptr(
120 known_contents,
121 offset,
122 len));
123 EXPECT_EQ(bl.length(), known.length());
124 EXPECT_EQ(bl, known);
125 }
126 void read(objaddr_t offset, extent_len_t len) {
127 auto t = create_read_transaction();
128 read(*t, offset, len);
129 }
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);
135 }
136 }
137 }
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);
142 }).unsafe_get0();
143 return ret;
144 }
145
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());
152 size = 0;
153 return tm_setup();
154 }
155
156 seastar::future<> tear_down_fut() final {
157 onode.reset();
158 size = 0;
159 return tm_teardown();
160 }
161 };
162
163 TEST_F(object_data_handler_test_t, single_write)
164 {
165 run_async([this] {
166 write(1<<20, 8<<10, 'c');
167
168 read_near(1<<20, 8<<10, 1);
169 read_near(1<<20, 8<<10, 512);
170 });
171 }
172
173 TEST_F(object_data_handler_test_t, multi_write)
174 {
175 run_async([this] {
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');
179
180 read_near(1<<20, 4<<10, 1);
181 read_near(1<<20, 4<<10, 512);
182
183 read_near((1<<20)-(4<<10), 12<<10, 1);
184 read_near((1<<20)-(4<<10), 12<<10, 512);
185 });
186 }
187
188 TEST_F(object_data_handler_test_t, write_hole)
189 {
190 run_async([this] {
191 write((1<<20) - (4<<10), 4<<10, 'a');
192 // hole at 1<<20
193 write((1<<20) + (4<<10), 4<<10, 'c');
194
195 read_near(1<<20, 4<<10, 1);
196 read_near(1<<20, 4<<10, 512);
197
198 read_near((1<<20)-(4<<10), 12<<10, 1);
199 read_near((1<<20)-(4<<10), 12<<10, 512);
200 });
201 }
202
203 TEST_F(object_data_handler_test_t, overwrite_single)
204 {
205 run_async([this] {
206 write((1<<20), 4<<10, 'a');
207 write((1<<20), 4<<10, 'c');
208
209 read_near(1<<20, 4<<10, 1);
210 read_near(1<<20, 4<<10, 512);
211 });
212 }
213
214 TEST_F(object_data_handler_test_t, overwrite_double)
215 {
216 run_async([this] {
217 write((1<<20), 4<<10, 'a');
218 write((1<<20)+(4<<10), 4<<10, 'c');
219 write((1<<20), 8<<10, 'b');
220
221 read_near(1<<20, 8<<10, 1);
222 read_near(1<<20, 8<<10, 512);
223
224 read_near(1<<20, 4<<10, 1);
225 read_near(1<<20, 4<<10, 512);
226
227 read_near((1<<20) + (4<<10), 4<<10, 1);
228 read_near((1<<20) + (4<<10), 4<<10, 512);
229 });
230 }
231
232 TEST_F(object_data_handler_test_t, overwrite_partial)
233 {
234 run_async([this] {
235 write((1<<20), 12<<10, 'a');
236 read_near(1<<20, 12<<10, 1);
237
238 write((1<<20)+(8<<10), 4<<10, 'b');
239 read_near(1<<20, 12<<10, 1);
240
241 write((1<<20)+(4<<10), 4<<10, 'c');
242 read_near(1<<20, 12<<10, 1);
243
244 write((1<<20), 4<<10, 'd');
245
246 read_near(1<<20, 12<<10, 1);
247 read_near(1<<20, 12<<10, 512);
248
249 read_near(1<<20, 4<<10, 1);
250 read_near(1<<20, 4<<10, 512);
251
252 read_near((1<<20) + (4<<10), 4<<10, 1);
253 read_near((1<<20) + (4<<10), 4<<10, 512);
254 });
255 }
256
257 TEST_F(object_data_handler_test_t, unaligned_write)
258 {
259 run_async([this] {
260 objaddr_t base = 1<<20;
261 write(base, (4<<10)+(1<<10), 'a');
262 read_near(base-(4<<10), 12<<10, 512);
263
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);
267
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);
271 });
272 }
273
274 TEST_F(object_data_handler_test_t, unaligned_overwrite)
275 {
276 run_async([this] {
277 objaddr_t base = 1<<20;
278 write(base, (128<<10) + (16<<10), 'x');
279
280 write(base, (4<<10)+(1<<10), 'a');
281 read_near(base-(4<<10), 12<<10, 2<<10);
282
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);
286
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);
290
291 read(base, (128<<10) + (16<<10));
292 });
293 }
294
295 TEST_F(object_data_handler_test_t, truncate)
296 {
297 run_async([this] {
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');
302
303 truncate(base + (32<<10));
304 read(base, 64<<10);
305
306 truncate(base + (24<<10));
307 read(base, 64<<10);
308
309 truncate(base + (12<<10));
310 read(base, 64<<10);
311
312 truncate(base - (12<<10));
313 read(base, 64<<10);
314 });
315 }
316
317 TEST_F(object_data_handler_test_t, no_split) {
318 run_async([this] {
319 write(0, 8<<10, 'x');
320 write(0, 8<<10, 'a');
321
322 auto pins = get_mappings(0, 8<<10);
323 EXPECT_EQ(pins.size(), 1);
324
325 read(0, 8<<10);
326 });
327 }
328
329 TEST_F(object_data_handler_test_t, split_left) {
330 run_async([this] {
331 write(0, 128<<10, 'x');
332
333 write(64<<10, 60<<10, 'a');
334
335 auto pins = get_mappings(0, 128<<10);
336 EXPECT_EQ(pins.size(), 2);
337
338 size_t res[2] = {0, 64<<10};
339 auto base = pins.front()->get_key();
340 int i = 0;
341 for (auto &pin : pins) {
342 EXPECT_EQ(pin->get_key() - base, res[i]);
343 i++;
344 }
345 read(0, 128<<10);
346 });
347 }
348
349 TEST_F(object_data_handler_test_t, split_right) {
350 run_async([this] {
351 write(0, 128<<10, 'x');
352 write(4<<10, 60<<10, 'a');
353
354 auto pins = get_mappings(0, 128<<10);
355 EXPECT_EQ(pins.size(), 2);
356
357 size_t res[2] = {0, 64<<10};
358 auto base = pins.front()->get_key();
359 int i = 0;
360 for (auto &pin : pins) {
361 EXPECT_EQ(pin->get_key() - base, res[i]);
362 i++;
363 }
364 read(0, 128<<10);
365 });
366 }
367 TEST_F(object_data_handler_test_t, split_left_right) {
368 run_async([this] {
369 write(0, 128<<10, 'x');
370 write(48<<10, 32<<10, 'a');
371
372 auto pins = get_mappings(0, 128<<10);
373 EXPECT_EQ(pins.size(), 3);
374
375 size_t res[3] = {0, 48<<10, 80<<10};
376 auto base = pins.front()->get_key();
377 int i = 0;
378 for (auto &pin : pins) {
379 EXPECT_EQ(pin->get_key() - base, res[i]);
380 i++;
381 }
382 });
383 }
384 TEST_F(object_data_handler_test_t, multiple_split) {
385 run_async([this] {
386 write(0, 128<<10, 'x');
387
388 auto t = create_mutate_transaction();
389 // normal split
390 write(*t, 120<<10, 4<<10, 'a');
391 // not aligned right
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');
397
398 write(*t, 64<<10, 32<<10, 'e');
399 // not split right
400 write(*t, 60<<10, 8<<10, 'f');
401
402 submit_transaction(std::move(t));
403
404 auto pins = get_mappings(0, 128<<10);
405 EXPECT_EQ(pins.size(), 10);
406
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();
410 int i = 0;
411 for (auto &pin : pins) {
412 EXPECT_EQ(pin->get_key() - base, res[i]);
413 i++;
414 }
415 read(0, 128<<10);
416 });
417 }