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"
24 using namespace librados
;
26 using std::ostringstream
;
29 typedef RadosTest LibRadosMisc
;
30 typedef RadosTestPP LibRadosMiscPP
;
32 TEST(LibRadosMiscVersion
, Version
) {
33 int major
, minor
, extra
;
34 rados_version(&major
, &minor
, &extra
);
37 TEST(LibRadosMiscVersion
, VersionPP
) {
38 int major
, minor
, extra
;
39 Rados::version(&major
, &minor
, &extra
);
42 static void test_rados_log_cb(void *arg
,
45 uint64_t sec
, uint64_t nsec
,
46 uint64_t seq
, const char *level
,
49 std::cerr
<< "monitor log callback invoked" << std::endl
;
52 TEST(LibRadosMiscConnectFailure
, ConnectFailure
) {
55 char *id
= getenv("CEPH_CLIENT_ID");
57 std::cerr
<< "Client id is: " << id
<< std::endl
;
59 ASSERT_EQ(0, rados_create(&cluster
, NULL
));
60 ASSERT_EQ(0, rados_conf_read_file(cluster
, NULL
));
61 ASSERT_EQ(0, rados_conf_parse_env(cluster
, NULL
));
63 ASSERT_EQ(0, rados_conf_set(cluster
, "client_mount_timeout", "0.000000001"));
64 ASSERT_EQ(0, rados_conf_set(cluster
, "debug_monc", "20"));
65 ASSERT_EQ(0, rados_conf_set(cluster
, "debug_ms", "1"));
66 ASSERT_EQ(0, rados_conf_set(cluster
, "log_to_stderr", "true"));
68 ASSERT_EQ(-ENOTCONN
, rados_monitor_log(cluster
, "error",
69 test_rados_log_cb
, NULL
));
71 // try this a few times; sometimes we don't schedule fast enough for the
74 for (unsigned i
=0; i
<16; ++i
) {
75 cout
<< i
<< std::endl
;
76 r
= rados_connect(cluster
);
78 break; // yay, we timed out
80 rados_shutdown(cluster
);
81 ASSERT_EQ(0, rados_create(&cluster
, NULL
));
85 rados_shutdown(cluster
);
88 TEST(LibRadosMiscPool
, PoolCreationRace
) {
89 rados_t cluster_a
, cluster_b
;
91 char *id
= getenv("CEPH_CLIENT_ID");
93 std::cerr
<< "Client id is: " << id
<< std::endl
;
95 ASSERT_EQ(0, rados_create(&cluster_a
, NULL
));
96 ASSERT_EQ(0, rados_conf_read_file(cluster_a
, NULL
));
97 // kludge: i want to --log-file foo and only get cluster b
98 //ASSERT_EQ(0, rados_conf_parse_env(cluster_a, NULL));
99 ASSERT_EQ(0, rados_connect(cluster_a
));
101 ASSERT_EQ(0, rados_create(&cluster_b
, NULL
));
102 ASSERT_EQ(0, rados_conf_read_file(cluster_b
, NULL
));
103 ASSERT_EQ(0, rados_conf_parse_env(cluster_b
, NULL
));
104 ASSERT_EQ(0, rados_conf_set(cluster_b
,
105 "objecter_debug_inject_relock_delay", "true"));
106 ASSERT_EQ(0, rados_connect(cluster_b
));
109 snprintf(poolname
, sizeof(poolname
), "poolrace.%d", rand());
110 rados_pool_create(cluster_a
, poolname
);
112 rados_ioctx_create(cluster_a
, poolname
, &a
);
113 int64_t poolid
= rados_ioctx_get_id(a
);
115 rados_ioctx_create2(cluster_b
, poolid
+1, &b
);
118 snprintf(pool2name
, sizeof(pool2name
), "poolrace2.%d", rand());
119 rados_pool_create(cluster_a
, pool2name
);
121 list
<rados_completion_t
> cls
;
122 // this should normally trigger pretty easily, but we need to bound
123 // the requests because if we get too many we'll get stuck by always
124 // sending enough messages that we hit the socket failure injection.
128 rados_completion_t c
;
129 rados_aio_create_completion(0, 0, 0, &c
);
131 rados_aio_read(b
, "PoolCreationRaceObj", c
, buf
, 100, 0);
132 cout
<< "started " << (void*)c
<< std::endl
;
133 if (rados_aio_is_complete(cls
.front())) {
137 while (!rados_aio_is_complete(cls
.front())) {
138 cout
<< "waiting 1 sec" << std::endl
;
142 cout
<< " started " << cls
.size() << " aios" << std::endl
;
144 cout
<< "waiting " << (void*)c
<< std::endl
;
145 rados_aio_wait_for_complete_and_cb(c
);
146 rados_aio_release(c
);
148 cout
<< "done." << std::endl
;
150 rados_ioctx_destroy(a
);
151 rados_ioctx_destroy(b
);
152 rados_pool_delete(cluster_a
, poolname
);
153 rados_pool_delete(cluster_a
, pool2name
);
154 rados_shutdown(cluster_b
);
155 rados_shutdown(cluster_a
);
158 TEST_F(LibRadosMisc
, ClusterFSID
) {
160 ASSERT_EQ(-ERANGE
, rados_cluster_fsid(cluster
, fsid
, sizeof(fsid
) - 1));
161 ASSERT_EQ(sizeof(fsid
) - 1,
162 (size_t)rados_cluster_fsid(cluster
, fsid
, sizeof(fsid
)));
165 TEST_F(LibRadosMiscPP
, WaitOSDMapPP
) {
166 ASSERT_EQ(0, cluster
.wait_for_latest_osdmap());
169 TEST_F(LibRadosMiscPP
, LongNamePP
) {
171 bl
.append("content");
172 int maxlen
= g_conf
->osd_max_object_name_len
;
173 ASSERT_EQ(0, ioctx
.write(string(maxlen
/2, 'a').c_str(), bl
, bl
.length(), 0));
174 ASSERT_EQ(0, ioctx
.write(string(maxlen
-1, 'a').c_str(), bl
, bl
.length(), 0));
175 ASSERT_EQ(0, ioctx
.write(string(maxlen
, 'a').c_str(), bl
, bl
.length(), 0));
176 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.write(string(maxlen
+1, 'a').c_str(), bl
, bl
.length(), 0));
177 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.write(string(maxlen
*2, 'a').c_str(), bl
, bl
.length(), 0));
180 TEST_F(LibRadosMiscPP
, LongLocatorPP
) {
182 bl
.append("content");
183 int maxlen
= g_conf
->osd_max_object_name_len
;
184 ioctx
.locator_set_key(
185 string((maxlen
/2), 'a'));
190 bl
, bl
.length(), 0));
191 ioctx
.locator_set_key(
192 string(maxlen
- 1, 'a'));
197 bl
, bl
.length(), 0));
198 ioctx
.locator_set_key(
199 string(maxlen
, 'a'));
204 bl
, bl
.length(), 0));
205 ioctx
.locator_set_key(
206 string(maxlen
+1, 'a'));
211 bl
, bl
.length(), 0));
212 ioctx
.locator_set_key(
213 string((maxlen
*2), 'a'));
218 bl
, bl
.length(), 0));
221 TEST_F(LibRadosMiscPP
, LongNSpacePP
) {
223 bl
.append("content");
224 int maxlen
= g_conf
->osd_max_object_namespace_len
;
226 string((maxlen
/2), 'a'));
231 bl
, bl
.length(), 0));
233 string(maxlen
- 1, 'a'));
238 bl
, bl
.length(), 0));
240 string(maxlen
, 'a'));
245 bl
, bl
.length(), 0));
247 string(maxlen
+1, 'a'));
252 bl
, bl
.length(), 0));
254 string((maxlen
*2), 'a'));
259 bl
, bl
.length(), 0));
262 TEST_F(LibRadosMiscPP
, LongAttrNamePP
) {
264 bl
.append("content");
265 int maxlen
= g_conf
->osd_max_attr_name_len
;
266 ASSERT_EQ(0, ioctx
.setxattr("bigattrobj", string(maxlen
/2, 'a').c_str(), bl
));
267 ASSERT_EQ(0, ioctx
.setxattr("bigattrobj", string(maxlen
-1, 'a').c_str(), bl
));
268 ASSERT_EQ(0, ioctx
.setxattr("bigattrobj", string(maxlen
, 'a').c_str(), bl
));
269 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.setxattr("bigattrobj", string(maxlen
+1, 'a').c_str(), bl
));
270 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.setxattr("bigattrobj", string(maxlen
*2, 'a').c_str(), bl
));
273 static std::string
read_key_from_tmap(IoCtx
& ioctx
, const std::string
&obj
,
274 const std::string
&key
)
277 int r
= ioctx
.read(obj
, bl
, 0, 0);
280 oss
<< "ioctx.read(" << obj
<< ", bl, 0, 0) returned " << r
;
283 bufferlist::iterator p
= bl
.begin();
285 map
<string
, bufferlist
> m
;
288 map
<string
, bufferlist
>::iterator i
= m
.find(key
);
291 std::string retstring
;
292 ::decode(retstring
, i
->second
);
296 static std::string
add_key_to_tmap(IoCtx
&ioctx
, const std::string
&obj
,
297 const std::string
&key
, const std::string
&val
)
299 __u8 c
= CEPH_OSD_TMAP_SET
;
306 ::encode(blbl
, tmbl
);
307 int ret
= ioctx
.tmap_update(obj
, tmbl
);
310 oss
<< "ioctx.tmap_update(obj=" << obj
<< ", key="
311 << key
<< ", val=" << val
<< ") failed with error " << ret
;
317 static int remove_key_from_tmap(IoCtx
&ioctx
, const std::string
&obj
,
318 const std::string
&key
)
320 __u8 c
= CEPH_OSD_TMAP_RM
;
325 int ret
= ioctx
.tmap_update(obj
, tmbl
);
328 oss
<< "ioctx.tmap_update(obj=" << obj
<< ", key="
329 << key
<< ") failed with error " << ret
;
334 TEST_F(LibRadosMiscPP
, TmapUpdatePP
) {
337 __u8 c
= CEPH_OSD_TMAP_CREATE
;
338 std::string
my_tmap("my_tmap");
343 ::encode(my_tmap
, tmbl
);
344 ::encode(emptybl
, tmbl
);
345 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
348 ASSERT_EQ(string(""), add_key_to_tmap(ioctx
, "foo", "key1", "val1"));
350 ASSERT_EQ(string(""), add_key_to_tmap(ioctx
, "foo", "key2", "val2"));
352 // read key1 from the tmap
353 ASSERT_EQ(string("val1"), read_key_from_tmap(ioctx
, "foo", "key1"));
355 // remove key1 from tmap
356 ASSERT_EQ(0, remove_key_from_tmap(ioctx
, "foo", "key1"));
357 ASSERT_EQ(-ENOENT
, remove_key_from_tmap(ioctx
, "foo", "key1"));
359 // key should be removed
360 ASSERT_EQ(string(""), read_key_from_tmap(ioctx
, "foo", "key1"));
363 TEST_F(LibRadosMiscPP
, TmapUpdateMisorderedPP
) {
366 __u8 c
= CEPH_OSD_TMAP_CREATE
;
367 std::string
my_tmap("my_tmap");
372 ::encode(my_tmap
, tmbl
);
373 ::encode(emptybl
, tmbl
);
374 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
379 __u8 c
= CEPH_OSD_TMAP_SET
;
384 ::encode("old", blbl
);
385 ::encode(blbl
, tmbl
);
389 ::encode(blbl
, tmbl
);
393 ::encode(blbl
, tmbl
);
395 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
400 __u8 c
= CEPH_OSD_TMAP_SET
;
405 ::encode("new", blbl
);
406 ::encode(blbl
, tmbl
);
410 ::encode(blbl
, tmbl
);
414 ::encode(blbl
, tmbl
);
416 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
420 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx
, "foo", "a"));
421 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx
, "foo", "b"));
422 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx
, "foo", "c"));
424 ASSERT_EQ(0, remove_key_from_tmap(ioctx
, "foo", "a"));
425 ASSERT_EQ(string(""), read_key_from_tmap(ioctx
, "foo", "a"));
427 ASSERT_EQ(0, remove_key_from_tmap(ioctx
, "foo", "b"));
428 ASSERT_EQ(string(""), read_key_from_tmap(ioctx
, "foo", "a"));
431 TEST_F(LibRadosMiscPP
, TmapUpdateMisorderedPutPP
) {
432 // create unsorted tmap
438 ::encode(string("b"), bl
);
439 ::encode(string("bval"), bl
);
440 ::encode(string("a"), bl
);
441 ::encode(string("aval"), bl
);
442 ::encode(string("c"), bl
);
443 ::encode(string("cval"), bl
);
444 bufferlist orig
= bl
; // tmap_put steals bl content
445 ASSERT_EQ(0, ioctx
.tmap_put("foo", bl
));
449 ioctx
.read("foo", newbl
, orig
.length(), 0);
450 ASSERT_EQ(orig
.contents_equal(newbl
), false);
453 TEST_F(LibRadosMiscPP
, Tmap2OmapPP
) {
456 hdr
.append("header");
457 map
<string
, bufferlist
> omap
;
458 omap
["1"].append("a");
459 omap
["2"].append("b");
460 omap
["3"].append("c");
465 ASSERT_EQ(0, ioctx
.tmap_put("foo", bl
));
468 // convert tmap to omap
469 ASSERT_EQ(0, ioctx
.tmap_to_omap("foo", false));
471 // if tmap was truncated ?
475 ASSERT_EQ(0, ioctx
.stat("foo", &size
, &mtime
));
480 ASSERT_EQ(0, ioctx
.tmap_to_omap("foo", true));
481 ASSERT_LE(ioctx
.tmap_to_omap("foo", false), 0);
486 map
<string
, bufferlist
> m
;
487 ObjectReadOperation o
;
488 o
.omap_get_header(&got
, NULL
);
489 o
.omap_get_vals2("", 1024, &m
, nullptr, nullptr);
490 ASSERT_EQ(0, ioctx
.operate("foo", &o
, NULL
));
493 ASSERT_TRUE(hdr
.contents_equal(got
));
496 ASSERT_EQ(omap
.size(), m
.size());
498 for (map
<string
, bufferlist
>::iterator p
= omap
.begin(); p
!= omap
.end(); ++p
) {
499 map
<string
, bufferlist
>::iterator q
= m
.find(p
->first
);
500 if (q
== m
.end() || !p
->second
.contents_equal(q
->second
)) {
509 TEST_F(LibRadosMisc
, Exec
) {
511 memset(buf
, 0xcc, sizeof(buf
));
512 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
514 int res
= rados_exec(ioctx
, "foo", "rbd", "get_all_features",
515 NULL
, 0, buf2
, sizeof(buf2
));
518 bl
.append(buf2
, res
);
519 bufferlist::iterator iter
= bl
.begin();
520 uint64_t all_features
;
521 ::decode(all_features
, iter
);
522 // make sure *some* features are specified; don't care which ones
523 ASSERT_NE(all_features
, (unsigned)0);
526 TEST_F(LibRadosMiscPP
, ExecPP
) {
528 ASSERT_EQ(0, ioctx
.write("foo", bl
, 0, 0));
530 int r
= ioctx
.exec("foo", "rbd", "get_all_features", bl2
, out
);
532 bufferlist::iterator iter
= out
.begin();
533 uint64_t all_features
;
534 ::decode(all_features
, iter
);
535 // make sure *some* features are specified; don't care which ones
536 ASSERT_NE(all_features
, (unsigned)0);
539 void set_completion_complete(rados_completion_t cb
, void *arg
)
541 bool *my_aio_complete
= (bool*)arg
;
542 *my_aio_complete
= true;
545 TEST_F(LibRadosMiscPP
, BadFlagsPP
) {
546 unsigned badflags
= CEPH_OSD_FLAG_PARALLELEXEC
;
550 ASSERT_EQ(0, ioctx
.write("badfoo", bl
, bl
.length(), 0));
553 ASSERT_EQ(-EINVAL
, ioctx
.remove("badfoo", badflags
));
557 TEST_F(LibRadosMiscPP
, Operate1PP
) {
558 ObjectWriteOperation o
;
563 std::string
val1("val1");
566 bl
.append(val1
.c_str(), val1
.size() + 1);
567 o
.setxattr("key1", bl
);
568 o
.omap_clear(); // shouldn't affect attrs!
570 ASSERT_EQ(0, ioctx
.operate("foo", &o
));
572 ObjectWriteOperation empty
;
573 ASSERT_EQ(0, ioctx
.operate("foo", &empty
));
577 ASSERT_GT(ioctx
.getxattr("foo", "key1", bl
), 0);
578 ASSERT_EQ(0, strcmp(bl
.c_str(), val1
.c_str()));
580 ObjectWriteOperation o2
;
584 o2
.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ
, bl
);
587 ASSERT_EQ(-ECANCELED
, ioctx
.operate("foo", &o2
));
588 ObjectWriteOperation o3
;
592 o3
.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ
, bl
);
594 ASSERT_EQ(-ECANCELED
, ioctx
.operate("foo", &o3
));
597 TEST_F(LibRadosMiscPP
, Operate2PP
) {
598 ObjectWriteOperation o
;
601 bl
.append("abcdefg");
604 std::string
val1("val1");
607 bl
.append(val1
.c_str(), val1
.size() + 1);
608 o
.setxattr("key1", bl
);
611 ASSERT_EQ(0, ioctx
.operate("foo", &o
));
614 ASSERT_EQ(0, ioctx
.stat("foo", &size
, &mtime
));
618 TEST_F(LibRadosMiscPP
, BigObjectPP
) {
620 bl
.append("abcdefg");
621 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
624 ObjectWriteOperation o
;
625 o
.truncate(500000000000ull);
626 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
629 ObjectWriteOperation o
;
630 o
.zero(500000000000ull, 1);
631 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
634 ObjectWriteOperation o
;
635 o
.zero(1, 500000000000ull);
636 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
639 ObjectWriteOperation o
;
640 o
.zero(500000000000ull, 500000000000ull);
641 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
645 // this test only works on 64-bit platforms
646 ASSERT_EQ(-EFBIG
, ioctx
.write("foo", bl
, bl
.length(), 500000000000ull));
650 TEST_F(LibRadosMiscPP
, AioOperatePP
) {
651 bool my_aio_complete
= false;
652 AioCompletion
*my_completion
= cluster
.aio_create_completion(
653 (void*)&my_aio_complete
, set_completion_complete
, NULL
);
654 AioCompletion
*my_completion_null
= NULL
;
655 ASSERT_NE(my_completion
, my_completion_null
);
657 ObjectWriteOperation o
;
662 std::string
val1("val1");
665 bl
.append(val1
.c_str(), val1
.size() + 1);
666 o
.setxattr("key1", bl
);
669 memset(buf2
, 0xdd, sizeof(buf2
));
670 bl2
.append(buf2
, sizeof(buf2
));
673 ASSERT_EQ(0, ioctx
.aio_operate("foo", my_completion
, &o
));
674 ASSERT_EQ(0, my_completion
->wait_for_complete_and_cb());
675 ASSERT_EQ(my_aio_complete
, true);
676 my_completion
->release();
680 ASSERT_EQ(0, ioctx
.stat("foo", &size
, &mtime
));
681 ASSERT_EQ(1024U, size
);
684 TEST_F(LibRadosMiscPP
, AssertExistsPP
) {
686 memset(buf
, 0xcc, sizeof(buf
));
688 bl
.append(buf
, sizeof(buf
));
690 ObjectWriteOperation op
;
693 ASSERT_EQ(-ENOENT
, ioctx
.operate("asdffoo", &op
));
694 ASSERT_EQ(0, ioctx
.create("asdffoo", true));
695 ASSERT_EQ(0, ioctx
.operate("asdffoo", &op
));
696 ASSERT_EQ(-EEXIST
, ioctx
.create("asdffoo", true));
699 TEST_F(LibRadosMiscPP
, AssertVersionPP
) {
701 memset(buf
, 0xcc, sizeof(buf
));
703 bl
.append(buf
, sizeof(buf
));
705 // Create test object...
706 ASSERT_EQ(0, ioctx
.create("asdfbar", true));
707 // ...then write it again to guarantee that the
708 // (unsigned) version must be at least 1 (not 0)
709 // since we want to decrement it by 1 later.
710 ASSERT_EQ(0, ioctx
.write_full("asdfbar", bl
));
712 uint64_t v
= ioctx
.get_last_version();
713 ObjectWriteOperation op1
;
714 op1
.assert_version(v
+1);
716 ASSERT_EQ(-EOVERFLOW
, ioctx
.operate("asdfbar", &op1
));
717 ObjectWriteOperation op2
;
718 op2
.assert_version(v
-1);
720 ASSERT_EQ(-ERANGE
, ioctx
.operate("asdfbar", &op2
));
721 ObjectWriteOperation op3
;
722 op3
.assert_version(v
);
724 ASSERT_EQ(0, ioctx
.operate("asdfbar", &op3
));
727 TEST_F(LibRadosMiscPP
, BigAttrPP
) {
729 memset(buf
, 0xcc, sizeof(buf
));
731 bl
.append(buf
, sizeof(buf
));
733 ASSERT_EQ(0, ioctx
.create("foo", true));
737 cout
<< "osd_max_attr_size = " << g_conf
->osd_max_attr_size
<< std::endl
;
738 if (g_conf
->osd_max_attr_size
) {
741 bl
.append(buffer::create(g_conf
->osd_max_attr_size
));
742 ASSERT_EQ(0, ioctx
.setxattr("foo", "one", bl
));
743 ASSERT_EQ((int)bl
.length(), ioctx
.getxattr("foo", "one", got
));
744 ASSERT_TRUE(bl
.contents_equal(got
));
747 bl
.append(buffer::create(g_conf
->osd_max_attr_size
+1));
748 ASSERT_EQ(-EFBIG
, ioctx
.setxattr("foo", "one", bl
));
750 cout
<< "osd_max_attr_size == 0; skipping test" << std::endl
;
753 for (int i
=0; i
<1000; i
++) {
756 bl
.append(buffer::create(MIN(g_conf
->osd_max_attr_size
, 1024)));
758 snprintf(n
, sizeof(n
), "a%d", i
);
759 ASSERT_EQ(0, ioctx
.setxattr("foo", n
, bl
));
760 ASSERT_EQ((int)bl
.length(), ioctx
.getxattr("foo", n
, got
));
761 ASSERT_TRUE(bl
.contents_equal(got
));
765 TEST_F(LibRadosMiscPP
, CopyPP
) {
767 bl
.append("hi there");
773 ASSERT_EQ(0, ioctx
.write_full("foo", blc
));
774 ASSERT_EQ(0, ioctx
.setxattr("foo", "myattr", xc
));
776 version_t uv
= ioctx
.get_last_version();
778 // pass future version
779 ObjectWriteOperation op
;
780 op
.copy_from2("foo", ioctx
, uv
+ 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
781 ASSERT_EQ(-EOVERFLOW
, ioctx
.operate("foo.copy", &op
));
785 ObjectWriteOperation op
;
786 op
.copy_from2("foo", ioctx
, uv
- 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
787 ASSERT_EQ(-ERANGE
, ioctx
.operate("foo.copy", &op
));
790 ObjectWriteOperation op
;
791 op
.copy_from2("foo", ioctx
, uv
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
792 ASSERT_EQ(0, ioctx
.operate("foo.copy", &op
));
795 ASSERT_EQ((int)bl
.length(), ioctx
.read("foo.copy", bl2
, 10000, 0));
796 ASSERT_TRUE(bl
.contents_equal(bl2
));
797 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy", "myattr", x2
));
798 ASSERT_TRUE(x
.contents_equal(x2
));
801 // small object without a version
803 ObjectWriteOperation op
;
804 op
.copy_from2("foo", ioctx
, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
805 ASSERT_EQ(0, ioctx
.operate("foo.copy2", &op
));
808 ASSERT_EQ((int)bl
.length(), ioctx
.read("foo.copy2", bl2
, 10000, 0));
809 ASSERT_TRUE(bl
.contents_equal(bl2
));
810 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy2", "myattr", x2
));
811 ASSERT_TRUE(x
.contents_equal(x2
));
815 bl
.append(buffer::create(g_conf
->osd_copyfrom_max_chunk
* 3));
820 ASSERT_EQ(0, ioctx
.write_full("big", blc
));
821 ASSERT_EQ(0, ioctx
.setxattr("big", "myattr", xc
));
824 ObjectWriteOperation op
;
825 op
.copy_from2("big", ioctx
, ioctx
.get_last_version(), LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
826 ASSERT_EQ(0, ioctx
.operate("big.copy", &op
));
829 ASSERT_EQ((int)bl
.length(), ioctx
.read("big.copy", bl2
, bl
.length(), 0));
830 ASSERT_TRUE(bl
.contents_equal(bl2
));
831 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy", "myattr", x2
));
832 ASSERT_TRUE(x
.contents_equal(x2
));
836 ObjectWriteOperation op
;
837 op
.copy_from2("big", ioctx
, 0, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
838 ASSERT_EQ(0, ioctx
.operate("big.copy2", &op
));
841 ASSERT_EQ((int)bl
.length(), ioctx
.read("big.copy2", bl2
, bl
.length(), 0));
842 ASSERT_TRUE(bl
.contents_equal(bl2
));
843 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy2", "myattr", x2
));
844 ASSERT_TRUE(x
.contents_equal(x2
));
848 class LibRadosTwoPoolsECPP
: public RadosTestECPP
851 LibRadosTwoPoolsECPP() {};
852 ~LibRadosTwoPoolsECPP() override
{};
854 static void SetUpTestCase() {
855 pool_name
= get_temp_pool_name();
856 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, s_cluster
));
857 src_pool_name
= get_temp_pool_name();
858 ASSERT_EQ(0, s_cluster
.pool_create(src_pool_name
.c_str()));
860 static void TearDownTestCase() {
861 ASSERT_EQ(0, s_cluster
.pool_delete(src_pool_name
.c_str()));
862 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, s_cluster
));
864 static std::string src_pool_name
;
866 void SetUp() override
{
867 RadosTestECPP::SetUp();
868 ASSERT_EQ(0, cluster
.ioctx_create(src_pool_name
.c_str(), src_ioctx
));
869 src_ioctx
.set_namespace(nspace
);
871 void TearDown() override
{
872 // wait for maps to settle before next test
873 cluster
.wait_for_latest_osdmap();
875 RadosTestECPP::TearDown();
877 cleanup_default_namespace(src_ioctx
);
878 cleanup_namespace(src_ioctx
, nspace
);
883 librados::IoCtx src_ioctx
;
885 std::string
LibRadosTwoPoolsECPP::src_pool_name
;
887 //copy_from between ecpool and no-ecpool.
888 TEST_F(LibRadosTwoPoolsECPP
, CopyFrom
) {
890 z
.append_zero(4194304*2);
892 b
.append("copyfrom");
894 // create big object w/ omapheader
896 ASSERT_EQ(0, src_ioctx
.write_full("foo", z
));
897 ASSERT_EQ(0, src_ioctx
.omap_set_header("foo", b
));
898 version_t uv
= src_ioctx
.get_last_version();
899 ObjectWriteOperation op
;
900 op
.copy_from("foo", src_ioctx
, uv
);
901 ASSERT_EQ(-EOPNOTSUPP
, ioctx
.operate("foo.copy", &op
));
904 // same with small object
906 ASSERT_EQ(0, src_ioctx
.omap_set_header("bar", b
));
907 version_t uv
= src_ioctx
.get_last_version();
908 ObjectWriteOperation op
;
909 op
.copy_from("bar", src_ioctx
, uv
);
910 ASSERT_EQ(-EOPNOTSUPP
, ioctx
.operate("bar.copy", &op
));
914 TEST_F(LibRadosMiscPP
, CopyScrubPP
) {
915 bufferlist inbl
, bl
, x
;
916 for (int i
=0; i
<100; ++i
)
917 x
.append("barrrrrrrrrrrrrrrrrrrrrrrrrr");
918 bl
.append(buffer::create(g_conf
->osd_copyfrom_max_chunk
* 3));
923 map
<string
, bufferlist
> to_set
;
924 for (int i
=0; i
<1000; ++i
)
925 to_set
[string("foo") + stringify(i
)] = x
;
929 ASSERT_EQ(0, ioctx
.write_full("small", cbl
));
930 ASSERT_EQ(0, ioctx
.setxattr("small", "myattr", x
));
934 ASSERT_EQ(0, ioctx
.write_full("big", cbl
));
938 ASSERT_EQ(0, ioctx
.write_full("big2", cbl
));
939 ASSERT_EQ(0, ioctx
.setxattr("big2", "myattr", x
));
940 ASSERT_EQ(0, ioctx
.setxattr("big2", "myattr2", x
));
941 ASSERT_EQ(0, ioctx
.omap_set("big2", to_set
));
945 ASSERT_EQ(0, ioctx
.write_full("big3", cbl
));
946 ASSERT_EQ(0, ioctx
.omap_set_header("big3", x
));
947 ASSERT_EQ(0, ioctx
.omap_set("big3", to_set
));
949 // deep scrub to ensure digests are in place
951 for (int i
=0; i
<10; ++i
) {
953 ss
<< "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
954 << ioctx
.get_id() << "." << i
956 cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
959 // give it a few seconds to go. this is sloppy but is usually enough time
960 cout
<< "waiting for initial deep scrubs..." << std::endl
;
962 cout
<< "done waiting, doing copies" << std::endl
;
966 ObjectWriteOperation op
;
967 op
.copy_from("small", ioctx
, 0);
968 ASSERT_EQ(0, ioctx
.operate("small.copy", &op
));
972 ObjectWriteOperation op
;
973 op
.copy_from("big", ioctx
, 0);
974 ASSERT_EQ(0, ioctx
.operate("big.copy", &op
));
978 ObjectWriteOperation op
;
979 op
.copy_from("big2", ioctx
, 0);
980 ASSERT_EQ(0, ioctx
.operate("big2.copy", &op
));
984 ObjectWriteOperation op
;
985 op
.copy_from("big3", ioctx
, 0);
986 ASSERT_EQ(0, ioctx
.operate("big3.copy", &op
));
989 // deep scrub to ensure digests are correct
991 for (int i
=0; i
<10; ++i
) {
993 ss
<< "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
994 << ioctx
.get_id() << "." << i
996 cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
999 // give it a few seconds to go. this is sloppy but is usually enough time
1000 cout
<< "waiting for final deep scrubs..." << std::endl
;
1002 cout
<< "done waiting" << std::endl
;
1006 TEST_F(LibRadosMiscPP
, WriteSamePP
) {
1013 /* zero the full range before using writesame */
1014 memset(full
, 0, sizeof(full
));
1015 fl
.append(full
, sizeof(full
));
1016 ASSERT_EQ(0, ioctx
.write("ws", fl
, fl
.length(), 0));
1018 memset(buf
, 0xcc, sizeof(buf
));
1020 bl
.append(buf
, sizeof(buf
));
1021 /* write the same buf four times */
1022 ASSERT_EQ(0, ioctx
.writesame("ws", bl
, sizeof(full
), 0));
1024 /* read back the full buffer and confirm that it matches */
1026 fl
.append(full
, sizeof(full
));
1027 ASSERT_EQ((int)fl
.length(), ioctx
.read("ws", fl
, fl
.length(), 0));
1029 for (cmp
= fl
.c_str(); cmp
< fl
.c_str() + fl
.length(); cmp
+= sizeof(buf
)) {
1030 ASSERT_EQ(0, memcmp(cmp
, buf
, sizeof(buf
)));
1033 /* write_len not a multiple of data_len should throw error */
1035 bl
.append(buf
, sizeof(buf
));
1036 ASSERT_EQ(-EINVAL
, ioctx
.writesame("ws", bl
, (sizeof(buf
) * 4) - 1, 0));
1038 ioctx
.writesame("ws", bl
, bl
.length() / 2, 0));
1039 /* write_len = data_len, i.e. same as write() */
1040 ASSERT_EQ(0, ioctx
.writesame("ws", bl
, sizeof(buf
), 0));
1043 ioctx
.writesame("ws", bl
, sizeof(buf
), 0));
1046 TEST_F(LibRadosMisc
, WriteSame
) {
1051 /* zero the full range before using writesame */
1052 memset(full
, 0, sizeof(full
));
1053 ASSERT_EQ(0, rados_write(ioctx
, "ws", full
, sizeof(full
), 0));
1055 memset(buf
, 0xcc, sizeof(buf
));
1056 /* write the same buf four times */
1057 ASSERT_EQ(0, rados_writesame(ioctx
, "ws", buf
, sizeof(buf
), sizeof(full
), 0));
1059 /* read back the full buffer and confirm that it matches */
1060 ASSERT_EQ((int)sizeof(full
), rados_read(ioctx
, "ws", full
, sizeof(full
), 0));
1062 for (cmp
= full
; cmp
< full
+ sizeof(full
); cmp
+= sizeof(buf
)) {
1063 ASSERT_EQ(0, memcmp(cmp
, buf
, sizeof(buf
)));
1066 /* write_len not a multiple of data_len should throw error */
1067 ASSERT_EQ(-EINVAL
, rados_writesame(ioctx
, "ws", buf
, sizeof(buf
),
1068 (sizeof(buf
) * 4) - 1, 0));
1070 rados_writesame(ioctx
, "ws", buf
, sizeof(buf
), sizeof(buf
) / 2, 0));
1072 rados_writesame(ioctx
, "ws", buf
, 0, sizeof(buf
), 0));
1073 /* write_len = data_len, i.e. same as rados_write() */
1074 ASSERT_EQ(0, rados_writesame(ioctx
, "ws", buf
, sizeof(buf
), sizeof(buf
), 0));
1077 template <typename T
>
1078 class LibRadosChecksum
: public LibRadosMiscPP
{
1080 typedef typename
T::alg_t alg_t
;
1081 typedef typename
T::value_t value_t
;
1082 typedef typename
alg_t::init_value_t init_value_t
;
1084 static const rados_checksum_type_t type
= T::type
;
1086 bufferlist content_bl
;
1088 using LibRadosMiscPP::SetUpTestCase
;
1089 using LibRadosMiscPP::TearDownTestCase
;
1091 void SetUp() override
{
1092 LibRadosMiscPP::SetUp();
1094 std::string
content(4096, '\0');
1095 for (size_t i
= 0; i
< content
.length(); ++i
) {
1096 content
[i
] = static_cast<char>(rand() % (126 - 33) + 33);
1098 content_bl
.append(content
);
1099 ASSERT_EQ(0, ioctx
.write("foo", content_bl
, content_bl
.length(), 0));
1103 template <rados_checksum_type_t _type
, typename AlgT
, typename ValueT
>
1104 class LibRadosChecksumParams
{
1107 typedef ValueT value_t
;
1108 static const rados_checksum_type_t type
= _type
;
1111 typedef ::testing::Types
<
1112 LibRadosChecksumParams
<LIBRADOS_CHECKSUM_TYPE_XXHASH32
,
1113 Checksummer::xxhash32
, uint32_t>,
1114 LibRadosChecksumParams
<LIBRADOS_CHECKSUM_TYPE_XXHASH64
,
1115 Checksummer::xxhash64
, uint64_t>,
1116 LibRadosChecksumParams
<LIBRADOS_CHECKSUM_TYPE_CRC32C
,
1117 Checksummer::crc32c
, uint32_t>
1118 > LibRadosChecksumTypes
;
1120 TYPED_TEST_CASE(LibRadosChecksum
, LibRadosChecksumTypes
);
1122 TYPED_TEST(LibRadosChecksum
, Subset
) {
1123 uint32_t chunk_size
= 1024;
1124 uint32_t csum_count
= this->content_bl
.length() / chunk_size
;
1126 typename
TestFixture::init_value_t init_value
= -1;
1127 bufferlist init_value_bl
;
1128 ::encode(init_value
, init_value_bl
);
1130 std::vector
<bufferlist
> checksum_bls(csum_count
);
1131 std::vector
<int> checksum_rvals(csum_count
);
1133 // individual checksum ops for each chunk
1134 ObjectReadOperation op
;
1135 for (uint32_t i
= 0; i
< csum_count
; ++i
) {
1136 op
.checksum(TestFixture::type
, init_value_bl
, i
* chunk_size
, chunk_size
,
1137 0, &checksum_bls
[i
], &checksum_rvals
[i
]);
1139 ASSERT_EQ(0, this->ioctx
.operate("foo", &op
, NULL
));
1141 for (uint32_t i
= 0; i
< csum_count
; ++i
) {
1142 ASSERT_EQ(0, checksum_rvals
[i
]);
1144 auto bl_it
= checksum_bls
[i
].begin();
1146 ::decode(count
, bl_it
);
1147 ASSERT_EQ(1U, count
);
1149 typename
TestFixture::value_t value
;
1150 ::decode(value
, bl_it
);
1152 bufferlist content_sub_bl
;
1153 content_sub_bl
.substr_of(this->content_bl
, i
* chunk_size
, chunk_size
);
1155 typename
TestFixture::value_t expected_value
;
1156 bufferptr expected_value_bp
= buffer::create_static(
1157 sizeof(expected_value
), reinterpret_cast<char*>(&expected_value
));
1158 Checksummer::template calculate
<typename
TestFixture::alg_t
>(
1159 init_value
, chunk_size
, 0, chunk_size
, content_sub_bl
,
1160 &expected_value_bp
);
1161 ASSERT_EQ(expected_value
, value
);
1165 TYPED_TEST(LibRadosChecksum
, Chunked
) {
1166 uint32_t chunk_size
= 1024;
1167 uint32_t csum_count
= this->content_bl
.length() / chunk_size
;
1169 typename
TestFixture::init_value_t init_value
= -1;
1170 bufferlist init_value_bl
;
1171 ::encode(init_value
, init_value_bl
);
1173 bufferlist checksum_bl
;
1176 // single op with chunked checksum results
1177 ObjectReadOperation op
;
1178 op
.checksum(TestFixture::type
, init_value_bl
, 0, this->content_bl
.length(),
1179 chunk_size
, &checksum_bl
, &checksum_rval
);
1180 ASSERT_EQ(0, this->ioctx
.operate("foo", &op
, NULL
));
1181 ASSERT_EQ(0, checksum_rval
);
1183 auto bl_it
= checksum_bl
.begin();
1185 ::decode(count
, bl_it
);
1186 ASSERT_EQ(csum_count
, count
);
1188 std::vector
<typename
TestFixture::value_t
> expected_values(csum_count
);
1189 bufferptr expected_values_bp
= buffer::create_static(
1190 csum_count
* sizeof(typename
TestFixture::value_t
),
1191 reinterpret_cast<char*>(&expected_values
[0]));
1193 Checksummer::template calculate
<typename
TestFixture::alg_t
>(
1194 init_value
, chunk_size
, 0, this->content_bl
.length(), this->content_bl
,
1195 &expected_values_bp
);
1197 for (uint32_t i
= 0; i
< csum_count
; ++i
) {
1198 typename
TestFixture::value_t value
;
1199 ::decode(value
, bl_it
);
1200 ASSERT_EQ(expected_values
[i
], value
);
1204 TEST_F(LibRadosMiscPP
, CmpExtPP
) {
1205 bufferlist cmp_bl
, bad_cmp_bl
, write_bl
;
1206 char stored_str
[] = "1234567891";
1207 char mismatch_str
[] = "1234577777";
1209 write_bl
.append(stored_str
);
1210 ioctx
.write("cmpextpp", write_bl
, write_bl
.length(), 0);
1211 cmp_bl
.append(stored_str
);
1212 ASSERT_EQ(0, ioctx
.cmpext("cmpextpp", 0, cmp_bl
));
1214 bad_cmp_bl
.append(mismatch_str
);
1215 ASSERT_EQ(-MAX_ERRNO
- 5, ioctx
.cmpext("cmpextpp", 0, bad_cmp_bl
));
1218 TEST_F(LibRadosMisc
, CmpExt
) {
1219 bufferlist cmp_bl
, bad_cmp_bl
, write_bl
;
1220 char stored_str
[] = "1234567891";
1221 char mismatch_str
[] = "1234577777";
1224 rados_write(ioctx
, "cmpextpp", stored_str
, sizeof(stored_str
), 0));
1227 rados_cmpext(ioctx
, "cmpextpp", stored_str
, sizeof(stored_str
), 0));
1229 ASSERT_EQ(-MAX_ERRNO
- 5,
1230 rados_cmpext(ioctx
, "cmpextpp", mismatch_str
, sizeof(mismatch_str
), 0));