]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librados/misc_cxx.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librados / misc_cxx.cc
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 #include "crimson_utils.h"
25
26 using namespace std;
27 using namespace librados;
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(
272 (void*)&my_aio_complete, set_completion_complete);
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 SKIP_IF_CRIMSON();
387 bufferlist bl, x;
388 bl.append("hi there");
389 x.append("bar");
390
391 // small object
392 bufferlist blc = bl;
393 bufferlist xc = x;
394 ASSERT_EQ(0, ioctx.write_full("foo", blc));
395 ASSERT_EQ(0, ioctx.setxattr("foo", "myattr", xc));
396
397 version_t uv = ioctx.get_last_version();
398 {
399 // pass future version
400 ObjectWriteOperation op;
401 op.copy_from("foo", ioctx, uv + 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
402 ASSERT_EQ(-EOVERFLOW, ioctx.operate("foo.copy", &op));
403 }
404 {
405 // pass old version
406 ObjectWriteOperation op;
407 op.copy_from("foo", ioctx, uv - 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
408 ASSERT_EQ(-ERANGE, ioctx.operate("foo.copy", &op));
409 }
410 {
411 ObjectWriteOperation op;
412 op.copy_from("foo", ioctx, uv, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
413 ASSERT_EQ(0, ioctx.operate("foo.copy", &op));
414
415 bufferlist bl2, x2;
416 ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy", bl2, 10000, 0));
417 ASSERT_TRUE(bl.contents_equal(bl2));
418 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
419 ASSERT_TRUE(x.contents_equal(x2));
420 }
421
422 // small object without a version
423 {
424 ObjectWriteOperation op;
425 op.copy_from("foo", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
426 ASSERT_EQ(0, ioctx.operate("foo.copy2", &op));
427
428 bufferlist bl2, x2;
429 ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy2", bl2, 10000, 0));
430 ASSERT_TRUE(bl.contents_equal(bl2));
431 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
432 ASSERT_TRUE(x.contents_equal(x2));
433 }
434
435 // do a big object
436 bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3));
437 bl.zero();
438 bl.append("tail");
439 blc = bl;
440 xc = x;
441 ASSERT_EQ(0, ioctx.write_full("big", blc));
442 ASSERT_EQ(0, ioctx.setxattr("big", "myattr", xc));
443
444 {
445 ObjectWriteOperation op;
446 op.copy_from("big", ioctx, ioctx.get_last_version(), LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
447 ASSERT_EQ(0, ioctx.operate("big.copy", &op));
448
449 bufferlist bl2, x2;
450 ASSERT_EQ((int)bl.length(), ioctx.read("big.copy", bl2, bl.length(), 0));
451 ASSERT_TRUE(bl.contents_equal(bl2));
452 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
453 ASSERT_TRUE(x.contents_equal(x2));
454 }
455
456 {
457 ObjectWriteOperation op;
458 op.copy_from("big", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
459 ASSERT_EQ(0, ioctx.operate("big.copy2", &op));
460
461 bufferlist bl2, x2;
462 ASSERT_EQ((int)bl.length(), ioctx.read("big.copy2", bl2, bl.length(), 0));
463 ASSERT_TRUE(bl.contents_equal(bl2));
464 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
465 ASSERT_TRUE(x.contents_equal(x2));
466 }
467 }
468
469 class LibRadosTwoPoolsECPP : public RadosTestECPP
470 {
471 public:
472 LibRadosTwoPoolsECPP() {};
473 ~LibRadosTwoPoolsECPP() override {};
474 protected:
475 static void SetUpTestCase() {
476 SKIP_IF_CRIMSON();
477 pool_name = get_temp_pool_name();
478 ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
479 src_pool_name = get_temp_pool_name();
480 ASSERT_EQ(0, s_cluster.pool_create(src_pool_name.c_str()));
481
482 librados::IoCtx ioctx;
483 ASSERT_EQ(0, s_cluster.ioctx_create(pool_name.c_str(), ioctx));
484 ioctx.application_enable("rados", true);
485
486 librados::IoCtx src_ioctx;
487 ASSERT_EQ(0, s_cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
488 src_ioctx.application_enable("rados", true);
489 }
490 static void TearDownTestCase() {
491 SKIP_IF_CRIMSON();
492 ASSERT_EQ(0, s_cluster.pool_delete(src_pool_name.c_str()));
493 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
494 }
495 static std::string src_pool_name;
496
497 void SetUp() override {
498 SKIP_IF_CRIMSON();
499 RadosTestECPP::SetUp();
500 ASSERT_EQ(0, cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
501 src_ioctx.set_namespace(nspace);
502 }
503 void TearDown() override {
504 SKIP_IF_CRIMSON();
505 // wait for maps to settle before next test
506 cluster.wait_for_latest_osdmap();
507
508 RadosTestECPP::TearDown();
509
510 cleanup_default_namespace(src_ioctx);
511 cleanup_namespace(src_ioctx, nspace);
512
513 src_ioctx.close();
514 }
515
516 librados::IoCtx src_ioctx;
517 };
518 std::string LibRadosTwoPoolsECPP::src_pool_name;
519
520 //copy_from between ecpool and no-ecpool.
521 TEST_F(LibRadosTwoPoolsECPP, CopyFrom) {
522 SKIP_IF_CRIMSON();
523 bufferlist z;
524 z.append_zero(4194304*2);
525 bufferlist b;
526 b.append("copyfrom");
527
528 // create big object w/ omapheader
529 {
530 ASSERT_EQ(0, src_ioctx.write_full("foo", z));
531 ASSERT_EQ(0, src_ioctx.omap_set_header("foo", b));
532 version_t uv = src_ioctx.get_last_version();
533 ObjectWriteOperation op;
534 op.copy_from("foo", src_ioctx, uv, 0);
535 ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("foo.copy", &op));
536 }
537
538 // same with small object
539 {
540 ASSERT_EQ(0, src_ioctx.omap_set_header("bar", b));
541 version_t uv = src_ioctx.get_last_version();
542 ObjectWriteOperation op;
543 op.copy_from("bar", src_ioctx, uv, 0);
544 ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("bar.copy", &op));
545 }
546 }
547
548 TEST_F(LibRadosMiscPP, CopyScrubPP) {
549 SKIP_IF_CRIMSON();
550 bufferlist inbl, bl, x;
551 for (int i=0; i<100; ++i)
552 x.append("barrrrrrrrrrrrrrrrrrrrrrrrrr");
553 bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3));
554 bl.zero();
555 bl.append("tail");
556 bufferlist cbl;
557
558 map<string, bufferlist> to_set;
559 for (int i=0; i<1000; ++i)
560 to_set[string("foo") + stringify(i)] = x;
561
562 // small
563 cbl = x;
564 ASSERT_EQ(0, ioctx.write_full("small", cbl));
565 ASSERT_EQ(0, ioctx.setxattr("small", "myattr", x));
566
567 // big
568 cbl = bl;
569 ASSERT_EQ(0, ioctx.write_full("big", cbl));
570
571 // without header
572 cbl = bl;
573 ASSERT_EQ(0, ioctx.write_full("big2", cbl));
574 ASSERT_EQ(0, ioctx.setxattr("big2", "myattr", x));
575 ASSERT_EQ(0, ioctx.setxattr("big2", "myattr2", x));
576 ASSERT_EQ(0, ioctx.omap_set("big2", to_set));
577
578 // with header
579 cbl = bl;
580 ASSERT_EQ(0, ioctx.write_full("big3", cbl));
581 ASSERT_EQ(0, ioctx.omap_set_header("big3", x));
582 ASSERT_EQ(0, ioctx.omap_set("big3", to_set));
583
584 // deep scrub to ensure digests are in place
585 {
586 for (int i=0; i<10; ++i) {
587 ostringstream ss;
588 ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
589 << ioctx.get_id() << "." << i
590 << "\"}";
591 cluster.mon_command(ss.str(), inbl, NULL, NULL);
592 }
593
594 // give it a few seconds to go. this is sloppy but is usually enough time
595 cout << "waiting for initial deep scrubs..." << std::endl;
596 sleep(30);
597 cout << "done waiting, doing copies" << std::endl;
598 }
599
600 {
601 ObjectWriteOperation op;
602 op.copy_from("small", ioctx, 0, 0);
603 ASSERT_EQ(0, ioctx.operate("small.copy", &op));
604 }
605
606 {
607 ObjectWriteOperation op;
608 op.copy_from("big", ioctx, 0, 0);
609 ASSERT_EQ(0, ioctx.operate("big.copy", &op));
610 }
611
612 {
613 ObjectWriteOperation op;
614 op.copy_from("big2", ioctx, 0, 0);
615 ASSERT_EQ(0, ioctx.operate("big2.copy", &op));
616 }
617
618 {
619 ObjectWriteOperation op;
620 op.copy_from("big3", ioctx, 0, 0);
621 ASSERT_EQ(0, ioctx.operate("big3.copy", &op));
622 }
623
624 // deep scrub to ensure digests are correct
625 {
626 for (int i=0; i<10; ++i) {
627 ostringstream ss;
628 ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
629 << ioctx.get_id() << "." << i
630 << "\"}";
631 cluster.mon_command(ss.str(), inbl, NULL, NULL);
632 }
633
634 // give it a few seconds to go. this is sloppy but is usually enough time
635 cout << "waiting for final deep scrubs..." << std::endl;
636 sleep(30);
637 cout << "done waiting" << std::endl;
638 }
639 }
640
641 TEST_F(LibRadosMiscPP, WriteSamePP) {
642 bufferlist bl;
643 char buf[128];
644 bufferlist fl;
645 char full[128 * 4];
646 char *cmp;
647
648 /* zero the full range before using writesame */
649 memset(full, 0, sizeof(full));
650 fl.append(full, sizeof(full));
651 ASSERT_EQ(0, ioctx.write("ws", fl, fl.length(), 0));
652
653 memset(buf, 0xcc, sizeof(buf));
654 bl.clear();
655 bl.append(buf, sizeof(buf));
656 /* write the same buf four times */
657 ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(full), 0));
658
659 /* read back the full buffer and confirm that it matches */
660 fl.clear();
661 fl.append(full, sizeof(full));
662 ASSERT_EQ((int)fl.length(), ioctx.read("ws", fl, fl.length(), 0));
663
664 for (cmp = fl.c_str(); cmp < fl.c_str() + fl.length(); cmp += sizeof(buf)) {
665 ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
666 }
667
668 /* write_len not a multiple of data_len should throw error */
669 bl.clear();
670 bl.append(buf, sizeof(buf));
671 ASSERT_EQ(-EINVAL, ioctx.writesame("ws", bl, (sizeof(buf) * 4) - 1, 0));
672 ASSERT_EQ(-EINVAL,
673 ioctx.writesame("ws", bl, bl.length() / 2, 0));
674 /* write_len = data_len, i.e. same as write() */
675 ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(buf), 0));
676 bl.clear();
677 ASSERT_EQ(-EINVAL,
678 ioctx.writesame("ws", bl, sizeof(buf), 0));
679 }
680
681 template <typename T>
682 class LibRadosChecksum : public LibRadosMiscPP {
683 public:
684 typedef typename T::alg_t alg_t;
685 typedef typename T::value_t value_t;
686 typedef typename alg_t::init_value_t init_value_t;
687
688 static const rados_checksum_type_t type = T::type;
689
690 bufferlist content_bl;
691
692 using LibRadosMiscPP::SetUpTestCase;
693 using LibRadosMiscPP::TearDownTestCase;
694
695 void SetUp() override {
696 LibRadosMiscPP::SetUp();
697
698 std::string content(4096, '\0');
699 for (size_t i = 0; i < content.length(); ++i) {
700 content[i] = static_cast<char>(rand() % (126 - 33) + 33);
701 }
702 content_bl.append(content);
703 ASSERT_EQ(0, ioctx.write("foo", content_bl, content_bl.length(), 0));
704 }
705 };
706
707 template <rados_checksum_type_t _type, typename AlgT, typename ValueT>
708 class LibRadosChecksumParams {
709 public:
710 typedef AlgT alg_t;
711 typedef ValueT value_t;
712 static const rados_checksum_type_t type = _type;
713 };
714
715 typedef ::testing::Types<
716 LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH32,
717 Checksummer::xxhash32, ceph_le32>,
718 LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH64,
719 Checksummer::xxhash64, ceph_le64>,
720 LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_CRC32C,
721 Checksummer::crc32c, ceph_le32>
722 > LibRadosChecksumTypes;
723
724 TYPED_TEST_SUITE(LibRadosChecksum, LibRadosChecksumTypes);
725
726 TYPED_TEST(LibRadosChecksum, Subset) {
727 uint32_t chunk_size = 1024;
728 uint32_t csum_count = this->content_bl.length() / chunk_size;
729
730 typename TestFixture::init_value_t init_value = -1;
731 bufferlist init_value_bl;
732 encode(init_value, init_value_bl);
733
734 std::vector<bufferlist> checksum_bls(csum_count);
735 std::vector<int> checksum_rvals(csum_count);
736
737 // individual checksum ops for each chunk
738 ObjectReadOperation op;
739 for (uint32_t i = 0; i < csum_count; ++i) {
740 op.checksum(TestFixture::type, init_value_bl, i * chunk_size, chunk_size,
741 0, &checksum_bls[i], &checksum_rvals[i]);
742 }
743 ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
744
745 for (uint32_t i = 0; i < csum_count; ++i) {
746 ASSERT_EQ(0, checksum_rvals[i]);
747
748 auto bl_it = checksum_bls[i].cbegin();
749 uint32_t count;
750 decode(count, bl_it);
751 ASSERT_EQ(1U, count);
752
753 typename TestFixture::value_t value;
754 decode(value, bl_it);
755
756 bufferlist content_sub_bl;
757 content_sub_bl.substr_of(this->content_bl, i * chunk_size, chunk_size);
758
759 typename TestFixture::value_t expected_value;
760 bufferptr expected_value_bp = buffer::create_static(
761 sizeof(expected_value), reinterpret_cast<char*>(&expected_value));
762 Checksummer::template calculate<typename TestFixture::alg_t>(
763 init_value, chunk_size, 0, chunk_size, content_sub_bl,
764 &expected_value_bp);
765 ASSERT_EQ(expected_value, value);
766 }
767 }
768
769 TYPED_TEST(LibRadosChecksum, Chunked) {
770 uint32_t chunk_size = 1024;
771 uint32_t csum_count = this->content_bl.length() / chunk_size;
772
773 typename TestFixture::init_value_t init_value = -1;
774 bufferlist init_value_bl;
775 encode(init_value, init_value_bl);
776
777 bufferlist checksum_bl;
778 int checksum_rval;
779
780 // single op with chunked checksum results
781 ObjectReadOperation op;
782 op.checksum(TestFixture::type, init_value_bl, 0, this->content_bl.length(),
783 chunk_size, &checksum_bl, &checksum_rval);
784 ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
785 ASSERT_EQ(0, checksum_rval);
786
787 auto bl_it = checksum_bl.cbegin();
788 uint32_t count;
789 decode(count, bl_it);
790 ASSERT_EQ(csum_count, count);
791
792 std::vector<typename TestFixture::value_t> expected_values(csum_count);
793 bufferptr expected_values_bp = buffer::create_static(
794 csum_count * sizeof(typename TestFixture::value_t),
795 reinterpret_cast<char*>(&expected_values[0]));
796
797 Checksummer::template calculate<typename TestFixture::alg_t>(
798 init_value, chunk_size, 0, this->content_bl.length(), this->content_bl,
799 &expected_values_bp);
800
801 for (uint32_t i = 0; i < csum_count; ++i) {
802 typename TestFixture::value_t value;
803 decode(value, bl_it);
804 ASSERT_EQ(expected_values[i], value);
805 }
806 }
807
808 TEST_F(LibRadosMiscPP, CmpExtPP) {
809 bufferlist cmp_bl, bad_cmp_bl, write_bl;
810 char stored_str[] = "1234567891";
811 char mismatch_str[] = "1234577777";
812
813 write_bl.append(stored_str);
814 ioctx.write("cmpextpp", write_bl, write_bl.length(), 0);
815 cmp_bl.append(stored_str);
816 ASSERT_EQ(0, ioctx.cmpext("cmpextpp", 0, cmp_bl));
817
818 bad_cmp_bl.append(mismatch_str);
819 ASSERT_EQ(-MAX_ERRNO - 5, ioctx.cmpext("cmpextpp", 0, bad_cmp_bl));
820 }
821
822 TEST_F(LibRadosMiscPP, Applications) {
823 bufferlist inbl, outbl;
824 string outs;
825 ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"osd dump\"}",
826 inbl, &outbl, &outs));
827 ASSERT_LT(0u, outbl.length());
828 ASSERT_LE(0u, outs.length());
829 if (!std::regex_search(outbl.to_str(),
830 std::regex("require_osd_release [l-z]"))) {
831 std::cout << "SKIPPING";
832 return;
833 }
834
835 std::set<std::string> expected_apps = {"rados"};
836 std::set<std::string> apps;
837 ASSERT_EQ(0, ioctx.application_list(&apps));
838 ASSERT_EQ(expected_apps, apps);
839
840 ASSERT_EQ(0, ioctx.application_enable("app1", true));
841 ASSERT_EQ(-EPERM, ioctx.application_enable("app2", false));
842 ASSERT_EQ(0, ioctx.application_enable("app2", true));
843
844 expected_apps = {"app1", "app2", "rados"};
845 ASSERT_EQ(0, ioctx.application_list(&apps));
846 ASSERT_EQ(expected_apps, apps);
847
848 std::map<std::string, std::string> expected_meta;
849 std::map<std::string, std::string> meta;
850 ASSERT_EQ(-ENOENT, ioctx.application_metadata_list("dne", &meta));
851 ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
852 ASSERT_EQ(expected_meta, meta);
853
854 ASSERT_EQ(-ENOENT, ioctx.application_metadata_set("dne", "key1", "value1"));
855 ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key1", "value1"));
856 ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key2", "value2"));
857
858 expected_meta = {{"key1", "value1"}, {"key2", "value2"}};
859 ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
860 ASSERT_EQ(expected_meta, meta);
861
862 ASSERT_EQ(0, ioctx.application_metadata_remove("app1", "key1"));
863
864 expected_meta = {{"key2", "value2"}};
865 ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
866 ASSERT_EQ(expected_meta, meta);
867 }
868
869 TEST_F(LibRadosMiscECPP, CompareExtentRange) {
870 SKIP_IF_CRIMSON();
871 bufferlist bl1;
872 bl1.append("ceph");
873 ObjectWriteOperation write;
874 write.write(0, bl1);
875 ASSERT_EQ(0, ioctx.operate("foo", &write));
876
877 bufferlist bl2;
878 bl2.append("ph");
879 bl2.append(std::string(2, '\0'));
880 ObjectReadOperation read1;
881 read1.cmpext(2, bl2, nullptr);
882 ASSERT_EQ(0, ioctx.operate("foo", &read1, nullptr));
883
884 bufferlist bl3;
885 bl3.append(std::string(4, '\0'));
886 ObjectReadOperation read2;
887 read2.cmpext(2097152, bl3, nullptr);
888 ASSERT_EQ(0, ioctx.operate("foo", &read2, nullptr));
889 }
890
891 TEST_F(LibRadosMiscPP, MinCompatOSD) {
892 int8_t require_osd_release;
893 ASSERT_EQ(0, cluster.get_min_compatible_osd(&require_osd_release));
894 ASSERT_LE(-1, require_osd_release);
895 ASSERT_GT(CEPH_RELEASE_MAX, require_osd_release);
896 }
897
898 TEST_F(LibRadosMiscPP, MinCompatClient) {
899 int8_t min_compat_client;
900 int8_t require_min_compat_client;
901 ASSERT_EQ(0, cluster.get_min_compatible_client(&min_compat_client,
902 &require_min_compat_client));
903 ASSERT_LE(-1, min_compat_client);
904 ASSERT_GT(CEPH_RELEASE_MAX, min_compat_client);
905
906 ASSERT_LE(-1, require_min_compat_client);
907 ASSERT_GT(CEPH_RELEASE_MAX, require_min_compat_client);
908 }
909
910 TEST_F(LibRadosMiscPP, Conf) {
911 const char* const option = "bluestore_throttle_bytes";
912 size_t new_size = 1 << 20;
913 std::string original;
914 ASSERT_EQ(0, cluster.conf_get(option, original));
915 auto restore_setting = make_scope_guard([&] {
916 cluster.conf_set(option, original.c_str());
917 });
918 std::string expected = std::to_string(new_size);
919 ASSERT_EQ(0, cluster.conf_set(option, expected.c_str()));
920 std::string actual;
921 ASSERT_EQ(0, cluster.conf_get(option, actual));
922 ASSERT_EQ(expected, actual);
923 }