1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "gtest/gtest.h"
5 #include "mds/mdstypes.h"
6 #include "include/err.h"
7 #include "include/buffer.h"
8 #include "include/rbd_types.h"
9 #include "include/rados/librados.h"
10 #include "include/rados/librados.hpp"
11 #include "include/stringify.h"
12 #include "common/Checksummer.h"
13 #include "global/global_context.h"
14 #include "test/librados/test.h"
15 #include "test/librados/TestCase.h"
16 #include "gtest/gtest.h"
22 #include <boost/regex.hpp>
24 using namespace librados;
26 using std::ostringstream;
29 typedef RadosTest LibRadosMisc;
30 typedef RadosTestPP LibRadosMiscPP;
31 typedef RadosTestECPP LibRadosMiscECPP;
33 TEST(LibRadosMiscVersion, Version) {
34 int major, minor, extra;
35 rados_version(&major, &minor, &extra);
38 TEST(LibRadosMiscVersion, VersionPP) {
39 int major, minor, extra;
40 Rados::version(&major, &minor, &extra);
43 static void test_rados_log_cb(void *arg,
46 uint64_t sec, uint64_t nsec,
47 uint64_t seq, const char *level,
50 std::cerr << "monitor log callback invoked" << std::endl;
53 TEST(LibRadosMiscConnectFailure, ConnectFailure) {
56 char *id = getenv("CEPH_CLIENT_ID");
58 std::cerr << "Client id is: " << id << std::endl;
60 ASSERT_EQ(0, rados_create(&cluster, NULL));
61 ASSERT_EQ(0, rados_conf_read_file(cluster, NULL));
62 ASSERT_EQ(0, rados_conf_parse_env(cluster, NULL));
64 ASSERT_EQ(0, rados_conf_set(cluster, "client_mount_timeout", "0.000000001"));
65 ASSERT_EQ(0, rados_conf_set(cluster, "debug_monc", "20"));
66 ASSERT_EQ(0, rados_conf_set(cluster, "debug_ms", "1"));
67 ASSERT_EQ(0, rados_conf_set(cluster, "log_to_stderr", "true"));
69 ASSERT_EQ(-ENOTCONN, rados_monitor_log(cluster, "error",
70 test_rados_log_cb, NULL));
72 // try this a few times; sometimes we don't schedule fast enough for the
75 for (unsigned i=0; i<16; ++i) {
76 cout << i << std::endl;
77 r = rados_connect(cluster);
79 break; // yay, we timed out
81 rados_shutdown(cluster);
82 ASSERT_EQ(0, rados_create(&cluster, NULL));
86 rados_shutdown(cluster);
89 TEST(LibRadosMiscPool, PoolCreationRace) {
90 rados_t cluster_a, cluster_b;
92 char *id = getenv("CEPH_CLIENT_ID");
94 std::cerr << "Client id is: " << id << std::endl;
96 ASSERT_EQ(0, rados_create(&cluster_a, NULL));
97 ASSERT_EQ(0, rados_conf_read_file(cluster_a, NULL));
98 // kludge: i want to --log-file foo and only get cluster b
99 //ASSERT_EQ(0, rados_conf_parse_env(cluster_a, NULL));
100 ASSERT_EQ(0, rados_connect(cluster_a));
102 ASSERT_EQ(0, rados_create(&cluster_b, NULL));
103 ASSERT_EQ(0, rados_conf_read_file(cluster_b, NULL));
104 ASSERT_EQ(0, rados_conf_parse_env(cluster_b, NULL));
105 ASSERT_EQ(0, rados_conf_set(cluster_b,
106 "objecter_debug_inject_relock_delay", "true"));
107 ASSERT_EQ(0, rados_connect(cluster_b));
110 snprintf(poolname, sizeof(poolname), "poolrace.%d", rand());
111 rados_pool_create(cluster_a, poolname);
113 rados_ioctx_create(cluster_a, poolname, &a);
114 int64_t poolid = rados_ioctx_get_id(a);
116 rados_ioctx_create2(cluster_b, poolid+1, &b);
119 snprintf(pool2name, sizeof(pool2name), "poolrace2.%d", rand());
120 rados_pool_create(cluster_a, pool2name);
122 list<rados_completion_t> cls;
123 // this should normally trigger pretty easily, but we need to bound
124 // the requests because if we get too many we'll get stuck by always
125 // sending enough messages that we hit the socket failure injection.
129 rados_completion_t c;
130 rados_aio_create_completion(0, 0, 0, &c);
132 rados_aio_read(b, "PoolCreationRaceObj", c, buf, 100, 0);
133 cout << "started " << (void*)c << std::endl;
134 if (rados_aio_is_complete(cls.front())) {
138 while (!rados_aio_is_complete(cls.front())) {
139 cout << "waiting 1 sec" << std::endl;
143 cout << " started " << cls.size() << " aios" << std::endl;
145 cout << "waiting " << (void*)c << std::endl;
146 rados_aio_wait_for_complete_and_cb(c);
147 rados_aio_release(c);
149 cout << "done." << std::endl;
151 rados_ioctx_destroy(a);
152 rados_ioctx_destroy(b);
153 rados_pool_delete(cluster_a, poolname);
154 rados_pool_delete(cluster_a, pool2name);
155 rados_shutdown(cluster_b);
156 rados_shutdown(cluster_a);
159 TEST_F(LibRadosMisc, ClusterFSID) {
161 ASSERT_EQ(-ERANGE, rados_cluster_fsid(cluster, fsid, sizeof(fsid) - 1));
162 ASSERT_EQ(sizeof(fsid) - 1,
163 (size_t)rados_cluster_fsid(cluster, fsid, sizeof(fsid)));
166 TEST_F(LibRadosMiscPP, WaitOSDMapPP) {
167 ASSERT_EQ(0, cluster.wait_for_latest_osdmap());
170 TEST_F(LibRadosMiscPP, LongNamePP) {
172 bl.append("content");
173 int maxlen = g_conf->osd_max_object_name_len;
174 ASSERT_EQ(0, ioctx.write(string(maxlen/2, 'a').c_str(), bl, bl.length(), 0));
175 ASSERT_EQ(0, ioctx.write(string(maxlen-1, 'a').c_str(), bl, bl.length(), 0));
176 ASSERT_EQ(0, ioctx.write(string(maxlen, 'a').c_str(), bl, bl.length(), 0));
177 ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen+1, 'a').c_str(), bl, bl.length(), 0));
178 ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen*2, 'a').c_str(), bl, bl.length(), 0));
181 TEST_F(LibRadosMiscPP, LongLocatorPP) {
183 bl.append("content");
184 int maxlen = g_conf->osd_max_object_name_len;
185 ioctx.locator_set_key(
186 string((maxlen/2), 'a'));
191 bl, bl.length(), 0));
192 ioctx.locator_set_key(
193 string(maxlen - 1, 'a'));
198 bl, bl.length(), 0));
199 ioctx.locator_set_key(
200 string(maxlen, 'a'));
205 bl, bl.length(), 0));
206 ioctx.locator_set_key(
207 string(maxlen+1, 'a'));
212 bl, bl.length(), 0));
213 ioctx.locator_set_key(
214 string((maxlen*2), 'a'));
219 bl, bl.length(), 0));
222 TEST_F(LibRadosMiscPP, LongNSpacePP) {
224 bl.append("content");
225 int maxlen = g_conf->osd_max_object_namespace_len;
227 string((maxlen/2), 'a'));
232 bl, bl.length(), 0));
234 string(maxlen - 1, 'a'));
239 bl, bl.length(), 0));
241 string(maxlen, 'a'));
246 bl, bl.length(), 0));
248 string(maxlen+1, 'a'));
253 bl, bl.length(), 0));
255 string((maxlen*2), 'a'));
260 bl, bl.length(), 0));
263 TEST_F(LibRadosMiscPP, LongAttrNamePP) {
265 bl.append("content");
266 int maxlen = g_conf->osd_max_attr_name_len;
267 ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen/2, 'a').c_str(), bl));
268 ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen-1, 'a').c_str(), bl));
269 ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen, 'a').c_str(), bl));
270 ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen+1, 'a').c_str(), bl));
271 ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen*2, 'a').c_str(), bl));
274 static std::string read_key_from_tmap(IoCtx& ioctx, const std::string &obj,
275 const std::string &key)
278 int r = ioctx.read(obj, bl, 0, 0);
281 oss << "ioctx.read(" << obj << ", bl, 0, 0) returned " << r;
284 bufferlist::iterator p = bl.begin();
286 map<string, bufferlist> m;
289 map<string, bufferlist>::iterator i = m.find(key);
292 std::string retstring;
293 ::decode(retstring, i->second);
297 static std::string add_key_to_tmap(IoCtx &ioctx, const std::string &obj,
298 const std::string &key, const std::string &val)
300 __u8 c = CEPH_OSD_TMAP_SET;
307 ::encode(blbl, tmbl);
308 int ret = ioctx.tmap_update(obj, tmbl);
311 oss << "ioctx.tmap_update(obj=" << obj << ", key="
312 << key << ", val=" << val << ") failed with error " << ret;
318 static int remove_key_from_tmap(IoCtx &ioctx, const std::string &obj,
319 const std::string &key)
321 __u8 c = CEPH_OSD_TMAP_RM;
326 int ret = ioctx.tmap_update(obj, tmbl);
329 oss << "ioctx.tmap_update(obj=" << obj << ", key="
330 << key << ") failed with error " << ret;
335 TEST_F(LibRadosMiscPP, TmapUpdatePP) {
338 __u8 c = CEPH_OSD_TMAP_CREATE;
339 std::string my_tmap("my_tmap");
344 ::encode(my_tmap, tmbl);
345 ::encode(emptybl, tmbl);
346 ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
349 ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key1", "val1"));
351 ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key2", "val2"));
353 // read key1 from the tmap
354 ASSERT_EQ(string("val1"), read_key_from_tmap(ioctx, "foo", "key1"));
356 // remove key1 from tmap
357 ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "key1"));
358 ASSERT_EQ(-ENOENT, remove_key_from_tmap(ioctx, "foo", "key1"));
360 // key should be removed
361 ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "key1"));
364 TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPP) {
367 __u8 c = CEPH_OSD_TMAP_CREATE;
368 std::string my_tmap("my_tmap");
373 ::encode(my_tmap, tmbl);
374 ::encode(emptybl, tmbl);
375 ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
380 __u8 c = CEPH_OSD_TMAP_SET;
385 ::encode("old", blbl);
386 ::encode(blbl, tmbl);
390 ::encode(blbl, tmbl);
394 ::encode(blbl, tmbl);
396 ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
401 __u8 c = CEPH_OSD_TMAP_SET;
406 ::encode("new", blbl);
407 ::encode(blbl, tmbl);
411 ::encode(blbl, tmbl);
415 ::encode(blbl, tmbl);
417 ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
421 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "a"));
422 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "b"));
423 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "c"));
425 ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "a"));
426 ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a"));
428 ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "b"));
429 ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a"));
432 TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPutPP) {
433 // create unsorted tmap
439 ::encode(string("b"), bl);
440 ::encode(string("bval"), bl);
441 ::encode(string("a"), bl);
442 ::encode(string("aval"), bl);
443 ::encode(string("c"), bl);
444 ::encode(string("cval"), bl);
445 bufferlist orig = bl; // tmap_put steals bl content
446 ASSERT_EQ(0, ioctx.tmap_put("foo", bl));
450 ioctx.read("foo", newbl, orig.length(), 0);
451 ASSERT_EQ(orig.contents_equal(newbl), false);
454 TEST_F(LibRadosMiscPP, Tmap2OmapPP) {
457 hdr.append("header");
458 map<string, bufferlist> omap;
459 omap["1"].append("a");
460 omap["2"].append("b");
461 omap["3"].append("c");
466 ASSERT_EQ(0, ioctx.tmap_put("foo", bl));
469 // convert tmap to omap
470 ASSERT_EQ(0, ioctx.tmap_to_omap("foo", false));
472 // if tmap was truncated ?
476 ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
481 ASSERT_EQ(0, ioctx.tmap_to_omap("foo", true));
482 ASSERT_LE(ioctx.tmap_to_omap("foo", false), 0);
487 map<string, bufferlist> m;
488 ObjectReadOperation o;
489 o.omap_get_header(&got, NULL);
490 o.omap_get_vals2("", 1024, &m, nullptr, nullptr);
491 ASSERT_EQ(0, ioctx.operate("foo", &o, NULL));
494 ASSERT_TRUE(hdr.contents_equal(got));
497 ASSERT_EQ(omap.size(), m.size());
499 for (map<string, bufferlist>::iterator p = omap.begin(); p != omap.end(); ++p) {
500 map<string, bufferlist>::iterator q = m.find(p->first);
501 if (q == m.end() || !p->second.contents_equal(q->second)) {
510 TEST_F(LibRadosMisc, Exec) {
512 memset(buf, 0xcc, sizeof(buf));
513 ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
515 int res = rados_exec(ioctx, "foo", "rbd", "get_all_features",
516 NULL, 0, buf2, sizeof(buf2));
519 bl.append(buf2, res);
520 bufferlist::iterator iter = bl.begin();
521 uint64_t all_features;
522 ::decode(all_features, iter);
523 // make sure *some* features are specified; don't care which ones
524 ASSERT_NE(all_features, (unsigned)0);
527 TEST_F(LibRadosMiscPP, ExecPP) {
529 ASSERT_EQ(0, ioctx.write("foo", bl, 0, 0));
531 int r = ioctx.exec("foo", "rbd", "get_all_features", bl2, out);
533 bufferlist::iterator iter = out.begin();
534 uint64_t all_features;
535 ::decode(all_features, iter);
536 // make sure *some* features are specified; don't care which ones
537 ASSERT_NE(all_features, (unsigned)0);
540 void set_completion_complete(rados_completion_t cb, void *arg)
542 bool *my_aio_complete = (bool*)arg;
543 *my_aio_complete = true;
546 TEST_F(LibRadosMiscPP, BadFlagsPP) {
547 unsigned badflags = CEPH_OSD_FLAG_PARALLELEXEC;
551 ASSERT_EQ(0, ioctx.write("badfoo", bl, bl.length(), 0));
554 ASSERT_EQ(-EINVAL, ioctx.remove("badfoo", badflags));
558 TEST_F(LibRadosMiscPP, Operate1PP) {
559 ObjectWriteOperation o;
564 std::string val1("val1");
567 bl.append(val1.c_str(), val1.size() + 1);
568 o.setxattr("key1", bl);
569 o.omap_clear(); // shouldn't affect attrs!
571 ASSERT_EQ(0, ioctx.operate("foo", &o));
573 ObjectWriteOperation empty;
574 ASSERT_EQ(0, ioctx.operate("foo", &empty));
578 ASSERT_GT(ioctx.getxattr("foo", "key1", bl), 0);
579 ASSERT_EQ(0, strcmp(bl.c_str(), val1.c_str()));
581 ObjectWriteOperation o2;
585 o2.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl);
588 ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o2));
589 ObjectWriteOperation o3;
593 o3.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl);
595 ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o3));
598 TEST_F(LibRadosMiscPP, Operate2PP) {
599 ObjectWriteOperation o;
602 bl.append("abcdefg");
605 std::string val1("val1");
608 bl.append(val1.c_str(), val1.size() + 1);
609 o.setxattr("key1", bl);
612 ASSERT_EQ(0, ioctx.operate("foo", &o));
615 ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
619 TEST_F(LibRadosMiscPP, BigObjectPP) {
621 bl.append("abcdefg");
622 ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0));
625 ObjectWriteOperation o;
626 o.truncate(500000000000ull);
627 ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
630 ObjectWriteOperation o;
631 o.zero(500000000000ull, 1);
632 ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
635 ObjectWriteOperation o;
636 o.zero(1, 500000000000ull);
637 ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
640 ObjectWriteOperation o;
641 o.zero(500000000000ull, 500000000000ull);
642 ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
646 // this test only works on 64-bit platforms
647 ASSERT_EQ(-EFBIG, ioctx.write("foo", bl, bl.length(), 500000000000ull));
651 TEST_F(LibRadosMiscPP, AioOperatePP) {
652 bool my_aio_complete = false;
653 AioCompletion *my_completion = cluster.aio_create_completion(
654 (void*)&my_aio_complete, set_completion_complete, NULL);
655 AioCompletion *my_completion_null = NULL;
656 ASSERT_NE(my_completion, my_completion_null);
658 ObjectWriteOperation o;
663 std::string val1("val1");
666 bl.append(val1.c_str(), val1.size() + 1);
667 o.setxattr("key1", bl);
670 memset(buf2, 0xdd, sizeof(buf2));
671 bl2.append(buf2, sizeof(buf2));
674 ASSERT_EQ(0, ioctx.aio_operate("foo", my_completion, &o));
675 ASSERT_EQ(0, my_completion->wait_for_complete_and_cb());
676 ASSERT_EQ(my_aio_complete, true);
677 my_completion->release();
681 ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
682 ASSERT_EQ(1024U, size);
685 TEST_F(LibRadosMiscPP, AssertExistsPP) {
687 memset(buf, 0xcc, sizeof(buf));
689 bl.append(buf, sizeof(buf));
691 ObjectWriteOperation op;
694 ASSERT_EQ(-ENOENT, ioctx.operate("asdffoo", &op));
695 ASSERT_EQ(0, ioctx.create("asdffoo", true));
696 ASSERT_EQ(0, ioctx.operate("asdffoo", &op));
697 ASSERT_EQ(-EEXIST, ioctx.create("asdffoo", true));
700 TEST_F(LibRadosMiscPP, AssertVersionPP) {
702 memset(buf, 0xcc, sizeof(buf));
704 bl.append(buf, sizeof(buf));
706 // Create test object...
707 ASSERT_EQ(0, ioctx.create("asdfbar", true));
708 // ...then write it again to guarantee that the
709 // (unsigned) version must be at least 1 (not 0)
710 // since we want to decrement it by 1 later.
711 ASSERT_EQ(0, ioctx.write_full("asdfbar", bl));
713 uint64_t v = ioctx.get_last_version();
714 ObjectWriteOperation op1;
715 op1.assert_version(v+1);
717 ASSERT_EQ(-EOVERFLOW, ioctx.operate("asdfbar", &op1));
718 ObjectWriteOperation op2;
719 op2.assert_version(v-1);
721 ASSERT_EQ(-ERANGE, ioctx.operate("asdfbar", &op2));
722 ObjectWriteOperation op3;
723 op3.assert_version(v);
725 ASSERT_EQ(0, ioctx.operate("asdfbar", &op3));
728 TEST_F(LibRadosMiscPP, BigAttrPP) {
730 memset(buf, 0xcc, sizeof(buf));
732 bl.append(buf, sizeof(buf));
734 ASSERT_EQ(0, ioctx.create("foo", true));
738 cout << "osd_max_attr_size = " << g_conf->osd_max_attr_size << std::endl;
739 if (g_conf->osd_max_attr_size) {
742 bl.append(buffer::create(g_conf->osd_max_attr_size));
743 ASSERT_EQ(0, ioctx.setxattr("foo", "one", bl));
744 ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", "one", got));
745 ASSERT_TRUE(bl.contents_equal(got));
748 bl.append(buffer::create(g_conf->osd_max_attr_size+1));
749 ASSERT_EQ(-EFBIG, ioctx.setxattr("foo", "one", bl));
751 cout << "osd_max_attr_size == 0; skipping test" << std::endl;
754 for (int i=0; i<1000; i++) {
757 bl.append(buffer::create(MIN(g_conf->osd_max_attr_size, 1024)));
759 snprintf(n, sizeof(n), "a%d", i);
760 ASSERT_EQ(0, ioctx.setxattr("foo", n, bl));
761 ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", n, got));
762 ASSERT_TRUE(bl.contents_equal(got));
766 TEST_F(LibRadosMiscPP, CopyPP) {
768 bl.append("hi there");
774 ASSERT_EQ(0, ioctx.write_full("foo", blc));
775 ASSERT_EQ(0, ioctx.setxattr("foo", "myattr", xc));
777 version_t uv = ioctx.get_last_version();
779 // pass future version
780 ObjectWriteOperation op;
781 op.copy_from2("foo", ioctx, uv + 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
782 ASSERT_EQ(-EOVERFLOW, ioctx.operate("foo.copy", &op));
786 ObjectWriteOperation op;
787 op.copy_from2("foo", ioctx, uv - 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
788 ASSERT_EQ(-ERANGE, ioctx.operate("foo.copy", &op));
791 ObjectWriteOperation op;
792 op.copy_from2("foo", ioctx, uv, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
793 ASSERT_EQ(0, ioctx.operate("foo.copy", &op));
796 ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy", bl2, 10000, 0));
797 ASSERT_TRUE(bl.contents_equal(bl2));
798 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
799 ASSERT_TRUE(x.contents_equal(x2));
802 // small object without a version
804 ObjectWriteOperation op;
805 op.copy_from2("foo", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
806 ASSERT_EQ(0, ioctx.operate("foo.copy2", &op));
809 ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy2", bl2, 10000, 0));
810 ASSERT_TRUE(bl.contents_equal(bl2));
811 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
812 ASSERT_TRUE(x.contents_equal(x2));
816 bl.append(buffer::create(g_conf->osd_copyfrom_max_chunk * 3));
821 ASSERT_EQ(0, ioctx.write_full("big", blc));
822 ASSERT_EQ(0, ioctx.setxattr("big", "myattr", xc));
825 ObjectWriteOperation op;
826 op.copy_from2("big", ioctx, ioctx.get_last_version(), LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
827 ASSERT_EQ(0, ioctx.operate("big.copy", &op));
830 ASSERT_EQ((int)bl.length(), ioctx.read("big.copy", bl2, bl.length(), 0));
831 ASSERT_TRUE(bl.contents_equal(bl2));
832 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
833 ASSERT_TRUE(x.contents_equal(x2));
837 ObjectWriteOperation op;
838 op.copy_from2("big", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
839 ASSERT_EQ(0, ioctx.operate("big.copy2", &op));
842 ASSERT_EQ((int)bl.length(), ioctx.read("big.copy2", bl2, bl.length(), 0));
843 ASSERT_TRUE(bl.contents_equal(bl2));
844 ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
845 ASSERT_TRUE(x.contents_equal(x2));
849 class LibRadosTwoPoolsECPP : public RadosTestECPP
852 LibRadosTwoPoolsECPP() {};
853 ~LibRadosTwoPoolsECPP() override {};
855 static void SetUpTestCase() {
856 pool_name = get_temp_pool_name();
857 ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
858 src_pool_name = get_temp_pool_name();
859 ASSERT_EQ(0, s_cluster.pool_create(src_pool_name.c_str()));
861 librados::IoCtx ioctx;
862 ASSERT_EQ(0, s_cluster.ioctx_create(pool_name.c_str(), ioctx));
863 ioctx.application_enable("rados", true);
865 librados::IoCtx src_ioctx;
866 ASSERT_EQ(0, s_cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
867 src_ioctx.application_enable("rados", true);
869 static void TearDownTestCase() {
870 ASSERT_EQ(0, s_cluster.pool_delete(src_pool_name.c_str()));
871 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
873 static std::string src_pool_name;
875 void SetUp() override {
876 RadosTestECPP::SetUp();
877 ASSERT_EQ(0, cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
878 src_ioctx.set_namespace(nspace);
880 void TearDown() override {
881 // wait for maps to settle before next test
882 cluster.wait_for_latest_osdmap();
884 RadosTestECPP::TearDown();
886 cleanup_default_namespace(src_ioctx);
887 cleanup_namespace(src_ioctx, nspace);
892 librados::IoCtx src_ioctx;
894 std::string LibRadosTwoPoolsECPP::src_pool_name;
896 //copy_from between ecpool and no-ecpool.
897 TEST_F(LibRadosTwoPoolsECPP, CopyFrom) {
899 z.append_zero(4194304*2);
901 b.append("copyfrom");
903 // create big object w/ omapheader
905 ASSERT_EQ(0, src_ioctx.write_full("foo", z));
906 ASSERT_EQ(0, src_ioctx.omap_set_header("foo", b));
907 version_t uv = src_ioctx.get_last_version();
908 ObjectWriteOperation op;
909 op.copy_from("foo", src_ioctx, uv);
910 ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("foo.copy", &op));
913 // same with small object
915 ASSERT_EQ(0, src_ioctx.omap_set_header("bar", b));
916 version_t uv = src_ioctx.get_last_version();
917 ObjectWriteOperation op;
918 op.copy_from("bar", src_ioctx, uv);
919 ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("bar.copy", &op));
923 TEST_F(LibRadosMiscPP, CopyScrubPP) {
924 bufferlist inbl, bl, x;
925 for (int i=0; i<100; ++i)
926 x.append("barrrrrrrrrrrrrrrrrrrrrrrrrr");
927 bl.append(buffer::create(g_conf->osd_copyfrom_max_chunk * 3));
932 map<string, bufferlist> to_set;
933 for (int i=0; i<1000; ++i)
934 to_set[string("foo") + stringify(i)] = x;
938 ASSERT_EQ(0, ioctx.write_full("small", cbl));
939 ASSERT_EQ(0, ioctx.setxattr("small", "myattr", x));
943 ASSERT_EQ(0, ioctx.write_full("big", cbl));
947 ASSERT_EQ(0, ioctx.write_full("big2", cbl));
948 ASSERT_EQ(0, ioctx.setxattr("big2", "myattr", x));
949 ASSERT_EQ(0, ioctx.setxattr("big2", "myattr2", x));
950 ASSERT_EQ(0, ioctx.omap_set("big2", to_set));
954 ASSERT_EQ(0, ioctx.write_full("big3", cbl));
955 ASSERT_EQ(0, ioctx.omap_set_header("big3", x));
956 ASSERT_EQ(0, ioctx.omap_set("big3", to_set));
958 // deep scrub to ensure digests are in place
960 for (int i=0; i<10; ++i) {
962 ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
963 << ioctx.get_id() << "." << i
965 cluster.mon_command(ss.str(), inbl, NULL, NULL);
968 // give it a few seconds to go. this is sloppy but is usually enough time
969 cout << "waiting for initial deep scrubs..." << std::endl;
971 cout << "done waiting, doing copies" << std::endl;
975 ObjectWriteOperation op;
976 op.copy_from("small", ioctx, 0);
977 ASSERT_EQ(0, ioctx.operate("small.copy", &op));
981 ObjectWriteOperation op;
982 op.copy_from("big", ioctx, 0);
983 ASSERT_EQ(0, ioctx.operate("big.copy", &op));
987 ObjectWriteOperation op;
988 op.copy_from("big2", ioctx, 0);
989 ASSERT_EQ(0, ioctx.operate("big2.copy", &op));
993 ObjectWriteOperation op;
994 op.copy_from("big3", ioctx, 0);
995 ASSERT_EQ(0, ioctx.operate("big3.copy", &op));
998 // deep scrub to ensure digests are correct
1000 for (int i=0; i<10; ++i) {
1002 ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
1003 << ioctx.get_id() << "." << i
1005 cluster.mon_command(ss.str(), inbl, NULL, NULL);
1008 // give it a few seconds to go. this is sloppy but is usually enough time
1009 cout << "waiting for final deep scrubs..." << std::endl;
1011 cout << "done waiting" << std::endl;
1015 TEST_F(LibRadosMiscPP, WriteSamePP) {
1022 /* zero the full range before using writesame */
1023 memset(full, 0, sizeof(full));
1024 fl.append(full, sizeof(full));
1025 ASSERT_EQ(0, ioctx.write("ws", fl, fl.length(), 0));
1027 memset(buf, 0xcc, sizeof(buf));
1029 bl.append(buf, sizeof(buf));
1030 /* write the same buf four times */
1031 ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(full), 0));
1033 /* read back the full buffer and confirm that it matches */
1035 fl.append(full, sizeof(full));
1036 ASSERT_EQ((int)fl.length(), ioctx.read("ws", fl, fl.length(), 0));
1038 for (cmp = fl.c_str(); cmp < fl.c_str() + fl.length(); cmp += sizeof(buf)) {
1039 ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
1042 /* write_len not a multiple of data_len should throw error */
1044 bl.append(buf, sizeof(buf));
1045 ASSERT_EQ(-EINVAL, ioctx.writesame("ws", bl, (sizeof(buf) * 4) - 1, 0));
1047 ioctx.writesame("ws", bl, bl.length() / 2, 0));
1048 /* write_len = data_len, i.e. same as write() */
1049 ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(buf), 0));
1052 ioctx.writesame("ws", bl, sizeof(buf), 0));
1055 TEST_F(LibRadosMisc, WriteSame) {
1060 /* zero the full range before using writesame */
1061 memset(full, 0, sizeof(full));
1062 ASSERT_EQ(0, rados_write(ioctx, "ws", full, sizeof(full), 0));
1064 memset(buf, 0xcc, sizeof(buf));
1065 /* write the same buf four times */
1066 ASSERT_EQ(0, rados_writesame(ioctx, "ws", buf, sizeof(buf), sizeof(full), 0));
1068 /* read back the full buffer and confirm that it matches */
1069 ASSERT_EQ((int)sizeof(full), rados_read(ioctx, "ws", full, sizeof(full), 0));
1071 for (cmp = full; cmp < full + sizeof(full); cmp += sizeof(buf)) {
1072 ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
1075 /* write_len not a multiple of data_len should throw error */
1076 ASSERT_EQ(-EINVAL, rados_writesame(ioctx, "ws", buf, sizeof(buf),
1077 (sizeof(buf) * 4) - 1, 0));
1079 rados_writesame(ioctx, "ws", buf, sizeof(buf), sizeof(buf) / 2, 0));
1081 rados_writesame(ioctx, "ws", buf, 0, sizeof(buf), 0));
1082 /* write_len = data_len, i.e. same as rados_write() */
1083 ASSERT_EQ(0, rados_writesame(ioctx, "ws", buf, sizeof(buf), sizeof(buf), 0));
1086 template <typename T>
1087 class LibRadosChecksum : public LibRadosMiscPP {
1089 typedef typename T::alg_t alg_t;
1090 typedef typename T::value_t value_t;
1091 typedef typename alg_t::init_value_t init_value_t;
1093 static const rados_checksum_type_t type = T::type;
1095 bufferlist content_bl;
1097 using LibRadosMiscPP::SetUpTestCase;
1098 using LibRadosMiscPP::TearDownTestCase;
1100 void SetUp() override {
1101 LibRadosMiscPP::SetUp();
1103 std::string content(4096, '\0');
1104 for (size_t i = 0; i < content.length(); ++i) {
1105 content[i] = static_cast<char>(rand() % (126 - 33) + 33);
1107 content_bl.append(content);
1108 ASSERT_EQ(0, ioctx.write("foo", content_bl, content_bl.length(), 0));
1112 template <rados_checksum_type_t _type, typename AlgT, typename ValueT>
1113 class LibRadosChecksumParams {
1116 typedef ValueT value_t;
1117 static const rados_checksum_type_t type = _type;
1120 typedef ::testing::Types<
1121 LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH32,
1122 Checksummer::xxhash32, uint32_t>,
1123 LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH64,
1124 Checksummer::xxhash64, uint64_t>,
1125 LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_CRC32C,
1126 Checksummer::crc32c, uint32_t>
1127 > LibRadosChecksumTypes;
1129 TYPED_TEST_CASE(LibRadosChecksum, LibRadosChecksumTypes);
1131 TYPED_TEST(LibRadosChecksum, Subset) {
1132 uint32_t chunk_size = 1024;
1133 uint32_t csum_count = this->content_bl.length() / chunk_size;
1135 typename TestFixture::init_value_t init_value = -1;
1136 bufferlist init_value_bl;
1137 ::encode(init_value, init_value_bl);
1139 std::vector<bufferlist> checksum_bls(csum_count);
1140 std::vector<int> checksum_rvals(csum_count);
1142 // individual checksum ops for each chunk
1143 ObjectReadOperation op;
1144 for (uint32_t i = 0; i < csum_count; ++i) {
1145 op.checksum(TestFixture::type, init_value_bl, i * chunk_size, chunk_size,
1146 0, &checksum_bls[i], &checksum_rvals[i]);
1148 ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
1150 for (uint32_t i = 0; i < csum_count; ++i) {
1151 ASSERT_EQ(0, checksum_rvals[i]);
1153 auto bl_it = checksum_bls[i].begin();
1155 ::decode(count, bl_it);
1156 ASSERT_EQ(1U, count);
1158 typename TestFixture::value_t value;
1159 ::decode(value, bl_it);
1161 bufferlist content_sub_bl;
1162 content_sub_bl.substr_of(this->content_bl, i * chunk_size, chunk_size);
1164 typename TestFixture::value_t expected_value;
1165 bufferptr expected_value_bp = buffer::create_static(
1166 sizeof(expected_value), reinterpret_cast<char*>(&expected_value));
1167 Checksummer::template calculate<typename TestFixture::alg_t>(
1168 init_value, chunk_size, 0, chunk_size, content_sub_bl,
1169 &expected_value_bp);
1170 ASSERT_EQ(expected_value, value);
1174 TYPED_TEST(LibRadosChecksum, Chunked) {
1175 uint32_t chunk_size = 1024;
1176 uint32_t csum_count = this->content_bl.length() / chunk_size;
1178 typename TestFixture::init_value_t init_value = -1;
1179 bufferlist init_value_bl;
1180 ::encode(init_value, init_value_bl);
1182 bufferlist checksum_bl;
1185 // single op with chunked checksum results
1186 ObjectReadOperation op;
1187 op.checksum(TestFixture::type, init_value_bl, 0, this->content_bl.length(),
1188 chunk_size, &checksum_bl, &checksum_rval);
1189 ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
1190 ASSERT_EQ(0, checksum_rval);
1192 auto bl_it = checksum_bl.begin();
1194 ::decode(count, bl_it);
1195 ASSERT_EQ(csum_count, count);
1197 std::vector<typename TestFixture::value_t> expected_values(csum_count);
1198 bufferptr expected_values_bp = buffer::create_static(
1199 csum_count * sizeof(typename TestFixture::value_t),
1200 reinterpret_cast<char*>(&expected_values[0]));
1202 Checksummer::template calculate<typename TestFixture::alg_t>(
1203 init_value, chunk_size, 0, this->content_bl.length(), this->content_bl,
1204 &expected_values_bp);
1206 for (uint32_t i = 0; i < csum_count; ++i) {
1207 typename TestFixture::value_t value;
1208 ::decode(value, bl_it);
1209 ASSERT_EQ(expected_values[i], value);
1213 TEST_F(LibRadosMiscPP, CmpExtPP) {
1214 bufferlist cmp_bl, bad_cmp_bl, write_bl;
1215 char stored_str[] = "1234567891";
1216 char mismatch_str[] = "1234577777";
1218 write_bl.append(stored_str);
1219 ioctx.write("cmpextpp", write_bl, write_bl.length(), 0);
1220 cmp_bl.append(stored_str);
1221 ASSERT_EQ(0, ioctx.cmpext("cmpextpp", 0, cmp_bl));
1223 bad_cmp_bl.append(mismatch_str);
1224 ASSERT_EQ(-MAX_ERRNO - 5, ioctx.cmpext("cmpextpp", 0, bad_cmp_bl));
1227 TEST_F(LibRadosMisc, CmpExt) {
1228 bufferlist cmp_bl, bad_cmp_bl, write_bl;
1229 char stored_str[] = "1234567891";
1230 char mismatch_str[] = "1234577777";
1233 rados_write(ioctx, "cmpextpp", stored_str, sizeof(stored_str), 0));
1236 rados_cmpext(ioctx, "cmpextpp", stored_str, sizeof(stored_str), 0));
1238 ASSERT_EQ(-MAX_ERRNO - 5,
1239 rados_cmpext(ioctx, "cmpextpp", mismatch_str, sizeof(mismatch_str), 0));
1242 TEST_F(LibRadosMisc, Applications) {
1243 const char *cmd[] = {"{\"prefix\":\"osd dump\"}", nullptr};
1245 size_t buflen, stlen;
1246 ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf,
1247 &buflen, &st, &stlen));
1248 ASSERT_LT(0u, buflen);
1250 rados_buffer_free(buf);
1251 rados_buffer_free(st);
1252 if (!boost::regex_search(result, boost::regex("require_osd_release [l-z]"))) {
1253 std::cout << "SKIPPING";
1260 app_len = sizeof(apps);
1261 ASSERT_EQ(0, rados_application_list(ioctx, apps, &app_len));
1262 ASSERT_EQ(6U, app_len);
1263 ASSERT_EQ(0, memcmp("rados\0", apps, app_len));
1265 ASSERT_EQ(0, rados_application_enable(ioctx, "app1", 1));
1266 ASSERT_EQ(-EPERM, rados_application_enable(ioctx, "app2", 0));
1267 ASSERT_EQ(0, rados_application_enable(ioctx, "app2", 1));
1269 ASSERT_EQ(-ERANGE, rados_application_list(ioctx, apps, &app_len));
1270 ASSERT_EQ(16U, app_len);
1271 ASSERT_EQ(0, rados_application_list(ioctx, apps, &app_len));
1272 ASSERT_EQ(16U, app_len);
1273 ASSERT_EQ(0, memcmp("app1\0app2\0rados\0", apps, app_len));
1280 key_len = sizeof(keys);
1281 val_len = sizeof(vals);
1282 ASSERT_EQ(-ENOENT, rados_application_metadata_list(ioctx, "dne", keys,
1283 &key_len, vals, &val_len));
1284 ASSERT_EQ(0, rados_application_metadata_list(ioctx, "app1", keys, &key_len,
1286 ASSERT_EQ(0U, key_len);
1287 ASSERT_EQ(0U, val_len);
1289 ASSERT_EQ(-ENOENT, rados_application_metadata_set(ioctx, "dne", "key",
1291 ASSERT_EQ(0, rados_application_metadata_set(ioctx, "app1", "key1", "value1"));
1292 ASSERT_EQ(0, rados_application_metadata_set(ioctx, "app1", "key2", "value2"));
1294 ASSERT_EQ(-ERANGE, rados_application_metadata_list(ioctx, "app1", keys,
1295 &key_len, vals, &val_len));
1296 ASSERT_EQ(10U, key_len);
1297 ASSERT_EQ(14U, val_len);
1298 ASSERT_EQ(0, rados_application_metadata_list(ioctx, "app1", keys, &key_len,
1300 ASSERT_EQ(10U, key_len);
1301 ASSERT_EQ(14U, val_len);
1302 ASSERT_EQ(0, memcmp("key1\0key2\0", keys, key_len));
1303 ASSERT_EQ(0, memcmp("value1\0value2\0", vals, val_len));
1305 ASSERT_EQ(0, rados_application_metadata_remove(ioctx, "app1", "key1"));
1306 ASSERT_EQ(0, rados_application_metadata_list(ioctx, "app1", keys, &key_len,
1308 ASSERT_EQ(5U, key_len);
1309 ASSERT_EQ(7U, val_len);
1310 ASSERT_EQ(0, memcmp("key2\0", keys, key_len));
1311 ASSERT_EQ(0, memcmp("value2\0", vals, val_len));
1314 TEST_F(LibRadosMiscPP, Applications) {
1315 bufferlist inbl, outbl;
1317 ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"osd dump\"}",
1318 inbl, &outbl, &outs));
1319 ASSERT_LT(0u, outbl.length());
1320 ASSERT_LE(0u, outs.length());
1321 if (!boost::regex_search(outbl.to_str(),
1322 boost::regex("require_osd_release [l-z]"))) {
1323 std::cout << "SKIPPING";
1327 std::set<std::string> expected_apps = {"rados"};
1328 std::set<std::string> apps;
1329 ASSERT_EQ(0, ioctx.application_list(&apps));
1330 ASSERT_EQ(expected_apps, apps);
1332 ASSERT_EQ(0, ioctx.application_enable("app1", true));
1333 ASSERT_EQ(-EPERM, ioctx.application_enable("app2", false));
1334 ASSERT_EQ(0, ioctx.application_enable("app2", true));
1336 expected_apps = {"app1", "app2", "rados"};
1337 ASSERT_EQ(0, ioctx.application_list(&apps));
1338 ASSERT_EQ(expected_apps, apps);
1340 std::map<std::string, std::string> expected_meta;
1341 std::map<std::string, std::string> meta;
1342 ASSERT_EQ(-ENOENT, ioctx.application_metadata_list("dne", &meta));
1343 ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
1344 ASSERT_EQ(expected_meta, meta);
1346 ASSERT_EQ(-ENOENT, ioctx.application_metadata_set("dne", "key1", "value1"));
1347 ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key1", "value1"));
1348 ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key2", "value2"));
1350 expected_meta = {{"key1", "value1"}, {"key2", "value2"}};
1351 ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
1352 ASSERT_EQ(expected_meta, meta);
1354 ASSERT_EQ(0, ioctx.application_metadata_remove("app1", "key1"));
1356 expected_meta = {{"key2", "value2"}};
1357 ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
1358 ASSERT_EQ(expected_meta, meta);
1361 TEST_F(LibRadosMiscECPP, CompareExtentRange) {
1364 ObjectWriteOperation write;
1365 write.write(0, bl1);
1366 ASSERT_EQ(0, ioctx.operate("foo", &write));
1370 bl2.append(std::string(2, '\0'));
1371 ObjectReadOperation read1;
1372 read1.cmpext(2, bl2, nullptr);
1373 ASSERT_EQ(0, ioctx.operate("foo", &read1, nullptr));
1376 bl3.append(std::string(4, '\0'));
1377 ObjectReadOperation read2;
1378 read2.cmpext(2097152, bl3, nullptr);
1379 ASSERT_EQ(0, ioctx.operate("foo", &read2, nullptr));