]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/crimson/seastore/test_object_data_handler.cc
import quincy beta 17.1.0
[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
139 seastar::future<> set_up_fut() final {
140 onode = new TestOnode(
141 DEFAULT_OBJECT_DATA_RESERVATION,
142 DEFAULT_OBJECT_METADATA_RESERVATION);
143 known_contents = buffer::create(4<<20 /* 4MB */);
144 memset(known_contents.c_str(), 0, known_contents.length());
145 size = 0;
146 return tm_setup();
147 }
148
149 seastar::future<> tear_down_fut() final {
150 onode.reset();
151 size = 0;
152 return tm_teardown();
153 }
154 };
155
156 TEST_F(object_data_handler_test_t, single_write)
157 {
158 run_async([this] {
159 write(1<<20, 8<<10, 'c');
160
161 read_near(1<<20, 8<<10, 1);
162 read_near(1<<20, 8<<10, 512);
163 });
164 }
165
166 TEST_F(object_data_handler_test_t, multi_write)
167 {
168 run_async([this] {
169 write((1<<20) - (4<<10), 4<<10, 'a');
170 write(1<<20, 4<<10, 'b');
171 write((1<<20) + (4<<10), 4<<10, 'c');
172
173 read_near(1<<20, 4<<10, 1);
174 read_near(1<<20, 4<<10, 512);
175
176 read_near((1<<20)-(4<<10), 12<<10, 1);
177 read_near((1<<20)-(4<<10), 12<<10, 512);
178 });
179 }
180
181 TEST_F(object_data_handler_test_t, write_hole)
182 {
183 run_async([this] {
184 write((1<<20) - (4<<10), 4<<10, 'a');
185 // hole at 1<<20
186 write((1<<20) + (4<<10), 4<<10, 'c');
187
188 read_near(1<<20, 4<<10, 1);
189 read_near(1<<20, 4<<10, 512);
190
191 read_near((1<<20)-(4<<10), 12<<10, 1);
192 read_near((1<<20)-(4<<10), 12<<10, 512);
193 });
194 }
195
196 TEST_F(object_data_handler_test_t, overwrite_single)
197 {
198 run_async([this] {
199 write((1<<20), 4<<10, 'a');
200 write((1<<20), 4<<10, 'c');
201
202 read_near(1<<20, 4<<10, 1);
203 read_near(1<<20, 4<<10, 512);
204 });
205 }
206
207 TEST_F(object_data_handler_test_t, overwrite_double)
208 {
209 run_async([this] {
210 write((1<<20), 4<<10, 'a');
211 write((1<<20)+(4<<10), 4<<10, 'c');
212 write((1<<20), 8<<10, 'b');
213
214 read_near(1<<20, 8<<10, 1);
215 read_near(1<<20, 8<<10, 512);
216
217 read_near(1<<20, 4<<10, 1);
218 read_near(1<<20, 4<<10, 512);
219
220 read_near((1<<20) + (4<<10), 4<<10, 1);
221 read_near((1<<20) + (4<<10), 4<<10, 512);
222 });
223 }
224
225 TEST_F(object_data_handler_test_t, overwrite_partial)
226 {
227 run_async([this] {
228 write((1<<20), 12<<10, 'a');
229 read_near(1<<20, 12<<10, 1);
230
231 write((1<<20)+(8<<10), 4<<10, 'b');
232 read_near(1<<20, 12<<10, 1);
233
234 write((1<<20)+(4<<10), 4<<10, 'c');
235 read_near(1<<20, 12<<10, 1);
236
237 write((1<<20), 4<<10, 'd');
238
239 read_near(1<<20, 12<<10, 1);
240 read_near(1<<20, 12<<10, 512);
241
242 read_near(1<<20, 4<<10, 1);
243 read_near(1<<20, 4<<10, 512);
244
245 read_near((1<<20) + (4<<10), 4<<10, 1);
246 read_near((1<<20) + (4<<10), 4<<10, 512);
247 });
248 }
249
250 TEST_F(object_data_handler_test_t, unaligned_write)
251 {
252 run_async([this] {
253 objaddr_t base = 1<<20;
254 write(base, (4<<10)+(1<<10), 'a');
255 read_near(base-(4<<10), 12<<10, 512);
256
257 base = (1<<20) + (64<<10);
258 write(base+(1<<10), (4<<10)+(1<<10), 'b');
259 read_near(base-(4<<10), 12<<10, 512);
260
261 base = (1<<20) + (128<<10);
262 write(base-(1<<10), (4<<10)+(2<<20), 'c');
263 read_near(base-(4<<10), 12<<10, 512);
264 });
265 }
266
267 TEST_F(object_data_handler_test_t, unaligned_overwrite)
268 {
269 run_async([this] {
270 objaddr_t base = 1<<20;
271 write(base, (128<<10) + (16<<10), 'x');
272
273 write(base, (4<<10)+(1<<10), 'a');
274 read_near(base-(4<<10), 12<<10, 2<<10);
275
276 base = (1<<20) + (64<<10);
277 write(base+(1<<10), (4<<10)+(1<<10), 'b');
278 read_near(base-(4<<10), 12<<10, 2<<10);
279
280 base = (1<<20) + (128<<10);
281 write(base-(1<<10), (4<<10)+(2<<20), 'c');
282 read_near(base-(4<<10), 12<<10, 2<<10);
283
284 read(base, (128<<10) + (16<<10));
285 });
286 }
287
288 TEST_F(object_data_handler_test_t, truncate)
289 {
290 run_async([this] {
291 objaddr_t base = 1<<20;
292 write(base, 8<<10, 'a');
293 write(base+(8<<10), 8<<10, 'b');
294 write(base+(16<<10), 8<<10, 'c');
295
296 truncate(base + (32<<10));
297 read(base, 64<<10);
298
299 truncate(base + (24<<10));
300 read(base, 64<<10);
301
302 truncate(base + (12<<10));
303 read(base, 64<<10);
304
305 truncate(base - (12<<10));
306 read(base, 64<<10);
307 });
308 }