]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | #include <errno.h> | |
4 | #include <map> | |
5 | #include <sstream> | |
6 | #include <string> | |
7 | #include <regex> | |
8 | ||
9 | #include "gtest/gtest.h" | |
10 | ||
11 | #include "include/err.h" | |
12 | #include "include/buffer.h" | |
13 | #include "include/rbd_types.h" | |
14 | #include "include/rados.h" | |
15 | #include "include/rados/librados.hpp" | |
16 | #include "include/scope_guard.h" | |
17 | #include "include/stringify.h" | |
18 | #include "common/Checksummer.h" | |
19 | #include "mds/mdstypes.h" | |
20 | #include "global/global_context.h" | |
21 | #include "test/librados/testcase_cxx.h" | |
22 | #include "test/librados/test_cxx.h" | |
23 | ||
24 | using namespace librados; | |
25 | using std::map; | |
26 | using std::ostringstream; | |
27 | using std::string; | |
28 | ||
29 | typedef RadosTestPP LibRadosMiscPP; | |
30 | typedef RadosTestECPP LibRadosMiscECPP; | |
31 | ||
32 | TEST(LibRadosMiscVersion, VersionPP) { | |
33 | int major, minor, extra; | |
34 | Rados::version(&major, &minor, &extra); | |
35 | } | |
36 | ||
37 | TEST_F(LibRadosMiscPP, WaitOSDMapPP) { | |
38 | ASSERT_EQ(0, cluster.wait_for_latest_osdmap()); | |
39 | } | |
40 | ||
41 | TEST_F(LibRadosMiscPP, LongNamePP) { | |
42 | bufferlist bl; | |
43 | bl.append("content"); | |
44 | int maxlen = g_conf()->osd_max_object_name_len; | |
45 | ASSERT_EQ(0, ioctx.write(string(maxlen/2, 'a').c_str(), bl, bl.length(), 0)); | |
46 | ASSERT_EQ(0, ioctx.write(string(maxlen-1, 'a').c_str(), bl, bl.length(), 0)); | |
47 | ASSERT_EQ(0, ioctx.write(string(maxlen, 'a').c_str(), bl, bl.length(), 0)); | |
48 | ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen+1, 'a').c_str(), bl, bl.length(), 0)); | |
49 | ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen*2, 'a').c_str(), bl, bl.length(), 0)); | |
50 | } | |
51 | ||
52 | TEST_F(LibRadosMiscPP, LongLocatorPP) { | |
53 | bufferlist bl; | |
54 | bl.append("content"); | |
55 | int maxlen = g_conf()->osd_max_object_name_len; | |
56 | ioctx.locator_set_key( | |
57 | string((maxlen/2), 'a')); | |
58 | ASSERT_EQ( | |
59 | 0, | |
60 | ioctx.write( | |
61 | string("a").c_str(), | |
62 | bl, bl.length(), 0)); | |
63 | ioctx.locator_set_key( | |
64 | string(maxlen - 1, 'a')); | |
65 | ASSERT_EQ( | |
66 | 0, | |
67 | ioctx.write( | |
68 | string("a").c_str(), | |
69 | bl, bl.length(), 0)); | |
70 | ioctx.locator_set_key( | |
71 | string(maxlen, 'a')); | |
72 | ASSERT_EQ( | |
73 | 0, | |
74 | ioctx.write( | |
75 | string("a").c_str(), | |
76 | bl, bl.length(), 0)); | |
77 | ioctx.locator_set_key( | |
78 | string(maxlen+1, 'a')); | |
79 | ASSERT_EQ( | |
80 | -ENAMETOOLONG, | |
81 | ioctx.write( | |
82 | string("a").c_str(), | |
83 | bl, bl.length(), 0)); | |
84 | ioctx.locator_set_key( | |
85 | string((maxlen*2), 'a')); | |
86 | ASSERT_EQ( | |
87 | -ENAMETOOLONG, | |
88 | ioctx.write( | |
89 | string("a").c_str(), | |
90 | bl, bl.length(), 0)); | |
91 | } | |
92 | ||
93 | TEST_F(LibRadosMiscPP, LongNSpacePP) { | |
94 | bufferlist bl; | |
95 | bl.append("content"); | |
96 | int maxlen = g_conf()->osd_max_object_namespace_len; | |
97 | ioctx.set_namespace( | |
98 | string((maxlen/2), 'a')); | |
99 | ASSERT_EQ( | |
100 | 0, | |
101 | ioctx.write( | |
102 | string("a").c_str(), | |
103 | bl, bl.length(), 0)); | |
104 | ioctx.set_namespace( | |
105 | string(maxlen - 1, 'a')); | |
106 | ASSERT_EQ( | |
107 | 0, | |
108 | ioctx.write( | |
109 | string("a").c_str(), | |
110 | bl, bl.length(), 0)); | |
111 | ioctx.set_namespace( | |
112 | string(maxlen, 'a')); | |
113 | ASSERT_EQ( | |
114 | 0, | |
115 | ioctx.write( | |
116 | string("a").c_str(), | |
117 | bl, bl.length(), 0)); | |
118 | ioctx.set_namespace( | |
119 | string(maxlen+1, 'a')); | |
120 | ASSERT_EQ( | |
121 | -ENAMETOOLONG, | |
122 | ioctx.write( | |
123 | string("a").c_str(), | |
124 | bl, bl.length(), 0)); | |
125 | ioctx.set_namespace( | |
126 | string((maxlen*2), 'a')); | |
127 | ASSERT_EQ( | |
128 | -ENAMETOOLONG, | |
129 | ioctx.write( | |
130 | string("a").c_str(), | |
131 | bl, bl.length(), 0)); | |
132 | } | |
133 | ||
134 | TEST_F(LibRadosMiscPP, LongAttrNamePP) { | |
135 | bufferlist bl; | |
136 | bl.append("content"); | |
137 | int maxlen = g_conf()->osd_max_attr_name_len; | |
138 | ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen/2, 'a').c_str(), bl)); | |
139 | ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen-1, 'a').c_str(), bl)); | |
140 | ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen, 'a').c_str(), bl)); | |
141 | ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen+1, 'a').c_str(), bl)); | |
142 | ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen*2, 'a').c_str(), bl)); | |
143 | } | |
144 | ||
145 | TEST_F(LibRadosMiscPP, ExecPP) { | |
146 | bufferlist bl; | |
147 | ASSERT_EQ(0, ioctx.write("foo", bl, 0, 0)); | |
148 | bufferlist bl2, out; | |
149 | int r = ioctx.exec("foo", "rbd", "get_all_features", bl2, out); | |
150 | ASSERT_EQ(0, r); | |
151 | auto iter = out.cbegin(); | |
152 | uint64_t all_features; | |
153 | decode(all_features, iter); | |
154 | // make sure *some* features are specified; don't care which ones | |
155 | ASSERT_NE(all_features, (unsigned)0); | |
156 | } | |
157 | ||
158 | void set_completion_complete(rados_completion_t cb, void *arg) | |
159 | { | |
160 | bool *my_aio_complete = (bool*)arg; | |
161 | *my_aio_complete = true; | |
162 | } | |
163 | ||
164 | TEST_F(LibRadosMiscPP, BadFlagsPP) { | |
165 | unsigned badflags = CEPH_OSD_FLAG_PARALLELEXEC; | |
166 | { | |
167 | bufferlist bl; | |
168 | bl.append("data"); | |
169 | ASSERT_EQ(0, ioctx.write("badfoo", bl, bl.length(), 0)); | |
170 | } | |
171 | { | |
172 | ASSERT_EQ(-EINVAL, ioctx.remove("badfoo", badflags)); | |
173 | } | |
174 | } | |
175 | ||
176 | TEST_F(LibRadosMiscPP, Operate1PP) { | |
177 | ObjectWriteOperation o; | |
178 | { | |
179 | bufferlist bl; | |
180 | o.write(0, bl); | |
181 | } | |
182 | std::string val1("val1"); | |
183 | { | |
184 | bufferlist bl; | |
185 | bl.append(val1.c_str(), val1.size() + 1); | |
186 | o.setxattr("key1", bl); | |
187 | o.omap_clear(); // shouldn't affect attrs! | |
188 | } | |
189 | ASSERT_EQ(0, ioctx.operate("foo", &o)); | |
190 | ||
191 | ObjectWriteOperation empty; | |
192 | ASSERT_EQ(0, ioctx.operate("foo", &empty)); | |
193 | ||
194 | { | |
195 | bufferlist bl; | |
196 | ASSERT_GT(ioctx.getxattr("foo", "key1", bl), 0); | |
197 | ASSERT_EQ(0, strcmp(bl.c_str(), val1.c_str())); | |
198 | } | |
199 | ObjectWriteOperation o2; | |
200 | { | |
201 | bufferlist bl; | |
202 | bl.append(val1); | |
203 | o2.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl); | |
204 | o2.rmxattr("key1"); | |
205 | } | |
206 | ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o2)); | |
207 | ObjectWriteOperation o3; | |
208 | { | |
209 | bufferlist bl; | |
210 | bl.append(val1); | |
211 | o3.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl); | |
212 | } | |
213 | ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o3)); | |
214 | } | |
215 | ||
216 | TEST_F(LibRadosMiscPP, Operate2PP) { | |
217 | ObjectWriteOperation o; | |
218 | { | |
219 | bufferlist bl; | |
220 | bl.append("abcdefg"); | |
221 | o.write(0, bl); | |
222 | } | |
223 | std::string val1("val1"); | |
224 | { | |
225 | bufferlist bl; | |
226 | bl.append(val1.c_str(), val1.size() + 1); | |
227 | o.setxattr("key1", bl); | |
228 | o.truncate(0); | |
229 | } | |
230 | ASSERT_EQ(0, ioctx.operate("foo", &o)); | |
231 | uint64_t size; | |
232 | time_t mtime; | |
233 | ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); | |
234 | ASSERT_EQ(0U, size); | |
235 | } | |
236 | ||
237 | TEST_F(LibRadosMiscPP, BigObjectPP) { | |
238 | bufferlist bl; | |
239 | bl.append("abcdefg"); | |
240 | ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0)); | |
241 | ||
242 | { | |
243 | ObjectWriteOperation o; | |
244 | o.truncate(500000000000ull); | |
245 | ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); | |
246 | } | |
247 | { | |
248 | ObjectWriteOperation o; | |
249 | o.zero(500000000000ull, 1); | |
250 | ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); | |
251 | } | |
252 | { | |
253 | ObjectWriteOperation o; | |
254 | o.zero(1, 500000000000ull); | |
255 | ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); | |
256 | } | |
257 | { | |
258 | ObjectWriteOperation o; | |
259 | o.zero(500000000000ull, 500000000000ull); | |
260 | ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o)); | |
261 | } | |
262 | ||
263 | #ifdef __LP64__ | |
264 | // this test only works on 64-bit platforms | |
265 | ASSERT_EQ(-EFBIG, ioctx.write("foo", bl, bl.length(), 500000000000ull)); | |
266 | #endif | |
267 | } | |
268 | ||
269 | TEST_F(LibRadosMiscPP, AioOperatePP) { | |
270 | bool my_aio_complete = false; | |
271 | AioCompletion *my_completion = cluster.aio_create_completion( | |
9f95a23c | 272 | (void*)&my_aio_complete, set_completion_complete); |
11fdf7f2 TL |
273 | AioCompletion *my_completion_null = NULL; |
274 | ASSERT_NE(my_completion, my_completion_null); | |
275 | ||
276 | ObjectWriteOperation o; | |
277 | { | |
278 | bufferlist bl; | |
279 | o.write(0, bl); | |
280 | } | |
281 | std::string val1("val1"); | |
282 | { | |
283 | bufferlist bl; | |
284 | bl.append(val1.c_str(), val1.size() + 1); | |
285 | o.setxattr("key1", bl); | |
286 | bufferlist bl2; | |
287 | char buf2[1024]; | |
288 | memset(buf2, 0xdd, sizeof(buf2)); | |
289 | bl2.append(buf2, sizeof(buf2)); | |
290 | o.append(bl2); | |
291 | } | |
292 | ASSERT_EQ(0, ioctx.aio_operate("foo", my_completion, &o)); | |
293 | ASSERT_EQ(0, my_completion->wait_for_complete_and_cb()); | |
294 | ASSERT_EQ(my_aio_complete, true); | |
295 | my_completion->release(); | |
296 | ||
297 | uint64_t size; | |
298 | time_t mtime; | |
299 | ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime)); | |
300 | ASSERT_EQ(1024U, size); | |
301 | } | |
302 | ||
303 | TEST_F(LibRadosMiscPP, AssertExistsPP) { | |
304 | char buf[64]; | |
305 | memset(buf, 0xcc, sizeof(buf)); | |
306 | bufferlist bl; | |
307 | bl.append(buf, sizeof(buf)); | |
308 | ||
309 | ObjectWriteOperation op; | |
310 | op.assert_exists(); | |
311 | op.write(0, bl); | |
312 | ASSERT_EQ(-ENOENT, ioctx.operate("asdffoo", &op)); | |
313 | ASSERT_EQ(0, ioctx.create("asdffoo", true)); | |
314 | ASSERT_EQ(0, ioctx.operate("asdffoo", &op)); | |
315 | ASSERT_EQ(-EEXIST, ioctx.create("asdffoo", true)); | |
316 | } | |
317 | ||
318 | TEST_F(LibRadosMiscPP, AssertVersionPP) { | |
319 | char buf[64]; | |
320 | memset(buf, 0xcc, sizeof(buf)); | |
321 | bufferlist bl; | |
322 | bl.append(buf, sizeof(buf)); | |
323 | ||
324 | // Create test object... | |
325 | ASSERT_EQ(0, ioctx.create("asdfbar", true)); | |
326 | // ...then write it again to guarantee that the | |
327 | // (unsigned) version must be at least 1 (not 0) | |
328 | // since we want to decrement it by 1 later. | |
329 | ASSERT_EQ(0, ioctx.write_full("asdfbar", bl)); | |
330 | ||
331 | uint64_t v = ioctx.get_last_version(); | |
332 | ObjectWriteOperation op1; | |
333 | op1.assert_version(v+1); | |
334 | op1.write(0, bl); | |
335 | ASSERT_EQ(-EOVERFLOW, ioctx.operate("asdfbar", &op1)); | |
336 | ObjectWriteOperation op2; | |
337 | op2.assert_version(v-1); | |
338 | op2.write(0, bl); | |
339 | ASSERT_EQ(-ERANGE, ioctx.operate("asdfbar", &op2)); | |
340 | ObjectWriteOperation op3; | |
341 | op3.assert_version(v); | |
342 | op3.write(0, bl); | |
343 | ASSERT_EQ(0, ioctx.operate("asdfbar", &op3)); | |
344 | } | |
345 | ||
346 | TEST_F(LibRadosMiscPP, BigAttrPP) { | |
347 | char buf[64]; | |
348 | memset(buf, 0xcc, sizeof(buf)); | |
349 | bufferlist bl; | |
350 | bl.append(buf, sizeof(buf)); | |
351 | ||
352 | ASSERT_EQ(0, ioctx.create("foo", true)); | |
353 | ||
354 | bufferlist got; | |
355 | ||
356 | cout << "osd_max_attr_size = " << g_conf()->osd_max_attr_size << std::endl; | |
357 | if (g_conf()->osd_max_attr_size) { | |
358 | bl.clear(); | |
359 | got.clear(); | |
360 | bl.append(buffer::create(g_conf()->osd_max_attr_size)); | |
361 | ASSERT_EQ(0, ioctx.setxattr("foo", "one", bl)); | |
362 | ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", "one", got)); | |
363 | ASSERT_TRUE(bl.contents_equal(got)); | |
364 | ||
365 | bl.clear(); | |
366 | bl.append(buffer::create(g_conf()->osd_max_attr_size+1)); | |
367 | ASSERT_EQ(-EFBIG, ioctx.setxattr("foo", "one", bl)); | |
368 | } else { | |
369 | cout << "osd_max_attr_size == 0; skipping test" << std::endl; | |
370 | } | |
371 | ||
372 | for (int i=0; i<1000; i++) { | |
373 | bl.clear(); | |
374 | got.clear(); | |
375 | bl.append(buffer::create(std::min<uint64_t>(g_conf()->osd_max_attr_size, | |
376 | 1024))); | |
377 | char n[10]; | |
378 | snprintf(n, sizeof(n), "a%d", i); | |
379 | ASSERT_EQ(0, ioctx.setxattr("foo", n, bl)); | |
380 | ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", n, got)); | |
381 | ASSERT_TRUE(bl.contents_equal(got)); | |
382 | } | |
383 | } | |
384 | ||
385 | TEST_F(LibRadosMiscPP, CopyPP) { | |
386 | bufferlist bl, x; | |
387 | bl.append("hi there"); | |
388 | x.append("bar"); | |
389 | ||
390 | // small object | |
391 | bufferlist blc = bl; | |
392 | bufferlist xc = x; | |
393 | ASSERT_EQ(0, ioctx.write_full("foo", blc)); | |
394 | ASSERT_EQ(0, ioctx.setxattr("foo", "myattr", xc)); | |
395 | ||
396 | version_t uv = ioctx.get_last_version(); | |
397 | { | |
398 | // pass future version | |
399 | ObjectWriteOperation op; | |
400 | op.copy_from("foo", ioctx, uv + 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); | |
401 | ASSERT_EQ(-EOVERFLOW, ioctx.operate("foo.copy", &op)); | |
402 | } | |
403 | { | |
404 | // pass old version | |
405 | ObjectWriteOperation op; | |
406 | op.copy_from("foo", ioctx, uv - 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); | |
407 | ASSERT_EQ(-ERANGE, ioctx.operate("foo.copy", &op)); | |
408 | } | |
409 | { | |
410 | ObjectWriteOperation op; | |
411 | op.copy_from("foo", ioctx, uv, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); | |
412 | ASSERT_EQ(0, ioctx.operate("foo.copy", &op)); | |
413 | ||
414 | bufferlist bl2, x2; | |
415 | ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy", bl2, 10000, 0)); | |
416 | ASSERT_TRUE(bl.contents_equal(bl2)); | |
417 | ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2)); | |
418 | ASSERT_TRUE(x.contents_equal(x2)); | |
419 | } | |
420 | ||
421 | // small object without a version | |
422 | { | |
423 | ObjectWriteOperation op; | |
424 | op.copy_from("foo", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED); | |
425 | ASSERT_EQ(0, ioctx.operate("foo.copy2", &op)); | |
426 | ||
427 | bufferlist bl2, x2; | |
428 | ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy2", bl2, 10000, 0)); | |
429 | ASSERT_TRUE(bl.contents_equal(bl2)); | |
430 | ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2)); | |
431 | ASSERT_TRUE(x.contents_equal(x2)); | |
432 | } | |
433 | ||
434 | // do a big object | |
435 | bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3)); | |
436 | bl.zero(); | |
437 | bl.append("tail"); | |
438 | blc = bl; | |
439 | xc = x; | |
440 | ASSERT_EQ(0, ioctx.write_full("big", blc)); | |
441 | ASSERT_EQ(0, ioctx.setxattr("big", "myattr", xc)); | |
442 | ||
443 | { | |
444 | ObjectWriteOperation op; | |
445 | op.copy_from("big", ioctx, ioctx.get_last_version(), LIBRADOS_OP_FLAG_FADVISE_DONTNEED); | |
446 | ASSERT_EQ(0, ioctx.operate("big.copy", &op)); | |
447 | ||
448 | bufferlist bl2, x2; | |
449 | ASSERT_EQ((int)bl.length(), ioctx.read("big.copy", bl2, bl.length(), 0)); | |
450 | ASSERT_TRUE(bl.contents_equal(bl2)); | |
451 | ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2)); | |
452 | ASSERT_TRUE(x.contents_equal(x2)); | |
453 | } | |
454 | ||
455 | { | |
456 | ObjectWriteOperation op; | |
457 | op.copy_from("big", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL); | |
458 | ASSERT_EQ(0, ioctx.operate("big.copy2", &op)); | |
459 | ||
460 | bufferlist bl2, x2; | |
461 | ASSERT_EQ((int)bl.length(), ioctx.read("big.copy2", bl2, bl.length(), 0)); | |
462 | ASSERT_TRUE(bl.contents_equal(bl2)); | |
463 | ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2)); | |
464 | ASSERT_TRUE(x.contents_equal(x2)); | |
465 | } | |
466 | } | |
467 | ||
468 | class LibRadosTwoPoolsECPP : public RadosTestECPP | |
469 | { | |
470 | public: | |
471 | LibRadosTwoPoolsECPP() {}; | |
472 | ~LibRadosTwoPoolsECPP() override {}; | |
473 | protected: | |
474 | static void SetUpTestCase() { | |
475 | pool_name = get_temp_pool_name(); | |
476 | ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster)); | |
477 | src_pool_name = get_temp_pool_name(); | |
478 | ASSERT_EQ(0, s_cluster.pool_create(src_pool_name.c_str())); | |
479 | ||
480 | librados::IoCtx ioctx; | |
481 | ASSERT_EQ(0, s_cluster.ioctx_create(pool_name.c_str(), ioctx)); | |
482 | ioctx.application_enable("rados", true); | |
483 | ||
484 | librados::IoCtx src_ioctx; | |
485 | ASSERT_EQ(0, s_cluster.ioctx_create(src_pool_name.c_str(), src_ioctx)); | |
486 | src_ioctx.application_enable("rados", true); | |
487 | } | |
488 | static void TearDownTestCase() { | |
489 | ASSERT_EQ(0, s_cluster.pool_delete(src_pool_name.c_str())); | |
490 | ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster)); | |
491 | } | |
492 | static std::string src_pool_name; | |
493 | ||
494 | void SetUp() override { | |
495 | RadosTestECPP::SetUp(); | |
496 | ASSERT_EQ(0, cluster.ioctx_create(src_pool_name.c_str(), src_ioctx)); | |
497 | src_ioctx.set_namespace(nspace); | |
498 | } | |
499 | void TearDown() override { | |
500 | // wait for maps to settle before next test | |
501 | cluster.wait_for_latest_osdmap(); | |
502 | ||
503 | RadosTestECPP::TearDown(); | |
504 | ||
505 | cleanup_default_namespace(src_ioctx); | |
506 | cleanup_namespace(src_ioctx, nspace); | |
507 | ||
508 | src_ioctx.close(); | |
509 | } | |
510 | ||
511 | librados::IoCtx src_ioctx; | |
512 | }; | |
513 | std::string LibRadosTwoPoolsECPP::src_pool_name; | |
514 | ||
515 | //copy_from between ecpool and no-ecpool. | |
516 | TEST_F(LibRadosTwoPoolsECPP, CopyFrom) { | |
517 | bufferlist z; | |
518 | z.append_zero(4194304*2); | |
519 | bufferlist b; | |
520 | b.append("copyfrom"); | |
521 | ||
522 | // create big object w/ omapheader | |
523 | { | |
524 | ASSERT_EQ(0, src_ioctx.write_full("foo", z)); | |
525 | ASSERT_EQ(0, src_ioctx.omap_set_header("foo", b)); | |
526 | version_t uv = src_ioctx.get_last_version(); | |
527 | ObjectWriteOperation op; | |
528 | op.copy_from("foo", src_ioctx, uv, 0); | |
529 | ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("foo.copy", &op)); | |
530 | } | |
531 | ||
532 | // same with small object | |
533 | { | |
534 | ASSERT_EQ(0, src_ioctx.omap_set_header("bar", b)); | |
535 | version_t uv = src_ioctx.get_last_version(); | |
536 | ObjectWriteOperation op; | |
537 | op.copy_from("bar", src_ioctx, uv, 0); | |
538 | ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("bar.copy", &op)); | |
539 | } | |
540 | } | |
541 | ||
542 | TEST_F(LibRadosMiscPP, CopyScrubPP) { | |
543 | bufferlist inbl, bl, x; | |
544 | for (int i=0; i<100; ++i) | |
545 | x.append("barrrrrrrrrrrrrrrrrrrrrrrrrr"); | |
546 | bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3)); | |
547 | bl.zero(); | |
548 | bl.append("tail"); | |
549 | bufferlist cbl; | |
550 | ||
551 | map<string, bufferlist> to_set; | |
552 | for (int i=0; i<1000; ++i) | |
553 | to_set[string("foo") + stringify(i)] = x; | |
554 | ||
555 | // small | |
556 | cbl = x; | |
557 | ASSERT_EQ(0, ioctx.write_full("small", cbl)); | |
558 | ASSERT_EQ(0, ioctx.setxattr("small", "myattr", x)); | |
559 | ||
560 | // big | |
561 | cbl = bl; | |
562 | ASSERT_EQ(0, ioctx.write_full("big", cbl)); | |
563 | ||
564 | // without header | |
565 | cbl = bl; | |
566 | ASSERT_EQ(0, ioctx.write_full("big2", cbl)); | |
567 | ASSERT_EQ(0, ioctx.setxattr("big2", "myattr", x)); | |
568 | ASSERT_EQ(0, ioctx.setxattr("big2", "myattr2", x)); | |
569 | ASSERT_EQ(0, ioctx.omap_set("big2", to_set)); | |
570 | ||
571 | // with header | |
572 | cbl = bl; | |
573 | ASSERT_EQ(0, ioctx.write_full("big3", cbl)); | |
574 | ASSERT_EQ(0, ioctx.omap_set_header("big3", x)); | |
575 | ASSERT_EQ(0, ioctx.omap_set("big3", to_set)); | |
576 | ||
577 | // deep scrub to ensure digests are in place | |
578 | { | |
579 | for (int i=0; i<10; ++i) { | |
580 | ostringstream ss; | |
581 | ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \"" | |
582 | << ioctx.get_id() << "." << i | |
583 | << "\"}"; | |
584 | cluster.mon_command(ss.str(), inbl, NULL, NULL); | |
585 | } | |
586 | ||
587 | // give it a few seconds to go. this is sloppy but is usually enough time | |
588 | cout << "waiting for initial deep scrubs..." << std::endl; | |
589 | sleep(30); | |
590 | cout << "done waiting, doing copies" << std::endl; | |
591 | } | |
592 | ||
593 | { | |
594 | ObjectWriteOperation op; | |
595 | op.copy_from("small", ioctx, 0, 0); | |
596 | ASSERT_EQ(0, ioctx.operate("small.copy", &op)); | |
597 | } | |
598 | ||
599 | { | |
600 | ObjectWriteOperation op; | |
601 | op.copy_from("big", ioctx, 0, 0); | |
602 | ASSERT_EQ(0, ioctx.operate("big.copy", &op)); | |
603 | } | |
604 | ||
605 | { | |
606 | ObjectWriteOperation op; | |
607 | op.copy_from("big2", ioctx, 0, 0); | |
608 | ASSERT_EQ(0, ioctx.operate("big2.copy", &op)); | |
609 | } | |
610 | ||
611 | { | |
612 | ObjectWriteOperation op; | |
613 | op.copy_from("big3", ioctx, 0, 0); | |
614 | ASSERT_EQ(0, ioctx.operate("big3.copy", &op)); | |
615 | } | |
616 | ||
617 | // deep scrub to ensure digests are correct | |
618 | { | |
619 | for (int i=0; i<10; ++i) { | |
620 | ostringstream ss; | |
621 | ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \"" | |
622 | << ioctx.get_id() << "." << i | |
623 | << "\"}"; | |
624 | cluster.mon_command(ss.str(), inbl, NULL, NULL); | |
625 | } | |
626 | ||
627 | // give it a few seconds to go. this is sloppy but is usually enough time | |
628 | cout << "waiting for final deep scrubs..." << std::endl; | |
629 | sleep(30); | |
630 | cout << "done waiting" << std::endl; | |
631 | } | |
632 | } | |
633 | ||
634 | TEST_F(LibRadosMiscPP, WriteSamePP) { | |
635 | bufferlist bl; | |
636 | char buf[128]; | |
637 | bufferlist fl; | |
638 | char full[128 * 4]; | |
639 | char *cmp; | |
640 | ||
641 | /* zero the full range before using writesame */ | |
642 | memset(full, 0, sizeof(full)); | |
643 | fl.append(full, sizeof(full)); | |
644 | ASSERT_EQ(0, ioctx.write("ws", fl, fl.length(), 0)); | |
645 | ||
646 | memset(buf, 0xcc, sizeof(buf)); | |
647 | bl.clear(); | |
648 | bl.append(buf, sizeof(buf)); | |
649 | /* write the same buf four times */ | |
650 | ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(full), 0)); | |
651 | ||
652 | /* read back the full buffer and confirm that it matches */ | |
653 | fl.clear(); | |
654 | fl.append(full, sizeof(full)); | |
655 | ASSERT_EQ((int)fl.length(), ioctx.read("ws", fl, fl.length(), 0)); | |
656 | ||
657 | for (cmp = fl.c_str(); cmp < fl.c_str() + fl.length(); cmp += sizeof(buf)) { | |
658 | ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf))); | |
659 | } | |
660 | ||
661 | /* write_len not a multiple of data_len should throw error */ | |
662 | bl.clear(); | |
663 | bl.append(buf, sizeof(buf)); | |
664 | ASSERT_EQ(-EINVAL, ioctx.writesame("ws", bl, (sizeof(buf) * 4) - 1, 0)); | |
665 | ASSERT_EQ(-EINVAL, | |
666 | ioctx.writesame("ws", bl, bl.length() / 2, 0)); | |
667 | /* write_len = data_len, i.e. same as write() */ | |
668 | ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(buf), 0)); | |
669 | bl.clear(); | |
670 | ASSERT_EQ(-EINVAL, | |
671 | ioctx.writesame("ws", bl, sizeof(buf), 0)); | |
672 | } | |
673 | ||
674 | template <typename T> | |
675 | class LibRadosChecksum : public LibRadosMiscPP { | |
676 | public: | |
677 | typedef typename T::alg_t alg_t; | |
678 | typedef typename T::value_t value_t; | |
679 | typedef typename alg_t::init_value_t init_value_t; | |
680 | ||
681 | static const rados_checksum_type_t type = T::type; | |
682 | ||
683 | bufferlist content_bl; | |
684 | ||
685 | using LibRadosMiscPP::SetUpTestCase; | |
686 | using LibRadosMiscPP::TearDownTestCase; | |
687 | ||
688 | void SetUp() override { | |
689 | LibRadosMiscPP::SetUp(); | |
690 | ||
691 | std::string content(4096, '\0'); | |
692 | for (size_t i = 0; i < content.length(); ++i) { | |
693 | content[i] = static_cast<char>(rand() % (126 - 33) + 33); | |
694 | } | |
695 | content_bl.append(content); | |
696 | ASSERT_EQ(0, ioctx.write("foo", content_bl, content_bl.length(), 0)); | |
697 | } | |
698 | }; | |
699 | ||
700 | template <rados_checksum_type_t _type, typename AlgT, typename ValueT> | |
701 | class LibRadosChecksumParams { | |
702 | public: | |
703 | typedef AlgT alg_t; | |
704 | typedef ValueT value_t; | |
705 | static const rados_checksum_type_t type = _type; | |
706 | }; | |
707 | ||
708 | typedef ::testing::Types< | |
709 | LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH32, | |
f91f0fd5 | 710 | Checksummer::xxhash32, ceph_le32>, |
11fdf7f2 | 711 | LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH64, |
f91f0fd5 | 712 | Checksummer::xxhash64, ceph_le64>, |
11fdf7f2 | 713 | LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_CRC32C, |
f91f0fd5 | 714 | Checksummer::crc32c, ceph_le32> |
11fdf7f2 TL |
715 | > LibRadosChecksumTypes; |
716 | ||
9f95a23c | 717 | TYPED_TEST_SUITE(LibRadosChecksum, LibRadosChecksumTypes); |
11fdf7f2 TL |
718 | |
719 | TYPED_TEST(LibRadosChecksum, Subset) { | |
720 | uint32_t chunk_size = 1024; | |
721 | uint32_t csum_count = this->content_bl.length() / chunk_size; | |
722 | ||
723 | typename TestFixture::init_value_t init_value = -1; | |
724 | bufferlist init_value_bl; | |
725 | encode(init_value, init_value_bl); | |
726 | ||
727 | std::vector<bufferlist> checksum_bls(csum_count); | |
728 | std::vector<int> checksum_rvals(csum_count); | |
729 | ||
730 | // individual checksum ops for each chunk | |
731 | ObjectReadOperation op; | |
732 | for (uint32_t i = 0; i < csum_count; ++i) { | |
733 | op.checksum(TestFixture::type, init_value_bl, i * chunk_size, chunk_size, | |
734 | 0, &checksum_bls[i], &checksum_rvals[i]); | |
735 | } | |
736 | ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL)); | |
737 | ||
738 | for (uint32_t i = 0; i < csum_count; ++i) { | |
739 | ASSERT_EQ(0, checksum_rvals[i]); | |
740 | ||
741 | auto bl_it = checksum_bls[i].cbegin(); | |
742 | uint32_t count; | |
743 | decode(count, bl_it); | |
744 | ASSERT_EQ(1U, count); | |
745 | ||
746 | typename TestFixture::value_t value; | |
747 | decode(value, bl_it); | |
748 | ||
749 | bufferlist content_sub_bl; | |
750 | content_sub_bl.substr_of(this->content_bl, i * chunk_size, chunk_size); | |
751 | ||
752 | typename TestFixture::value_t expected_value; | |
753 | bufferptr expected_value_bp = buffer::create_static( | |
754 | sizeof(expected_value), reinterpret_cast<char*>(&expected_value)); | |
755 | Checksummer::template calculate<typename TestFixture::alg_t>( | |
756 | init_value, chunk_size, 0, chunk_size, content_sub_bl, | |
757 | &expected_value_bp); | |
758 | ASSERT_EQ(expected_value, value); | |
759 | } | |
760 | } | |
761 | ||
762 | TYPED_TEST(LibRadosChecksum, Chunked) { | |
763 | uint32_t chunk_size = 1024; | |
764 | uint32_t csum_count = this->content_bl.length() / chunk_size; | |
765 | ||
766 | typename TestFixture::init_value_t init_value = -1; | |
767 | bufferlist init_value_bl; | |
768 | encode(init_value, init_value_bl); | |
769 | ||
770 | bufferlist checksum_bl; | |
771 | int checksum_rval; | |
772 | ||
773 | // single op with chunked checksum results | |
774 | ObjectReadOperation op; | |
775 | op.checksum(TestFixture::type, init_value_bl, 0, this->content_bl.length(), | |
776 | chunk_size, &checksum_bl, &checksum_rval); | |
777 | ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL)); | |
778 | ASSERT_EQ(0, checksum_rval); | |
779 | ||
780 | auto bl_it = checksum_bl.cbegin(); | |
781 | uint32_t count; | |
782 | decode(count, bl_it); | |
783 | ASSERT_EQ(csum_count, count); | |
784 | ||
785 | std::vector<typename TestFixture::value_t> expected_values(csum_count); | |
786 | bufferptr expected_values_bp = buffer::create_static( | |
787 | csum_count * sizeof(typename TestFixture::value_t), | |
788 | reinterpret_cast<char*>(&expected_values[0])); | |
789 | ||
790 | Checksummer::template calculate<typename TestFixture::alg_t>( | |
791 | init_value, chunk_size, 0, this->content_bl.length(), this->content_bl, | |
792 | &expected_values_bp); | |
793 | ||
794 | for (uint32_t i = 0; i < csum_count; ++i) { | |
795 | typename TestFixture::value_t value; | |
796 | decode(value, bl_it); | |
797 | ASSERT_EQ(expected_values[i], value); | |
798 | } | |
799 | } | |
800 | ||
801 | TEST_F(LibRadosMiscPP, CmpExtPP) { | |
802 | bufferlist cmp_bl, bad_cmp_bl, write_bl; | |
803 | char stored_str[] = "1234567891"; | |
804 | char mismatch_str[] = "1234577777"; | |
805 | ||
806 | write_bl.append(stored_str); | |
807 | ioctx.write("cmpextpp", write_bl, write_bl.length(), 0); | |
808 | cmp_bl.append(stored_str); | |
809 | ASSERT_EQ(0, ioctx.cmpext("cmpextpp", 0, cmp_bl)); | |
810 | ||
811 | bad_cmp_bl.append(mismatch_str); | |
812 | ASSERT_EQ(-MAX_ERRNO - 5, ioctx.cmpext("cmpextpp", 0, bad_cmp_bl)); | |
813 | } | |
814 | ||
815 | TEST_F(LibRadosMiscPP, Applications) { | |
816 | bufferlist inbl, outbl; | |
817 | string outs; | |
818 | ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"osd dump\"}", | |
819 | inbl, &outbl, &outs)); | |
820 | ASSERT_LT(0u, outbl.length()); | |
821 | ASSERT_LE(0u, outs.length()); | |
822 | if (!std::regex_search(outbl.to_str(), | |
823 | std::regex("require_osd_release [l-z]"))) { | |
824 | std::cout << "SKIPPING"; | |
825 | return; | |
826 | } | |
827 | ||
828 | std::set<std::string> expected_apps = {"rados"}; | |
829 | std::set<std::string> apps; | |
830 | ASSERT_EQ(0, ioctx.application_list(&apps)); | |
831 | ASSERT_EQ(expected_apps, apps); | |
832 | ||
833 | ASSERT_EQ(0, ioctx.application_enable("app1", true)); | |
834 | ASSERT_EQ(-EPERM, ioctx.application_enable("app2", false)); | |
835 | ASSERT_EQ(0, ioctx.application_enable("app2", true)); | |
836 | ||
837 | expected_apps = {"app1", "app2", "rados"}; | |
838 | ASSERT_EQ(0, ioctx.application_list(&apps)); | |
839 | ASSERT_EQ(expected_apps, apps); | |
840 | ||
841 | std::map<std::string, std::string> expected_meta; | |
842 | std::map<std::string, std::string> meta; | |
843 | ASSERT_EQ(-ENOENT, ioctx.application_metadata_list("dne", &meta)); | |
844 | ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta)); | |
845 | ASSERT_EQ(expected_meta, meta); | |
846 | ||
847 | ASSERT_EQ(-ENOENT, ioctx.application_metadata_set("dne", "key1", "value1")); | |
848 | ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key1", "value1")); | |
849 | ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key2", "value2")); | |
850 | ||
851 | expected_meta = {{"key1", "value1"}, {"key2", "value2"}}; | |
852 | ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta)); | |
853 | ASSERT_EQ(expected_meta, meta); | |
854 | ||
855 | ASSERT_EQ(0, ioctx.application_metadata_remove("app1", "key1")); | |
856 | ||
857 | expected_meta = {{"key2", "value2"}}; | |
858 | ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta)); | |
859 | ASSERT_EQ(expected_meta, meta); | |
860 | } | |
861 | ||
862 | TEST_F(LibRadosMiscECPP, CompareExtentRange) { | |
863 | bufferlist bl1; | |
864 | bl1.append("ceph"); | |
865 | ObjectWriteOperation write; | |
866 | write.write(0, bl1); | |
867 | ASSERT_EQ(0, ioctx.operate("foo", &write)); | |
868 | ||
869 | bufferlist bl2; | |
870 | bl2.append("ph"); | |
871 | bl2.append(std::string(2, '\0')); | |
872 | ObjectReadOperation read1; | |
873 | read1.cmpext(2, bl2, nullptr); | |
874 | ASSERT_EQ(0, ioctx.operate("foo", &read1, nullptr)); | |
875 | ||
876 | bufferlist bl3; | |
877 | bl3.append(std::string(4, '\0')); | |
878 | ObjectReadOperation read2; | |
879 | read2.cmpext(2097152, bl3, nullptr); | |
880 | ASSERT_EQ(0, ioctx.operate("foo", &read2, nullptr)); | |
881 | } | |
882 | ||
883 | TEST_F(LibRadosMiscPP, MinCompatOSD) { | |
884 | int8_t require_osd_release; | |
885 | ASSERT_EQ(0, cluster.get_min_compatible_osd(&require_osd_release)); | |
886 | ASSERT_LE(-1, require_osd_release); | |
887 | ASSERT_GT(CEPH_RELEASE_MAX, require_osd_release); | |
888 | } | |
889 | ||
890 | TEST_F(LibRadosMiscPP, MinCompatClient) { | |
891 | int8_t min_compat_client; | |
892 | int8_t require_min_compat_client; | |
893 | ASSERT_EQ(0, cluster.get_min_compatible_client(&min_compat_client, | |
894 | &require_min_compat_client)); | |
895 | ASSERT_LE(-1, min_compat_client); | |
896 | ASSERT_GT(CEPH_RELEASE_MAX, min_compat_client); | |
897 | ||
898 | ASSERT_LE(-1, require_min_compat_client); | |
899 | ASSERT_GT(CEPH_RELEASE_MAX, require_min_compat_client); | |
900 | } | |
901 | ||
902 | TEST_F(LibRadosMiscPP, Conf) { | |
903 | const char* const option = "bluestore_throttle_bytes"; | |
904 | size_t new_size = 1 << 20; | |
905 | std::string original; | |
906 | ASSERT_EQ(0, cluster.conf_get(option, original)); | |
907 | auto restore_setting = make_scope_guard([&] { | |
908 | cluster.conf_set(option, original.c_str()); | |
909 | }); | |
910 | std::string expected = std::to_string(new_size); | |
911 | ASSERT_EQ(0, cluster.conf_set(option, expected.c_str())); | |
912 | std::string actual; | |
913 | ASSERT_EQ(0, cluster.conf_get(option, actual)); | |
914 | ASSERT_EQ(expected, actual); | |
915 | } |