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/buffer.h"
7 #include "include/rbd_types.h"
8 #include "include/rados/librados.hpp"
9 #include "include/stringify.h"
10 #include "include/types.h"
11 #include "global/global_context.h"
12 #include "common/Cond.h"
13 #include "test/librados/test_cxx.h"
14 #include "test/librados/testcase_cxx.h"
15 #include "json_spirit/json_spirit.h"
16 #include "cls/cas/cls_cas_ops.h"
17 #include "cls/cas/cls_cas_internal.h"
19 #include "osd/HitSet.h"
26 #include "cls/cas/cls_cas_client.h"
27 #include "cls/cas/cls_cas_internal.h"
30 using namespace librados
;
32 typedef RadosTestPP LibRadosTierPP
;
33 typedef RadosTestECPP LibRadosTierECPP
;
35 void flush_evict_all(librados::Rados
& cluster
, librados::IoCtx
& cache_ioctx
)
38 cache_ioctx
.set_namespace(all_nspaces
);
39 for (NObjectIterator it
= cache_ioctx
.nobjects_begin();
40 it
!= cache_ioctx
.nobjects_end(); ++it
) {
41 cache_ioctx
.locator_set_key(it
->get_locator());
42 cache_ioctx
.set_namespace(it
->get_nspace());
44 ObjectReadOperation op
;
46 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
47 cache_ioctx
.aio_operate(
48 it
->get_oid(), completion
, &op
,
49 librados::OPERATION_IGNORE_OVERLAY
, NULL
);
50 completion
->wait_for_complete();
51 completion
->get_return_value();
52 completion
->release();
55 ObjectReadOperation op
;
57 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
58 cache_ioctx
.aio_operate(
59 it
->get_oid(), completion
, &op
,
60 librados::OPERATION_IGNORE_OVERLAY
, NULL
);
61 completion
->wait_for_complete();
62 completion
->get_return_value();
63 completion
->release();
68 static string
_get_required_osd_release(Rados
& cluster
)
71 string cmd
= string("{\"prefix\": \"osd dump\",\"format\":\"json\"}");
73 int r
= cluster
.mon_command(cmd
, inbl
, &outbl
, NULL
);
75 string
outstr(outbl
.c_str(), outbl
.length());
77 if (!json_spirit::read(outstr
, v
)) {
78 cerr
<<" unable to parse json " << outstr
<< std::endl
;
82 json_spirit::Object
& o
= v
.get_obj();
83 for (json_spirit::Object::size_type i
=0; i
<o
.size(); i
++) {
84 json_spirit::Pair
& p
= o
[i
];
85 if (p
.name_
== "require_osd_release") {
86 cout
<< "require_osd_release = " << p
.value_
.get_str() << std::endl
;
87 return p
.value_
.get_str();
90 cerr
<< "didn't find require_osd_release in " << outstr
<< std::endl
;
94 void manifest_set_chunk(Rados
& cluster
, librados::IoCtx
& src_ioctx
,
95 librados::IoCtx
& tgt_ioctx
,
96 uint64_t src_offset
, uint64_t length
,
97 std::string src_oid
, std::string tgt_oid
)
99 ObjectReadOperation op
;
100 op
.set_chunk(src_offset
, length
, src_ioctx
, src_oid
, 0,
101 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
102 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
103 ASSERT_EQ(0, tgt_ioctx
.aio_operate(tgt_oid
, completion
, &op
,
104 librados::OPERATION_IGNORE_CACHE
, NULL
));
105 completion
->wait_for_complete();
106 ASSERT_EQ(0, completion
->get_return_value());
107 completion
->release();
110 #include "common/ceph_crypto.h"
111 using ceph::crypto::SHA1
;
112 #include "rgw/rgw_common.h"
114 void check_fp_oid_refcount(librados::IoCtx
& ioctx
, std::string foid
, uint64_t count
,
115 std::string fp_algo
= NULL
)
118 int size
= foid
.length();
119 if (fp_algo
== "sha1") {
120 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
121 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
123 sha1_gen
.Update((const unsigned char *)foid
.c_str(), size
);
124 sha1_gen
.Final(fingerprint
);
125 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
126 ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
127 } else if (fp_algo
.empty()) {
128 ioctx
.getxattr(foid
, CHUNK_REFCOUNT_ATTR
, t
);
129 } else if (!fp_algo
.empty()) {
130 ceph_assert(0 == "unrecognized fingerprint algorithm");
135 auto iter
= t
.cbegin();
137 } catch (buffer::error
& err
) {
140 ASSERT_LE(count
, refs
.count());
143 string
get_fp_oid(string oid
, std::string fp_algo
= NULL
)
145 if (fp_algo
== "sha1") {
146 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
147 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
149 int size
= oid
.length();
150 sha1_gen
.Update((const unsigned char *)oid
.c_str(), size
);
151 sha1_gen
.Final(fingerprint
);
152 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
153 return string(p_str
);
159 void is_intended_refcount_state(librados::IoCtx
& src_ioctx
,
161 librados::IoCtx
& dst_ioctx
,
163 int expected_refcount
)
165 int src_refcount
= 0, dst_refcount
= 0;
167 int r
= dst_ioctx
.getxattr(dst_oid
, CHUNK_REFCOUNT_ATTR
, t
);
173 auto iter
= t
.cbegin();
175 } catch (buffer::error
& err
) {
178 dst_refcount
= refs
.count();
181 for (; tries
< 30; ++tries
) {
182 r
= cls_cas_references_chunk(src_ioctx
, src_oid
, dst_oid
);
183 if (r
== -ENOENT
|| r
== -ENOLINK
) {
185 } else if (r
== -EBUSY
) {
193 ASSERT_TRUE(tries
< 30);
194 ASSERT_TRUE(src_refcount
>= 0);
195 ASSERT_TRUE(src_refcount
== expected_refcount
);
196 ASSERT_TRUE(src_refcount
<= dst_refcount
);
199 class LibRadosTwoPoolsPP
: public RadosTestPP
202 LibRadosTwoPoolsPP() {};
203 ~LibRadosTwoPoolsPP() override
{};
205 static void SetUpTestCase() {
206 pool_name
= get_temp_pool_name();
207 ASSERT_EQ("", create_one_pool_pp(pool_name
, s_cluster
));
209 static void TearDownTestCase() {
210 ASSERT_EQ(0, destroy_one_pool_pp(pool_name
, s_cluster
));
212 static std::string cache_pool_name
;
214 void SetUp() override
{
215 cache_pool_name
= get_temp_pool_name();
216 ASSERT_EQ(0, s_cluster
.pool_create(cache_pool_name
.c_str()));
217 RadosTestPP::SetUp();
219 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
220 cache_ioctx
.application_enable("rados", true);
221 cache_ioctx
.set_namespace(nspace
);
223 void TearDown() override
{
224 // flush + evict cache
225 flush_evict_all(cluster
, cache_ioctx
);
229 ASSERT_EQ(0, cluster
.mon_command(
230 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
233 ASSERT_EQ(0, cluster
.mon_command(
234 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
235 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
238 // wait for maps to settle before next test
239 cluster
.wait_for_latest_osdmap();
241 RadosTestPP::TearDown();
243 cleanup_default_namespace(cache_ioctx
);
244 cleanup_namespace(cache_ioctx
, nspace
);
247 ASSERT_EQ(0, s_cluster
.pool_delete(cache_pool_name
.c_str()));
249 librados::IoCtx cache_ioctx
;
255 Completions() = default;
256 librados::AioCompletion
* getCompletion() {
257 librados::AioCompletion
* comp
= librados::Rados::aio_create_completion();
258 m_completions
.push_back(comp
);
263 for (auto& comp
: m_completions
) {
269 vector
<librados::AioCompletion
*> m_completions
;
272 Completions completions
;
274 std::string
LibRadosTwoPoolsPP::cache_pool_name
;
276 TEST_F(LibRadosTierPP
, Dirty
) {
278 ObjectWriteOperation op
;
280 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still get 0 if it dne
283 ObjectWriteOperation op
;
285 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
290 ObjectReadOperation op
;
291 op
.is_dirty(&dirty
, &r
);
292 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
297 ObjectWriteOperation op
;
299 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
302 ObjectWriteOperation op
;
304 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still 0 if already clean
309 ObjectReadOperation op
;
310 op
.is_dirty(&dirty
, &r
);
311 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
316 ObjectWriteOperation op
;
317 op
.truncate(0); // still a write even tho it is a no-op
318 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
323 ObjectReadOperation op
;
324 op
.is_dirty(&dirty
, &r
);
325 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
331 TEST_F(LibRadosTwoPoolsPP
, Overlay
) {
336 ObjectWriteOperation op
;
338 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
343 ObjectWriteOperation op
;
345 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
350 ASSERT_EQ(0, cluster
.mon_command(
351 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
352 "\", \"tierpool\": \"" + cache_pool_name
+
353 "\", \"force_nonempty\": \"--force-nonempty\" }",
355 ASSERT_EQ(0, cluster
.mon_command(
356 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
357 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
360 // wait for maps to settle
361 cluster
.wait_for_latest_osdmap();
363 // by default, the overlay sends us to cache pool
366 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
367 ASSERT_EQ('c', bl
[0]);
371 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
372 ASSERT_EQ('c', bl
[0]);
375 // unless we say otherwise
378 ObjectReadOperation op
;
379 op
.read(0, 1, &bl
, NULL
);
380 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
381 ASSERT_EQ(0, ioctx
.aio_operate(
382 "foo", completion
, &op
,
383 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
384 completion
->wait_for_complete();
385 ASSERT_EQ(0, completion
->get_return_value());
386 completion
->release();
387 ASSERT_EQ('b', bl
[0]);
391 TEST_F(LibRadosTwoPoolsPP
, Promote
) {
395 bl
.append("hi there");
396 ObjectWriteOperation op
;
398 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
403 ASSERT_EQ(0, cluster
.mon_command(
404 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
405 "\", \"tierpool\": \"" + cache_pool_name
+
406 "\", \"force_nonempty\": \"--force-nonempty\" }",
408 ASSERT_EQ(0, cluster
.mon_command(
409 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
410 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
412 ASSERT_EQ(0, cluster
.mon_command(
413 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
414 "\", \"mode\": \"writeback\"}",
417 // wait for maps to settle
418 cluster
.wait_for_latest_osdmap();
420 // read, trigger a promote
423 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
426 // read, trigger a whiteout
429 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
430 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
433 // verify the object is present in the cache tier
435 NObjectIterator it
= cache_ioctx
.nobjects_begin();
436 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
437 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
439 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
441 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
445 TEST_F(LibRadosTwoPoolsPP
, PromoteSnap
) {
449 bl
.append("hi there");
450 ObjectWriteOperation op
;
452 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
456 bl
.append("hi there");
457 ObjectWriteOperation op
;
459 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
463 bl
.append("hi there");
464 ObjectWriteOperation op
;
466 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
470 bl
.append("hi there");
471 ObjectWriteOperation op
;
473 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
476 // create a snapshot, clone
477 vector
<uint64_t> my_snaps(1);
478 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
479 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
484 ObjectWriteOperation op
;
486 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
491 ObjectWriteOperation op
;
493 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
496 ObjectWriteOperation op
;
498 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
503 ObjectWriteOperation op
;
505 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
510 ASSERT_EQ(0, cluster
.mon_command(
511 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
512 "\", \"tierpool\": \"" + cache_pool_name
+
513 "\", \"force_nonempty\": \"--force-nonempty\" }",
515 ASSERT_EQ(0, cluster
.mon_command(
516 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
517 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
519 ASSERT_EQ(0, cluster
.mon_command(
520 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
521 "\", \"mode\": \"writeback\"}",
524 // wait for maps to settle
525 cluster
.wait_for_latest_osdmap();
527 // read, trigger a promote on the head
530 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
531 ASSERT_EQ('c', bl
[0]);
535 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
536 ASSERT_EQ('c', bl
[0]);
539 ioctx
.snap_set_read(my_snaps
[0]);
544 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
545 ASSERT_EQ('h', bl
[0]);
551 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
552 ASSERT_EQ('h', bl
[0]);
558 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
559 ASSERT_EQ('h', bl
[0]);
562 ioctx
.snap_set_read(librados::SNAP_HEAD
);
567 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
568 ASSERT_EQ('c', bl
[0]);
574 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
575 ASSERT_EQ('c', bl
[0]);
581 ASSERT_EQ(-ENOENT
, ioctx
.read("baz", bl
, 1, 0));
585 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
588 TEST_F(LibRadosTwoPoolsPP
, PromoteSnapScrub
) {
592 for (int i
=0; i
<num
; ++i
) {
594 bl
.append("hi there");
595 ObjectWriteOperation op
;
597 ASSERT_EQ(0, ioctx
.operate(string("foo") + stringify(i
), &op
));
600 vector
<uint64_t> my_snaps
;
601 for (int snap
=0; snap
<4; ++snap
) {
602 // create a snapshot, clone
603 vector
<uint64_t> ns(1);
604 ns
.insert(ns
.end(), my_snaps
.begin(), my_snaps
.end());
606 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
607 cout
<< "my_snaps " << my_snaps
<< std::endl
;
608 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
610 for (int i
=0; i
<num
; ++i
) {
612 bl
.append(string("ciao! snap") + stringify(snap
));
613 ObjectWriteOperation op
;
615 ASSERT_EQ(0, ioctx
.operate(string("foo") + stringify(i
), &op
));
621 ASSERT_EQ(0, cluster
.mon_command(
622 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
623 "\", \"tierpool\": \"" + cache_pool_name
+
624 "\", \"force_nonempty\": \"--force-nonempty\" }",
626 ASSERT_EQ(0, cluster
.mon_command(
627 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
628 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
630 ASSERT_EQ(0, cluster
.mon_command(
631 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
632 "\", \"mode\": \"writeback\"}",
635 // wait for maps to settle
636 cluster
.wait_for_latest_osdmap();
638 // read, trigger a promote on _some_ heads to make sure we handle cases
639 // where snaps are present and where they are not.
640 cout
<< "promoting some heads" << std::endl
;
641 for (int i
=0; i
<num
; ++i
) {
642 if (i
% 5 == 0 || i
> num
- 3) {
644 ASSERT_EQ(1, ioctx
.read(string("foo") + stringify(i
), bl
, 1, 0));
645 ASSERT_EQ('c', bl
[0]);
649 for (unsigned snap
= 0; snap
< my_snaps
.size(); ++snap
) {
650 cout
<< "promoting from clones for snap " << my_snaps
[snap
] << std::endl
;
651 ioctx
.snap_set_read(my_snaps
[snap
]);
653 // read some snaps, semi-randomly
654 for (int i
=0; i
<50; ++i
) {
656 string o
= string("foo") + stringify((snap
* i
* 137) % 80);
657 //cout << o << std::endl;
658 ASSERT_EQ(1, ioctx
.read(o
, bl
, 1, 0));
662 // ok, stop and scrub this pool (to make sure scrub can handle
663 // missing clones in the cache tier).
666 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
667 for (int i
=0; i
<10; ++i
) {
670 ss
<< "{\"prefix\": \"pg scrub\", \"pgid\": \""
671 << cache_ioctx
.get_id() << "." << i
673 int r
= cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
674 if (r
== -ENOENT
|| // in case mgr osdmap is stale
682 // give it a few seconds to go. this is sloppy but is usually enough time
683 cout
<< "waiting for scrubs..." << std::endl
;
685 cout
<< "done waiting" << std::endl
;
688 ioctx
.snap_set_read(librados::SNAP_HEAD
);
691 for (unsigned snap
= 0; snap
< my_snaps
.size(); ++snap
) {
692 ioctx
.selfmanaged_snap_remove(my_snaps
[snap
]);
696 TEST_F(LibRadosTwoPoolsPP
, PromoteSnapTrimRace
) {
700 bl
.append("hi there");
701 ObjectWriteOperation op
;
703 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
706 // create a snapshot, clone
707 vector
<uint64_t> my_snaps(1);
708 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
709 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
714 ObjectWriteOperation op
;
716 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
721 ASSERT_EQ(0, cluster
.mon_command(
722 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
723 "\", \"tierpool\": \"" + cache_pool_name
+
724 "\", \"force_nonempty\": \"--force-nonempty\" }",
726 ASSERT_EQ(0, cluster
.mon_command(
727 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
728 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
730 ASSERT_EQ(0, cluster
.mon_command(
731 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
732 "\", \"mode\": \"writeback\"}",
735 // wait for maps to settle
736 cluster
.wait_for_latest_osdmap();
739 ASSERT_EQ(0, ioctx
.selfmanaged_snap_remove(my_snaps
[0]));
741 ioctx
.snap_set_read(my_snaps
[0]);
743 // read foo snap. the OSD may or may not realize that this snap has
744 // been logically deleted; either response is valid.
747 int r
= ioctx
.read("foo", bl
, 1, 0);
748 ASSERT_TRUE(r
== 1 || r
== -ENOENT
);
752 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
755 TEST_F(LibRadosTwoPoolsPP
, Whiteout
) {
759 bl
.append("hi there");
760 ObjectWriteOperation op
;
762 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
767 ASSERT_EQ(0, cluster
.mon_command(
768 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
769 "\", \"tierpool\": \"" + cache_pool_name
+
770 "\", \"force_nonempty\": \"--force-nonempty\" }",
772 ASSERT_EQ(0, cluster
.mon_command(
773 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
774 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
776 ASSERT_EQ(0, cluster
.mon_command(
777 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
778 "\", \"mode\": \"writeback\"}",
781 // wait for maps to settle
782 cluster
.wait_for_latest_osdmap();
784 // create some whiteouts, verify they behave
786 ObjectWriteOperation op
;
789 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
793 ObjectWriteOperation op
;
796 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
799 ObjectWriteOperation op
;
802 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
805 // verify the whiteouts are there in the cache tier
807 NObjectIterator it
= cache_ioctx
.nobjects_begin();
808 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
809 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
811 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
813 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
816 // delete a whiteout and verify it goes away
817 ASSERT_EQ(-ENOENT
, ioctx
.remove("foo"));
819 ObjectWriteOperation op
;
821 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
822 ASSERT_EQ(0, ioctx
.aio_operate("bar", completion
, &op
,
823 librados::OPERATION_IGNORE_CACHE
));
824 completion
->wait_for_complete();
825 ASSERT_EQ(0, completion
->get_return_value());
826 completion
->release();
828 NObjectIterator it
= cache_ioctx
.nobjects_begin();
829 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
830 ASSERT_TRUE(it
->get_oid() == string("foo"));
832 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
835 // recreate an object and verify we can read it
838 bl
.append("hi there");
839 ObjectWriteOperation op
;
841 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
845 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
846 ASSERT_EQ('h', bl
[0]);
850 TEST_F(LibRadosTwoPoolsPP
, WhiteoutDeleteCreate
) {
853 ASSERT_EQ(0, cluster
.mon_command(
854 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
855 "\", \"tierpool\": \"" + cache_pool_name
+
856 "\", \"force_nonempty\": \"--force-nonempty\" }",
858 ASSERT_EQ(0, cluster
.mon_command(
859 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
860 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
862 ASSERT_EQ(0, cluster
.mon_command(
863 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
864 "\", \"mode\": \"writeback\"}",
867 // wait for maps to settle
868 cluster
.wait_for_latest_osdmap();
874 ASSERT_EQ(0, ioctx
.write_full("foo", bl
));
877 // do delete + create operation
879 ObjectWriteOperation op
;
884 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
887 // verify it still "exists" (w/ new content)
890 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
891 ASSERT_EQ('b', bl
[0]);
895 TEST_F(LibRadosTwoPoolsPP
, Evict
) {
899 bl
.append("hi there");
900 ObjectWriteOperation op
;
902 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
907 ASSERT_EQ(0, cluster
.mon_command(
908 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
909 "\", \"tierpool\": \"" + cache_pool_name
+
910 "\", \"force_nonempty\": \"--force-nonempty\" }",
912 ASSERT_EQ(0, cluster
.mon_command(
913 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
914 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
916 ASSERT_EQ(0, cluster
.mon_command(
917 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
918 "\", \"mode\": \"writeback\"}",
921 // wait for maps to settle
922 cluster
.wait_for_latest_osdmap();
924 // read, trigger a promote
927 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
930 // read, trigger a whiteout, and a dirty object
933 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
934 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
935 ASSERT_EQ(0, ioctx
.write("bar", bl
, bl
.length(), 0));
938 // verify the object is present in the cache tier
940 NObjectIterator it
= cache_ioctx
.nobjects_begin();
941 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
942 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
944 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
946 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
951 ObjectWriteOperation op
;
953 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
954 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
955 completion
->wait_for_complete();
956 ASSERT_EQ(0, completion
->get_return_value());
957 completion
->release();
960 // evict the pinned object with -EPERM
962 ObjectReadOperation op
;
964 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
965 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
966 librados::OPERATION_IGNORE_CACHE
,
968 completion
->wait_for_complete();
969 ASSERT_EQ(-EPERM
, completion
->get_return_value());
970 completion
->release();
975 ObjectWriteOperation op
;
977 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
978 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
979 completion
->wait_for_complete();
980 ASSERT_EQ(0, completion
->get_return_value());
981 completion
->release();
986 ObjectReadOperation op
;
988 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
989 ASSERT_EQ(0, cache_ioctx
.aio_operate(
990 "foo", completion
, &op
,
991 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
992 completion
->wait_for_complete();
993 ASSERT_EQ(0, completion
->get_return_value());
994 completion
->release();
1001 ObjectReadOperation op
;
1002 op
.is_dirty(&dirty
, &r
);
1003 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1004 ASSERT_FALSE(dirty
);
1010 ObjectReadOperation op
;
1012 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1013 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
1014 librados::OPERATION_IGNORE_CACHE
,
1016 completion
->wait_for_complete();
1017 ASSERT_EQ(0, completion
->get_return_value());
1018 completion
->release();
1021 ObjectReadOperation op
;
1023 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1024 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1025 "foo", completion
, &op
,
1026 librados::OPERATION_IGNORE_CACHE
, NULL
));
1027 completion
->wait_for_complete();
1028 ASSERT_EQ(0, completion
->get_return_value());
1029 completion
->release();
1032 ObjectReadOperation op
;
1034 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1035 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1036 "bar", completion
, &op
,
1037 librados::OPERATION_IGNORE_CACHE
, NULL
));
1038 completion
->wait_for_complete();
1039 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
1040 completion
->release();
1044 TEST_F(LibRadosTwoPoolsPP
, EvictSnap
) {
1048 bl
.append("hi there");
1049 ObjectWriteOperation op
;
1051 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1055 bl
.append("hi there");
1056 ObjectWriteOperation op
;
1058 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
1062 bl
.append("hi there");
1063 ObjectWriteOperation op
;
1065 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
1069 bl
.append("hi there");
1070 ObjectWriteOperation op
;
1072 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
1075 // create a snapshot, clone
1076 vector
<uint64_t> my_snaps(1);
1077 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1078 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1083 ObjectWriteOperation op
;
1085 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1090 ObjectWriteOperation op
;
1092 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
1095 ObjectWriteOperation op
;
1097 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
1102 ObjectWriteOperation op
;
1104 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
1109 ASSERT_EQ(0, cluster
.mon_command(
1110 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1111 "\", \"tierpool\": \"" + cache_pool_name
+
1112 "\", \"force_nonempty\": \"--force-nonempty\" }",
1114 ASSERT_EQ(0, cluster
.mon_command(
1115 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1116 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1118 ASSERT_EQ(0, cluster
.mon_command(
1119 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1120 "\", \"mode\": \"writeback\"}",
1123 // wait for maps to settle
1124 cluster
.wait_for_latest_osdmap();
1126 // read, trigger a promote on the head
1129 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1130 ASSERT_EQ('c', bl
[0]);
1134 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
1135 ASSERT_EQ('c', bl
[0]);
1140 ObjectReadOperation op
;
1142 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1143 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1144 "bam", completion
, &op
,
1145 librados::OPERATION_IGNORE_CACHE
, NULL
));
1146 completion
->wait_for_complete();
1147 ASSERT_EQ(0, completion
->get_return_value());
1148 completion
->release();
1152 ObjectReadOperation op
;
1153 op
.read(1, 0, &bl
, NULL
);
1154 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1155 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1156 "bam", completion
, &op
,
1157 librados::OPERATION_IGNORE_CACHE
, NULL
));
1158 completion
->wait_for_complete();
1159 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1160 completion
->release();
1164 ioctx
.snap_set_read(my_snaps
[0]);
1167 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1168 ASSERT_EQ('h', bl
[0]);
1173 ObjectReadOperation op
;
1175 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1176 ASSERT_EQ(0, ioctx
.aio_operate(
1177 "foo", completion
, &op
,
1178 librados::OPERATION_IGNORE_CACHE
, NULL
));
1179 completion
->wait_for_complete();
1180 ASSERT_EQ(0, completion
->get_return_value());
1181 completion
->release();
1186 ObjectReadOperation op
;
1187 op
.read(1, 0, &bl
, NULL
);
1188 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1189 ASSERT_EQ(0, ioctx
.aio_operate(
1190 "foo", completion
, &op
,
1191 librados::OPERATION_IGNORE_CACHE
, NULL
));
1192 completion
->wait_for_complete();
1193 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1194 completion
->release();
1196 // head is still there...
1197 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1200 ObjectReadOperation op
;
1201 op
.read(1, 0, &bl
, NULL
);
1202 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1203 ASSERT_EQ(0, ioctx
.aio_operate(
1204 "foo", completion
, &op
,
1205 librados::OPERATION_IGNORE_CACHE
, NULL
));
1206 completion
->wait_for_complete();
1207 ASSERT_EQ(0, completion
->get_return_value());
1208 completion
->release();
1211 // promote head + snap of bar
1212 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1215 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
1216 ASSERT_EQ('c', bl
[0]);
1218 ioctx
.snap_set_read(my_snaps
[0]);
1221 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
1222 ASSERT_EQ('h', bl
[0]);
1225 // evict bar head (fail)
1226 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1228 ObjectReadOperation op
;
1230 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1231 ASSERT_EQ(0, ioctx
.aio_operate(
1232 "bar", completion
, &op
,
1233 librados::OPERATION_IGNORE_CACHE
, NULL
));
1234 completion
->wait_for_complete();
1235 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
1236 completion
->release();
1240 ioctx
.snap_set_read(my_snaps
[0]);
1242 ObjectReadOperation op
;
1244 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1245 ASSERT_EQ(0, ioctx
.aio_operate(
1246 "bar", completion
, &op
,
1247 librados::OPERATION_IGNORE_CACHE
, NULL
));
1248 completion
->wait_for_complete();
1249 ASSERT_EQ(0, completion
->get_return_value());
1250 completion
->release();
1253 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1256 ObjectReadOperation op
;
1257 op
.read(1, 0, &bl
, NULL
);
1258 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1259 ASSERT_EQ(0, ioctx
.aio_operate(
1260 "bar", completion
, &op
,
1261 librados::OPERATION_IGNORE_CACHE
, NULL
));
1262 completion
->wait_for_complete();
1263 ASSERT_EQ(0, completion
->get_return_value());
1264 completion
->release();
1267 ObjectReadOperation op
;
1269 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1270 ASSERT_EQ(0, ioctx
.aio_operate(
1271 "bar", completion
, &op
,
1272 librados::OPERATION_IGNORE_CACHE
, NULL
));
1273 completion
->wait_for_complete();
1274 ASSERT_EQ(0, completion
->get_return_value());
1275 completion
->release();
1279 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
1282 // this test case reproduces http://tracker.ceph.com/issues/8629
1283 TEST_F(LibRadosTwoPoolsPP
, EvictSnap2
) {
1287 bl
.append("hi there");
1288 ObjectWriteOperation op
;
1290 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1292 // create a snapshot, clone
1293 vector
<uint64_t> my_snaps(1);
1294 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1295 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1300 ObjectWriteOperation op
;
1302 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1306 ASSERT_EQ(0, cluster
.mon_command(
1307 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1308 "\", \"tierpool\": \"" + cache_pool_name
+
1309 "\", \"force_nonempty\": \"--force-nonempty\" }",
1311 ASSERT_EQ(0, cluster
.mon_command(
1312 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1313 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1315 ASSERT_EQ(0, cluster
.mon_command(
1316 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1317 "\", \"mode\": \"writeback\"}",
1320 // wait for maps to settle
1321 cluster
.wait_for_latest_osdmap();
1323 // read, trigger a promote on the head
1326 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1327 ASSERT_EQ('c', bl
[0]);
1332 ObjectReadOperation op
;
1334 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1335 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1336 "foo", completion
, &op
,
1337 librados::OPERATION_IGNORE_CACHE
, NULL
));
1338 completion
->wait_for_complete();
1339 ASSERT_EQ(0, completion
->get_return_value());
1340 completion
->release();
1343 // verify the snapdir is not present in the cache pool
1345 ObjectReadOperation op
;
1346 librados::snap_set_t snapset
;
1347 op
.list_snaps(&snapset
, NULL
);
1348 ioctx
.snap_set_read(librados::SNAP_DIR
);
1349 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1350 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
,
1351 librados::OPERATION_IGNORE_CACHE
, NULL
));
1352 completion
->wait_for_complete();
1353 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1354 completion
->release();
1358 //This test case reproduces http://tracker.ceph.com/issues/17445
1359 TEST_F(LibRadosTwoPoolsPP
, ListSnap
){
1363 bl
.append("hi there");
1364 ObjectWriteOperation op
;
1366 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1370 bl
.append("hi there");
1371 ObjectWriteOperation op
;
1373 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
1377 bl
.append("hi there");
1378 ObjectWriteOperation op
;
1380 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
1384 bl
.append("hi there");
1385 ObjectWriteOperation op
;
1387 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
1390 // Create a snapshot, clone
1391 vector
<uint64_t> my_snaps(1);
1392 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1393 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1398 ObjectWriteOperation op
;
1400 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1405 ObjectWriteOperation op
;
1407 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
1410 ObjectWriteOperation op
;
1412 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
1417 ObjectWriteOperation op
;
1419 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
1424 ASSERT_EQ(0, cluster
.mon_command(
1425 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1426 "\", \"tierpool\": \"" + cache_pool_name
+
1427 "\", \"force_nonempty\": \"--force-nonempty\" }",
1429 ASSERT_EQ(0, cluster
.mon_command(
1430 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1431 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1433 ASSERT_EQ(0, cluster
.mon_command(
1434 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1435 "\", \"mode\": \"writeback\"}",
1438 // Wait for maps to settle
1439 cluster
.wait_for_latest_osdmap();
1441 // Read, trigger a promote on the head
1444 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1445 ASSERT_EQ('c', bl
[0]);
1449 ioctx
.snap_set_read(my_snaps
[0]);
1452 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1453 ASSERT_EQ('h', bl
[0]);
1458 ObjectReadOperation op
;
1460 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1461 ASSERT_EQ(0, ioctx
.aio_operate(
1462 "foo", completion
, &op
,
1463 librados::OPERATION_IGNORE_CACHE
, NULL
));
1464 completion
->wait_for_complete();
1465 ASSERT_EQ(0, completion
->get_return_value());
1466 completion
->release();
1471 ObjectReadOperation op
;
1472 op
.read(1, 0, &bl
, NULL
);
1473 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1474 ASSERT_EQ(0, ioctx
.aio_operate(
1475 "foo", completion
, &op
,
1476 librados::OPERATION_IGNORE_CACHE
, NULL
));
1477 completion
->wait_for_complete();
1478 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1479 completion
->release();
1483 ioctx
.snap_set_read(CEPH_SNAPDIR
);
1485 snap_set_t snap_set
;
1487 ObjectReadOperation op
;
1488 op
.list_snaps(&snap_set
, &snap_ret
);
1489 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1490 ASSERT_EQ(0, ioctx
.aio_operate(
1491 "foo", completion
, &op
,
1493 completion
->wait_for_complete();
1494 ASSERT_EQ(0, snap_ret
);
1495 ASSERT_LT(0u, snap_set
.clones
.size());
1496 for (vector
<librados::clone_info_t
>::const_iterator r
= snap_set
.clones
.begin();
1497 r
!= snap_set
.clones
.end();
1499 if (r
->cloneid
!= librados::SNAP_HEAD
) {
1500 ASSERT_LT(0u, r
->snaps
.size());
1506 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
1509 // This test case reproduces https://tracker.ceph.com/issues/49409
1510 TEST_F(LibRadosTwoPoolsPP
, EvictSnapRollbackReadRace
) {
1514 int len
= string("hi there").length() * 2;
1515 // append more chrunk data make sure the second promote
1516 // op coming before the first promote op finished
1517 for (int i
=0; i
<4*1024*1024/len
; ++i
)
1518 bl
.append("hi therehi there");
1519 ObjectWriteOperation op
;
1521 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1524 // create two snapshot, a clone
1525 vector
<uint64_t> my_snaps(2);
1526 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[1]));
1527 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1528 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1533 ObjectWriteOperation op
;
1535 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1540 ASSERT_EQ(0, cluster
.mon_command(
1541 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1542 "\", \"tierpool\": \"" + cache_pool_name
+
1543 "\", \"force_nonempty\": \"--force-nonempty\" }",
1545 ASSERT_EQ(0, cluster
.mon_command(
1546 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1547 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1549 ASSERT_EQ(0, cluster
.mon_command(
1550 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1551 "\", \"mode\": \"writeback\"}",
1554 // wait for maps to settle
1555 cluster
.wait_for_latest_osdmap();
1557 // read, trigger a promote on the head
1560 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1561 ASSERT_EQ('c', bl
[0]);
1566 for (int i
=0; i
<retries
; ++i
)
1569 librados::AioCompletion
* completion
= cluster
.aio_create_completion();
1570 librados::AioCompletion
* completion1
= cluster
.aio_create_completion();
1572 // send a snap rollback op and a snap read op parallel
1573 // trigger two promote(copy) to the same snap clone obj
1574 // the second snap read op is read-ordered make sure
1575 // op not wait for objects_blocked_on_snap_promotion
1576 ObjectWriteOperation op
;
1577 op
.selfmanaged_snap_rollback(my_snaps
[0]);
1578 ASSERT_EQ(0, ioctx
.aio_operate(
1579 "foo", completion
, &op
));
1581 ioctx
.snap_set_read(my_snaps
[1]);
1582 std::map
<uint64_t, uint64_t> extents
;
1585 ObjectReadOperation op1
;
1586 op1
.sparse_read(0, 8, &extents
, &read_bl
, &rval
);
1587 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion1
, &op1
, &read_bl
));
1588 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1590 completion
->wait_for_complete();
1591 ASSERT_EQ(0, completion
->get_return_value());
1592 completion
->release();
1594 completion1
->wait_for_complete();
1595 ASSERT_EQ(0, completion1
->get_return_value());
1596 completion1
->release();
1600 ioctx
.snap_set_read(my_snaps
[0]);
1602 ObjectReadOperation op
;
1604 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1605 ASSERT_EQ(0, ioctx
.aio_operate(
1606 "foo", completion
, &op
,
1607 librados::OPERATION_IGNORE_CACHE
, NULL
));
1608 completion
->wait_for_complete();
1609 ASSERT_EQ(0, completion
->get_return_value());
1610 completion
->release();
1612 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1616 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
1617 ioctx
.selfmanaged_snap_remove(my_snaps
[1]);
1620 TEST_F(LibRadosTwoPoolsPP
, TryFlush
) {
1623 ASSERT_EQ(0, cluster
.mon_command(
1624 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1625 "\", \"tierpool\": \"" + cache_pool_name
+
1626 "\", \"force_nonempty\": \"--force-nonempty\" }",
1628 ASSERT_EQ(0, cluster
.mon_command(
1629 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1630 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1632 ASSERT_EQ(0, cluster
.mon_command(
1633 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1634 "\", \"mode\": \"writeback\"}",
1637 // wait for maps to settle
1638 cluster
.wait_for_latest_osdmap();
1643 bl
.append("hi there");
1644 ObjectWriteOperation op
;
1646 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1649 // verify the object is present in the cache tier
1651 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1652 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
1653 ASSERT_TRUE(it
->get_oid() == string("foo"));
1655 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1658 // verify the object is NOT present in the base tier
1660 NObjectIterator it
= ioctx
.nobjects_begin();
1661 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1668 ObjectReadOperation op
;
1669 op
.is_dirty(&dirty
, &r
);
1670 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1677 ObjectWriteOperation op
;
1679 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1680 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1681 completion
->wait_for_complete();
1682 ASSERT_EQ(0, completion
->get_return_value());
1683 completion
->release();
1686 // flush the pinned object with -EPERM
1688 ObjectReadOperation op
;
1689 op
.cache_try_flush();
1690 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1691 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1692 "foo", completion
, &op
,
1693 librados::OPERATION_IGNORE_OVERLAY
|
1694 librados::OPERATION_SKIPRWLOCKS
, NULL
));
1695 completion
->wait_for_complete();
1696 ASSERT_EQ(-EPERM
, completion
->get_return_value());
1697 completion
->release();
1702 ObjectWriteOperation op
;
1704 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1705 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1706 completion
->wait_for_complete();
1707 ASSERT_EQ(0, completion
->get_return_value());
1708 completion
->release();
1713 ObjectReadOperation op
;
1714 op
.cache_try_flush();
1715 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1716 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1717 "foo", completion
, &op
,
1718 librados::OPERATION_IGNORE_OVERLAY
|
1719 librados::OPERATION_SKIPRWLOCKS
, NULL
));
1720 completion
->wait_for_complete();
1721 ASSERT_EQ(0, completion
->get_return_value());
1722 completion
->release();
1729 ObjectReadOperation op
;
1730 op
.is_dirty(&dirty
, &r
);
1731 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1732 ASSERT_FALSE(dirty
);
1736 // verify in base tier
1738 NObjectIterator it
= ioctx
.nobjects_begin();
1739 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
1740 ASSERT_TRUE(it
->get_oid() == string("foo"));
1742 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1747 ObjectReadOperation op
;
1749 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1750 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1751 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
1752 completion
->wait_for_complete();
1753 ASSERT_EQ(0, completion
->get_return_value());
1754 completion
->release();
1757 // verify no longer in cache tier
1759 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1760 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1764 TEST_F(LibRadosTwoPoolsPP
, Flush
) {
1767 ASSERT_EQ(0, cluster
.mon_command(
1768 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1769 "\", \"tierpool\": \"" + cache_pool_name
+
1770 "\", \"force_nonempty\": \"--force-nonempty\" }",
1772 ASSERT_EQ(0, cluster
.mon_command(
1773 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1774 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1776 ASSERT_EQ(0, cluster
.mon_command(
1777 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1778 "\", \"mode\": \"writeback\"}",
1781 // wait for maps to settle
1782 cluster
.wait_for_latest_osdmap();
1784 uint64_t user_version
= 0;
1789 bl
.append("hi there");
1790 ObjectWriteOperation op
;
1792 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1795 // verify the object is present in the cache tier
1797 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1798 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
1799 ASSERT_TRUE(it
->get_oid() == string("foo"));
1801 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1804 // verify the object is NOT present in the base tier
1806 NObjectIterator it
= ioctx
.nobjects_begin();
1807 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1814 ObjectReadOperation op
;
1815 op
.is_dirty(&dirty
, &r
);
1816 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1819 user_version
= cache_ioctx
.get_last_version();
1824 ObjectWriteOperation op
;
1826 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1827 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1828 completion
->wait_for_complete();
1829 ASSERT_EQ(0, completion
->get_return_value());
1830 completion
->release();
1833 // flush the pinned object with -EPERM
1835 ObjectReadOperation op
;
1836 op
.cache_try_flush();
1837 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1838 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1839 "foo", completion
, &op
,
1840 librados::OPERATION_IGNORE_OVERLAY
|
1841 librados::OPERATION_SKIPRWLOCKS
, NULL
));
1842 completion
->wait_for_complete();
1843 ASSERT_EQ(-EPERM
, completion
->get_return_value());
1844 completion
->release();
1849 ObjectWriteOperation op
;
1851 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1852 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1853 completion
->wait_for_complete();
1854 ASSERT_EQ(0, completion
->get_return_value());
1855 completion
->release();
1860 ObjectReadOperation op
;
1862 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1863 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1864 "foo", completion
, &op
,
1865 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
1866 completion
->wait_for_complete();
1867 ASSERT_EQ(0, completion
->get_return_value());
1868 completion
->release();
1875 ObjectReadOperation op
;
1876 op
.is_dirty(&dirty
, &r
);
1877 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1878 ASSERT_FALSE(dirty
);
1882 // verify in base tier
1884 NObjectIterator it
= ioctx
.nobjects_begin();
1885 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
1886 ASSERT_TRUE(it
->get_oid() == string("foo"));
1888 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1893 ObjectReadOperation op
;
1895 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1896 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1897 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
1898 completion
->wait_for_complete();
1899 ASSERT_EQ(0, completion
->get_return_value());
1900 completion
->release();
1903 // verify no longer in cache tier
1905 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1906 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1909 // read it again and verify the version is consistent
1912 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
1913 ASSERT_EQ(user_version
, cache_ioctx
.get_last_version());
1918 ObjectWriteOperation op
;
1920 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1925 ObjectReadOperation op
;
1927 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1928 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1929 "foo", completion
, &op
,
1930 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
1931 completion
->wait_for_complete();
1932 ASSERT_EQ(0, completion
->get_return_value());
1933 completion
->release();
1938 ObjectReadOperation op
;
1940 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1941 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1942 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
1943 completion
->wait_for_complete();
1944 ASSERT_EQ(0, completion
->get_return_value());
1945 completion
->release();
1948 // verify no longer in cache tier
1950 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1951 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1955 NObjectIterator it
= ioctx
.nobjects_begin();
1956 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1960 TEST_F(LibRadosTwoPoolsPP
, FlushSnap
) {
1963 ASSERT_EQ(0, cluster
.mon_command(
1964 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1965 "\", \"tierpool\": \"" + cache_pool_name
+
1966 "\", \"force_nonempty\": \"--force-nonempty\" }",
1968 ASSERT_EQ(0, cluster
.mon_command(
1969 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1970 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1972 ASSERT_EQ(0, cluster
.mon_command(
1973 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1974 "\", \"mode\": \"writeback\"}",
1977 // wait for maps to settle
1978 cluster
.wait_for_latest_osdmap();
1984 ObjectWriteOperation op
;
1986 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1989 // create a snapshot, clone
1990 vector
<uint64_t> my_snaps(1);
1991 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1992 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1997 ObjectWriteOperation op
;
1999 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2004 my_snaps
[1] = my_snaps
[0];
2005 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
2006 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
2011 ObjectWriteOperation op
;
2013 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2016 // verify the object is present in the cache tier
2018 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2019 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
2020 ASSERT_TRUE(it
->get_oid() == string("foo"));
2022 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
2025 // verify the object is NOT present in the base tier
2027 NObjectIterator it
= ioctx
.nobjects_begin();
2028 ASSERT_TRUE(it
== ioctx
.nobjects_end());
2031 // flush on head (should fail)
2032 ioctx
.snap_set_read(librados::SNAP_HEAD
);
2034 ObjectReadOperation op
;
2036 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2037 ASSERT_EQ(0, ioctx
.aio_operate(
2038 "foo", completion
, &op
,
2039 librados::OPERATION_IGNORE_CACHE
, NULL
));
2040 completion
->wait_for_complete();
2041 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
2042 completion
->release();
2044 // flush on recent snap (should fail)
2045 ioctx
.snap_set_read(my_snaps
[0]);
2047 ObjectReadOperation op
;
2049 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2050 ASSERT_EQ(0, ioctx
.aio_operate(
2051 "foo", completion
, &op
,
2052 librados::OPERATION_IGNORE_CACHE
, NULL
));
2053 completion
->wait_for_complete();
2054 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
2055 completion
->release();
2057 // flush on oldest snap
2058 ioctx
.snap_set_read(my_snaps
[1]);
2060 ObjectReadOperation op
;
2062 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2063 ASSERT_EQ(0, ioctx
.aio_operate(
2064 "foo", completion
, &op
,
2065 librados::OPERATION_IGNORE_CACHE
, NULL
));
2066 completion
->wait_for_complete();
2067 ASSERT_EQ(0, completion
->get_return_value());
2068 completion
->release();
2070 // flush on next oldest snap
2071 ioctx
.snap_set_read(my_snaps
[0]);
2073 ObjectReadOperation op
;
2075 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2076 ASSERT_EQ(0, ioctx
.aio_operate(
2077 "foo", completion
, &op
,
2078 librados::OPERATION_IGNORE_CACHE
, NULL
));
2079 completion
->wait_for_complete();
2080 ASSERT_EQ(0, completion
->get_return_value());
2081 completion
->release();
2084 ioctx
.snap_set_read(librados::SNAP_HEAD
);
2086 ObjectReadOperation op
;
2088 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2089 ASSERT_EQ(0, ioctx
.aio_operate(
2090 "foo", completion
, &op
,
2091 librados::OPERATION_IGNORE_CACHE
, NULL
));
2092 completion
->wait_for_complete();
2093 ASSERT_EQ(0, completion
->get_return_value());
2094 completion
->release();
2097 // verify i can read the snaps from the cache pool
2098 ioctx
.snap_set_read(librados::SNAP_HEAD
);
2101 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2102 ASSERT_EQ('c', bl
[0]);
2104 ioctx
.snap_set_read(my_snaps
[0]);
2107 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2108 ASSERT_EQ('b', bl
[0]);
2110 ioctx
.snap_set_read(my_snaps
[1]);
2113 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2114 ASSERT_EQ('a', bl
[0]);
2118 ASSERT_EQ(0, cluster
.mon_command(
2119 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
2123 // wait for maps to settle
2124 cluster
.wait_for_latest_osdmap();
2126 // verify i can read the snaps from the base pool
2127 ioctx
.snap_set_read(librados::SNAP_HEAD
);
2130 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2131 ASSERT_EQ('c', bl
[0]);
2133 ioctx
.snap_set_read(my_snaps
[0]);
2136 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2137 ASSERT_EQ('b', bl
[0]);
2139 ioctx
.snap_set_read(my_snaps
[1]);
2142 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2143 ASSERT_EQ('a', bl
[0]);
2146 ASSERT_EQ(0, cluster
.mon_command(
2147 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2148 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2152 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
2155 TEST_F(LibRadosTierPP
, FlushWriteRaces
) {
2157 std::string pool_name
= get_temp_pool_name();
2158 std::string cache_pool_name
= pool_name
+ "-cache";
2159 ASSERT_EQ("", create_one_pool_pp(pool_name
, cluster
));
2160 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
2162 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
2163 cache_ioctx
.application_enable("rados", true);
2165 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
2169 ASSERT_EQ(0, cluster
.mon_command(
2170 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2171 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2173 ASSERT_EQ(0, cluster
.mon_command(
2174 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2175 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2177 ASSERT_EQ(0, cluster
.mon_command(
2178 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2179 "\", \"mode\": \"writeback\"}",
2182 // wait for maps to settle
2183 cluster
.wait_for_latest_osdmap();
2185 // create/dirty object
2187 bl
.append("hi there");
2189 ObjectWriteOperation op
;
2191 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2196 ObjectReadOperation op
;
2198 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2199 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2200 "foo", completion
, &op
,
2201 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2203 ObjectWriteOperation op2
;
2205 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2206 ASSERT_EQ(0, ioctx
.aio_operate(
2207 "foo", completion2
, &op2
, 0));
2209 completion
->wait_for_complete();
2210 completion2
->wait_for_complete();
2211 ASSERT_EQ(0, completion
->get_return_value());
2212 ASSERT_EQ(0, completion2
->get_return_value());
2213 completion
->release();
2214 completion2
->release();
2219 // create/dirty object
2222 bl
.append("hi there");
2223 ObjectWriteOperation op
;
2225 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2228 // try-flush + write
2230 ObjectReadOperation op
;
2231 op
.cache_try_flush();
2232 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2233 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2234 "foo", completion
, &op
,
2235 librados::OPERATION_IGNORE_OVERLAY
|
2236 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2238 ObjectWriteOperation op2
;
2240 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2241 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion2
, &op2
, 0));
2243 completion
->wait_for_complete();
2244 completion2
->wait_for_complete();
2245 int r
= completion
->get_return_value();
2246 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
2247 ASSERT_EQ(0, completion2
->get_return_value());
2248 completion
->release();
2249 completion2
->release();
2252 cout
<< "didn't get EBUSY, trying again" << std::endl
;
2254 ASSERT_TRUE(--tries
);
2258 ASSERT_EQ(0, cluster
.mon_command(
2259 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
2262 ASSERT_EQ(0, cluster
.mon_command(
2263 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
2264 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2267 // wait for maps to settle before next test
2268 cluster
.wait_for_latest_osdmap();
2270 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
2271 ASSERT_EQ(0, destroy_one_pool_pp(pool_name
, cluster
));
2274 TEST_F(LibRadosTwoPoolsPP
, FlushTryFlushRaces
) {
2277 ASSERT_EQ(0, cluster
.mon_command(
2278 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2279 "\", \"tierpool\": \"" + cache_pool_name
+
2280 "\", \"force_nonempty\": \"--force-nonempty\" }",
2282 ASSERT_EQ(0, cluster
.mon_command(
2283 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2284 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2286 ASSERT_EQ(0, cluster
.mon_command(
2287 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2288 "\", \"mode\": \"writeback\"}",
2291 // wait for maps to settle
2292 cluster
.wait_for_latest_osdmap();
2294 // create/dirty object
2297 bl
.append("hi there");
2298 ObjectWriteOperation op
;
2300 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2305 ObjectReadOperation op
;
2307 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2308 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2309 "foo", completion
, &op
,
2310 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2312 ObjectReadOperation op2
;
2314 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2315 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2316 "foo", completion2
, &op2
,
2317 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2319 completion
->wait_for_complete();
2320 completion2
->wait_for_complete();
2321 ASSERT_EQ(0, completion
->get_return_value());
2322 ASSERT_EQ(0, completion2
->get_return_value());
2323 completion
->release();
2324 completion2
->release();
2327 // create/dirty object
2330 bl
.append("hi there");
2331 ObjectWriteOperation op
;
2333 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2336 // flush + try-flush
2338 ObjectReadOperation op
;
2340 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2341 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2342 "foo", completion
, &op
,
2343 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2345 ObjectReadOperation op2
;
2346 op2
.cache_try_flush();
2347 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2348 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2349 "foo", completion2
, &op2
,
2350 librados::OPERATION_IGNORE_OVERLAY
|
2351 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2353 completion
->wait_for_complete();
2354 completion2
->wait_for_complete();
2355 ASSERT_EQ(0, completion
->get_return_value());
2356 ASSERT_EQ(0, completion2
->get_return_value());
2357 completion
->release();
2358 completion2
->release();
2361 // create/dirty object
2366 bl
.append("hi there");
2367 ObjectWriteOperation op
;
2369 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2372 // try-flush + flush
2373 // (flush will not piggyback on try-flush)
2375 ObjectReadOperation op
;
2376 op
.cache_try_flush();
2377 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2378 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2379 "foo", completion
, &op
,
2380 librados::OPERATION_IGNORE_OVERLAY
|
2381 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2383 ObjectReadOperation op2
;
2385 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2386 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2387 "foo", completion2
, &op2
,
2388 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2390 completion
->wait_for_complete();
2391 completion2
->wait_for_complete();
2392 int r
= completion
->get_return_value();
2393 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
2394 ASSERT_EQ(0, completion2
->get_return_value());
2395 completion
->release();
2396 completion2
->release();
2399 cout
<< "didn't get EBUSY, trying again" << std::endl
;
2401 ASSERT_TRUE(--tries
);
2404 // create/dirty object
2407 bl
.append("hi there");
2408 ObjectWriteOperation op
;
2410 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2413 // try-flush + try-flush
2415 ObjectReadOperation op
;
2416 op
.cache_try_flush();
2417 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2418 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2419 "foo", completion
, &op
,
2420 librados::OPERATION_IGNORE_OVERLAY
|
2421 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2423 ObjectReadOperation op2
;
2424 op2
.cache_try_flush();
2425 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2426 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2427 "foo", completion2
, &op2
,
2428 librados::OPERATION_IGNORE_OVERLAY
|
2429 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2431 completion
->wait_for_complete();
2432 completion2
->wait_for_complete();
2433 ASSERT_EQ(0, completion
->get_return_value());
2434 ASSERT_EQ(0, completion2
->get_return_value());
2435 completion
->release();
2436 completion2
->release();
2441 IoCtx
*read_ioctx
= 0;
2442 ceph::mutex test_lock
= ceph::make_mutex("FlushReadRaces::lock");
2443 ceph::condition_variable cond
;
2444 int max_reads
= 100;
2445 int num_reads
= 0; // in progress
2447 void flush_read_race_cb(completion_t cb
, void *arg
);
2449 void start_flush_read()
2451 //cout << " starting read" << std::endl;
2452 ObjectReadOperation op
;
2453 op
.stat(NULL
, NULL
, NULL
);
2454 librados::AioCompletion
*completion
= completions
.getCompletion();
2455 completion
->set_complete_callback(0, flush_read_race_cb
);
2456 read_ioctx
->aio_operate("foo", completion
, &op
, NULL
);
2459 void flush_read_race_cb(completion_t cb
, void *arg
)
2461 //cout << " finished read" << std::endl;
2462 std::lock_guard l
{test_lock
};
2463 if (num_reads
> max_reads
) {
2471 TEST_F(LibRadosTwoPoolsPP
, TryFlushReadRace
) {
2474 ASSERT_EQ(0, cluster
.mon_command(
2475 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2476 "\", \"tierpool\": \"" + cache_pool_name
+
2477 "\", \"force_nonempty\": \"--force-nonempty\" }",
2479 ASSERT_EQ(0, cluster
.mon_command(
2480 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2481 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2483 ASSERT_EQ(0, cluster
.mon_command(
2484 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2485 "\", \"mode\": \"writeback\"}",
2488 // wait for maps to settle
2489 cluster
.wait_for_latest_osdmap();
2491 // create/dirty object
2494 bl
.append("hi there");
2495 bufferptr
bp(4000000); // make it big!
2498 ObjectWriteOperation op
;
2500 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2503 // start a continuous stream of reads
2504 read_ioctx
= &ioctx
;
2506 for (int i
= 0; i
< max_reads
; ++i
) {
2513 ObjectReadOperation op
;
2514 op
.cache_try_flush();
2515 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2516 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2517 "foo", completion
, &op
,
2518 librados::OPERATION_IGNORE_OVERLAY
|
2519 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2521 completion
->wait_for_complete();
2522 ASSERT_EQ(0, completion
->get_return_value());
2523 completion
->release();
2526 std::unique_lock locker
{test_lock
};
2528 cond
.wait(locker
, [] { return num_reads
== 0;});
2531 TEST_F(LibRadosTierPP
, HitSetNone
) {
2533 list
< pair
<time_t,time_t> > ls
;
2534 AioCompletion
*c
= librados::Rados::aio_create_completion();
2535 ASSERT_EQ(0, ioctx
.hit_set_list(123, c
, &ls
));
2536 c
->wait_for_complete();
2537 ASSERT_EQ(0, c
->get_return_value());
2538 ASSERT_TRUE(ls
.empty());
2543 AioCompletion
*c
= librados::Rados::aio_create_completion();
2544 ASSERT_EQ(0, ioctx
.hit_set_get(123, c
, 12345, &bl
));
2545 c
->wait_for_complete();
2546 ASSERT_EQ(-ENOENT
, c
->get_return_value());
2551 string
set_pool_str(string pool
, string var
, string val
)
2553 return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
2554 + string("\",\"var\": \"") + var
+ string("\",\"val\": \"")
2555 + val
+ string("\"}");
2558 string
set_pool_str(string pool
, string var
, int val
)
2560 return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
2561 + string("\",\"var\": \"") + var
+ string("\",\"val\": \"")
2562 + stringify(val
) + string("\"}");
2565 TEST_F(LibRadosTwoPoolsPP
, HitSetRead
) {
2568 ASSERT_EQ(0, cluster
.mon_command(
2569 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2570 "\", \"tierpool\": \"" + cache_pool_name
+
2571 "\", \"force_nonempty\": \"--force-nonempty\" }",
2574 // enable hitset tracking for this pool
2575 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", 2),
2577 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", 600),
2579 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type",
2583 // wait for maps to settle
2584 cluster
.wait_for_latest_osdmap();
2586 cache_ioctx
.set_namespace("");
2588 // keep reading until we see our object appear in the HitSet
2589 utime_t start
= ceph_clock_now();
2590 utime_t hard_stop
= start
+ utime_t(600, 0);
2593 utime_t now
= ceph_clock_now();
2594 ASSERT_TRUE(now
< hard_stop
);
2596 string name
= "foo";
2598 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
2599 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
,
2600 cluster
.pool_lookup(cache_pool_name
.c_str()), "");
2603 ASSERT_EQ(-ENOENT
, cache_ioctx
.read("foo", bl
, 1, 0));
2606 AioCompletion
*c
= librados::Rados::aio_create_completion();
2607 ASSERT_EQ(0, cache_ioctx
.hit_set_get(hash
, c
, now
.sec(), &hbl
));
2608 c
->wait_for_complete();
2612 auto p
= hbl
.cbegin();
2615 if (hs
.contains(oid
)) {
2616 cout
<< "ok, hit_set contains " << oid
<< std::endl
;
2619 cout
<< "hmm, not in HitSet yet" << std::endl
;
2621 cout
<< "hmm, no HitSet yet" << std::endl
;
2628 static int _get_pg_num(Rados
& cluster
, string pool_name
)
2631 string cmd
= string("{\"prefix\": \"osd pool get\",\"pool\":\"")
2633 + string("\",\"var\": \"pg_num\",\"format\": \"json\"}");
2635 int r
= cluster
.mon_command(cmd
, inbl
, &outbl
, NULL
);
2636 ceph_assert(r
>= 0);
2637 string
outstr(outbl
.c_str(), outbl
.length());
2638 json_spirit::Value v
;
2639 if (!json_spirit::read(outstr
, v
)) {
2640 cerr
<<" unable to parse json " << outstr
<< std::endl
;
2644 json_spirit::Object
& o
= v
.get_obj();
2645 for (json_spirit::Object::size_type i
=0; i
<o
.size(); i
++) {
2646 json_spirit::Pair
& p
= o
[i
];
2647 if (p
.name_
== "pg_num") {
2648 cout
<< "pg_num = " << p
.value_
.get_int() << std::endl
;
2649 return p
.value_
.get_int();
2652 cerr
<< "didn't find pg_num in " << outstr
<< std::endl
;
2656 int make_hitset(Rados
& cluster
, librados::IoCtx
& cache_ioctx
, int num_pg
,
2657 int num
, std::map
<int, HitSet
>& hitsets
, std::string
& cache_pool_name
)
2660 // do a bunch of writes
2661 for (int i
=0; i
<num
; ++i
) {
2664 ceph_assert(0 == cache_ioctx
.write(stringify(i
), bl
, 1, 0));
2668 for (int i
=0; i
<pg
; ++i
) {
2669 list
< pair
<time_t,time_t> > ls
;
2670 AioCompletion
*c
= librados::Rados::aio_create_completion();
2671 ceph_assert(0 == cache_ioctx
.hit_set_list(i
, c
, &ls
));
2672 c
->wait_for_complete();
2674 std::cout
<< "pg " << i
<< " ls " << ls
<< std::endl
;
2675 ceph_assert(!ls
.empty());
2678 c
= librados::Rados::aio_create_completion();
2680 ceph_assert(0 == cache_ioctx
.hit_set_get(i
, c
, ls
.back().first
, &bl
));
2681 c
->wait_for_complete();
2685 auto p
= bl
.cbegin();
2686 decode(hitsets
[i
], p
);
2688 catch (buffer::error
& e
) {
2689 std::cout
<< "failed to decode hit set; bl len is " << bl
.length() << "\n";
2690 bl
.hexdump(std::cout
);
2691 std::cout
<< std::endl
;
2695 // cope with racing splits by refreshing pg_num
2697 pg
= _get_pg_num(cluster
, cache_pool_name
);
2702 TEST_F(LibRadosTwoPoolsPP
, HitSetWrite
) {
2703 int num_pg
= _get_pg_num(cluster
, pool_name
);
2704 ceph_assert(num_pg
> 0);
2708 ASSERT_EQ(0, cluster
.mon_command(
2709 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2710 "\", \"tierpool\": \"" + cache_pool_name
+
2711 "\", \"force_nonempty\": \"--force-nonempty\" }",
2714 // enable hitset tracking for this pool
2715 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", 8),
2717 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", 600),
2719 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type",
2723 // wait for maps to settle
2724 cluster
.wait_for_latest_osdmap();
2726 cache_ioctx
.set_namespace("");
2730 std::map
<int,HitSet
> hitsets
;
2732 num_pg
= make_hitset(cluster
, cache_ioctx
, num_pg
, num
, hitsets
, cache_pool_name
);
2736 for (int i
=0; i
<num
; ++i
) {
2737 string n
= stringify(i
);
2739 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(n
, &hash
));
2740 hobject_t
oid(sobject_t(n
, CEPH_NOSNAP
), "", hash
,
2741 cluster
.pool_lookup(cache_pool_name
.c_str()), "");
2742 std::cout
<< "checking for " << oid
<< std::endl
;
2744 for (int p
=0; p
<num_pg
; ++p
) {
2745 if (hitsets
[p
].contains(oid
)) {
2750 if (!found
&& retry
< 5) {
2751 num_pg
= make_hitset(cluster
, cache_ioctx
, num_pg
, num
, hitsets
, cache_pool_name
);
2760 TEST_F(LibRadosTwoPoolsPP
, HitSetTrim
) {
2762 unsigned period
= 3;
2766 ASSERT_EQ(0, cluster
.mon_command(
2767 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2768 "\", \"tierpool\": \"" + cache_pool_name
+
2769 "\", \"force_nonempty\": \"--force-nonempty\" }",
2772 // enable hitset tracking for this pool
2773 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", count
),
2775 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", period
),
2777 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
2779 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_fpp", ".01"),
2782 // wait for maps to settle
2783 cluster
.wait_for_latest_osdmap();
2785 cache_ioctx
.set_namespace("");
2787 // do a bunch of writes and make sure the hitsets rotate
2788 utime_t start
= ceph_clock_now();
2789 utime_t hard_stop
= start
+ utime_t(count
* period
* 50, 0);
2793 string name
= "foo";
2795 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
2796 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
, -1, "");
2800 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, 1, 0));
2802 list
<pair
<time_t, time_t> > ls
;
2803 AioCompletion
*c
= librados::Rados::aio_create_completion();
2804 ASSERT_EQ(0, cache_ioctx
.hit_set_list(hash
, c
, &ls
));
2805 c
->wait_for_complete();
2808 cout
<< " got ls " << ls
<< std::endl
;
2811 first
= ls
.front().first
;
2812 cout
<< "first is " << first
<< std::endl
;
2814 if (ls
.front().first
!= first
) {
2815 cout
<< "first now " << ls
.front().first
<< ", trimmed" << std::endl
;
2821 utime_t now
= ceph_clock_now();
2822 ASSERT_TRUE(now
< hard_stop
);
2828 TEST_F(LibRadosTwoPoolsPP
, PromoteOn2ndRead
) {
2830 for (int i
=0; i
<20; ++i
) {
2832 bl
.append("hi there");
2833 ObjectWriteOperation op
;
2835 ASSERT_EQ(0, ioctx
.operate("foo" + stringify(i
), &op
));
2840 ASSERT_EQ(0, cluster
.mon_command(
2841 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2842 "\", \"tierpool\": \"" + cache_pool_name
+
2843 "\", \"force_nonempty\": \"--force-nonempty\" }",
2845 ASSERT_EQ(0, cluster
.mon_command(
2846 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2847 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2849 ASSERT_EQ(0, cluster
.mon_command(
2850 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2851 "\", \"mode\": \"writeback\"}",
2854 // enable hitset tracking for this pool
2855 ASSERT_EQ(0, cluster
.mon_command(
2856 set_pool_str(cache_pool_name
, "hit_set_count", 2),
2858 ASSERT_EQ(0, cluster
.mon_command(
2859 set_pool_str(cache_pool_name
, "hit_set_period", 600),
2861 ASSERT_EQ(0, cluster
.mon_command(
2862 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
2864 ASSERT_EQ(0, cluster
.mon_command(
2865 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
2867 ASSERT_EQ(0, cluster
.mon_command(
2868 set_pool_str(cache_pool_name
, "hit_set_grade_decay_rate", 20),
2870 ASSERT_EQ(0, cluster
.mon_command(
2871 set_pool_str(cache_pool_name
, "hit_set_search_last_n", 1),
2874 // wait for maps to settle
2875 cluster
.wait_for_latest_osdmap();
2877 int fake
= 0; // set this to non-zero to test spurious promotion,
2878 // e.g. from thrashing
2882 // 1st read, don't trigger a promote
2883 obj
= "foo" + stringify(attempt
);
2884 cout
<< obj
<< std::endl
;
2887 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
2890 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
2895 // verify the object is NOT present in the cache tier
2898 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2899 while (it
!= cache_ioctx
.nobjects_end()) {
2900 cout
<< " see " << it
->get_oid() << std::endl
;
2901 if (it
->get_oid() == string(obj
.c_str())) {
2912 ASSERT_LE(attempt
, 20);
2913 cout
<< "hrm, object is present in cache on attempt " << attempt
2914 << ", retrying" << std::endl
;
2917 // Read until the object is present in the cache tier
2918 cout
<< "verifying " << obj
<< " is eventually promoted" << std::endl
;
2921 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
2924 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2925 while (it
!= cache_ioctx
.nobjects_end()) {
2926 if (it
->get_oid() == string(obj
.c_str())) {
2939 ASSERT_EQ(0, cluster
.mon_command(
2940 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
2943 ASSERT_EQ(0, cluster
.mon_command(
2944 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
2945 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2948 // wait for maps to settle before next test
2949 cluster
.wait_for_latest_osdmap();
2952 TEST_F(LibRadosTwoPoolsPP
, ProxyRead
) {
2956 bl
.append("hi there");
2957 ObjectWriteOperation op
;
2959 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2964 ASSERT_EQ(0, cluster
.mon_command(
2965 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2966 "\", \"tierpool\": \"" + cache_pool_name
+
2967 "\", \"force_nonempty\": \"--force-nonempty\" }",
2969 ASSERT_EQ(0, cluster
.mon_command(
2970 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2971 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2973 ASSERT_EQ(0, cluster
.mon_command(
2974 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2975 "\", \"mode\": \"readproxy\"}",
2978 // wait for maps to settle
2979 cluster
.wait_for_latest_osdmap();
2981 // read and verify the object
2984 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2985 ASSERT_EQ('h', bl
[0]);
2988 // Verify 10 times the object is NOT present in the cache tier
2991 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2992 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
2997 ASSERT_EQ(0, cluster
.mon_command(
2998 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
3001 ASSERT_EQ(0, cluster
.mon_command(
3002 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
3003 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
3006 // wait for maps to settle before next test
3007 cluster
.wait_for_latest_osdmap();
3010 TEST_F(LibRadosTwoPoolsPP
, CachePin
) {
3014 bl
.append("hi there");
3015 ObjectWriteOperation op
;
3017 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3021 bl
.append("hi there");
3022 ObjectWriteOperation op
;
3024 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
3028 bl
.append("hi there");
3029 ObjectWriteOperation op
;
3031 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
3035 bl
.append("hi there");
3036 ObjectWriteOperation op
;
3038 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
3043 ASSERT_EQ(0, cluster
.mon_command(
3044 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
3045 "\", \"tierpool\": \"" + cache_pool_name
+
3046 "\", \"force_nonempty\": \"--force-nonempty\" }",
3048 ASSERT_EQ(0, cluster
.mon_command(
3049 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
3050 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
3052 ASSERT_EQ(0, cluster
.mon_command(
3053 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
3054 "\", \"mode\": \"writeback\"}",
3057 // wait for maps to settle
3058 cluster
.wait_for_latest_osdmap();
3060 // read, trigger promote
3063 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3064 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
3065 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
3066 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
3069 // verify the objects are present in the cache tier
3071 NObjectIterator it
= cache_ioctx
.nobjects_begin();
3072 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
3073 for (uint32_t i
= 0; i
< 4; i
++) {
3074 ASSERT_TRUE(it
->get_oid() == string("foo") ||
3075 it
->get_oid() == string("bar") ||
3076 it
->get_oid() == string("baz") ||
3077 it
->get_oid() == string("bam"));
3080 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
3085 ObjectWriteOperation op
;
3087 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3088 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
3089 completion
->wait_for_complete();
3090 ASSERT_EQ(0, completion
->get_return_value());
3091 completion
->release();
3094 ObjectWriteOperation op
;
3096 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3097 ASSERT_EQ(0, cache_ioctx
.aio_operate("baz", completion
, &op
));
3098 completion
->wait_for_complete();
3099 ASSERT_EQ(0, completion
->get_return_value());
3100 completion
->release();
3104 ASSERT_EQ(0, cluster
.mon_command(
3105 set_pool_str(cache_pool_name
, "hit_set_count", 2),
3107 ASSERT_EQ(0, cluster
.mon_command(
3108 set_pool_str(cache_pool_name
, "hit_set_period", 600),
3110 ASSERT_EQ(0, cluster
.mon_command(
3111 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
3113 ASSERT_EQ(0, cluster
.mon_command(
3114 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
3116 ASSERT_EQ(0, cluster
.mon_command(
3117 set_pool_str(cache_pool_name
, "target_max_objects", 1),
3122 // Verify the pinned object 'foo' is not flushed/evicted
3126 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
3129 NObjectIterator it
= cache_ioctx
.nobjects_begin();
3130 while (it
!= cache_ioctx
.nobjects_end()) {
3131 ASSERT_TRUE(it
->get_oid() == string("foo") ||
3132 it
->get_oid() == string("bar") ||
3133 it
->get_oid() == string("baz") ||
3134 it
->get_oid() == string("bam"));
3139 ASSERT_TRUE(it
->get_oid() == string("foo") ||
3140 it
->get_oid() == string("baz"));
3148 ASSERT_EQ(0, cluster
.mon_command(
3149 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
3152 ASSERT_EQ(0, cluster
.mon_command(
3153 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
3154 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
3157 // wait for maps to settle before next test
3158 cluster
.wait_for_latest_osdmap();
3161 TEST_F(LibRadosTwoPoolsPP
, SetRedirectRead
) {
3165 bl
.append("hi there");
3166 ObjectWriteOperation op
;
3168 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3173 ObjectWriteOperation op
;
3175 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3178 // wait for maps to settle
3179 cluster
.wait_for_latest_osdmap();
3182 ObjectWriteOperation op
;
3183 op
.set_redirect("bar", cache_ioctx
, 0);
3184 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3185 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3186 completion
->wait_for_complete();
3187 ASSERT_EQ(0, completion
->get_return_value());
3188 completion
->release();
3190 // read and verify the object
3193 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3194 ASSERT_EQ('t', bl
[0]);
3197 // wait for maps to settle before next test
3198 cluster
.wait_for_latest_osdmap();
3201 TEST_F(LibRadosTwoPoolsPP
, ManifestPromoteRead
) {
3202 // skip test if not yet mimic
3203 if (_get_required_osd_release(cluster
) < "mimic") {
3204 GTEST_SKIP() << "cluster is not yet mimic, skipping test";
3210 bl
.append("hi there");
3211 ObjectWriteOperation op
;
3213 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3217 bl
.append("base chunk");
3218 ObjectWriteOperation op
;
3220 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3225 ObjectWriteOperation op
;
3227 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3232 ObjectWriteOperation op
;
3234 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3237 // wait for maps to settle
3238 cluster
.wait_for_latest_osdmap();
3242 ObjectWriteOperation op
;
3243 op
.set_redirect("bar", cache_ioctx
, 0);
3244 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3245 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3246 completion
->wait_for_complete();
3247 ASSERT_EQ(0, completion
->get_return_value());
3248 completion
->release();
3251 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 2, "bar-chunk", "foo-chunk");
3255 ObjectWriteOperation op
;
3257 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3258 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3259 completion
->wait_for_complete();
3260 ASSERT_EQ(0, completion
->get_return_value());
3261 completion
->release();
3263 // read and verify the object (redirect)
3266 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3267 ASSERT_EQ('t', bl
[0]);
3271 ObjectWriteOperation op
;
3273 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3274 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3275 completion
->wait_for_complete();
3276 ASSERT_EQ(0, completion
->get_return_value());
3277 completion
->release();
3279 // read and verify the object
3282 ASSERT_EQ(1, ioctx
.read("foo-chunk", bl
, 1, 0));
3283 ASSERT_EQ('C', bl
[0]);
3286 // wait for maps to settle before next test
3287 cluster
.wait_for_latest_osdmap();
3290 TEST_F(LibRadosTwoPoolsPP
, ManifestRefRead
) {
3291 // note: require >= mimic
3296 bl
.append("hi there");
3297 ObjectWriteOperation op
;
3299 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3303 bl
.append("base chunk");
3304 ObjectWriteOperation op
;
3306 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3311 ObjectWriteOperation op
;
3313 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3318 ObjectWriteOperation op
;
3320 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3323 // wait for maps to settle
3324 cluster
.wait_for_latest_osdmap();
3328 ObjectWriteOperation op
;
3329 op
.set_redirect("bar", cache_ioctx
, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3330 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3331 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3332 completion
->wait_for_complete();
3333 ASSERT_EQ(0, completion
->get_return_value());
3334 completion
->release();
3338 ObjectReadOperation op
;
3339 op
.set_chunk(0, 2, cache_ioctx
, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3340 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3341 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
,
3342 librados::OPERATION_IGNORE_CACHE
, NULL
));
3343 completion
->wait_for_complete();
3344 ASSERT_EQ(0, completion
->get_return_value());
3345 completion
->release();
3347 // redirect's refcount
3350 cache_ioctx
.getxattr("bar", CHUNK_REFCOUNT_ATTR
, t
);
3353 auto iter
= t
.cbegin();
3355 } catch (buffer::error
& err
) {
3358 ASSERT_EQ(1U, refs
.count());
3363 cache_ioctx
.getxattr("bar-chunk", CHUNK_REFCOUNT_ATTR
, t
);
3366 auto iter
= t
.cbegin();
3368 } catch (buffer::error
& err
) {
3371 ASSERT_EQ(1u, refs
.count());
3374 // wait for maps to settle before next test
3375 cluster
.wait_for_latest_osdmap();
3378 TEST_F(LibRadosTwoPoolsPP
, ManifestUnset
) {
3379 // skip test if not yet nautilus
3380 if (_get_required_osd_release(cluster
) < "nautilus") {
3381 GTEST_SKIP() << "cluster is not yet nautilus, skipping test";
3387 bl
.append("hi there");
3388 ObjectWriteOperation op
;
3390 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3394 bl
.append("base chunk");
3395 ObjectWriteOperation op
;
3397 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3402 ObjectWriteOperation op
;
3404 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3409 ObjectWriteOperation op
;
3411 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3414 // wait for maps to settle
3415 cluster
.wait_for_latest_osdmap();
3419 ObjectWriteOperation op
;
3420 op
.set_redirect("bar", cache_ioctx
, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3421 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3422 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3423 completion
->wait_for_complete();
3424 ASSERT_EQ(0, completion
->get_return_value());
3425 completion
->release();
3429 ObjectReadOperation op
;
3430 op
.set_chunk(0, 2, cache_ioctx
, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3431 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3432 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
,
3433 librados::OPERATION_IGNORE_CACHE
, NULL
));
3434 completion
->wait_for_complete();
3435 ASSERT_EQ(0, completion
->get_return_value());
3436 completion
->release();
3438 // redirect's refcount
3441 cache_ioctx
.getxattr("bar", CHUNK_REFCOUNT_ATTR
, t
);
3444 auto iter
= t
.cbegin();
3446 } catch (buffer::error
& err
) {
3449 ASSERT_EQ(1u, refs
.count());
3454 cache_ioctx
.getxattr("bar-chunk", CHUNK_REFCOUNT_ATTR
, t
);
3457 auto iter
= t
.cbegin();
3459 } catch (buffer::error
& err
) {
3462 ASSERT_EQ(1u, refs
.count());
3465 // unset-manifest for set-redirect
3467 ObjectWriteOperation op
;
3468 op
.unset_manifest();
3469 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3470 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3471 completion
->wait_for_complete();
3472 ASSERT_EQ(0, completion
->get_return_value());
3473 completion
->release();
3476 // unset-manifest for set-chunk
3478 ObjectWriteOperation op
;
3479 op
.unset_manifest();
3480 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3481 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3482 completion
->wait_for_complete();
3483 ASSERT_EQ(0, completion
->get_return_value());
3484 completion
->release();
3486 // redirect's refcount
3489 cache_ioctx
.getxattr("bar-chunk", CHUNK_REFCOUNT_ATTR
, t
);
3490 if (t
.length() != 0U) {
3491 ObjectWriteOperation op
;
3492 op
.unset_manifest();
3493 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3494 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3495 completion
->wait_for_complete();
3496 ASSERT_EQ(-EOPNOTSUPP
, completion
->get_return_value());
3497 completion
->release();
3503 cache_ioctx
.getxattr("bar-chunk", CHUNK_REFCOUNT_ATTR
, t
);
3504 if (t
.length() != 0U) {
3505 ObjectWriteOperation op
;
3506 op
.unset_manifest();
3507 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3508 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3509 completion
->wait_for_complete();
3510 ASSERT_EQ(-EOPNOTSUPP
, completion
->get_return_value());
3511 completion
->release();
3515 // wait for maps to settle before next test
3516 cluster
.wait_for_latest_osdmap();
3519 #include "common/ceph_crypto.h"
3520 using ceph::crypto::SHA1
;
3521 #include "rgw/rgw_common.h"
3522 TEST_F(LibRadosTwoPoolsPP
, ManifestDedupRefRead
) {
3523 // skip test if not yet nautilus
3524 if (_get_required_osd_release(cluster
) < "nautilus") {
3525 GTEST_SKIP() << "cluster is not yet nautilus, skipping test";
3529 ASSERT_EQ(0, cluster
.mon_command(
3530 set_pool_str(pool_name
, "fingerprint_algorithm", "sha1"),
3532 cluster
.wait_for_latest_osdmap();
3536 tgt_oid
= get_fp_oid("There hi", "sha1");
3541 bl
.append("There hi");
3542 ObjectWriteOperation op
;
3544 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3548 bl
.append("There hi");
3549 ObjectWriteOperation op
;
3551 ASSERT_EQ(0, ioctx
.operate("foo-dedup", &op
));
3556 ObjectWriteOperation op
;
3558 bl
.append("There hi");
3560 ASSERT_EQ(0, cache_ioctx
.operate(tgt_oid
, &op
));
3563 // set-chunk (dedup)
3564 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 8, tgt_oid
, "foo-dedup");
3565 // set-chunk (dedup)
3566 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 8, tgt_oid
, "foo");
3570 cache_ioctx
.getxattr(tgt_oid
, CHUNK_REFCOUNT_ATTR
, t
);
3573 auto iter
= t
.cbegin();
3575 } catch (buffer::error
& err
) {
3578 ASSERT_LE(2u, refs
.count());
3581 // wait for maps to settle before next test
3582 cluster
.wait_for_latest_osdmap();
3585 TEST_F(LibRadosTwoPoolsPP
, ManifestSnapRefcount
) {
3586 // skip test if not yet octopus
3587 if (_get_required_osd_release(cluster
) < "octopus") {
3588 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
3593 ASSERT_EQ(0, cluster
.mon_command(
3594 set_pool_str(pool_name
, "fingerprint_algorithm", "sha1"),
3596 cluster
.wait_for_latest_osdmap();
3601 bl
.append("there hi");
3602 ObjectWriteOperation op
;
3604 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3608 bl
.append("there hi");
3609 ObjectWriteOperation op
;
3611 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3614 // wait for maps to settle
3615 cluster
.wait_for_latest_osdmap();
3617 string er_fp_oid
, hi_fp_oid
, bb_fp_oid
;
3620 er_fp_oid
= get_fp_oid("er", "sha1");
3621 hi_fp_oid
= get_fp_oid("hi", "sha1");
3622 bb_fp_oid
= get_fp_oid("bb", "sha1");
3626 ObjectWriteOperation op
;
3630 ASSERT_EQ(0, cache_ioctx
.operate(er_fp_oid
, &op
));
3634 ObjectWriteOperation op
;
3638 ASSERT_EQ(0, cache_ioctx
.operate(hi_fp_oid
, &op
));
3642 ObjectWriteOperation op
;
3646 ASSERT_EQ(0, cache_ioctx
.operate(bb_fp_oid
, &op
));
3649 // set-chunk (dedup)
3650 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, er_fp_oid
, "foo");
3651 // set-chunk (dedup)
3652 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, hi_fp_oid
, "foo");
3654 // make all chunks dirty --> flush
3657 // check chunk's refcount
3661 int size
= strlen("er");
3662 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3663 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3664 sha1_gen
.Update((const unsigned char *)"er", size
);
3665 sha1_gen
.Final(fingerprint
);
3666 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3667 cache_ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
3670 auto iter
= t
.cbegin();
3672 } catch (buffer::error
& err
) {
3675 ASSERT_LE(1u, refs
.count());
3678 // create a snapshot, clone
3679 vector
<uint64_t> my_snaps(1);
3680 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
3681 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
3689 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3695 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3697 // set-chunk (dedup)
3698 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, bb_fp_oid
, "foo");
3702 my_snaps
[1] = my_snaps
[0];
3703 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
3704 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
3712 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3718 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3720 // set-chunk (dedup)
3721 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, er_fp_oid
, "foo");
3723 // check chunk's refcount
3727 int size
= strlen("er");
3728 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3729 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3730 sha1_gen
.Update((const unsigned char *)"er", size
);
3731 sha1_gen
.Final(fingerprint
);
3732 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3733 cache_ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
3736 auto iter
= t
.cbegin();
3738 } catch (buffer::error
& err
) {
3741 ASSERT_LE(2u, refs
.count());
3746 my_snaps
[2] = my_snaps
[1];
3747 my_snaps
[1] = my_snaps
[0];
3748 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
3749 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
3757 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3763 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3765 // set-chunk (dedup)
3766 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, bb_fp_oid
, "foo");
3769 * snap[2]: [er] [hi]
3770 * snap[1]: [bb] [hi]
3771 * snap[0]: [er] [hi]
3775 // check chunk's refcount
3779 int size
= strlen("hi");
3780 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3781 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3782 sha1_gen
.Update((const unsigned char *)"hi", size
);
3783 sha1_gen
.Final(fingerprint
);
3784 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3785 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 1);
3788 // check chunk's refcount
3792 int size
= strlen("er");
3793 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3794 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3795 sha1_gen
.Update((const unsigned char *)"er", size
);
3796 sha1_gen
.Final(fingerprint
);
3797 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3798 cache_ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
3801 auto iter
= t
.cbegin();
3803 } catch (buffer::error
& err
) {
3806 ASSERT_LE(2u, refs
.count());
3810 ioctx
.selfmanaged_snap_remove(my_snaps
[2]);
3813 * snap[1]: [bb] [hi]
3814 * snap[0]: [er] [hi]
3820 // check chunk's refcount
3824 int size
= strlen("hi");
3825 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3826 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3827 sha1_gen
.Update((const unsigned char *)"hi", size
);
3828 sha1_gen
.Final(fingerprint
);
3829 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3830 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 1);
3834 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
3837 * snap[1]: [bb] [hi]
3843 // check chunk's refcount
3847 int size
= strlen("bb");
3848 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3849 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3850 sha1_gen
.Update((const unsigned char *)"bb", size
);
3851 sha1_gen
.Final(fingerprint
);
3852 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3853 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 1);
3857 ioctx
.selfmanaged_snap_remove(my_snaps
[1]);
3860 * snap[1]: [bb] [hi]
3865 // check chunk's refcount
3869 int size
= strlen("bb");
3870 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3871 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3872 sha1_gen
.Update((const unsigned char *)"bb", size
);
3873 sha1_gen
.Final(fingerprint
);
3874 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3875 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 1);
3878 // check chunk's refcount
3882 int size
= strlen("hi");
3883 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3884 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3885 sha1_gen
.Update((const unsigned char *)"hi", size
);
3886 sha1_gen
.Final(fingerprint
);
3887 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3888 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 1);
3892 TEST_F(LibRadosTwoPoolsPP
, ManifestSnapRefcount2
) {
3893 // skip test if not yet octopus
3894 if (_get_required_osd_release(cluster
) < "octopus") {
3895 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
3900 ASSERT_EQ(0, cluster
.mon_command(
3901 set_pool_str(pool_name
, "fingerprint_algorithm", "sha1"),
3903 cluster
.wait_for_latest_osdmap();
3908 bl
.append("Thabe cdHI");
3909 ObjectWriteOperation op
;
3911 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3915 bl
.append("there hiHI");
3916 ObjectWriteOperation op
;
3918 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3921 string ab_fp_oid
, cd_fp_oid
, ef_fp_oid
, BB_fp_oid
;
3924 ab_fp_oid
= get_fp_oid("ab", "sha1");
3925 cd_fp_oid
= get_fp_oid("cd", "sha1");
3926 ef_fp_oid
= get_fp_oid("ef", "sha1");
3927 BB_fp_oid
= get_fp_oid("BB", "sha1");
3931 ObjectWriteOperation op
;
3935 ASSERT_EQ(0, cache_ioctx
.operate(ab_fp_oid
, &op
));
3939 ObjectWriteOperation op
;
3943 ASSERT_EQ(0, cache_ioctx
.operate(cd_fp_oid
, &op
));
3947 ObjectWriteOperation op
;
3951 ASSERT_EQ(0, cache_ioctx
.operate(ef_fp_oid
, &op
));
3955 ObjectWriteOperation op
;
3959 ASSERT_EQ(0, cache_ioctx
.operate(BB_fp_oid
, &op
));
3962 // set-chunk (dedup)
3963 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, ab_fp_oid
, "foo");
3964 // set-chunk (dedup)
3965 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, cd_fp_oid
, "foo");
3966 // set-chunk (dedup)
3967 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, ef_fp_oid
, "foo");
3970 // make all chunks dirty --> flush
3971 // foo: [ab] [cd] [ef]
3973 // create a snapshot, clone
3974 vector
<uint64_t> my_snaps(1);
3975 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
3976 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
3979 // foo: [BB] [BB] [ef]
3983 bl
.append("ThBBe BB");
3984 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3989 bl
.append("ThBBe BB");
3990 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
3992 // set-chunk (dedup)
3993 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, BB_fp_oid
, "foo");
3994 // set-chunk (dedup)
3995 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, BB_fp_oid
, "foo");
3999 my_snaps
[1] = my_snaps
[0];
4000 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4001 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4004 // foo: [ab] [cd] [ef]
4008 bl
.append("Thabe cd");
4009 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
4014 bl
.append("Thabe cd");
4015 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
4017 // set-chunk (dedup)
4018 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, ab_fp_oid
, "foo");
4019 // set-chunk (dedup)
4020 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, cd_fp_oid
, "foo");
4023 * snap[1]: [ab] [cd] [ef]
4024 * snap[0]: [BB] [BB] [ef]
4025 * head: [ab] [cd] [ef]
4028 // check chunk's refcount
4032 int size
= strlen("ab");
4033 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
4034 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
4035 sha1_gen
.Update((const unsigned char *)"ab", size
);
4036 sha1_gen
.Final(fingerprint
);
4037 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
4038 cache_ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
4041 auto iter
= t
.cbegin();
4043 } catch (buffer::error
& err
) {
4046 ASSERT_LE(2u, refs
.count());
4049 // check chunk's refcount
4053 int size
= strlen("cd");
4054 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
4055 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
4056 sha1_gen
.Update((const unsigned char *)"cd", size
);
4057 sha1_gen
.Final(fingerprint
);
4058 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
4059 cache_ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
4062 auto iter
= t
.cbegin();
4064 } catch (buffer::error
& err
) {
4067 ASSERT_LE(2u, refs
.count());
4070 // check chunk's refcount
4074 int size
= strlen("BB");
4075 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
4076 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
4077 sha1_gen
.Update((const unsigned char *)"BB", size
);
4078 sha1_gen
.Final(fingerprint
);
4079 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
4080 cache_ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
4083 auto iter
= t
.cbegin();
4085 } catch (buffer::error
& err
) {
4088 ASSERT_LE(2u, refs
.count());
4092 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
4095 * snap[1]: [ab] [cd] [ef]
4096 * head: [ab] [cd] [ef]
4101 // check chunk's refcount
4105 int size
= strlen("BB");
4106 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
4107 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
4108 sha1_gen
.Update((const unsigned char *)"BB", size
);
4109 sha1_gen
.Final(fingerprint
);
4110 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
4111 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 0);
4115 TEST_F(LibRadosTwoPoolsPP
, ManifestTestSnapCreate
) {
4116 // skip test if not yet octopus
4117 if (_get_required_osd_release(cluster
) < "octopus") {
4118 GTEST_SKIP() << "cluster is not yet octopus, skipping test";
4124 bl
.append("base chunk");
4125 ObjectWriteOperation op
;
4127 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4131 bl
.append("CHUNKS CHUNKS");
4132 ObjectWriteOperation op
;
4134 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
4137 string ba_fp_oid
, se_fp_oid
, ch_fp_oid
;
4140 ba_fp_oid
= get_fp_oid("ba", "sha1");
4141 se_fp_oid
= get_fp_oid("se", "sha1");
4142 ch_fp_oid
= get_fp_oid("ch", "sha1");
4146 ObjectWriteOperation op
;
4150 ASSERT_EQ(0, cache_ioctx
.operate(ba_fp_oid
, &op
));
4154 ObjectWriteOperation op
;
4158 ASSERT_EQ(0, cache_ioctx
.operate(se_fp_oid
, &op
));
4162 ObjectWriteOperation op
;
4166 ASSERT_EQ(0, cache_ioctx
.operate(ch_fp_oid
, &op
));
4169 // set-chunk (dedup)
4170 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 2, ba_fp_oid
, "foo");
4172 // try to create a snapshot, clone
4173 vector
<uint64_t> my_snaps(1);
4174 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4175 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4178 // set-chunk (dedup)
4179 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, se_fp_oid
, "foo");
4181 // check whether clone is created
4182 ioctx
.snap_set_read(librados::SNAP_DIR
);
4184 snap_set_t snap_set
;
4186 ObjectReadOperation op
;
4187 op
.list_snaps(&snap_set
, &snap_ret
);
4188 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4189 ASSERT_EQ(0, ioctx
.aio_operate(
4190 "foo", completion
, &op
,
4192 completion
->wait_for_complete();
4193 ASSERT_EQ(0, snap_ret
);
4194 ASSERT_LT(0u, snap_set
.clones
.size());
4195 ASSERT_EQ(1, snap_set
.clones
.size());
4199 ioctx
.snap_set_read(librados::SNAP_HEAD
);
4203 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 0));
4206 ioctx
.snap_set_read(my_snaps
[0]);
4207 // set-chunk to clone
4208 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, ch_fp_oid
, "foo");
4211 TEST_F(LibRadosTwoPoolsPP
, ManifestRedirectAfterPromote
) {
4212 // skip test if not yet octopus
4213 if (_get_required_osd_release(cluster
) < "octopus") {
4214 GTEST_SKIP() << "cluster is not yet octopus, skipping test";
4220 bl
.append("base chunk");
4221 ObjectWriteOperation op
;
4223 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4227 bl
.append("BASE CHUNK");
4228 ObjectWriteOperation op
;
4230 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
4235 ObjectWriteOperation op
;
4236 op
.set_redirect("bar", cache_ioctx
, 0);
4237 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4238 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
4239 completion
->wait_for_complete();
4240 ASSERT_EQ(0, completion
->get_return_value());
4241 completion
->release();
4246 ObjectWriteOperation op
;
4248 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4249 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
4250 completion
->wait_for_complete();
4251 ASSERT_EQ(0, completion
->get_return_value());
4252 completion
->release();
4259 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 0));
4262 // read and verify the object (redirect)
4265 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
4266 ASSERT_EQ('a', bl
[0]);
4269 // read and verify the object (redirect)
4272 ASSERT_EQ(1, cache_ioctx
.read("bar", bl
, 1, 0));
4273 ASSERT_EQ('B', bl
[0]);
4277 TEST_F(LibRadosTwoPoolsPP
, ManifestCheckRefcountWhenModification
) {
4278 // skip test if not yet octopus
4279 if (_get_required_osd_release(cluster
) < "octopus") {
4280 GTEST_SKIP() << "cluster is not yet octopus, skipping test";
4284 ASSERT_EQ(0, cluster
.mon_command(
4285 set_pool_str(pool_name
, "fingerprint_algorithm", "sha1"),
4287 cluster
.wait_for_latest_osdmap();
4292 bl
.append("there hiHI");
4293 ObjectWriteOperation op
;
4295 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4298 string er_fp_oid
, hi_fp_oid
, HI_fp_oid
, ai_fp_oid
, bi_fp_oid
,
4299 Er_fp_oid
, Hi_fp_oid
, Si_fp_oid
;
4302 er_fp_oid
= get_fp_oid("er", "sha1");
4303 hi_fp_oid
= get_fp_oid("hi", "sha1");
4304 HI_fp_oid
= get_fp_oid("HI", "sha1");
4305 ai_fp_oid
= get_fp_oid("ai", "sha1");
4306 bi_fp_oid
= get_fp_oid("bi", "sha1");
4307 Er_fp_oid
= get_fp_oid("Er", "sha1");
4308 Hi_fp_oid
= get_fp_oid("Hi", "sha1");
4309 Si_fp_oid
= get_fp_oid("Si", "sha1");
4313 ObjectWriteOperation op
;
4317 ASSERT_EQ(0, cache_ioctx
.operate(er_fp_oid
, &op
));
4321 ObjectWriteOperation op
;
4325 ASSERT_EQ(0, cache_ioctx
.operate(hi_fp_oid
, &op
));
4329 ObjectWriteOperation op
;
4333 ASSERT_EQ(0, cache_ioctx
.operate(HI_fp_oid
, &op
));
4337 ObjectWriteOperation op
;
4341 ASSERT_EQ(0, cache_ioctx
.operate(ai_fp_oid
, &op
));
4345 ObjectWriteOperation op
;
4349 ASSERT_EQ(0, cache_ioctx
.operate(bi_fp_oid
, &op
));
4353 ObjectWriteOperation op
;
4357 ASSERT_EQ(0, cache_ioctx
.operate(Er_fp_oid
, &op
));
4361 ObjectWriteOperation op
;
4365 ASSERT_EQ(0, cache_ioctx
.operate(Hi_fp_oid
, &op
));
4369 ObjectWriteOperation op
;
4373 ASSERT_EQ(0, cache_ioctx
.operate(Si_fp_oid
, &op
));
4376 // set-chunk (dedup)
4377 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, er_fp_oid
, "foo");
4378 // set-chunk (dedup)
4379 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, hi_fp_oid
, "foo");
4380 // set-chunk (dedup)
4381 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, HI_fp_oid
, "foo");
4383 // foo head: [er] [hi] [HI]
4385 // create a snapshot, clone
4386 vector
<uint64_t> my_snaps(1);
4387 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4388 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4392 // foo snap[0]: [er] [hi] [HI]
4393 // foo head : [er] [ai] [HI]
4398 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
4404 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
4407 // set-chunk (dedup)
4408 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, ai_fp_oid
, "foo");
4410 // foo snap[0]: [er] [hi] [HI]
4411 // foo head : [er] [bi] [HI]
4416 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
4422 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
4425 // set-chunk (dedup)
4426 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, bi_fp_oid
, "foo");
4430 // check chunk's refcount
4431 // [ai]'s refcount should be 0
4435 int size
= strlen("ai");
4436 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
4437 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
4438 sha1_gen
.Update((const unsigned char *)"ai", size
);
4439 sha1_gen
.Final(fingerprint
);
4440 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
4441 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 0);
4444 // foo snap[0]: [er] [hi] [HI]
4445 // foo head : [Er] [Hi] [Si]
4449 bl
.append("thEre HiSi");
4450 ObjectWriteOperation op
;
4452 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4457 bl
.append("thEre HiSi");
4458 ObjectWriteOperation op
;
4460 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4463 // set-chunk (dedup)
4464 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, Er_fp_oid
, "foo");
4465 // set-chunk (dedup)
4466 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, Hi_fp_oid
, "foo");
4467 // set-chunk (dedup)
4468 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, Si_fp_oid
, "foo");
4470 // foo snap[0]: [er] [hi] [HI]
4471 // foo head : [ER] [HI] [SI]
4475 bl
.append("thERe HISI");
4476 ObjectWriteOperation op
;
4478 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4483 // check chunk's refcount
4484 // [Er]'s refcount should be 0
4488 int size
= strlen("Er");
4489 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
4490 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
4491 sha1_gen
.Update((const unsigned char *)"Er", size
);
4492 sha1_gen
.Final(fingerprint
);
4493 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
4494 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, p_str
, 0);
4498 TEST_F(LibRadosTwoPoolsPP
, ManifestSnapIncCount
) {
4499 // skip test if not yet octopus
4500 if (_get_required_osd_release(cluster
) < "octopus") {
4501 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
4508 bl
.append("there hiHI");
4509 ObjectWriteOperation op
;
4511 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4515 bl
.append("there hiHI");
4516 ObjectWriteOperation op
;
4518 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
4522 bl
.append("there hiHI");
4523 ObjectWriteOperation op
;
4525 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
4529 bl
.append("there hiHI");
4530 ObjectWriteOperation op
;
4532 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
4536 bl
.append("there hiHI");
4537 ObjectWriteOperation op
;
4539 ASSERT_EQ(0, cache_ioctx
.operate("chunk4", &op
));
4542 // wait for maps to settle
4543 cluster
.wait_for_latest_osdmap();
4545 // create a snapshot, clone
4546 vector
<uint64_t> my_snaps(1);
4547 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4548 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4553 bl
.append("there hiHI");
4554 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
4558 my_snaps
[1] = my_snaps
[0];
4559 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4560 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4565 bl
.append("there hiHI");
4566 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
4570 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
4571 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk4", "foo");
4574 // foo head : [chunk1] [chunk4]
4576 ioctx
.snap_set_read(my_snaps
[1]);
4578 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, "chunk2", "foo");
4579 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk4", "foo");
4580 // foo snap[1]: [chunk2] [chunk4]
4582 // foo head : [chunk1] [chunk4]
4584 ioctx
.snap_set_read(my_snaps
[0]);
4586 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, "chunk2", "foo");
4587 // foo snap[1]: [chunk2] [chunk4]
4588 // foo snap[0]: [chunk2]
4589 // foo head : [chunk1] [chunk4]
4591 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk3", "foo");
4592 // foo snap[1]: [chunk2] [chunk4]
4593 // foo snap[0]: [chunk3] [chunk2]
4594 // foo head : [chunk1] [chunk4]
4595 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk4", "foo");
4596 // foo snap[1]: [chunk2] [chunk4]
4597 // foo snap[0]: [chunk3] [chunk2] [chunk4]
4598 // foo head : [chunk1] [chunk4]
4600 // check chunk's refcount
4601 check_fp_oid_refcount(cache_ioctx
, "chunk1", 1u, "");
4603 // check chunk's refcount
4604 check_fp_oid_refcount(cache_ioctx
, "chunk2", 1u, "");
4606 // check chunk's refcount
4607 check_fp_oid_refcount(cache_ioctx
, "chunk3", 1u, "");
4610 // check chunk's refcount
4611 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk4", 1);
4614 TEST_F(LibRadosTwoPoolsPP
, ManifestEvict
) {
4615 // skip test if not yet octopus
4616 if (_get_required_osd_release(cluster
) < "octopus") {
4617 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
4624 bl
.append("there hiHI");
4625 ObjectWriteOperation op
;
4627 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4631 bl
.append("there hiHI");
4632 ObjectWriteOperation op
;
4634 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
4638 bl
.append("there hiHI");
4639 ObjectWriteOperation op
;
4641 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
4645 bl
.append("there hiHI");
4646 ObjectWriteOperation op
;
4648 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
4652 bl
.append("there hiHI");
4653 ObjectWriteOperation op
;
4655 ASSERT_EQ(0, cache_ioctx
.operate("chunk4", &op
));
4658 // wait for maps to settle
4659 cluster
.wait_for_latest_osdmap();
4661 // create a snapshot, clone
4662 vector
<uint64_t> my_snaps(1);
4663 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4664 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4669 bl
.append("there hiHI");
4670 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
4674 my_snaps
[1] = my_snaps
[0];
4675 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4676 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4681 bl
.append("there hiHI");
4682 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
4686 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
4687 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk4", "foo");
4690 // foo head : [chunk1] [chunk4]
4692 ioctx
.snap_set_read(my_snaps
[1]);
4694 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk2", "foo");
4695 // foo snap[1]: [ chunk2 ]
4697 // foo head : [chunk1] [chunk4]
4699 ioctx
.snap_set_read(my_snaps
[0]);
4701 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, "chunk2", "foo");
4702 // foo snap[1]: [ chunk2 ]
4703 // foo snap[0]: [chunk2]
4704 // foo head : [chunk1] [chunk4]
4706 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk3", "foo");
4707 // foo snap[1]: [ chunk2 ]
4708 // foo snap[0]: [chunk3] [chunk2]
4709 // foo head : [chunk1] [chunk4]
4710 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk4", "foo");
4711 // foo snap[1]: [ chunk2 ]
4712 // foo snap[0]: [chunk3] [chunk2] [chunk4]
4713 // foo head : [chunk1] [chunk4]
4714 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 2, "chunk4", "foo");
4715 // foo snap[1]: [ chunk2 ]
4716 // foo snap[0]: [chunk4] [chunk3] [chunk2] [chunk4]
4717 // foo head : [chunk1] [chunk4]
4718 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 4, 2, "chunk1", "foo");
4719 // foo snap[1]: [ chunk2 ]
4720 // foo snap[0]: [chunk4] [chunk3] [chunk1] [chunk2] [chunk4]
4721 // foo head : [chunk1] [chunk4]
4724 ObjectReadOperation op
, stat_op
;
4727 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4728 ASSERT_EQ(0, ioctx
.aio_operate(
4729 "foo", completion
, &op
,
4730 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4731 completion
->wait_for_complete();
4732 ASSERT_EQ(0, completion
->get_return_value());
4734 stat_op
.stat(&size
, NULL
, NULL
);
4735 ASSERT_EQ(0, ioctx
.operate("foo", &stat_op
, NULL
));
4736 ASSERT_EQ(10, size
);
4739 ioctx
.snap_set_read(librados::SNAP_HEAD
);
4741 ObjectReadOperation op
, stat_op
;
4744 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4745 ASSERT_EQ(0, ioctx
.aio_operate(
4746 "foo", completion
, &op
,
4747 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4748 completion
->wait_for_complete();
4749 ASSERT_EQ(0, completion
->get_return_value());
4751 stat_op
.stat(&size
, NULL
, NULL
);
4752 ASSERT_EQ(0, ioctx
.operate("foo", &stat_op
, NULL
));
4753 ASSERT_EQ(strlen("there hiHI"), size
);
4758 TEST_F(LibRadosTwoPoolsPP
, ManifestEvictPromote
) {
4759 // skip test if not yet octopus
4760 if (_get_required_osd_release(cluster
) < "octopus") {
4761 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
4768 bl
.append("there hiHI");
4769 ObjectWriteOperation op
;
4771 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4775 bl
.append("EREHT hiHI");
4776 ObjectWriteOperation op
;
4778 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
4782 bl
.append("there hiHI");
4783 ObjectWriteOperation op
;
4785 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
4789 bl
.append("THERE HIHI");
4790 ObjectWriteOperation op
;
4792 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
4795 // wait for maps to settle
4796 cluster
.wait_for_latest_osdmap();
4798 // create a snapshot, clone
4799 vector
<uint64_t> my_snaps(1);
4800 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4801 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4807 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
4811 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 2, "chunk1", "foo");
4812 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk2", "foo");
4814 // foo head : [chunk1] [chunk2]
4816 ioctx
.snap_set_read(my_snaps
[0]);
4818 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk3", "foo");
4819 // foo snap[0]: [ chunk3 ]
4820 // foo head : [chunk1] [chunk2]
4824 ObjectReadOperation op
, stat_op
;
4827 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4828 ASSERT_EQ(0, ioctx
.aio_operate(
4829 "foo", completion
, &op
,
4830 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4831 completion
->wait_for_complete();
4832 ASSERT_EQ(0, completion
->get_return_value());
4834 stat_op
.stat(&size
, NULL
, NULL
);
4835 ASSERT_EQ(0, ioctx
.operate("foo", &stat_op
, NULL
));
4836 ASSERT_EQ(10, size
);
4841 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
4842 ASSERT_EQ('T', bl
[0]);
4845 ioctx
.snap_set_read(librados::SNAP_HEAD
);
4848 ASSERT_EQ(10, ioctx
.read("foo", bl
, 10, 0));
4849 ASSERT_EQ('H', bl
[8]);
4854 TEST_F(LibRadosTwoPoolsPP
, ManifestSnapSizeMismatch
) {
4855 // skip test if not yet octopus
4856 if (_get_required_osd_release(cluster
) < "octopus") {
4857 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
4864 bl
.append("there hiHI");
4865 ObjectWriteOperation op
;
4867 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
4871 bl
.append("there hiHI");
4872 ObjectWriteOperation op
;
4874 ASSERT_EQ(0, ioctx
.operate("chunk1", &op
));
4878 bl
.append("there HIHI");
4879 ObjectWriteOperation op
;
4881 ASSERT_EQ(0, ioctx
.operate("chunk2", &op
));
4884 // wait for maps to settle
4885 cluster
.wait_for_latest_osdmap();
4887 // create a snapshot, clone
4888 vector
<uint64_t> my_snaps(1);
4889 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4890 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4895 bl
.append("There hiHI");
4896 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, bl
.length(), 0));
4900 my_snaps
[1] = my_snaps
[0];
4901 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4902 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4907 bl
.append("tHere hiHI");
4908 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, bl
.length(), 0));
4912 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 0, 10, "chunk1", "foo");
4914 cache_ioctx
.snap_set_read(my_snaps
[1]);
4917 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 0, 10, "chunk2", "foo");
4921 ObjectReadOperation op
, stat_op
;
4923 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4924 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4925 "foo", completion
, &op
,
4926 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4927 completion
->wait_for_complete();
4928 ASSERT_EQ(0, completion
->get_return_value());
4932 ASSERT_EQ(0, cache_ioctx
.get_object_pg_hash_position2("foo", &hash
));
4936 for (int tries
= 0; tries
< 5; ++tries
) {
4939 ss
<< "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
4940 << cache_ioctx
.get_id() << "."
4943 int r
= cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
4952 cout
<< "waiting for scrubs..." << std::endl
;
4954 cout
<< "done waiting" << std::endl
;
4959 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
4960 ASSERT_EQ('t', bl
[0]);
4964 #include <common/CDC.h>
4965 TEST_F(LibRadosTwoPoolsPP
, DedupFlushRead
) {
4966 // skip test if not yet octopus
4967 if (_get_required_osd_release(cluster
) < "octopus") {
4968 GTEST_SKIP() << "cluster is not yet octopus, skipping test";
4972 ASSERT_EQ(0, cluster
.mon_command(
4973 set_pool_str(cache_pool_name
, "fingerprint_algorithm", "sha1"),
4975 ASSERT_EQ(0, cluster
.mon_command(
4976 set_pool_str(cache_pool_name
, "dedup_tier", pool_name
),
4978 ASSERT_EQ(0, cluster
.mon_command(
4979 set_pool_str(cache_pool_name
, "dedup_chunk_algorithm", "fastcdc"),
4981 ASSERT_EQ(0, cluster
.mon_command(
4982 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 1024),
4985 // wait for maps to settle
4986 cluster
.wait_for_latest_osdmap();
4991 generate_buffer(1024*8, &gbl
);
4992 ObjectWriteOperation op
;
4994 ASSERT_EQ(0, cache_ioctx
.operate("foo-chunk", &op
));
4998 bl
.append("DDse chunk");
4999 ObjectWriteOperation op
;
5001 ASSERT_EQ(0, ioctx
.operate("bar-chunk", &op
));
5004 // set-chunk to set manifest object
5006 ObjectReadOperation op
;
5007 op
.set_chunk(0, 2, ioctx
, "bar-chunk", 0,
5008 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
5009 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5010 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo-chunk", completion
, &op
,
5011 librados::OPERATION_IGNORE_CACHE
, NULL
));
5012 completion
->wait_for_complete();
5013 ASSERT_EQ(0, completion
->get_return_value());
5014 completion
->release();
5018 ObjectReadOperation op
;
5020 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5021 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5022 "foo-chunk", completion
, &op
,
5023 librados::OPERATION_IGNORE_CACHE
, NULL
));
5024 completion
->wait_for_complete();
5025 ASSERT_EQ(0, completion
->get_return_value());
5026 completion
->release();
5029 std::unique_ptr
<CDC
> cdc
= CDC::create("fastcdc", cbits(1024)-1);
5030 vector
<pair
<uint64_t, uint64_t>> chunks
;
5032 cdc
->calc_chunks(gbl
, &chunks
);
5033 chunk
.substr_of(gbl
, chunks
[1].first
, chunks
[1].second
);
5036 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5037 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5039 int size
= chunk
.length();
5040 sha1_gen
.Update((const unsigned char *)chunk
.c_str(), size
);
5041 sha1_gen
.Final(fingerprint
);
5042 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5043 tgt_oid
= string(p_str
);
5046 // read and verify the chunked object
5049 ASSERT_EQ(2, ioctx
.read(tgt_oid
, test_bl
, 2, 0));
5050 ASSERT_EQ(test_bl
[1], chunk
[1]);
5053 ASSERT_EQ(0, cluster
.mon_command(
5054 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 512),
5056 cluster
.wait_for_latest_osdmap();
5058 // make a dirty chunks
5062 ASSERT_EQ(0, cache_ioctx
.write("foo-chunk", bl
, bl
.length(), 0));
5067 ObjectReadOperation op
;
5069 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5070 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5071 "foo-chunk", completion
, &op
,
5072 librados::OPERATION_IGNORE_CACHE
, NULL
));
5073 completion
->wait_for_complete();
5074 ASSERT_EQ(0, completion
->get_return_value());
5075 completion
->release();
5078 cdc
= CDC::create("fastcdc", cbits(512)-1);
5080 cdc
->calc_chunks(gbl
, &chunks
);
5081 bufferlist chunk_512
;
5082 chunk_512
.substr_of(gbl
, chunks
[3].first
, chunks
[3].second
);
5084 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5085 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5087 int size
= chunk_512
.length();
5088 sha1_gen
.Update((const unsigned char *)chunk_512
.c_str(), size
);
5089 sha1_gen
.Final(fingerprint
);
5090 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5091 tgt_oid
= string(p_str
);
5094 // read and verify the chunked object
5097 ASSERT_EQ(2, ioctx
.read(tgt_oid
, test_bl
, 2, 0));
5098 ASSERT_EQ(test_bl
[1], chunk_512
[1]);
5101 ASSERT_EQ(0, cluster
.mon_command(
5102 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 16384),
5104 cluster
.wait_for_latest_osdmap();
5106 // make a dirty chunks
5110 ASSERT_EQ(0, cache_ioctx
.write("foo-chunk", bl
, bl
.length(), 0));
5111 gbl
.begin(0).copy_in(bl
.length(), bl
);
5115 ObjectReadOperation op
;
5117 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5118 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5119 "foo-chunk", completion
, &op
,
5120 librados::OPERATION_IGNORE_CACHE
, NULL
));
5121 completion
->wait_for_complete();
5122 ASSERT_EQ(0, completion
->get_return_value());
5123 completion
->release();
5126 cdc
= CDC::create("fastcdc", cbits(16384)-1);
5128 cdc
->calc_chunks(gbl
, &chunks
);
5129 bufferlist chunk_16384
;
5130 chunk_16384
.substr_of(gbl
, chunks
[0].first
, chunks
[0].second
);
5132 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5133 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5135 int size
= chunk_16384
.length();
5136 sha1_gen
.Update((const unsigned char *)chunk_16384
.c_str(), size
);
5137 sha1_gen
.Final(fingerprint
);
5138 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5139 tgt_oid
= string(p_str
);
5141 // read and verify the chunked object
5144 ASSERT_EQ(2, ioctx
.read(tgt_oid
, test_bl
, 2, 0));
5145 ASSERT_EQ(test_bl
[0], chunk_16384
[0]);
5148 // less than object size
5149 ASSERT_EQ(0, cluster
.mon_command(
5150 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 1024),
5152 cluster
.wait_for_latest_osdmap();
5154 // make a dirty chunks
5155 // a chunk_info is deleted by write, which converts the manifest object to non-manifest object
5159 ASSERT_EQ(0, cache_ioctx
.write("foo-chunk", bl
, bl
.length(), 0));
5165 bl
.append("DDse chunk");
5166 ObjectWriteOperation op
;
5168 ASSERT_EQ(0, ioctx
.operate("bar-chunk", &op
));
5170 // set-chunk to set manifest object
5172 ObjectReadOperation op
;
5173 op
.set_chunk(0, 2, ioctx
, "bar-chunk", 0,
5174 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
5175 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5176 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo-chunk", completion
, &op
,
5177 librados::OPERATION_IGNORE_CACHE
, NULL
));
5178 completion
->wait_for_complete();
5179 ASSERT_EQ(0, completion
->get_return_value());
5180 completion
->release();
5184 ObjectReadOperation op
;
5186 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5187 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5188 "foo-chunk", completion
, &op
,
5189 librados::OPERATION_IGNORE_CACHE
, NULL
));
5190 completion
->wait_for_complete();
5191 ASSERT_EQ(0, completion
->get_return_value());
5192 completion
->release();
5195 cdc
= CDC::create("fastcdc", cbits(1024)-1);
5197 cdc
->calc_chunks(gbl
, &chunks
);
5198 bufferlist small_chunk
;
5199 small_chunk
.substr_of(gbl
, chunks
[1].first
, chunks
[1].second
);
5201 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5202 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5204 int size
= small_chunk
.length();
5205 sha1_gen
.Update((const unsigned char *)small_chunk
.c_str(), size
);
5206 sha1_gen
.Final(fingerprint
);
5207 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5208 tgt_oid
= string(p_str
);
5210 // read and verify the chunked object
5213 ASSERT_EQ(2, ioctx
.read(tgt_oid
, test_bl
, 2, 0));
5214 ASSERT_EQ(test_bl
[0], small_chunk
[0]);
5219 TEST_F(LibRadosTwoPoolsPP
, ManifestFlushSnap
) {
5220 // skip test if not yet octopus
5221 if (_get_required_osd_release(cluster
) < "octopus") {
5222 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
5227 ASSERT_EQ(0, cluster
.mon_command(
5228 set_pool_str(cache_pool_name
, "fingerprint_algorithm", "sha1"),
5230 ASSERT_EQ(0, cluster
.mon_command(
5231 set_pool_str(cache_pool_name
, "dedup_tier", pool_name
),
5233 ASSERT_EQ(0, cluster
.mon_command(
5234 set_pool_str(cache_pool_name
, "dedup_chunk_algorithm", "fastcdc"),
5236 ASSERT_EQ(0, cluster
.mon_command(
5237 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 1024),
5240 // wait for maps to settle
5241 cluster
.wait_for_latest_osdmap();
5247 //bl.append("there hi");
5248 generate_buffer(1024*8, &gbl
);
5249 ObjectWriteOperation op
;
5251 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
5255 bl
.append("there hi");
5256 ObjectWriteOperation op
;
5258 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
5261 // set-chunk (dedup)
5262 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 2, 2, "bar", "foo");
5263 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 6, 2, "bar", "foo");
5265 // create a snapshot, clone
5266 vector
<uint64_t> my_snaps(1);
5267 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5268 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5271 // make a dirty chunks
5275 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, bl
.length(), 0));
5280 my_snaps
[1] = my_snaps
[0];
5281 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5282 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5285 // make a dirty chunks
5289 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, bl
.length(), 0));
5292 // flush on head (should fail)
5293 cache_ioctx
.snap_set_read(librados::SNAP_HEAD
);
5296 ObjectReadOperation op
;
5298 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5299 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5300 "foo", completion
, &op
,
5301 librados::OPERATION_IGNORE_CACHE
, NULL
));
5302 completion
->wait_for_complete();
5303 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
5304 completion
->release();
5307 // flush on recent snap (should fail)
5308 cache_ioctx
.snap_set_read(my_snaps
[0]);
5310 ObjectReadOperation op
;
5312 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5313 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5314 "foo", completion
, &op
,
5315 librados::OPERATION_IGNORE_CACHE
, NULL
));
5316 completion
->wait_for_complete();
5317 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
5318 completion
->release();
5321 // flush on oldest snap
5322 cache_ioctx
.snap_set_read(my_snaps
[1]);
5324 ObjectReadOperation op
;
5326 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5327 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5328 "foo", completion
, &op
,
5329 librados::OPERATION_IGNORE_CACHE
, NULL
));
5330 completion
->wait_for_complete();
5331 ASSERT_EQ(0, completion
->get_return_value());
5332 completion
->release();
5335 // flush on oldest snap
5336 cache_ioctx
.snap_set_read(my_snaps
[0]);
5338 ObjectReadOperation op
;
5340 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5341 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5342 "foo", completion
, &op
,
5343 librados::OPERATION_IGNORE_CACHE
, NULL
));
5344 completion
->wait_for_complete();
5345 ASSERT_EQ(0, completion
->get_return_value());
5346 completion
->release();
5349 // flush on oldest snap
5350 cache_ioctx
.snap_set_read(librados::SNAP_HEAD
);
5352 ObjectReadOperation op
;
5354 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5355 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5356 "foo", completion
, &op
,
5357 librados::OPERATION_IGNORE_CACHE
, NULL
));
5358 completion
->wait_for_complete();
5359 ASSERT_EQ(0, completion
->get_return_value());
5360 completion
->release();
5363 // check chunk's refcount
5364 std::unique_ptr
<CDC
> cdc
= CDC::create("fastcdc", cbits(1024)-1);
5365 vector
<pair
<uint64_t, uint64_t>> chunks
;
5367 cdc
->calc_chunks(gbl
, &chunks
);
5368 chunk
.substr_of(gbl
, chunks
[1].first
, chunks
[1].second
);
5371 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5372 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5374 int size
= chunk
.length();
5375 sha1_gen
.Update((const unsigned char *)chunk
.c_str(), size
);
5376 sha1_gen
.Final(fingerprint
);
5377 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5378 tgt_oid
= string(p_str
);
5380 // read and verify the chunked object
5383 ASSERT_EQ(2, ioctx
.read(tgt_oid
, test_bl
, 2, 0));
5384 ASSERT_EQ(test_bl
[1], chunk
[1]);
5387 cache_ioctx
.snap_set_read(librados::SNAP_HEAD
);
5390 ASSERT_EQ(4, cache_ioctx
.read("foo", bl
, 4, 0));
5391 ASSERT_EQ('c', bl
[2]);
5394 cache_ioctx
.snap_set_read(my_snaps
[0]);
5397 ASSERT_EQ(4, cache_ioctx
.read("foo", bl
, 4, 0));
5398 ASSERT_EQ('b', bl
[2]);
5402 TEST_F(LibRadosTwoPoolsPP
, ManifestFlushDupCount
) {
5403 // skip test if not yet octopus
5404 if (_get_required_osd_release(cluster
) < "octopus") {
5405 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
5410 ASSERT_EQ(0, cluster
.mon_command(
5411 set_pool_str(cache_pool_name
, "fingerprint_algorithm", "sha1"),
5413 ASSERT_EQ(0, cluster
.mon_command(
5414 set_pool_str(cache_pool_name
, "dedup_tier", pool_name
),
5416 ASSERT_EQ(0, cluster
.mon_command(
5417 set_pool_str(cache_pool_name
, "dedup_chunk_algorithm", "fastcdc"),
5419 ASSERT_EQ(0, cluster
.mon_command(
5420 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 1024),
5427 generate_buffer(1024*8, &gbl
);
5428 ObjectWriteOperation op
;
5430 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
5434 bl
.append("there hiHI");
5435 ObjectWriteOperation op
;
5437 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
5440 // wait for maps to settle
5441 cluster
.wait_for_latest_osdmap();
5443 // set-chunk to set manifest object
5445 ObjectReadOperation op
;
5446 op
.set_chunk(0, 2, ioctx
, "bar", 0,
5447 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
5448 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5449 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
5450 librados::OPERATION_IGNORE_CACHE
, NULL
));
5451 completion
->wait_for_complete();
5452 ASSERT_EQ(0, completion
->get_return_value());
5453 completion
->release();
5456 // create a snapshot, clone
5457 vector
<uint64_t> my_snaps(1);
5458 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5459 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5462 // make a dirty chunks
5465 bl
.append("Thbbe hi");
5466 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, bl
.length(), 0));
5471 my_snaps
[1] = my_snaps
[0];
5472 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5473 ASSERT_EQ(0, cache_ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5476 // make a dirty chunks
5479 bl
.append("Thcce hi");
5480 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, bl
.length(), 0));
5483 //flush on oldest snap
5484 cache_ioctx
.snap_set_read(my_snaps
[1]);
5487 ObjectReadOperation op
;
5489 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5490 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5491 "foo", completion
, &op
,
5492 librados::OPERATION_IGNORE_CACHE
, NULL
));
5493 completion
->wait_for_complete();
5494 ASSERT_EQ(0, completion
->get_return_value());
5495 completion
->release();
5498 // flush on oldest snap
5499 cache_ioctx
.snap_set_read(my_snaps
[0]);
5502 ObjectReadOperation op
;
5504 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5505 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5506 "foo", completion
, &op
,
5507 librados::OPERATION_IGNORE_CACHE
, NULL
));
5508 completion
->wait_for_complete();
5509 ASSERT_EQ(0, completion
->get_return_value());
5510 completion
->release();
5513 cache_ioctx
.snap_set_read(librados::SNAP_HEAD
);
5516 ObjectReadOperation op
;
5518 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5519 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5520 "foo", completion
, &op
,
5521 librados::OPERATION_IGNORE_CACHE
, NULL
));
5522 completion
->wait_for_complete();
5523 ASSERT_EQ(0, completion
->get_return_value());
5524 completion
->release();
5527 std::unique_ptr
<CDC
> cdc
= CDC::create("fastcdc", cbits(1024)-1);
5528 vector
<pair
<uint64_t, uint64_t>> chunks
;
5530 cdc
->calc_chunks(gbl
, &chunks
);
5531 chunk
.substr_of(gbl
, chunks
[1].first
, chunks
[1].second
);
5533 // check chunk's refcount
5535 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5536 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5539 int size
= chunk
.length();
5540 sha1_gen
.Update((const unsigned char *)chunk
.c_str(), size
);
5541 sha1_gen
.Final(fingerprint
);
5542 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5543 tgt_oid
= string(p_str
);
5544 ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
5547 auto iter
= t
.cbegin();
5549 } catch (buffer::error
& err
) {
5552 ASSERT_LE(1u, refs
.count());
5556 chunk2
.substr_of(gbl
, chunks
[0].first
, chunks
[0].second
);
5557 // check chunk's refcount
5559 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5560 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5563 int size
= chunk2
.length();
5564 sha1_gen
.Update((const unsigned char *)chunk2
.c_str(), size
);
5565 sha1_gen
.Final(fingerprint
);
5566 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5567 tgt_oid
= string(p_str
);
5568 ioctx
.getxattr(p_str
, CHUNK_REFCOUNT_ATTR
, t
);
5571 auto iter
= t
.cbegin();
5573 } catch (buffer::error
& err
) {
5576 ASSERT_LE(1u, refs
.count());
5579 // make a dirty chunks
5582 bl
.append("ThDDe hi");
5583 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, bl
.length(), 0));
5588 ObjectReadOperation op
;
5590 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5591 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5592 "foo", completion
, &op
,
5593 librados::OPERATION_IGNORE_CACHE
, NULL
));
5594 completion
->wait_for_complete();
5595 ASSERT_EQ(0, completion
->get_return_value());
5596 completion
->release();
5600 tmp
.append("Thcce hi");
5601 gbl
.begin(0).copy_in(tmp
.length(), tmp
);
5603 cdc
->calc_chunks(gbl
, &chunks
);
5604 chunk3
.substr_of(gbl
, chunks
[0].first
, chunks
[0].second
);
5605 // check chunk's refcount
5607 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1] = {0};
5608 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
5611 int size
= chunk2
.length();
5612 sha1_gen
.Update((const unsigned char *)chunk2
.c_str(), size
);
5613 sha1_gen
.Final(fingerprint
);
5614 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
5615 is_intended_refcount_state(cache_ioctx
, "foo", ioctx
, p_str
, 0);
5619 TEST_F(LibRadosTwoPoolsPP
, TierFlushDuringFlush
) {
5620 // skip test if not yet octopus
5621 if (_get_required_osd_release(cluster
) < "octopus") {
5622 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
5628 // create a new pool
5629 std::string temp_pool_name
= get_temp_pool_name() + "-test-flush";
5630 ASSERT_EQ(0, cluster
.pool_create(temp_pool_name
.c_str()));
5632 ASSERT_EQ(0, cluster
.mon_command(
5633 set_pool_str(cache_pool_name
, "fingerprint_algorithm", "sha1"),
5635 ASSERT_EQ(0, cluster
.mon_command(
5636 set_pool_str(cache_pool_name
, "dedup_tier", temp_pool_name
),
5638 ASSERT_EQ(0, cluster
.mon_command(
5639 set_pool_str(cache_pool_name
, "dedup_chunk_algorithm", "fastcdc"),
5641 ASSERT_EQ(0, cluster
.mon_command(
5642 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 1024),
5649 generate_buffer(1024*8, &gbl
);
5650 ObjectWriteOperation op
;
5652 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
5656 bl
.append("there hiHI");
5657 ObjectWriteOperation op
;
5659 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
5662 // set-chunk to set manifest object
5664 ObjectReadOperation op
;
5665 op
.set_chunk(0, 2, ioctx
, "bar", 0,
5666 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
5667 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5668 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
5669 librados::OPERATION_IGNORE_CACHE
, NULL
));
5670 completion
->wait_for_complete();
5671 ASSERT_EQ(0, completion
->get_return_value());
5672 completion
->release();
5675 // delete temp pool, so flushing chunk will fail
5676 ASSERT_EQ(0, s_cluster
.pool_delete(temp_pool_name
.c_str()));
5678 // flush to check if proper error is returned
5680 ObjectReadOperation op
;
5682 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5683 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5684 "foo", completion
, &op
,
5685 librados::OPERATION_IGNORE_CACHE
, NULL
));
5686 completion
->wait_for_complete();
5687 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
5688 completion
->release();
5693 TEST_F(LibRadosTwoPoolsPP
, ManifestSnapHasChunk
) {
5694 // skip test if not yet octopus
5695 if (_get_required_osd_release(cluster
) < "octopus") {
5696 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
5701 ASSERT_EQ(0, cluster
.mon_command(
5702 set_pool_str(pool_name
, "fingerprint_algorithm", "sha1"),
5704 cluster
.wait_for_latest_osdmap();
5709 bl
.append("there HIHI");
5710 ObjectWriteOperation op
;
5712 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5715 string er_fp_oid
, hi_fp_oid
, HI_fp_oid
, ai_fp_oid
, bi_fp_oid
,
5716 Er_fp_oid
, Hi_fp_oid
, SI_fp_oid
;
5719 er_fp_oid
= get_fp_oid("er", "sha1");
5720 hi_fp_oid
= get_fp_oid("hi", "sha1");
5721 HI_fp_oid
= get_fp_oid("HI", "sha1");
5722 ai_fp_oid
= get_fp_oid("ai", "sha1");
5723 bi_fp_oid
= get_fp_oid("bi", "sha1");
5724 Er_fp_oid
= get_fp_oid("Er", "sha1");
5725 Hi_fp_oid
= get_fp_oid("Hi", "sha1");
5726 SI_fp_oid
= get_fp_oid("SI", "sha1");
5730 ObjectWriteOperation op
;
5734 ASSERT_EQ(0, cache_ioctx
.operate(er_fp_oid
, &op
));
5738 ObjectWriteOperation op
;
5742 ASSERT_EQ(0, cache_ioctx
.operate(hi_fp_oid
, &op
));
5746 ObjectWriteOperation op
;
5750 ASSERT_EQ(0, cache_ioctx
.operate(HI_fp_oid
, &op
));
5754 ObjectWriteOperation op
;
5758 ASSERT_EQ(0, cache_ioctx
.operate(ai_fp_oid
, &op
));
5762 ObjectWriteOperation op
;
5766 ASSERT_EQ(0, cache_ioctx
.operate(bi_fp_oid
, &op
));
5770 ObjectWriteOperation op
;
5774 ASSERT_EQ(0, cache_ioctx
.operate(Er_fp_oid
, &op
));
5778 ObjectWriteOperation op
;
5782 ASSERT_EQ(0, cache_ioctx
.operate(Hi_fp_oid
, &op
));
5786 ObjectWriteOperation op
;
5790 ASSERT_EQ(0, cache_ioctx
.operate(SI_fp_oid
, &op
));
5793 // set-chunk (dedup)
5794 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, HI_fp_oid
, "foo");
5795 // set-chunk (dedup)
5796 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, HI_fp_oid
, "foo");
5798 // foo head: [hi] [HI]
5800 // create a snapshot, clone
5801 vector
<uint64_t> my_snaps(1);
5802 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5803 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5811 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5817 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5823 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 8));
5826 // foo snap[0]: [hi] [HI]
5827 // foo head : [er] [ai] [SI]
5829 // set-chunk (dedup)
5830 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, er_fp_oid
, "foo");
5831 // set-chunk (dedup)
5832 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, ai_fp_oid
, "foo");
5833 // set-chunk (dedup)
5834 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, SI_fp_oid
, "foo");
5837 my_snaps
[1] = my_snaps
[0];
5838 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5839 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5846 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5852 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5855 // foo snap[1]: [HI] [HI]
5856 // foo snap[0]: [er] [ai] [SI]
5857 // foo head : [er] [bi] [SI]
5859 // set-chunk (dedup)
5860 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, bi_fp_oid
, "foo");
5863 ASSERT_EQ(1, cls_cas_references_chunk(ioctx
, "foo", SI_fp_oid
));
5864 ASSERT_EQ(1, cls_cas_references_chunk(ioctx
, "foo", er_fp_oid
));
5865 ASSERT_EQ(1, cls_cas_references_chunk(ioctx
, "foo", ai_fp_oid
));
5866 ASSERT_EQ(2, cls_cas_references_chunk(ioctx
, "foo", HI_fp_oid
));
5867 ASSERT_EQ(-ENOLINK
, cls_cas_references_chunk(ioctx
, "foo", Hi_fp_oid
));
5871 TEST_F(LibRadosTwoPoolsPP
, ManifestRollback
) {
5872 // skip test if not yet pacific
5873 if (_get_required_osd_release(cluster
) < "pacific") {
5874 cout
<< "cluster is not yet pacific, skipping test" << std::endl
;
5881 bl
.append("CDere hiHI");
5882 ObjectWriteOperation op
;
5884 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5888 bl
.append("ABere hiHI");
5889 ObjectWriteOperation op
;
5891 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
5895 bl
.append("CDere hiHI");
5896 ObjectWriteOperation op
;
5898 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
5902 bl
.append("EFere hiHI");
5903 ObjectWriteOperation op
;
5905 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
5908 // wait for maps to settle
5909 cluster
.wait_for_latest_osdmap();
5911 // create a snapshot, clone
5912 vector
<uint64_t> my_snaps(1);
5913 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5914 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5919 bl
.append("there hiHI");
5920 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
5924 my_snaps
[1] = my_snaps
[0];
5925 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5926 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5931 bl
.append("thABe hiEF");
5932 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
5936 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
5937 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk3", "foo");
5940 // foo head : [chunk1] [chunk3]
5942 ioctx
.snap_set_read(my_snaps
[1]);
5944 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk2", "foo");
5945 // foo snap[1]: [ chunk2 ]
5947 // foo head : [chunk1] [chunk3]
5949 // foo snap[1]: [ chunk2 ]
5951 // foo head : [chunk1] [chunk3]
5953 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[0]));
5955 ioctx
.snap_set_read(librados::SNAP_HEAD
);
5958 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5959 ASSERT_EQ('t', bl
[0]);
5962 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[1]));
5966 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5967 ASSERT_EQ('C', bl
[0]);
5972 TEST_F(LibRadosTwoPoolsPP
, ManifestRollbackRefcount
) {
5973 // skip test if not yet pacific
5974 if (_get_required_osd_release(cluster
) < "pacific") {
5975 cout
<< "cluster is not yet pacific, skipping test" << std::endl
;
5982 bl
.append("CDere hiHI");
5983 ObjectWriteOperation op
;
5985 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5989 bl
.append("ABere hiHI");
5990 ObjectWriteOperation op
;
5992 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
5996 bl
.append("CDere hiHI");
5997 ObjectWriteOperation op
;
5999 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
6003 bl
.append("EFere hiHI");
6004 ObjectWriteOperation op
;
6006 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
6010 bl
.append("DDDDD hiHI");
6011 ObjectWriteOperation op
;
6013 ASSERT_EQ(0, cache_ioctx
.operate("chunk4", &op
));
6017 bl
.append("EEEEE hiHI");
6018 ObjectWriteOperation op
;
6020 ASSERT_EQ(0, cache_ioctx
.operate("chunk5", &op
));
6023 // wait for maps to settle
6024 cluster
.wait_for_latest_osdmap();
6026 // create a snapshot, clone
6027 vector
<uint64_t> my_snaps(1);
6028 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6029 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6034 bl
.append("there hiHI");
6035 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6039 my_snaps
[1] = my_snaps
[0];
6040 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6041 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6046 bl
.append("thABe hiEF");
6047 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6051 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
6052 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk3", "foo");
6055 // foo head : [chunk1] [chunk3]
6057 ioctx
.snap_set_read(my_snaps
[1]);
6058 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk4", "foo");
6059 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, "chunk5", "foo");
6060 // foo snap[1]: [chunk4] [chunk5]
6062 // foo head : [chunk1] [chunk3]
6064 ioctx
.snap_set_read(my_snaps
[0]);
6065 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk2", "foo");
6066 // foo snap[1]: [chunk4] [chunk5]
6067 // foo snap[0]: [ chunk2 ]
6068 // foo head : [chunk1] [chunk3]
6070 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[1]));
6071 // foo snap[1]: [chunk4] [chunk5]
6072 // foo snap[0]: [ chunk2 ]
6073 // foo head : [chunk4] [chunk5] <-- will contain these contents
6076 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk1", 0);
6077 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk3", 0);
6079 ioctx
.selfmanaged_snap_remove(my_snaps
[1]);
6082 // foo snap[0]: [ chunk2 ]
6083 // foo head : [chunk4] [chunk5]
6084 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6085 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk4", 1);
6086 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk5", 1);
6090 bl
.append("thABe hiEF");
6091 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6094 // foo snap[0]: [ chunk2 ]
6096 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk1", 0);
6097 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk3", 0);
6098 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk4", 0);
6099 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk5", 0);
6100 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk2", 1);
6103 TEST_F(LibRadosTwoPoolsPP
, ManifestEvictRollback
) {
6104 // skip test if not yet pacific
6105 if (_get_required_osd_release(cluster
) < "pacific") {
6106 cout
<< "cluster is not yet pacific, skipping test" << std::endl
;
6113 bl
.append("CDere hiHI");
6114 ObjectWriteOperation op
;
6116 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6120 bl
.append("ABere hiHI");
6121 ObjectWriteOperation op
;
6123 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
6127 bl
.append("CDere hiHI");
6128 ObjectWriteOperation op
;
6130 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
6134 bl
.append("EFere hiHI");
6135 ObjectWriteOperation op
;
6137 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
6140 // wait for maps to settle
6141 cluster
.wait_for_latest_osdmap();
6143 // create a snapshot, clone
6144 vector
<uint64_t> my_snaps(1);
6145 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6146 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6151 bl
.append("there hiHI");
6152 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6157 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
6158 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk3", "foo");
6160 // foo head : [chunk1] [chunk3]
6162 ioctx
.snap_set_read(my_snaps
[0]);
6163 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk2", "foo");
6164 // foo snap[0]: [ chunk2 ]
6165 // foo head : [chunk1] [chunk3]
6168 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6169 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk1", 1);
6170 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk3", 1);
6173 ioctx
.snap_set_read(my_snaps
[0]);
6174 // evict--this makes the chunk missing state
6176 ObjectReadOperation op
, stat_op
;
6178 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6179 ASSERT_EQ(0, ioctx
.aio_operate(
6180 "foo", completion
, &op
,
6181 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
6182 completion
->wait_for_complete();
6183 ASSERT_EQ(0, completion
->get_return_value());
6186 // rollback to my_snaps[0]
6187 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[0]));
6189 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6192 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6193 ASSERT_EQ('C', bl
[0]);
6196 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk2", 1);
6199 class LibRadosTwoPoolsECPP
: public RadosTestECPP
6202 LibRadosTwoPoolsECPP() {};
6203 ~LibRadosTwoPoolsECPP() override
{};
6205 static void SetUpTestCase() {
6206 pool_name
= get_temp_pool_name();
6207 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, s_cluster
));
6209 static void TearDownTestCase() {
6210 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, s_cluster
));
6212 static std::string cache_pool_name
;
6214 void SetUp() override
{
6215 cache_pool_name
= get_temp_pool_name();
6216 ASSERT_EQ(0, s_cluster
.pool_create(cache_pool_name
.c_str()));
6217 RadosTestECPP::SetUp();
6219 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
6220 cache_ioctx
.application_enable("rados", true);
6221 cache_ioctx
.set_namespace(nspace
);
6223 void TearDown() override
{
6224 // flush + evict cache
6225 flush_evict_all(cluster
, cache_ioctx
);
6229 ASSERT_EQ(0, cluster
.mon_command(
6230 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
6233 ASSERT_EQ(0, cluster
.mon_command(
6234 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6235 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6238 // wait for maps to settle before next test
6239 cluster
.wait_for_latest_osdmap();
6241 RadosTestECPP::TearDown();
6243 cleanup_default_namespace(cache_ioctx
);
6244 cleanup_namespace(cache_ioctx
, nspace
);
6246 cache_ioctx
.close();
6247 ASSERT_EQ(0, s_cluster
.pool_delete(cache_pool_name
.c_str()));
6250 librados::IoCtx cache_ioctx
;
6253 std::string
LibRadosTwoPoolsECPP::cache_pool_name
;
6255 TEST_F(LibRadosTierECPP
, Dirty
) {
6257 ObjectWriteOperation op
;
6259 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still get 0 if it dne
6262 ObjectWriteOperation op
;
6264 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6269 ObjectReadOperation op
;
6270 op
.is_dirty(&dirty
, &r
);
6271 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
6276 ObjectWriteOperation op
;
6278 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6281 ObjectWriteOperation op
;
6283 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still 0 if already clean
6288 ObjectReadOperation op
;
6289 op
.is_dirty(&dirty
, &r
);
6290 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
6291 ASSERT_FALSE(dirty
);
6295 // ObjectWriteOperation op;
6296 // op.truncate(0); // still a write even tho it is a no-op
6297 // ASSERT_EQ(0, ioctx.operate("foo", &op));
6300 // bool dirty = false;
6302 // ObjectReadOperation op;
6303 // op.is_dirty(&dirty, &r);
6304 // ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
6305 // ASSERT_TRUE(dirty);
6310 TEST_F(LibRadosTwoPoolsECPP
, Overlay
) {
6315 ObjectWriteOperation op
;
6317 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6322 ObjectWriteOperation op
;
6324 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
6329 ASSERT_EQ(0, cluster
.mon_command(
6330 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6331 "\", \"tierpool\": \"" + cache_pool_name
+
6332 "\", \"force_nonempty\": \"--force-nonempty\" }",
6334 ASSERT_EQ(0, cluster
.mon_command(
6335 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6336 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6339 // wait for maps to settle
6340 cluster
.wait_for_latest_osdmap();
6342 // by default, the overlay sends us to cache pool
6345 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6346 ASSERT_EQ('c', bl
[0]);
6350 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
6351 ASSERT_EQ('c', bl
[0]);
6354 // unless we say otherwise
6357 ObjectReadOperation op
;
6358 op
.read(0, 1, &bl
, NULL
);
6359 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6360 ASSERT_EQ(0, ioctx
.aio_operate(
6361 "foo", completion
, &op
,
6362 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
6363 completion
->wait_for_complete();
6364 ASSERT_EQ(0, completion
->get_return_value());
6365 completion
->release();
6366 ASSERT_EQ('b', bl
[0]);
6370 TEST_F(LibRadosTwoPoolsECPP
, Promote
) {
6374 bl
.append("hi there");
6375 ObjectWriteOperation op
;
6377 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6382 ASSERT_EQ(0, cluster
.mon_command(
6383 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6384 "\", \"tierpool\": \"" + cache_pool_name
+
6385 "\", \"force_nonempty\": \"--force-nonempty\" }",
6387 ASSERT_EQ(0, cluster
.mon_command(
6388 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6389 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6391 ASSERT_EQ(0, cluster
.mon_command(
6392 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6393 "\", \"mode\": \"writeback\"}",
6396 // wait for maps to settle
6397 cluster
.wait_for_latest_osdmap();
6399 // read, trigger a promote
6402 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6405 // read, trigger a whiteout
6408 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6409 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6412 // verify the object is present in the cache tier
6414 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6415 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6416 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6418 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6420 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6424 TEST_F(LibRadosTwoPoolsECPP
, PromoteSnap
) {
6428 bl
.append("hi there");
6429 ObjectWriteOperation op
;
6431 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6435 bl
.append("hi there");
6436 ObjectWriteOperation op
;
6438 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6442 bl
.append("hi there");
6443 ObjectWriteOperation op
;
6445 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6449 bl
.append("hi there");
6450 ObjectWriteOperation op
;
6452 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6455 // create a snapshot, clone
6456 vector
<uint64_t> my_snaps(1);
6457 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6458 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6463 ObjectWriteOperation op
;
6465 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6470 ObjectWriteOperation op
;
6472 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6475 ObjectWriteOperation op
;
6477 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6482 ObjectWriteOperation op
;
6484 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6489 ASSERT_EQ(0, cluster
.mon_command(
6490 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6491 "\", \"tierpool\": \"" + cache_pool_name
+
6492 "\", \"force_nonempty\": \"--force-nonempty\" }",
6494 ASSERT_EQ(0, cluster
.mon_command(
6495 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6496 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6498 ASSERT_EQ(0, cluster
.mon_command(
6499 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6500 "\", \"mode\": \"writeback\"}",
6503 // wait for maps to settle
6504 cluster
.wait_for_latest_osdmap();
6506 // read, trigger a promote on the head
6509 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6510 ASSERT_EQ('c', bl
[0]);
6514 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
6515 ASSERT_EQ('c', bl
[0]);
6518 ioctx
.snap_set_read(my_snaps
[0]);
6520 // stop and scrub this pg (to make sure scrub can handle missing
6521 // clones in the cache tier)
6522 // This test requires cache tier and base tier to have the same pg_num/pgp_num
6524 for (int tries
= 0; tries
< 5; ++tries
) {
6526 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
6528 ASSERT_EQ(0, ioctx
.get_object_pg_hash_position2("foo", &hash
));
6530 ss
<< "{\"prefix\": \"pg scrub\", \"pgid\": \""
6531 << cache_ioctx
.get_id() << "."
6534 int r
= cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
6536 r
== -ENOENT
) { // in case mgr osdmap is a bit stale
6543 // give it a few seconds to go. this is sloppy but is usually enough time
6544 cout
<< "waiting for scrub..." << std::endl
;
6546 cout
<< "done waiting" << std::endl
;
6552 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6553 ASSERT_EQ('h', bl
[0]);
6559 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
6560 ASSERT_EQ('h', bl
[0]);
6566 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
6567 ASSERT_EQ('h', bl
[0]);
6570 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6575 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6576 ASSERT_EQ('c', bl
[0]);
6582 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
6583 ASSERT_EQ('c', bl
[0]);
6589 ASSERT_EQ(-ENOENT
, ioctx
.read("baz", bl
, 1, 0));
6593 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
6596 TEST_F(LibRadosTwoPoolsECPP
, PromoteSnapTrimRace
) {
6600 bl
.append("hi there");
6601 ObjectWriteOperation op
;
6603 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6606 // create a snapshot, clone
6607 vector
<uint64_t> my_snaps(1);
6608 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6609 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6614 ObjectWriteOperation op
;
6616 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6621 ASSERT_EQ(0, cluster
.mon_command(
6622 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6623 "\", \"tierpool\": \"" + cache_pool_name
+
6624 "\", \"force_nonempty\": \"--force-nonempty\" }",
6626 ASSERT_EQ(0, cluster
.mon_command(
6627 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6628 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6630 ASSERT_EQ(0, cluster
.mon_command(
6631 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6632 "\", \"mode\": \"writeback\"}",
6635 // wait for maps to settle
6636 cluster
.wait_for_latest_osdmap();
6639 ASSERT_EQ(0, ioctx
.selfmanaged_snap_remove(my_snaps
[0]));
6641 ioctx
.snap_set_read(my_snaps
[0]);
6643 // read foo snap. the OSD may or may not realize that this snap has
6644 // been logically deleted; either response is valid.
6647 int r
= ioctx
.read("foo", bl
, 1, 0);
6648 ASSERT_TRUE(r
== 1 || r
== -ENOENT
);
6652 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
6655 TEST_F(LibRadosTwoPoolsECPP
, Whiteout
) {
6659 bl
.append("hi there");
6660 ObjectWriteOperation op
;
6662 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6667 ASSERT_EQ(0, cluster
.mon_command(
6668 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6669 "\", \"tierpool\": \"" + cache_pool_name
+
6670 "\", \"force_nonempty\": \"--force-nonempty\" }",
6672 ASSERT_EQ(0, cluster
.mon_command(
6673 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6674 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6676 ASSERT_EQ(0, cluster
.mon_command(
6677 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6678 "\", \"mode\": \"writeback\"}",
6681 // wait for maps to settle
6682 cluster
.wait_for_latest_osdmap();
6684 // create some whiteouts, verify they behave
6686 ObjectWriteOperation op
;
6689 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6693 ObjectWriteOperation op
;
6696 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
6699 ObjectWriteOperation op
;
6702 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
6705 // verify the whiteouts are there in the cache tier
6707 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6708 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6709 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6711 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6713 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6716 // delete a whiteout and verify it goes away
6717 ASSERT_EQ(-ENOENT
, ioctx
.remove("foo"));
6719 ObjectWriteOperation op
;
6721 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6722 ASSERT_EQ(0, ioctx
.aio_operate("bar", completion
, &op
,
6723 librados::OPERATION_IGNORE_CACHE
));
6724 completion
->wait_for_complete();
6725 ASSERT_EQ(0, completion
->get_return_value());
6726 completion
->release();
6728 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6729 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6730 ASSERT_TRUE(it
->get_oid() == string("foo"));
6732 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6735 // recreate an object and verify we can read it
6738 bl
.append("hi there");
6739 ObjectWriteOperation op
;
6741 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6745 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6746 ASSERT_EQ('h', bl
[0]);
6750 TEST_F(LibRadosTwoPoolsECPP
, Evict
) {
6754 bl
.append("hi there");
6755 ObjectWriteOperation op
;
6757 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6762 ASSERT_EQ(0, cluster
.mon_command(
6763 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6764 "\", \"tierpool\": \"" + cache_pool_name
+
6765 "\", \"force_nonempty\": \"--force-nonempty\" }",
6767 ASSERT_EQ(0, cluster
.mon_command(
6768 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6769 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6771 ASSERT_EQ(0, cluster
.mon_command(
6772 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6773 "\", \"mode\": \"writeback\"}",
6776 // wait for maps to settle
6777 cluster
.wait_for_latest_osdmap();
6779 // read, trigger a promote
6782 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6785 // read, trigger a whiteout, and a dirty object
6788 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6789 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6790 ASSERT_EQ(0, ioctx
.write("bar", bl
, bl
.length(), 0));
6793 // verify the object is present in the cache tier
6795 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6796 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6797 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6799 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6801 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6806 ObjectWriteOperation op
;
6808 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6809 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
6810 completion
->wait_for_complete();
6811 ASSERT_EQ(0, completion
->get_return_value());
6812 completion
->release();
6815 // evict the pinned object with -EPERM
6817 ObjectReadOperation op
;
6819 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6820 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
6821 librados::OPERATION_IGNORE_CACHE
,
6823 completion
->wait_for_complete();
6824 ASSERT_EQ(-EPERM
, completion
->get_return_value());
6825 completion
->release();
6830 ObjectWriteOperation op
;
6832 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6833 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
6834 completion
->wait_for_complete();
6835 ASSERT_EQ(0, completion
->get_return_value());
6836 completion
->release();
6841 ObjectReadOperation op
;
6843 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6844 ASSERT_EQ(0, cache_ioctx
.aio_operate(
6845 "foo", completion
, &op
,
6846 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
6847 completion
->wait_for_complete();
6848 ASSERT_EQ(0, completion
->get_return_value());
6849 completion
->release();
6856 ObjectReadOperation op
;
6857 op
.is_dirty(&dirty
, &r
);
6858 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
6859 ASSERT_FALSE(dirty
);
6865 ObjectReadOperation op
;
6867 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6868 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
6869 librados::OPERATION_IGNORE_CACHE
,
6871 completion
->wait_for_complete();
6872 ASSERT_EQ(0, completion
->get_return_value());
6873 completion
->release();
6876 ObjectReadOperation op
;
6878 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6879 ASSERT_EQ(0, cache_ioctx
.aio_operate(
6880 "foo", completion
, &op
,
6881 librados::OPERATION_IGNORE_CACHE
, NULL
));
6882 completion
->wait_for_complete();
6883 ASSERT_EQ(0, completion
->get_return_value());
6884 completion
->release();
6887 ObjectReadOperation op
;
6889 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6890 ASSERT_EQ(0, cache_ioctx
.aio_operate(
6891 "bar", completion
, &op
,
6892 librados::OPERATION_IGNORE_CACHE
, NULL
));
6893 completion
->wait_for_complete();
6894 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
6895 completion
->release();
6899 TEST_F(LibRadosTwoPoolsECPP
, EvictSnap
) {
6903 bl
.append("hi there");
6904 ObjectWriteOperation op
;
6906 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6910 bl
.append("hi there");
6911 ObjectWriteOperation op
;
6913 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6917 bl
.append("hi there");
6918 ObjectWriteOperation op
;
6920 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6924 bl
.append("hi there");
6925 ObjectWriteOperation op
;
6927 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6930 // create a snapshot, clone
6931 vector
<uint64_t> my_snaps(1);
6932 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6933 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6938 ObjectWriteOperation op
;
6940 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6945 ObjectWriteOperation op
;
6947 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6950 ObjectWriteOperation op
;
6952 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6957 ObjectWriteOperation op
;
6959 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6964 ASSERT_EQ(0, cluster
.mon_command(
6965 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6966 "\", \"tierpool\": \"" + cache_pool_name
+
6967 "\", \"force_nonempty\": \"--force-nonempty\" }",
6969 ASSERT_EQ(0, cluster
.mon_command(
6970 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6971 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6973 ASSERT_EQ(0, cluster
.mon_command(
6974 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6975 "\", \"mode\": \"writeback\"}",
6978 // wait for maps to settle
6979 cluster
.wait_for_latest_osdmap();
6981 // read, trigger a promote on the head
6984 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6985 ASSERT_EQ('c', bl
[0]);
6989 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
6990 ASSERT_EQ('c', bl
[0]);
6995 ObjectReadOperation op
;
6997 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6998 ASSERT_EQ(0, cache_ioctx
.aio_operate(
6999 "bam", completion
, &op
,
7000 librados::OPERATION_IGNORE_CACHE
, NULL
));
7001 completion
->wait_for_complete();
7002 ASSERT_EQ(0, completion
->get_return_value());
7003 completion
->release();
7007 ObjectReadOperation op
;
7008 op
.read(1, 0, &bl
, NULL
);
7009 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7010 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7011 "bam", completion
, &op
,
7012 librados::OPERATION_IGNORE_CACHE
, NULL
));
7013 completion
->wait_for_complete();
7014 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
7015 completion
->release();
7019 ioctx
.snap_set_read(my_snaps
[0]);
7022 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7023 ASSERT_EQ('h', bl
[0]);
7028 ObjectReadOperation op
;
7030 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7031 ASSERT_EQ(0, ioctx
.aio_operate(
7032 "foo", completion
, &op
,
7033 librados::OPERATION_IGNORE_CACHE
, NULL
));
7034 completion
->wait_for_complete();
7035 ASSERT_EQ(0, completion
->get_return_value());
7036 completion
->release();
7041 ObjectReadOperation op
;
7042 op
.read(1, 0, &bl
, NULL
);
7043 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7044 ASSERT_EQ(0, ioctx
.aio_operate(
7045 "foo", completion
, &op
,
7046 librados::OPERATION_IGNORE_CACHE
, NULL
));
7047 completion
->wait_for_complete();
7048 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
7049 completion
->release();
7051 // head is still there...
7052 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7055 ObjectReadOperation op
;
7056 op
.read(1, 0, &bl
, NULL
);
7057 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7058 ASSERT_EQ(0, ioctx
.aio_operate(
7059 "foo", completion
, &op
,
7060 librados::OPERATION_IGNORE_CACHE
, NULL
));
7061 completion
->wait_for_complete();
7062 ASSERT_EQ(0, completion
->get_return_value());
7063 completion
->release();
7066 // promote head + snap of bar
7067 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7070 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
7071 ASSERT_EQ('c', bl
[0]);
7073 ioctx
.snap_set_read(my_snaps
[0]);
7076 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
7077 ASSERT_EQ('h', bl
[0]);
7080 // evict bar head (fail)
7081 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7083 ObjectReadOperation op
;
7085 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7086 ASSERT_EQ(0, ioctx
.aio_operate(
7087 "bar", completion
, &op
,
7088 librados::OPERATION_IGNORE_CACHE
, NULL
));
7089 completion
->wait_for_complete();
7090 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
7091 completion
->release();
7095 ioctx
.snap_set_read(my_snaps
[0]);
7097 ObjectReadOperation op
;
7099 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7100 ASSERT_EQ(0, ioctx
.aio_operate(
7101 "bar", completion
, &op
,
7102 librados::OPERATION_IGNORE_CACHE
, NULL
));
7103 completion
->wait_for_complete();
7104 ASSERT_EQ(0, completion
->get_return_value());
7105 completion
->release();
7108 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7111 ObjectReadOperation op
;
7112 op
.read(1, 0, &bl
, NULL
);
7113 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7114 ASSERT_EQ(0, ioctx
.aio_operate(
7115 "bar", completion
, &op
,
7116 librados::OPERATION_IGNORE_CACHE
, NULL
));
7117 completion
->wait_for_complete();
7118 ASSERT_EQ(0, completion
->get_return_value());
7119 completion
->release();
7122 ObjectReadOperation op
;
7124 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7125 ASSERT_EQ(0, ioctx
.aio_operate(
7126 "bar", completion
, &op
,
7127 librados::OPERATION_IGNORE_CACHE
, NULL
));
7128 completion
->wait_for_complete();
7129 ASSERT_EQ(0, completion
->get_return_value());
7130 completion
->release();
7134 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
7137 TEST_F(LibRadosTwoPoolsECPP
, TryFlush
) {
7140 ASSERT_EQ(0, cluster
.mon_command(
7141 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7142 "\", \"tierpool\": \"" + cache_pool_name
+
7143 "\", \"force_nonempty\": \"--force-nonempty\" }",
7145 ASSERT_EQ(0, cluster
.mon_command(
7146 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7147 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7149 ASSERT_EQ(0, cluster
.mon_command(
7150 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7151 "\", \"mode\": \"writeback\"}",
7154 // wait for maps to settle
7155 cluster
.wait_for_latest_osdmap();
7160 bl
.append("hi there");
7161 ObjectWriteOperation op
;
7163 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7166 // verify the object is present in the cache tier
7168 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7169 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7170 ASSERT_TRUE(it
->get_oid() == string("foo"));
7172 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7175 // verify the object is NOT present in the base tier
7177 NObjectIterator it
= ioctx
.nobjects_begin();
7178 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7185 ObjectReadOperation op
;
7186 op
.is_dirty(&dirty
, &r
);
7187 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7194 ObjectWriteOperation op
;
7196 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7197 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7198 completion
->wait_for_complete();
7199 ASSERT_EQ(0, completion
->get_return_value());
7200 completion
->release();
7203 // flush the pinned object with -EPERM
7205 ObjectReadOperation op
;
7206 op
.cache_try_flush();
7207 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7208 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7209 "foo", completion
, &op
,
7210 librados::OPERATION_IGNORE_OVERLAY
|
7211 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7212 completion
->wait_for_complete();
7213 ASSERT_EQ(-EPERM
, completion
->get_return_value());
7214 completion
->release();
7219 ObjectWriteOperation op
;
7221 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7222 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7223 completion
->wait_for_complete();
7224 ASSERT_EQ(0, completion
->get_return_value());
7225 completion
->release();
7230 ObjectReadOperation op
;
7231 op
.cache_try_flush();
7232 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7233 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7234 "foo", completion
, &op
,
7235 librados::OPERATION_IGNORE_OVERLAY
|
7236 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7237 completion
->wait_for_complete();
7238 ASSERT_EQ(0, completion
->get_return_value());
7239 completion
->release();
7246 ObjectReadOperation op
;
7247 op
.is_dirty(&dirty
, &r
);
7248 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7249 ASSERT_FALSE(dirty
);
7253 // verify in base tier
7255 NObjectIterator it
= ioctx
.nobjects_begin();
7256 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
7257 ASSERT_TRUE(it
->get_oid() == string("foo"));
7259 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7264 ObjectReadOperation op
;
7266 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7267 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7268 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7269 completion
->wait_for_complete();
7270 ASSERT_EQ(0, completion
->get_return_value());
7271 completion
->release();
7274 // verify no longer in cache tier
7276 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7277 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7281 TEST_F(LibRadosTwoPoolsECPP
, FailedFlush
) {
7284 ASSERT_EQ(0, cluster
.mon_command(
7285 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7286 "\", \"tierpool\": \"" + cache_pool_name
+
7287 "\", \"force_nonempty\": \"--force-nonempty\" }",
7289 ASSERT_EQ(0, cluster
.mon_command(
7290 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7291 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7293 ASSERT_EQ(0, cluster
.mon_command(
7294 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7295 "\", \"mode\": \"writeback\"}",
7298 // wait for maps to settle
7299 cluster
.wait_for_latest_osdmap();
7304 bl
.append("hi there");
7305 ObjectWriteOperation op
;
7307 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7310 // verify the object is present in the cache tier
7312 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7313 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7314 ASSERT_TRUE(it
->get_oid() == string("foo"));
7316 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7319 // verify the object is NOT present in the base tier
7321 NObjectIterator it
= ioctx
.nobjects_begin();
7322 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7327 ObjectWriteOperation op
;
7328 std::map
<std::string
, bufferlist
> omap
;
7329 omap
["somekey"] = bufferlist();
7331 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7332 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7333 completion
->wait_for_complete();
7334 ASSERT_EQ(0, completion
->get_return_value());
7335 completion
->release();
7340 ObjectReadOperation op
;
7342 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7343 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7344 "foo", completion
, &op
,
7345 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7346 completion
->wait_for_complete();
7347 ASSERT_NE(0, completion
->get_return_value());
7348 completion
->release();
7353 ObjectReadOperation op
;
7356 std::set
<std::string
> keys
;
7357 keys
.insert("somekey");
7358 std::map
<std::string
, bufferlist
> map
;
7360 op
.omap_get_vals_by_keys(keys
, &map
, &prval
);
7361 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7362 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
, &bl
));
7364 bool completed
= completion
->is_complete();
7366 cache_ioctx
.aio_cancel(completion
);
7367 std::cerr
<< "Most probably test case will hang here, please reset manually" << std::endl
;
7368 ASSERT_TRUE(completed
); //in fact we are locked forever at test case shutdown unless fix for http://tracker.ceph.com/issues/14511 is applied. Seems there is no workaround for that
7370 completion
->release();
7372 // verify still not in base tier
7374 ASSERT_TRUE(ioctx
.nobjects_begin() == ioctx
.nobjects_end());
7378 ObjectWriteOperation op
;
7380 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7384 ObjectReadOperation op
;
7386 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7387 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7388 "foo", completion
, &op
,
7389 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7390 completion
->wait_for_complete();
7391 ASSERT_EQ(0, completion
->get_return_value());
7392 completion
->release();
7396 ObjectReadOperation op
;
7398 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7399 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7400 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7401 completion
->wait_for_complete();
7402 ASSERT_EQ(0, completion
->get_return_value());
7403 completion
->release();
7406 // verify no longer in cache tier
7408 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7409 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7413 NObjectIterator it
= ioctx
.nobjects_begin();
7414 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7418 TEST_F(LibRadosTwoPoolsECPP
, Flush
) {
7421 ASSERT_EQ(0, cluster
.mon_command(
7422 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7423 "\", \"tierpool\": \"" + cache_pool_name
+
7424 "\", \"force_nonempty\": \"--force-nonempty\" }",
7426 ASSERT_EQ(0, cluster
.mon_command(
7427 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7428 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7430 ASSERT_EQ(0, cluster
.mon_command(
7431 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7432 "\", \"mode\": \"writeback\"}",
7435 // wait for maps to settle
7436 cluster
.wait_for_latest_osdmap();
7438 uint64_t user_version
= 0;
7443 bl
.append("hi there");
7444 ObjectWriteOperation op
;
7446 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7449 // verify the object is present in the cache tier
7451 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7452 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7453 ASSERT_TRUE(it
->get_oid() == string("foo"));
7455 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7458 // verify the object is NOT present in the base tier
7460 NObjectIterator it
= ioctx
.nobjects_begin();
7461 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7468 ObjectReadOperation op
;
7469 op
.is_dirty(&dirty
, &r
);
7470 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7473 user_version
= cache_ioctx
.get_last_version();
7478 ObjectWriteOperation op
;
7480 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7481 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7482 completion
->wait_for_complete();
7483 ASSERT_EQ(0, completion
->get_return_value());
7484 completion
->release();
7487 // flush the pinned object with -EPERM
7489 ObjectReadOperation op
;
7490 op
.cache_try_flush();
7491 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7492 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7493 "foo", completion
, &op
,
7494 librados::OPERATION_IGNORE_OVERLAY
|
7495 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7496 completion
->wait_for_complete();
7497 ASSERT_EQ(-EPERM
, completion
->get_return_value());
7498 completion
->release();
7503 ObjectWriteOperation op
;
7505 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7506 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7507 completion
->wait_for_complete();
7508 ASSERT_EQ(0, completion
->get_return_value());
7509 completion
->release();
7514 ObjectReadOperation op
;
7516 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7517 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7518 "foo", completion
, &op
,
7519 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7520 completion
->wait_for_complete();
7521 ASSERT_EQ(0, completion
->get_return_value());
7522 completion
->release();
7529 ObjectReadOperation op
;
7530 op
.is_dirty(&dirty
, &r
);
7531 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7532 ASSERT_FALSE(dirty
);
7536 // verify in base tier
7538 NObjectIterator it
= ioctx
.nobjects_begin();
7539 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
7540 ASSERT_TRUE(it
->get_oid() == string("foo"));
7542 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7547 ObjectReadOperation op
;
7549 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7550 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7551 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7552 completion
->wait_for_complete();
7553 ASSERT_EQ(0, completion
->get_return_value());
7554 completion
->release();
7557 // verify no longer in cache tier
7559 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7560 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7563 // read it again and verify the version is consistent
7566 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
7567 ASSERT_EQ(user_version
, cache_ioctx
.get_last_version());
7572 ObjectWriteOperation op
;
7574 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7579 ObjectReadOperation op
;
7581 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7582 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7583 "foo", completion
, &op
,
7584 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7585 completion
->wait_for_complete();
7586 ASSERT_EQ(0, completion
->get_return_value());
7587 completion
->release();
7592 ObjectReadOperation op
;
7594 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7595 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7596 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7597 completion
->wait_for_complete();
7598 ASSERT_EQ(0, completion
->get_return_value());
7599 completion
->release();
7602 // verify no longer in cache tier
7604 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7605 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7609 NObjectIterator it
= ioctx
.nobjects_begin();
7610 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7614 TEST_F(LibRadosTwoPoolsECPP
, FlushSnap
) {
7617 ASSERT_EQ(0, cluster
.mon_command(
7618 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7619 "\", \"tierpool\": \"" + cache_pool_name
+
7620 "\", \"force_nonempty\": \"--force-nonempty\" }",
7622 ASSERT_EQ(0, cluster
.mon_command(
7623 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7624 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7626 ASSERT_EQ(0, cluster
.mon_command(
7627 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7628 "\", \"mode\": \"writeback\"}",
7631 // wait for maps to settle
7632 cluster
.wait_for_latest_osdmap();
7638 ObjectWriteOperation op
;
7640 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7643 // create a snapshot, clone
7644 vector
<uint64_t> my_snaps(1);
7645 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
7646 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
7651 ObjectWriteOperation op
;
7653 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7658 my_snaps
[1] = my_snaps
[0];
7659 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
7660 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
7665 ObjectWriteOperation op
;
7667 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7670 // verify the object is present in the cache tier
7672 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7673 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7674 ASSERT_TRUE(it
->get_oid() == string("foo"));
7676 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7679 // verify the object is NOT present in the base tier
7681 NObjectIterator it
= ioctx
.nobjects_begin();
7682 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7685 // flush on head (should fail)
7686 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7688 ObjectReadOperation op
;
7690 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7691 ASSERT_EQ(0, ioctx
.aio_operate(
7692 "foo", completion
, &op
,
7693 librados::OPERATION_IGNORE_CACHE
, NULL
));
7694 completion
->wait_for_complete();
7695 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
7696 completion
->release();
7698 // flush on recent snap (should fail)
7699 ioctx
.snap_set_read(my_snaps
[0]);
7701 ObjectReadOperation op
;
7703 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7704 ASSERT_EQ(0, ioctx
.aio_operate(
7705 "foo", completion
, &op
,
7706 librados::OPERATION_IGNORE_CACHE
, NULL
));
7707 completion
->wait_for_complete();
7708 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
7709 completion
->release();
7711 // flush on oldest snap
7712 ioctx
.snap_set_read(my_snaps
[1]);
7714 ObjectReadOperation op
;
7716 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7717 ASSERT_EQ(0, ioctx
.aio_operate(
7718 "foo", completion
, &op
,
7719 librados::OPERATION_IGNORE_CACHE
, NULL
));
7720 completion
->wait_for_complete();
7721 ASSERT_EQ(0, completion
->get_return_value());
7722 completion
->release();
7724 // flush on next oldest snap
7725 ioctx
.snap_set_read(my_snaps
[0]);
7727 ObjectReadOperation op
;
7729 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7730 ASSERT_EQ(0, ioctx
.aio_operate(
7731 "foo", completion
, &op
,
7732 librados::OPERATION_IGNORE_CACHE
, NULL
));
7733 completion
->wait_for_complete();
7734 ASSERT_EQ(0, completion
->get_return_value());
7735 completion
->release();
7738 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7740 ObjectReadOperation op
;
7742 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7743 ASSERT_EQ(0, ioctx
.aio_operate(
7744 "foo", completion
, &op
,
7745 librados::OPERATION_IGNORE_CACHE
, NULL
));
7746 completion
->wait_for_complete();
7747 ASSERT_EQ(0, completion
->get_return_value());
7748 completion
->release();
7751 // verify i can read the snaps from the cache pool
7752 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7755 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7756 ASSERT_EQ('c', bl
[0]);
7758 ioctx
.snap_set_read(my_snaps
[0]);
7761 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7762 ASSERT_EQ('b', bl
[0]);
7764 ioctx
.snap_set_read(my_snaps
[1]);
7767 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7768 ASSERT_EQ('a', bl
[0]);
7772 ASSERT_EQ(0, cluster
.mon_command(
7773 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
7777 // wait for maps to settle
7778 cluster
.wait_for_latest_osdmap();
7780 // verify i can read the snaps from the base pool
7781 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7784 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7785 ASSERT_EQ('c', bl
[0]);
7787 ioctx
.snap_set_read(my_snaps
[0]);
7790 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7791 ASSERT_EQ('b', bl
[0]);
7793 ioctx
.snap_set_read(my_snaps
[1]);
7796 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7797 ASSERT_EQ('a', bl
[0]);
7800 ASSERT_EQ(0, cluster
.mon_command(
7801 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7802 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7804 cluster
.wait_for_latest_osdmap();
7807 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
7810 TEST_F(LibRadosTierECPP
, FlushWriteRaces
) {
7812 std::string pool_name
= get_temp_pool_name();
7813 std::string cache_pool_name
= pool_name
+ "-cache";
7814 ASSERT_EQ("", create_one_pool_pp(pool_name
, cluster
));
7815 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
7817 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
7818 cache_ioctx
.application_enable("rados", true);
7820 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
7824 ASSERT_EQ(0, cluster
.mon_command(
7825 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7826 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
7828 ASSERT_EQ(0, cluster
.mon_command(
7829 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7830 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7832 ASSERT_EQ(0, cluster
.mon_command(
7833 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7834 "\", \"mode\": \"writeback\"}",
7837 // wait for maps to settle
7838 cluster
.wait_for_latest_osdmap();
7840 // create/dirty object
7842 bl
.append("hi there");
7844 ObjectWriteOperation op
;
7846 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7851 ObjectReadOperation op
;
7853 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7854 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7855 "foo", completion
, &op
,
7856 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7858 ObjectWriteOperation op2
;
7860 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
7861 ASSERT_EQ(0, ioctx
.aio_operate(
7862 "foo", completion2
, &op2
, 0));
7864 completion
->wait_for_complete();
7865 completion2
->wait_for_complete();
7866 ASSERT_EQ(0, completion
->get_return_value());
7867 ASSERT_EQ(0, completion2
->get_return_value());
7868 completion
->release();
7869 completion2
->release();
7874 // create/dirty object
7877 bl
.append("hi there");
7878 ObjectWriteOperation op
;
7880 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7883 // try-flush + write
7885 ObjectReadOperation op
;
7886 op
.cache_try_flush();
7887 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7888 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7889 "foo", completion
, &op
,
7890 librados::OPERATION_IGNORE_OVERLAY
|
7891 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7893 ObjectWriteOperation op2
;
7895 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
7896 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion2
, &op2
, 0));
7898 completion
->wait_for_complete();
7899 completion2
->wait_for_complete();
7900 int r
= completion
->get_return_value();
7901 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
7902 ASSERT_EQ(0, completion2
->get_return_value());
7903 completion
->release();
7904 completion2
->release();
7907 cout
<< "didn't get EBUSY, trying again" << std::endl
;
7909 ASSERT_TRUE(--tries
);
7913 ASSERT_EQ(0, cluster
.mon_command(
7914 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
7917 ASSERT_EQ(0, cluster
.mon_command(
7918 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
7919 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
7922 // wait for maps to settle before next test
7923 cluster
.wait_for_latest_osdmap();
7925 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
7926 ASSERT_EQ(0, destroy_one_pool_pp(pool_name
, cluster
));
7929 TEST_F(LibRadosTwoPoolsECPP
, FlushTryFlushRaces
) {
7932 ASSERT_EQ(0, cluster
.mon_command(
7933 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7934 "\", \"tierpool\": \"" + cache_pool_name
+
7935 "\", \"force_nonempty\": \"--force-nonempty\" }",
7937 ASSERT_EQ(0, cluster
.mon_command(
7938 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7939 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7941 ASSERT_EQ(0, cluster
.mon_command(
7942 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7943 "\", \"mode\": \"writeback\"}",
7946 // wait for maps to settle
7947 cluster
.wait_for_latest_osdmap();
7949 // create/dirty object
7952 bl
.append("hi there");
7953 ObjectWriteOperation op
;
7955 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7960 ObjectReadOperation op
;
7962 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7963 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7964 "foo", completion
, &op
,
7965 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7967 ObjectReadOperation op2
;
7969 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
7970 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7971 "foo", completion2
, &op2
,
7972 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7974 completion
->wait_for_complete();
7975 completion2
->wait_for_complete();
7976 ASSERT_EQ(0, completion
->get_return_value());
7977 ASSERT_EQ(0, completion2
->get_return_value());
7978 completion
->release();
7979 completion2
->release();
7982 // create/dirty object
7985 bl
.append("hi there");
7986 ObjectWriteOperation op
;
7988 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7991 // flush + try-flush
7993 ObjectReadOperation op
;
7995 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7996 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7997 "foo", completion
, &op
,
7998 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
8000 ObjectReadOperation op2
;
8001 op2
.cache_try_flush();
8002 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
8003 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8004 "foo", completion2
, &op2
,
8005 librados::OPERATION_IGNORE_OVERLAY
|
8006 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8008 completion
->wait_for_complete();
8009 completion2
->wait_for_complete();
8010 ASSERT_EQ(0, completion
->get_return_value());
8011 ASSERT_EQ(0, completion2
->get_return_value());
8012 completion
->release();
8013 completion2
->release();
8016 // create/dirty object
8021 bl
.append("hi there");
8022 ObjectWriteOperation op
;
8024 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8027 // try-flush + flush
8028 // (flush will not piggyback on try-flush)
8030 ObjectReadOperation op
;
8031 op
.cache_try_flush();
8032 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8033 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8034 "foo", completion
, &op
,
8035 librados::OPERATION_IGNORE_OVERLAY
|
8036 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8038 ObjectReadOperation op2
;
8040 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
8041 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8042 "foo", completion2
, &op2
,
8043 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
8045 completion
->wait_for_complete();
8046 completion2
->wait_for_complete();
8047 int r
= completion
->get_return_value();
8048 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
8049 ASSERT_EQ(0, completion2
->get_return_value());
8050 completion
->release();
8051 completion2
->release();
8054 cout
<< "didn't get EBUSY, trying again" << std::endl
;
8056 ASSERT_TRUE(--tries
);
8059 // create/dirty object
8062 bl
.append("hi there");
8063 ObjectWriteOperation op
;
8065 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8068 // try-flush + try-flush
8070 ObjectReadOperation op
;
8071 op
.cache_try_flush();
8072 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8073 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8074 "foo", completion
, &op
,
8075 librados::OPERATION_IGNORE_OVERLAY
|
8076 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8078 ObjectReadOperation op2
;
8079 op2
.cache_try_flush();
8080 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
8081 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8082 "foo", completion2
, &op2
,
8083 librados::OPERATION_IGNORE_OVERLAY
|
8084 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8086 completion
->wait_for_complete();
8087 completion2
->wait_for_complete();
8088 ASSERT_EQ(0, completion
->get_return_value());
8089 ASSERT_EQ(0, completion2
->get_return_value());
8090 completion
->release();
8091 completion2
->release();
8095 TEST_F(LibRadosTwoPoolsECPP
, TryFlushReadRace
) {
8098 ASSERT_EQ(0, cluster
.mon_command(
8099 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8100 "\", \"tierpool\": \"" + cache_pool_name
+
8101 "\", \"force_nonempty\": \"--force-nonempty\" }",
8103 ASSERT_EQ(0, cluster
.mon_command(
8104 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8105 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8107 ASSERT_EQ(0, cluster
.mon_command(
8108 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8109 "\", \"mode\": \"writeback\"}",
8112 // wait for maps to settle
8113 cluster
.wait_for_latest_osdmap();
8115 // create/dirty object
8118 bl
.append("hi there");
8119 bufferptr
bp(4000000); // make it big!
8122 ObjectWriteOperation op
;
8124 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8127 // start a continuous stream of reads
8128 read_ioctx
= &ioctx
;
8130 for (int i
= 0; i
< max_reads
; ++i
) {
8137 ObjectReadOperation op
;
8138 op
.cache_try_flush();
8139 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8140 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8141 "foo", completion
, &op
,
8142 librados::OPERATION_IGNORE_OVERLAY
|
8143 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8145 completion
->wait_for_complete();
8146 ASSERT_EQ(0, completion
->get_return_value());
8147 completion
->release();
8150 std::unique_lock locker
{test_lock
};
8152 cond
.wait(locker
, [] { return num_reads
== 0;});
8155 TEST_F(LibRadosTierECPP
, CallForcesPromote
) {
8157 std::string pool_name
= get_temp_pool_name();
8158 std::string cache_pool_name
= pool_name
+ "-cache";
8159 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, cluster
));
8160 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
8162 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
8163 cache_ioctx
.application_enable("rados", true);
8165 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
8169 ASSERT_EQ(0, cluster
.mon_command(
8170 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8171 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8173 ASSERT_EQ(0, cluster
.mon_command(
8174 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8175 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8177 ASSERT_EQ(0, cluster
.mon_command(
8178 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8179 "\", \"mode\": \"writeback\"}",
8182 // set things up such that the op would normally be proxied
8183 ASSERT_EQ(0, cluster
.mon_command(
8184 set_pool_str(cache_pool_name
, "hit_set_count", 2),
8186 ASSERT_EQ(0, cluster
.mon_command(
8187 set_pool_str(cache_pool_name
, "hit_set_period", 600),
8189 ASSERT_EQ(0, cluster
.mon_command(
8190 set_pool_str(cache_pool_name
, "hit_set_type",
8193 ASSERT_EQ(0, cluster
.mon_command(
8194 set_pool_str(cache_pool_name
, "min_read_recency_for_promote",
8198 // wait for maps to settle
8199 cluster
.wait_for_latest_osdmap();
8201 // create/dirty object
8203 bl
.append("hi there");
8205 ObjectWriteOperation op
;
8207 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8212 ObjectReadOperation op
;
8214 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8215 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8216 "foo", completion
, &op
,
8217 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
8218 completion
->wait_for_complete();
8219 ASSERT_EQ(0, completion
->get_return_value());
8220 completion
->release();
8225 ObjectReadOperation op
;
8227 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8228 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
8229 librados::OPERATION_IGNORE_CACHE
,
8231 completion
->wait_for_complete();
8232 ASSERT_EQ(0, completion
->get_return_value());
8233 completion
->release();
8238 ObjectReadOperation op
;
8240 op
.exec("rbd", "get_id", bl
);
8242 // should get EIO (not an rbd object), not -EOPNOTSUPP (we didn't promote)
8243 ASSERT_EQ(-5, ioctx
.operate("foo", &op
, &out
));
8246 // make sure foo is back in the cache tier
8248 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8249 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
8250 ASSERT_TRUE(it
->get_oid() == string("foo"));
8252 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
8256 ASSERT_EQ(0, cluster
.mon_command(
8257 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8260 ASSERT_EQ(0, cluster
.mon_command(
8261 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8262 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8265 // wait for maps to settle before next test
8266 cluster
.wait_for_latest_osdmap();
8268 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
8269 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, cluster
));
8272 TEST_F(LibRadosTierECPP
, HitSetNone
) {
8274 list
< pair
<time_t,time_t> > ls
;
8275 AioCompletion
*c
= librados::Rados::aio_create_completion();
8276 ASSERT_EQ(0, ioctx
.hit_set_list(123, c
, &ls
));
8277 c
->wait_for_complete();
8278 ASSERT_EQ(0, c
->get_return_value());
8279 ASSERT_TRUE(ls
.empty());
8284 AioCompletion
*c
= librados::Rados::aio_create_completion();
8285 ASSERT_EQ(0, ioctx
.hit_set_get(123, c
, 12345, &bl
));
8286 c
->wait_for_complete();
8287 ASSERT_EQ(-ENOENT
, c
->get_return_value());
8292 TEST_F(LibRadosTwoPoolsECPP
, HitSetRead
) {
8295 ASSERT_EQ(0, cluster
.mon_command(
8296 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8297 "\", \"tierpool\": \"" + cache_pool_name
+
8298 "\", \"force_nonempty\": \"--force-nonempty\" }",
8301 // enable hitset tracking for this pool
8302 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", 2),
8304 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", 600),
8306 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type",
8310 // wait for maps to settle
8311 cluster
.wait_for_latest_osdmap();
8313 cache_ioctx
.set_namespace("");
8315 // keep reading until we see our object appear in the HitSet
8316 utime_t start
= ceph_clock_now();
8317 utime_t hard_stop
= start
+ utime_t(600, 0);
8320 utime_t now
= ceph_clock_now();
8321 ASSERT_TRUE(now
< hard_stop
);
8323 string name
= "foo";
8325 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
8326 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
,
8327 cluster
.pool_lookup(cache_pool_name
.c_str()), "");
8330 ASSERT_EQ(-ENOENT
, cache_ioctx
.read("foo", bl
, 1, 0));
8333 AioCompletion
*c
= librados::Rados::aio_create_completion();
8334 ASSERT_EQ(0, cache_ioctx
.hit_set_get(hash
, c
, now
.sec(), &hbl
));
8335 c
->wait_for_complete();
8339 auto p
= hbl
.cbegin();
8342 if (hs
.contains(oid
)) {
8343 cout
<< "ok, hit_set contains " << oid
<< std::endl
;
8346 cout
<< "hmm, not in HitSet yet" << std::endl
;
8348 cout
<< "hmm, no HitSet yet" << std::endl
;
8355 // disable this test until hitset-get reliably works on EC pools
8357 TEST_F(LibRadosTierECPP
, HitSetWrite
) {
8358 int num_pg
= _get_pg_num(cluster
, pool_name
);
8359 ceph_assert(num_pg
> 0);
8361 // enable hitset tracking for this pool
8363 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_count", 8),
8365 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_period", 600),
8367 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_type",
8371 // wait for maps to settle
8372 cluster
.wait_for_latest_osdmap();
8374 ioctx
.set_namespace("");
8376 // do a bunch of writes
8377 for (int i
=0; i
<1000; ++i
) {
8380 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, 1, 0));
8384 std::map
<int,HitSet
> hitsets
;
8385 for (int i
=0; i
<num_pg
; ++i
) {
8386 list
< pair
<time_t,time_t> > ls
;
8387 AioCompletion
*c
= librados::Rados::aio_create_completion();
8388 ASSERT_EQ(0, ioctx
.hit_set_list(i
, c
, &ls
));
8389 c
->wait_for_complete();
8391 std::cout
<< "pg " << i
<< " ls " << ls
<< std::endl
;
8392 ASSERT_FALSE(ls
.empty());
8395 c
= librados::Rados::aio_create_completion();
8397 ASSERT_EQ(0, ioctx
.hit_set_get(i
, c
, ls
.back().first
, &bl
));
8398 c
->wait_for_complete();
8401 //std::cout << "bl len is " << bl.length() << "\n";
8402 //bl.hexdump(std::cout);
8403 //std::cout << std::endl;
8405 auto p
= bl
.cbegin();
8406 decode(hitsets
[i
], p
);
8408 // cope with racing splits by refreshing pg_num
8409 if (i
== num_pg
- 1)
8410 num_pg
= _get_pg_num(cluster
, pool_name
);
8413 for (int i
=0; i
<1000; ++i
) {
8414 string n
= stringify(i
);
8415 uint32_t hash
= ioctx
.get_object_hash_position(n
);
8416 hobject_t
oid(sobject_t(n
, CEPH_NOSNAP
), "", hash
,
8417 cluster
.pool_lookup(pool_name
.c_str()), "");
8418 std::cout
<< "checking for " << oid
<< std::endl
;
8420 for (int p
=0; p
<num_pg
; ++p
) {
8421 if (hitsets
[p
].contains(oid
)) {
8431 TEST_F(LibRadosTwoPoolsECPP
, HitSetTrim
) {
8433 unsigned period
= 3;
8437 ASSERT_EQ(0, cluster
.mon_command(
8438 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8439 "\", \"tierpool\": \"" + cache_pool_name
+
8440 "\", \"force_nonempty\": \"--force-nonempty\" }",
8443 // enable hitset tracking for this pool
8444 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", count
),
8446 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", period
),
8448 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
8450 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_fpp", ".01"),
8453 // wait for maps to settle
8454 cluster
.wait_for_latest_osdmap();
8456 cache_ioctx
.set_namespace("");
8458 // do a bunch of writes and make sure the hitsets rotate
8459 utime_t start
= ceph_clock_now();
8460 utime_t hard_stop
= start
+ utime_t(count
* period
* 50, 0);
8463 int bsize
= alignment
;
8464 char *buf
= (char *)new char[bsize
];
8465 memset(buf
, 'f', bsize
);
8468 string name
= "foo";
8470 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
8471 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
, -1, "");
8474 bl
.append(buf
, bsize
);
8475 ASSERT_EQ(0, cache_ioctx
.append("foo", bl
, bsize
));
8477 list
<pair
<time_t, time_t> > ls
;
8478 AioCompletion
*c
= librados::Rados::aio_create_completion();
8479 ASSERT_EQ(0, cache_ioctx
.hit_set_list(hash
, c
, &ls
));
8480 c
->wait_for_complete();
8483 cout
<< " got ls " << ls
<< std::endl
;
8486 first
= ls
.front().first
;
8487 cout
<< "first is " << first
<< std::endl
;
8489 if (ls
.front().first
!= first
) {
8490 cout
<< "first now " << ls
.front().first
<< ", trimmed" << std::endl
;
8496 utime_t now
= ceph_clock_now();
8497 ASSERT_TRUE(now
< hard_stop
);
8504 TEST_F(LibRadosTwoPoolsECPP
, PromoteOn2ndRead
) {
8506 for (int i
=0; i
<20; ++i
) {
8508 bl
.append("hi there");
8509 ObjectWriteOperation op
;
8511 ASSERT_EQ(0, ioctx
.operate("foo" + stringify(i
), &op
));
8516 ASSERT_EQ(0, cluster
.mon_command(
8517 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8518 "\", \"tierpool\": \"" + cache_pool_name
+
8519 "\", \"force_nonempty\": \"--force-nonempty\" }",
8521 ASSERT_EQ(0, cluster
.mon_command(
8522 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8523 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8525 ASSERT_EQ(0, cluster
.mon_command(
8526 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8527 "\", \"mode\": \"writeback\"}",
8530 // enable hitset tracking for this pool
8531 ASSERT_EQ(0, cluster
.mon_command(
8532 set_pool_str(cache_pool_name
, "hit_set_count", 2),
8534 ASSERT_EQ(0, cluster
.mon_command(
8535 set_pool_str(cache_pool_name
, "hit_set_period", 600),
8537 ASSERT_EQ(0, cluster
.mon_command(
8538 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
8540 ASSERT_EQ(0, cluster
.mon_command(
8541 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
8543 ASSERT_EQ(0, cluster
.mon_command(
8544 set_pool_str(cache_pool_name
, "hit_set_grade_decay_rate", 20),
8546 ASSERT_EQ(0, cluster
.mon_command(
8547 set_pool_str(cache_pool_name
, "hit_set_search_last_n", 1),
8550 // wait for maps to settle
8551 cluster
.wait_for_latest_osdmap();
8553 int fake
= 0; // set this to non-zero to test spurious promotion,
8554 // e.g. from thrashing
8558 // 1st read, don't trigger a promote
8559 obj
= "foo" + stringify(attempt
);
8560 cout
<< obj
<< std::endl
;
8563 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
8566 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
8571 // verify the object is NOT present in the cache tier
8574 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8575 while (it
!= cache_ioctx
.nobjects_end()) {
8576 cout
<< " see " << it
->get_oid() << std::endl
;
8577 if (it
->get_oid() == string(obj
.c_str())) {
8588 ASSERT_LE(attempt
, 20);
8589 cout
<< "hrm, object is present in cache on attempt " << attempt
8590 << ", retrying" << std::endl
;
8593 // Read until the object is present in the cache tier
8594 cout
<< "verifying " << obj
<< " is eventually promoted" << std::endl
;
8597 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
8600 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8601 while (it
!= cache_ioctx
.nobjects_end()) {
8602 if (it
->get_oid() == string(obj
.c_str())) {
8615 ASSERT_EQ(0, cluster
.mon_command(
8616 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8619 ASSERT_EQ(0, cluster
.mon_command(
8620 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8621 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8624 // wait for maps to settle before next test
8625 cluster
.wait_for_latest_osdmap();
8628 TEST_F(LibRadosTwoPoolsECPP
, ProxyRead
) {
8632 bl
.append("hi there");
8633 ObjectWriteOperation op
;
8635 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8640 ASSERT_EQ(0, cluster
.mon_command(
8641 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8642 "\", \"tierpool\": \"" + cache_pool_name
+
8643 "\", \"force_nonempty\": \"--force-nonempty\" }",
8645 ASSERT_EQ(0, cluster
.mon_command(
8646 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8647 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8649 ASSERT_EQ(0, cluster
.mon_command(
8650 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8651 "\", \"mode\": \"readproxy\"}",
8654 // wait for maps to settle
8655 cluster
.wait_for_latest_osdmap();
8657 // read and verify the object
8660 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
8661 ASSERT_EQ('h', bl
[0]);
8664 // Verify 10 times the object is NOT present in the cache tier
8667 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8668 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
8673 ASSERT_EQ(0, cluster
.mon_command(
8674 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8677 ASSERT_EQ(0, cluster
.mon_command(
8678 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8679 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8682 // wait for maps to settle before next test
8683 cluster
.wait_for_latest_osdmap();
8686 TEST_F(LibRadosTwoPoolsECPP
, CachePin
) {
8690 bl
.append("hi there");
8691 ObjectWriteOperation op
;
8693 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8697 bl
.append("hi there");
8698 ObjectWriteOperation op
;
8700 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
8704 bl
.append("hi there");
8705 ObjectWriteOperation op
;
8707 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
8711 bl
.append("hi there");
8712 ObjectWriteOperation op
;
8714 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
8719 ASSERT_EQ(0, cluster
.mon_command(
8720 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8721 "\", \"tierpool\": \"" + cache_pool_name
+
8722 "\", \"force_nonempty\": \"--force-nonempty\" }",
8724 ASSERT_EQ(0, cluster
.mon_command(
8725 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8726 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8728 ASSERT_EQ(0, cluster
.mon_command(
8729 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8730 "\", \"mode\": \"writeback\"}",
8733 // wait for maps to settle
8734 cluster
.wait_for_latest_osdmap();
8736 // read, trigger promote
8739 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
8740 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
8741 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
8742 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
8745 // verify the objects are present in the cache tier
8747 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8748 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
8749 for (uint32_t i
= 0; i
< 4; i
++) {
8750 ASSERT_TRUE(it
->get_oid() == string("foo") ||
8751 it
->get_oid() == string("bar") ||
8752 it
->get_oid() == string("baz") ||
8753 it
->get_oid() == string("bam"));
8756 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
8761 ObjectWriteOperation op
;
8763 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8764 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8765 completion
->wait_for_complete();
8766 ASSERT_EQ(0, completion
->get_return_value());
8767 completion
->release();
8770 ObjectWriteOperation op
;
8772 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8773 ASSERT_EQ(0, cache_ioctx
.aio_operate("baz", completion
, &op
));
8774 completion
->wait_for_complete();
8775 ASSERT_EQ(0, completion
->get_return_value());
8776 completion
->release();
8780 ASSERT_EQ(0, cluster
.mon_command(
8781 set_pool_str(cache_pool_name
, "hit_set_count", 2),
8783 ASSERT_EQ(0, cluster
.mon_command(
8784 set_pool_str(cache_pool_name
, "hit_set_period", 600),
8786 ASSERT_EQ(0, cluster
.mon_command(
8787 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
8789 ASSERT_EQ(0, cluster
.mon_command(
8790 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
8792 ASSERT_EQ(0, cluster
.mon_command(
8793 set_pool_str(cache_pool_name
, "target_max_objects", 1),
8798 // Verify the pinned object 'foo' is not flushed/evicted
8802 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
8805 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8806 while (it
!= cache_ioctx
.nobjects_end()) {
8807 ASSERT_TRUE(it
->get_oid() == string("foo") ||
8808 it
->get_oid() == string("bar") ||
8809 it
->get_oid() == string("baz") ||
8810 it
->get_oid() == string("bam"));
8815 ASSERT_TRUE(it
->get_oid() == string("foo") ||
8816 it
->get_oid() == string("baz"));
8824 ASSERT_EQ(0, cluster
.mon_command(
8825 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8828 ASSERT_EQ(0, cluster
.mon_command(
8829 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8830 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8833 // wait for maps to settle before next test
8834 cluster
.wait_for_latest_osdmap();
8836 TEST_F(LibRadosTwoPoolsECPP
, SetRedirectRead
) {
8840 bl
.append("hi there");
8841 ObjectWriteOperation op
;
8843 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8848 ObjectWriteOperation op
;
8850 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
8855 ASSERT_EQ(0, cluster
.mon_command(
8856 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8857 "\", \"tierpool\": \"" + cache_pool_name
+
8858 "\", \"force_nonempty\": \"--force-nonempty\" }",
8861 // wait for maps to settle
8862 cluster
.wait_for_latest_osdmap();
8865 ObjectWriteOperation op
;
8866 op
.set_redirect("bar", cache_ioctx
, 0);
8867 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8868 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
8869 completion
->wait_for_complete();
8870 ASSERT_EQ(0, completion
->get_return_value());
8871 completion
->release();
8873 // read and verify the object
8876 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
8877 ASSERT_EQ('t', bl
[0]);
8880 ASSERT_EQ(0, cluster
.mon_command(
8881 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8882 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8885 // wait for maps to settle before next test
8886 cluster
.wait_for_latest_osdmap();
8889 TEST_F(LibRadosTwoPoolsECPP
, SetChunkRead
) {
8890 // note: require >= mimic
8894 bl
.append("there hi");
8895 ObjectWriteOperation op
;
8897 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
8902 bl
.append("There hi");
8903 ObjectWriteOperation op
;
8905 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
8908 // wait for maps to settle
8909 cluster
.wait_for_latest_osdmap();
8912 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 0, 4, "bar", "foo");
8916 ObjectWriteOperation op
;
8918 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8919 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8920 completion
->wait_for_complete();
8921 ASSERT_EQ(0, completion
->get_return_value());
8922 completion
->release();
8925 // read and verify the object
8928 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
8929 ASSERT_EQ('T', bl
[0]);
8932 // wait for maps to settle before next test
8933 cluster
.wait_for_latest_osdmap();
8936 TEST_F(LibRadosTwoPoolsECPP
, ManifestPromoteRead
) {
8937 // note: require >= mimic
8942 bl
.append("hiaa there");
8943 ObjectWriteOperation op
;
8945 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
8949 bl
.append("base chunk");
8950 ObjectWriteOperation op
;
8952 ASSERT_EQ(0, cache_ioctx
.operate("foo-chunk", &op
));
8956 bl
.append("HIaa there");
8957 ObjectWriteOperation op
;
8959 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
8963 bl
.append("BASE CHUNK");
8964 ObjectWriteOperation op
;
8966 ASSERT_EQ(0, ioctx
.operate("bar-chunk", &op
));
8971 ObjectWriteOperation op
;
8972 op
.set_redirect("bar", ioctx
, 0);
8973 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8974 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8975 completion
->wait_for_complete();
8976 ASSERT_EQ(0, completion
->get_return_value());
8977 completion
->release();
8980 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 0, 10, "bar-chunk", "foo-chunk");
8983 ObjectWriteOperation op
;
8985 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8986 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8987 completion
->wait_for_complete();
8988 ASSERT_EQ(0, completion
->get_return_value());
8989 completion
->release();
8991 // read and verify the object (redirect)
8994 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
8995 ASSERT_EQ('H', bl
[0]);
8999 ObjectWriteOperation op
;
9001 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9002 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo-chunk", completion
, &op
));
9003 completion
->wait_for_complete();
9004 ASSERT_EQ(0, completion
->get_return_value());
9005 completion
->release();
9007 // read and verify the object
9010 ASSERT_EQ(1, cache_ioctx
.read("foo-chunk", bl
, 1, 0));
9011 ASSERT_EQ('B', bl
[0]);
9014 // wait for maps to settle before next test
9015 cluster
.wait_for_latest_osdmap();
9018 TEST_F(LibRadosTwoPoolsECPP
, TrySetDedupTier
) {
9019 // note: require >= mimic
9022 ASSERT_EQ(-EOPNOTSUPP
, cluster
.mon_command(
9023 set_pool_str(pool_name
, "dedup_tier", cache_pool_name
),
9027 TEST_F(LibRadosTwoPoolsPP
, PropagateBaseTierError
) {
9028 // write object to base tier
9030 encode(static_cast<uint32_t>(0U), omap_bl
);
9032 ObjectWriteOperation op1
;
9033 op1
.omap_set({{"somekey", omap_bl
}});
9034 ASSERT_EQ(0, ioctx
.operate("propagate-base-tier-error", &op1
));
9038 ASSERT_EQ(0, cluster
.mon_command(
9039 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
9040 "\", \"tierpool\": \"" + cache_pool_name
+
9041 "\", \"force_nonempty\": \"--force-nonempty\" }",
9043 ASSERT_EQ(0, cluster
.mon_command(
9044 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
9045 "\", \"mode\": \"writeback\"}",
9047 ASSERT_EQ(0, cluster
.mon_command(
9048 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
9049 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
9052 ASSERT_EQ(0, cluster
.mon_command(
9053 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
9055 ASSERT_EQ(0, cluster
.mon_command(
9056 set_pool_str(cache_pool_name
, "hit_set_count", 1),
9058 ASSERT_EQ(0, cluster
.mon_command(
9059 set_pool_str(cache_pool_name
, "hit_set_period", 600),
9061 ASSERT_EQ(0, cluster
.mon_command(
9062 set_pool_str(cache_pool_name
, "target_max_objects", 250),
9065 // wait for maps to settle
9066 cluster
.wait_for_latest_osdmap();
9068 // guarded op should fail so expect error to propagate to cache tier
9069 bufferlist test_omap_bl
;
9070 encode(static_cast<uint32_t>(1U), test_omap_bl
);
9072 ObjectWriteOperation op2
;
9073 op2
.omap_cmp({{"somekey", {test_omap_bl
, CEPH_OSD_CMPXATTR_OP_EQ
}}}, nullptr);
9074 op2
.omap_set({{"somekey", test_omap_bl
}});
9076 ASSERT_EQ(-ECANCELED
, ioctx
.operate("propagate-base-tier-error", &op2
));
9079 TEST_F(LibRadosTwoPoolsPP
, HelloWriteReturn
) {
9082 ASSERT_EQ(0, cluster
.mon_command(
9083 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
9084 "\", \"tierpool\": \"" + cache_pool_name
+
9085 "\", \"force_nonempty\": \"--force-nonempty\" }",
9087 ASSERT_EQ(0, cluster
.mon_command(
9088 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
9089 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
9091 ASSERT_EQ(0, cluster
.mon_command(
9092 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
9093 "\", \"mode\": \"writeback\"}",
9096 // set things up such that the op would normally be proxied
9097 ASSERT_EQ(0, cluster
.mon_command(
9098 set_pool_str(cache_pool_name
, "hit_set_count", 2),
9100 ASSERT_EQ(0, cluster
.mon_command(
9101 set_pool_str(cache_pool_name
, "hit_set_period", 600),
9103 ASSERT_EQ(0, cluster
.mon_command(
9104 set_pool_str(cache_pool_name
, "hit_set_type",
9107 ASSERT_EQ(0, cluster
.mon_command(
9108 set_pool_str(cache_pool_name
, "min_read_recency_for_promote",
9112 // wait for maps to settle
9113 cluster
.wait_for_latest_osdmap();
9115 // this *will* return data due to the RETURNVEC flag
9119 ObjectWriteOperation o
;
9120 o
.exec("hello", "write_return_data", in
, &out
, &rval
);
9121 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9122 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &o
,
9123 librados::OPERATION_RETURNVEC
));
9124 completion
->wait_for_complete();
9125 ASSERT_EQ(42, completion
->get_return_value());
9126 ASSERT_EQ(42, rval
);
9127 out
.hexdump(std::cout
);
9128 ASSERT_EQ("you might see this", std::string(out
.c_str(), out
.length()));
9131 // this will overflow because the return data is too big
9135 ObjectWriteOperation o
;
9136 o
.exec("hello", "write_too_much_return_data", in
, &out
, &rval
);
9137 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9138 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &o
,
9139 librados::OPERATION_RETURNVEC
));
9140 completion
->wait_for_complete();
9141 ASSERT_EQ(-EOVERFLOW
, completion
->get_return_value());
9142 ASSERT_EQ(-EOVERFLOW
, rval
);
9143 ASSERT_EQ("", std::string(out
.c_str(), out
.length()));