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 // wait for maps to settle
5663 cluster
.wait_for_latest_osdmap();
5665 // set-chunk to set manifest object
5667 ObjectReadOperation op
;
5668 op
.set_chunk(0, 2, ioctx
, "bar", 0,
5669 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
5670 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5671 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
5672 librados::OPERATION_IGNORE_CACHE
, NULL
));
5673 completion
->wait_for_complete();
5674 ASSERT_EQ(0, completion
->get_return_value());
5675 completion
->release();
5678 // delete temp pool, so flushing chunk will fail
5679 ASSERT_EQ(0, s_cluster
.pool_delete(temp_pool_name
.c_str()));
5681 // flush to check if proper error is returned
5683 ObjectReadOperation op
;
5685 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5686 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5687 "foo", completion
, &op
,
5688 librados::OPERATION_IGNORE_CACHE
, NULL
));
5689 completion
->wait_for_complete();
5690 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
5691 completion
->release();
5696 TEST_F(LibRadosTwoPoolsPP
, ManifestSnapHasChunk
) {
5697 // skip test if not yet octopus
5698 if (_get_required_osd_release(cluster
) < "octopus") {
5699 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
5704 ASSERT_EQ(0, cluster
.mon_command(
5705 set_pool_str(pool_name
, "fingerprint_algorithm", "sha1"),
5707 cluster
.wait_for_latest_osdmap();
5712 bl
.append("there HIHI");
5713 ObjectWriteOperation op
;
5715 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5718 string er_fp_oid
, hi_fp_oid
, HI_fp_oid
, ai_fp_oid
, bi_fp_oid
,
5719 Er_fp_oid
, Hi_fp_oid
, SI_fp_oid
;
5722 er_fp_oid
= get_fp_oid("er", "sha1");
5723 hi_fp_oid
= get_fp_oid("hi", "sha1");
5724 HI_fp_oid
= get_fp_oid("HI", "sha1");
5725 ai_fp_oid
= get_fp_oid("ai", "sha1");
5726 bi_fp_oid
= get_fp_oid("bi", "sha1");
5727 Er_fp_oid
= get_fp_oid("Er", "sha1");
5728 Hi_fp_oid
= get_fp_oid("Hi", "sha1");
5729 SI_fp_oid
= get_fp_oid("SI", "sha1");
5733 ObjectWriteOperation op
;
5737 ASSERT_EQ(0, cache_ioctx
.operate(er_fp_oid
, &op
));
5741 ObjectWriteOperation op
;
5745 ASSERT_EQ(0, cache_ioctx
.operate(hi_fp_oid
, &op
));
5749 ObjectWriteOperation op
;
5753 ASSERT_EQ(0, cache_ioctx
.operate(HI_fp_oid
, &op
));
5757 ObjectWriteOperation op
;
5761 ASSERT_EQ(0, cache_ioctx
.operate(ai_fp_oid
, &op
));
5765 ObjectWriteOperation op
;
5769 ASSERT_EQ(0, cache_ioctx
.operate(bi_fp_oid
, &op
));
5773 ObjectWriteOperation op
;
5777 ASSERT_EQ(0, cache_ioctx
.operate(Er_fp_oid
, &op
));
5781 ObjectWriteOperation op
;
5785 ASSERT_EQ(0, cache_ioctx
.operate(Hi_fp_oid
, &op
));
5789 ObjectWriteOperation op
;
5793 ASSERT_EQ(0, cache_ioctx
.operate(SI_fp_oid
, &op
));
5796 // set-chunk (dedup)
5797 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, HI_fp_oid
, "foo");
5798 // set-chunk (dedup)
5799 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, HI_fp_oid
, "foo");
5801 // foo head: [hi] [HI]
5803 // create a snapshot, clone
5804 vector
<uint64_t> my_snaps(1);
5805 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5806 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5814 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5820 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5826 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 8));
5829 // foo snap[0]: [hi] [HI]
5830 // foo head : [er] [ai] [SI]
5832 // set-chunk (dedup)
5833 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, er_fp_oid
, "foo");
5834 // set-chunk (dedup)
5835 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, ai_fp_oid
, "foo");
5836 // set-chunk (dedup)
5837 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, SI_fp_oid
, "foo");
5840 my_snaps
[1] = my_snaps
[0];
5841 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5842 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5849 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5855 ASSERT_EQ(0, ioctx
.write("foo", bl
, 1, 6));
5858 // foo snap[1]: [HI] [HI]
5859 // foo snap[0]: [er] [ai] [SI]
5860 // foo head : [er] [bi] [SI]
5862 // set-chunk (dedup)
5863 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, bi_fp_oid
, "foo");
5866 ASSERT_EQ(1, cls_cas_references_chunk(ioctx
, "foo", SI_fp_oid
));
5867 ASSERT_EQ(1, cls_cas_references_chunk(ioctx
, "foo", er_fp_oid
));
5868 ASSERT_EQ(1, cls_cas_references_chunk(ioctx
, "foo", ai_fp_oid
));
5869 ASSERT_EQ(2, cls_cas_references_chunk(ioctx
, "foo", HI_fp_oid
));
5870 ASSERT_EQ(-ENOLINK
, cls_cas_references_chunk(ioctx
, "foo", Hi_fp_oid
));
5874 TEST_F(LibRadosTwoPoolsPP
, ManifestRollback
) {
5875 // skip test if not yet pacific
5876 if (_get_required_osd_release(cluster
) < "pacific") {
5877 cout
<< "cluster is not yet pacific, skipping test" << std::endl
;
5884 bl
.append("CDere hiHI");
5885 ObjectWriteOperation op
;
5887 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5891 bl
.append("ABere hiHI");
5892 ObjectWriteOperation op
;
5894 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
5898 bl
.append("CDere hiHI");
5899 ObjectWriteOperation op
;
5901 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
5905 bl
.append("EFere hiHI");
5906 ObjectWriteOperation op
;
5908 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
5911 // wait for maps to settle
5912 cluster
.wait_for_latest_osdmap();
5914 // create a snapshot, clone
5915 vector
<uint64_t> my_snaps(1);
5916 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5917 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5922 bl
.append("there hiHI");
5923 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
5927 my_snaps
[1] = my_snaps
[0];
5928 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5929 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5934 bl
.append("thABe hiEF");
5935 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
5939 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
5940 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk3", "foo");
5943 // foo head : [chunk1] [chunk3]
5945 ioctx
.snap_set_read(my_snaps
[1]);
5947 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk2", "foo");
5948 // foo snap[1]: [ chunk2 ]
5950 // foo head : [chunk1] [chunk3]
5952 // foo snap[1]: [ chunk2 ]
5954 // foo head : [chunk1] [chunk3]
5956 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[0]));
5958 ioctx
.snap_set_read(librados::SNAP_HEAD
);
5961 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5962 ASSERT_EQ('t', bl
[0]);
5965 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[1]));
5969 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5970 ASSERT_EQ('C', bl
[0]);
5975 TEST_F(LibRadosTwoPoolsPP
, ManifestRollbackRefcount
) {
5976 // skip test if not yet pacific
5977 if (_get_required_osd_release(cluster
) < "pacific") {
5978 cout
<< "cluster is not yet pacific, skipping test" << std::endl
;
5985 bl
.append("CDere hiHI");
5986 ObjectWriteOperation op
;
5988 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5992 bl
.append("ABere hiHI");
5993 ObjectWriteOperation op
;
5995 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
5999 bl
.append("CDere hiHI");
6000 ObjectWriteOperation op
;
6002 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
6006 bl
.append("EFere hiHI");
6007 ObjectWriteOperation op
;
6009 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
6013 bl
.append("DDDDD hiHI");
6014 ObjectWriteOperation op
;
6016 ASSERT_EQ(0, cache_ioctx
.operate("chunk4", &op
));
6020 bl
.append("EEEEE hiHI");
6021 ObjectWriteOperation op
;
6023 ASSERT_EQ(0, cache_ioctx
.operate("chunk5", &op
));
6026 // wait for maps to settle
6027 cluster
.wait_for_latest_osdmap();
6029 // create a snapshot, clone
6030 vector
<uint64_t> my_snaps(1);
6031 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6032 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6037 bl
.append("there hiHI");
6038 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6042 my_snaps
[1] = my_snaps
[0];
6043 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6044 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6049 bl
.append("thABe hiEF");
6050 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6054 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
6055 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk3", "foo");
6058 // foo head : [chunk1] [chunk3]
6060 ioctx
.snap_set_read(my_snaps
[1]);
6061 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk4", "foo");
6062 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 6, 2, "chunk5", "foo");
6063 // foo snap[1]: [chunk4] [chunk5]
6065 // foo head : [chunk1] [chunk3]
6067 ioctx
.snap_set_read(my_snaps
[0]);
6068 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk2", "foo");
6069 // foo snap[1]: [chunk4] [chunk5]
6070 // foo snap[0]: [ chunk2 ]
6071 // foo head : [chunk1] [chunk3]
6073 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[1]));
6074 // foo snap[1]: [chunk4] [chunk5]
6075 // foo snap[0]: [ chunk2 ]
6076 // foo head : [chunk4] [chunk5] <-- will contain these contents
6079 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk1", 0);
6080 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk3", 0);
6082 ioctx
.selfmanaged_snap_remove(my_snaps
[1]);
6085 // foo snap[0]: [ chunk2 ]
6086 // foo head : [chunk4] [chunk5]
6087 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6088 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk4", 1);
6089 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk5", 1);
6093 bl
.append("thABe hiEF");
6094 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6097 // foo snap[0]: [ chunk2 ]
6099 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk1", 0);
6100 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk3", 0);
6101 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk4", 0);
6102 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk5", 0);
6103 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk2", 1);
6106 TEST_F(LibRadosTwoPoolsPP
, ManifestEvictRollback
) {
6107 // skip test if not yet pacific
6108 if (_get_required_osd_release(cluster
) < "pacific") {
6109 cout
<< "cluster is not yet pacific, skipping test" << std::endl
;
6116 bl
.append("CDere hiHI");
6117 ObjectWriteOperation op
;
6119 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6123 bl
.append("ABere hiHI");
6124 ObjectWriteOperation op
;
6126 ASSERT_EQ(0, cache_ioctx
.operate("chunk1", &op
));
6130 bl
.append("CDere hiHI");
6131 ObjectWriteOperation op
;
6133 ASSERT_EQ(0, cache_ioctx
.operate("chunk2", &op
));
6137 bl
.append("EFere hiHI");
6138 ObjectWriteOperation op
;
6140 ASSERT_EQ(0, cache_ioctx
.operate("chunk3", &op
));
6143 // wait for maps to settle
6144 cluster
.wait_for_latest_osdmap();
6146 // create a snapshot, clone
6147 vector
<uint64_t> my_snaps(1);
6148 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6149 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6154 bl
.append("there hiHI");
6155 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
6160 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 2, 2, "chunk1", "foo");
6161 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 8, 2, "chunk3", "foo");
6163 // foo head : [chunk1] [chunk3]
6165 ioctx
.snap_set_read(my_snaps
[0]);
6166 manifest_set_chunk(cluster
, cache_ioctx
, ioctx
, 0, 10, "chunk2", "foo");
6167 // foo snap[0]: [ chunk2 ]
6168 // foo head : [chunk1] [chunk3]
6171 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6172 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk1", 1);
6173 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk3", 1);
6176 ioctx
.snap_set_read(my_snaps
[0]);
6177 // evict--this makes the chunk missing state
6179 ObjectReadOperation op
, stat_op
;
6181 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6182 ASSERT_EQ(0, ioctx
.aio_operate(
6183 "foo", completion
, &op
,
6184 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
6185 completion
->wait_for_complete();
6186 ASSERT_EQ(0, completion
->get_return_value());
6189 // rollback to my_snaps[0]
6190 ASSERT_EQ(0, ioctx
.selfmanaged_snap_rollback("foo", my_snaps
[0]));
6192 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6195 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6196 ASSERT_EQ('C', bl
[0]);
6199 is_intended_refcount_state(ioctx
, "foo", cache_ioctx
, "chunk2", 1);
6202 class LibRadosTwoPoolsECPP
: public RadosTestECPP
6205 LibRadosTwoPoolsECPP() {};
6206 ~LibRadosTwoPoolsECPP() override
{};
6208 static void SetUpTestCase() {
6209 pool_name
= get_temp_pool_name();
6210 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, s_cluster
));
6212 static void TearDownTestCase() {
6213 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, s_cluster
));
6215 static std::string cache_pool_name
;
6217 void SetUp() override
{
6218 cache_pool_name
= get_temp_pool_name();
6219 ASSERT_EQ(0, s_cluster
.pool_create(cache_pool_name
.c_str()));
6220 RadosTestECPP::SetUp();
6222 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
6223 cache_ioctx
.application_enable("rados", true);
6224 cache_ioctx
.set_namespace(nspace
);
6226 void TearDown() override
{
6227 // flush + evict cache
6228 flush_evict_all(cluster
, cache_ioctx
);
6232 ASSERT_EQ(0, cluster
.mon_command(
6233 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
6236 ASSERT_EQ(0, cluster
.mon_command(
6237 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6238 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6241 // wait for maps to settle before next test
6242 cluster
.wait_for_latest_osdmap();
6244 RadosTestECPP::TearDown();
6246 cleanup_default_namespace(cache_ioctx
);
6247 cleanup_namespace(cache_ioctx
, nspace
);
6249 cache_ioctx
.close();
6250 ASSERT_EQ(0, s_cluster
.pool_delete(cache_pool_name
.c_str()));
6253 librados::IoCtx cache_ioctx
;
6256 std::string
LibRadosTwoPoolsECPP::cache_pool_name
;
6258 TEST_F(LibRadosTierECPP
, Dirty
) {
6260 ObjectWriteOperation op
;
6262 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still get 0 if it dne
6265 ObjectWriteOperation op
;
6267 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6272 ObjectReadOperation op
;
6273 op
.is_dirty(&dirty
, &r
);
6274 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
6279 ObjectWriteOperation op
;
6281 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6284 ObjectWriteOperation op
;
6286 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still 0 if already clean
6291 ObjectReadOperation op
;
6292 op
.is_dirty(&dirty
, &r
);
6293 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
6294 ASSERT_FALSE(dirty
);
6298 // ObjectWriteOperation op;
6299 // op.truncate(0); // still a write even tho it is a no-op
6300 // ASSERT_EQ(0, ioctx.operate("foo", &op));
6303 // bool dirty = false;
6305 // ObjectReadOperation op;
6306 // op.is_dirty(&dirty, &r);
6307 // ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
6308 // ASSERT_TRUE(dirty);
6313 TEST_F(LibRadosTwoPoolsECPP
, Overlay
) {
6318 ObjectWriteOperation op
;
6320 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6325 ObjectWriteOperation op
;
6327 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
6332 ASSERT_EQ(0, cluster
.mon_command(
6333 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6334 "\", \"tierpool\": \"" + cache_pool_name
+
6335 "\", \"force_nonempty\": \"--force-nonempty\" }",
6337 ASSERT_EQ(0, cluster
.mon_command(
6338 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6339 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6342 // wait for maps to settle
6343 cluster
.wait_for_latest_osdmap();
6345 // by default, the overlay sends us to cache pool
6348 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6349 ASSERT_EQ('c', bl
[0]);
6353 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
6354 ASSERT_EQ('c', bl
[0]);
6357 // unless we say otherwise
6360 ObjectReadOperation op
;
6361 op
.read(0, 1, &bl
, NULL
);
6362 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6363 ASSERT_EQ(0, ioctx
.aio_operate(
6364 "foo", completion
, &op
,
6365 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
6366 completion
->wait_for_complete();
6367 ASSERT_EQ(0, completion
->get_return_value());
6368 completion
->release();
6369 ASSERT_EQ('b', bl
[0]);
6373 TEST_F(LibRadosTwoPoolsECPP
, Promote
) {
6377 bl
.append("hi there");
6378 ObjectWriteOperation op
;
6380 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6385 ASSERT_EQ(0, cluster
.mon_command(
6386 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6387 "\", \"tierpool\": \"" + cache_pool_name
+
6388 "\", \"force_nonempty\": \"--force-nonempty\" }",
6390 ASSERT_EQ(0, cluster
.mon_command(
6391 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6392 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6394 ASSERT_EQ(0, cluster
.mon_command(
6395 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6396 "\", \"mode\": \"writeback\"}",
6399 // wait for maps to settle
6400 cluster
.wait_for_latest_osdmap();
6402 // read, trigger a promote
6405 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6408 // read, trigger a whiteout
6411 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6412 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6415 // verify the object is present in the cache tier
6417 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6418 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6419 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6421 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6423 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6427 TEST_F(LibRadosTwoPoolsECPP
, PromoteSnap
) {
6431 bl
.append("hi there");
6432 ObjectWriteOperation op
;
6434 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6438 bl
.append("hi there");
6439 ObjectWriteOperation op
;
6441 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6445 bl
.append("hi there");
6446 ObjectWriteOperation op
;
6448 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6452 bl
.append("hi there");
6453 ObjectWriteOperation op
;
6455 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6458 // create a snapshot, clone
6459 vector
<uint64_t> my_snaps(1);
6460 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6461 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6466 ObjectWriteOperation op
;
6468 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6473 ObjectWriteOperation op
;
6475 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6478 ObjectWriteOperation op
;
6480 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6485 ObjectWriteOperation op
;
6487 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6492 ASSERT_EQ(0, cluster
.mon_command(
6493 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6494 "\", \"tierpool\": \"" + cache_pool_name
+
6495 "\", \"force_nonempty\": \"--force-nonempty\" }",
6497 ASSERT_EQ(0, cluster
.mon_command(
6498 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6499 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6501 ASSERT_EQ(0, cluster
.mon_command(
6502 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6503 "\", \"mode\": \"writeback\"}",
6506 // wait for maps to settle
6507 cluster
.wait_for_latest_osdmap();
6509 // read, trigger a promote on the head
6512 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6513 ASSERT_EQ('c', bl
[0]);
6517 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
6518 ASSERT_EQ('c', bl
[0]);
6521 ioctx
.snap_set_read(my_snaps
[0]);
6523 // stop and scrub this pg (to make sure scrub can handle missing
6524 // clones in the cache tier)
6525 // This test requires cache tier and base tier to have the same pg_num/pgp_num
6527 for (int tries
= 0; tries
< 5; ++tries
) {
6529 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
6531 ASSERT_EQ(0, ioctx
.get_object_pg_hash_position2("foo", &hash
));
6533 ss
<< "{\"prefix\": \"pg scrub\", \"pgid\": \""
6534 << cache_ioctx
.get_id() << "."
6537 int r
= cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
6539 r
== -ENOENT
) { // in case mgr osdmap is a bit stale
6546 // give it a few seconds to go. this is sloppy but is usually enough time
6547 cout
<< "waiting for scrub..." << std::endl
;
6549 cout
<< "done waiting" << std::endl
;
6555 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6556 ASSERT_EQ('h', bl
[0]);
6562 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
6563 ASSERT_EQ('h', bl
[0]);
6569 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
6570 ASSERT_EQ('h', bl
[0]);
6573 ioctx
.snap_set_read(librados::SNAP_HEAD
);
6578 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6579 ASSERT_EQ('c', bl
[0]);
6585 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
6586 ASSERT_EQ('c', bl
[0]);
6592 ASSERT_EQ(-ENOENT
, ioctx
.read("baz", bl
, 1, 0));
6596 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
6599 TEST_F(LibRadosTwoPoolsECPP
, PromoteSnapTrimRace
) {
6603 bl
.append("hi there");
6604 ObjectWriteOperation op
;
6606 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6609 // create a snapshot, clone
6610 vector
<uint64_t> my_snaps(1);
6611 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6612 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6617 ObjectWriteOperation op
;
6619 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6624 ASSERT_EQ(0, cluster
.mon_command(
6625 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6626 "\", \"tierpool\": \"" + cache_pool_name
+
6627 "\", \"force_nonempty\": \"--force-nonempty\" }",
6629 ASSERT_EQ(0, cluster
.mon_command(
6630 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6631 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6633 ASSERT_EQ(0, cluster
.mon_command(
6634 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6635 "\", \"mode\": \"writeback\"}",
6638 // wait for maps to settle
6639 cluster
.wait_for_latest_osdmap();
6642 ASSERT_EQ(0, ioctx
.selfmanaged_snap_remove(my_snaps
[0]));
6644 ioctx
.snap_set_read(my_snaps
[0]);
6646 // read foo snap. the OSD may or may not realize that this snap has
6647 // been logically deleted; either response is valid.
6650 int r
= ioctx
.read("foo", bl
, 1, 0);
6651 ASSERT_TRUE(r
== 1 || r
== -ENOENT
);
6655 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
6658 TEST_F(LibRadosTwoPoolsECPP
, Whiteout
) {
6662 bl
.append("hi there");
6663 ObjectWriteOperation op
;
6665 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6670 ASSERT_EQ(0, cluster
.mon_command(
6671 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6672 "\", \"tierpool\": \"" + cache_pool_name
+
6673 "\", \"force_nonempty\": \"--force-nonempty\" }",
6675 ASSERT_EQ(0, cluster
.mon_command(
6676 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6677 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6679 ASSERT_EQ(0, cluster
.mon_command(
6680 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6681 "\", \"mode\": \"writeback\"}",
6684 // wait for maps to settle
6685 cluster
.wait_for_latest_osdmap();
6687 // create some whiteouts, verify they behave
6689 ObjectWriteOperation op
;
6692 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6696 ObjectWriteOperation op
;
6699 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
6702 ObjectWriteOperation op
;
6705 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
6708 // verify the whiteouts are there in the cache tier
6710 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6711 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6712 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6714 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6716 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6719 // delete a whiteout and verify it goes away
6720 ASSERT_EQ(-ENOENT
, ioctx
.remove("foo"));
6722 ObjectWriteOperation op
;
6724 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6725 ASSERT_EQ(0, ioctx
.aio_operate("bar", completion
, &op
,
6726 librados::OPERATION_IGNORE_CACHE
));
6727 completion
->wait_for_complete();
6728 ASSERT_EQ(0, completion
->get_return_value());
6729 completion
->release();
6731 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6732 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6733 ASSERT_TRUE(it
->get_oid() == string("foo"));
6735 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6738 // recreate an object and verify we can read it
6741 bl
.append("hi there");
6742 ObjectWriteOperation op
;
6744 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6748 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6749 ASSERT_EQ('h', bl
[0]);
6753 TEST_F(LibRadosTwoPoolsECPP
, Evict
) {
6757 bl
.append("hi there");
6758 ObjectWriteOperation op
;
6760 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6765 ASSERT_EQ(0, cluster
.mon_command(
6766 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6767 "\", \"tierpool\": \"" + cache_pool_name
+
6768 "\", \"force_nonempty\": \"--force-nonempty\" }",
6770 ASSERT_EQ(0, cluster
.mon_command(
6771 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6772 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6774 ASSERT_EQ(0, cluster
.mon_command(
6775 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6776 "\", \"mode\": \"writeback\"}",
6779 // wait for maps to settle
6780 cluster
.wait_for_latest_osdmap();
6782 // read, trigger a promote
6785 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6788 // read, trigger a whiteout, and a dirty object
6791 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6792 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
6793 ASSERT_EQ(0, ioctx
.write("bar", bl
, bl
.length(), 0));
6796 // verify the object is present in the cache tier
6798 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6799 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6800 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6802 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
6804 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6809 ObjectWriteOperation op
;
6811 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6812 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
6813 completion
->wait_for_complete();
6814 ASSERT_EQ(0, completion
->get_return_value());
6815 completion
->release();
6818 // evict the pinned object with -EPERM
6820 ObjectReadOperation op
;
6822 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6823 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
6824 librados::OPERATION_IGNORE_CACHE
,
6826 completion
->wait_for_complete();
6827 ASSERT_EQ(-EPERM
, completion
->get_return_value());
6828 completion
->release();
6833 ObjectWriteOperation op
;
6835 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6836 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
6837 completion
->wait_for_complete();
6838 ASSERT_EQ(0, completion
->get_return_value());
6839 completion
->release();
6844 ObjectReadOperation op
;
6846 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6847 ASSERT_EQ(0, cache_ioctx
.aio_operate(
6848 "foo", completion
, &op
,
6849 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
6850 completion
->wait_for_complete();
6851 ASSERT_EQ(0, completion
->get_return_value());
6852 completion
->release();
6859 ObjectReadOperation op
;
6860 op
.is_dirty(&dirty
, &r
);
6861 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
6862 ASSERT_FALSE(dirty
);
6868 ObjectReadOperation op
;
6870 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6871 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
6872 librados::OPERATION_IGNORE_CACHE
,
6874 completion
->wait_for_complete();
6875 ASSERT_EQ(0, completion
->get_return_value());
6876 completion
->release();
6879 ObjectReadOperation op
;
6881 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6882 ASSERT_EQ(0, cache_ioctx
.aio_operate(
6883 "foo", completion
, &op
,
6884 librados::OPERATION_IGNORE_CACHE
, NULL
));
6885 completion
->wait_for_complete();
6886 ASSERT_EQ(0, completion
->get_return_value());
6887 completion
->release();
6890 ObjectReadOperation op
;
6892 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6893 ASSERT_EQ(0, cache_ioctx
.aio_operate(
6894 "bar", completion
, &op
,
6895 librados::OPERATION_IGNORE_CACHE
, NULL
));
6896 completion
->wait_for_complete();
6897 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
6898 completion
->release();
6902 TEST_F(LibRadosTwoPoolsECPP
, EvictSnap
) {
6906 bl
.append("hi there");
6907 ObjectWriteOperation op
;
6909 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6913 bl
.append("hi there");
6914 ObjectWriteOperation op
;
6916 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6920 bl
.append("hi there");
6921 ObjectWriteOperation op
;
6923 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6927 bl
.append("hi there");
6928 ObjectWriteOperation op
;
6930 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6933 // create a snapshot, clone
6934 vector
<uint64_t> my_snaps(1);
6935 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
6936 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
6941 ObjectWriteOperation op
;
6943 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6948 ObjectWriteOperation op
;
6950 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6953 ObjectWriteOperation op
;
6955 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6960 ObjectWriteOperation op
;
6962 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6967 ASSERT_EQ(0, cluster
.mon_command(
6968 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6969 "\", \"tierpool\": \"" + cache_pool_name
+
6970 "\", \"force_nonempty\": \"--force-nonempty\" }",
6972 ASSERT_EQ(0, cluster
.mon_command(
6973 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6974 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6976 ASSERT_EQ(0, cluster
.mon_command(
6977 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6978 "\", \"mode\": \"writeback\"}",
6981 // wait for maps to settle
6982 cluster
.wait_for_latest_osdmap();
6984 // read, trigger a promote on the head
6987 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6988 ASSERT_EQ('c', bl
[0]);
6992 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
6993 ASSERT_EQ('c', bl
[0]);
6998 ObjectReadOperation op
;
7000 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7001 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7002 "bam", completion
, &op
,
7003 librados::OPERATION_IGNORE_CACHE
, NULL
));
7004 completion
->wait_for_complete();
7005 ASSERT_EQ(0, completion
->get_return_value());
7006 completion
->release();
7010 ObjectReadOperation op
;
7011 op
.read(1, 0, &bl
, NULL
);
7012 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7013 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7014 "bam", completion
, &op
,
7015 librados::OPERATION_IGNORE_CACHE
, NULL
));
7016 completion
->wait_for_complete();
7017 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
7018 completion
->release();
7022 ioctx
.snap_set_read(my_snaps
[0]);
7025 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7026 ASSERT_EQ('h', bl
[0]);
7031 ObjectReadOperation op
;
7033 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7034 ASSERT_EQ(0, ioctx
.aio_operate(
7035 "foo", completion
, &op
,
7036 librados::OPERATION_IGNORE_CACHE
, NULL
));
7037 completion
->wait_for_complete();
7038 ASSERT_EQ(0, completion
->get_return_value());
7039 completion
->release();
7044 ObjectReadOperation op
;
7045 op
.read(1, 0, &bl
, NULL
);
7046 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7047 ASSERT_EQ(0, ioctx
.aio_operate(
7048 "foo", completion
, &op
,
7049 librados::OPERATION_IGNORE_CACHE
, NULL
));
7050 completion
->wait_for_complete();
7051 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
7052 completion
->release();
7054 // head is still there...
7055 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7058 ObjectReadOperation op
;
7059 op
.read(1, 0, &bl
, NULL
);
7060 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7061 ASSERT_EQ(0, ioctx
.aio_operate(
7062 "foo", completion
, &op
,
7063 librados::OPERATION_IGNORE_CACHE
, NULL
));
7064 completion
->wait_for_complete();
7065 ASSERT_EQ(0, completion
->get_return_value());
7066 completion
->release();
7069 // promote head + snap of bar
7070 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7073 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
7074 ASSERT_EQ('c', bl
[0]);
7076 ioctx
.snap_set_read(my_snaps
[0]);
7079 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
7080 ASSERT_EQ('h', bl
[0]);
7083 // evict bar head (fail)
7084 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7086 ObjectReadOperation op
;
7088 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7089 ASSERT_EQ(0, ioctx
.aio_operate(
7090 "bar", completion
, &op
,
7091 librados::OPERATION_IGNORE_CACHE
, NULL
));
7092 completion
->wait_for_complete();
7093 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
7094 completion
->release();
7098 ioctx
.snap_set_read(my_snaps
[0]);
7100 ObjectReadOperation op
;
7102 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7103 ASSERT_EQ(0, ioctx
.aio_operate(
7104 "bar", completion
, &op
,
7105 librados::OPERATION_IGNORE_CACHE
, NULL
));
7106 completion
->wait_for_complete();
7107 ASSERT_EQ(0, completion
->get_return_value());
7108 completion
->release();
7111 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7114 ObjectReadOperation op
;
7115 op
.read(1, 0, &bl
, NULL
);
7116 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7117 ASSERT_EQ(0, ioctx
.aio_operate(
7118 "bar", completion
, &op
,
7119 librados::OPERATION_IGNORE_CACHE
, NULL
));
7120 completion
->wait_for_complete();
7121 ASSERT_EQ(0, completion
->get_return_value());
7122 completion
->release();
7125 ObjectReadOperation op
;
7127 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7128 ASSERT_EQ(0, ioctx
.aio_operate(
7129 "bar", completion
, &op
,
7130 librados::OPERATION_IGNORE_CACHE
, NULL
));
7131 completion
->wait_for_complete();
7132 ASSERT_EQ(0, completion
->get_return_value());
7133 completion
->release();
7137 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
7140 TEST_F(LibRadosTwoPoolsECPP
, TryFlush
) {
7143 ASSERT_EQ(0, cluster
.mon_command(
7144 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7145 "\", \"tierpool\": \"" + cache_pool_name
+
7146 "\", \"force_nonempty\": \"--force-nonempty\" }",
7148 ASSERT_EQ(0, cluster
.mon_command(
7149 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7150 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7152 ASSERT_EQ(0, cluster
.mon_command(
7153 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7154 "\", \"mode\": \"writeback\"}",
7157 // wait for maps to settle
7158 cluster
.wait_for_latest_osdmap();
7163 bl
.append("hi there");
7164 ObjectWriteOperation op
;
7166 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7169 // verify the object is present in the cache tier
7171 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7172 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7173 ASSERT_TRUE(it
->get_oid() == string("foo"));
7175 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7178 // verify the object is NOT present in the base tier
7180 NObjectIterator it
= ioctx
.nobjects_begin();
7181 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7188 ObjectReadOperation op
;
7189 op
.is_dirty(&dirty
, &r
);
7190 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7197 ObjectWriteOperation op
;
7199 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7200 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7201 completion
->wait_for_complete();
7202 ASSERT_EQ(0, completion
->get_return_value());
7203 completion
->release();
7206 // flush the pinned object with -EPERM
7208 ObjectReadOperation op
;
7209 op
.cache_try_flush();
7210 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7211 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7212 "foo", completion
, &op
,
7213 librados::OPERATION_IGNORE_OVERLAY
|
7214 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7215 completion
->wait_for_complete();
7216 ASSERT_EQ(-EPERM
, completion
->get_return_value());
7217 completion
->release();
7222 ObjectWriteOperation op
;
7224 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7225 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7226 completion
->wait_for_complete();
7227 ASSERT_EQ(0, completion
->get_return_value());
7228 completion
->release();
7233 ObjectReadOperation op
;
7234 op
.cache_try_flush();
7235 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7236 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7237 "foo", completion
, &op
,
7238 librados::OPERATION_IGNORE_OVERLAY
|
7239 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7240 completion
->wait_for_complete();
7241 ASSERT_EQ(0, completion
->get_return_value());
7242 completion
->release();
7249 ObjectReadOperation op
;
7250 op
.is_dirty(&dirty
, &r
);
7251 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7252 ASSERT_FALSE(dirty
);
7256 // verify in base tier
7258 NObjectIterator it
= ioctx
.nobjects_begin();
7259 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
7260 ASSERT_TRUE(it
->get_oid() == string("foo"));
7262 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7267 ObjectReadOperation op
;
7269 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7270 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7271 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7272 completion
->wait_for_complete();
7273 ASSERT_EQ(0, completion
->get_return_value());
7274 completion
->release();
7277 // verify no longer in cache tier
7279 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7280 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7284 TEST_F(LibRadosTwoPoolsECPP
, FailedFlush
) {
7287 ASSERT_EQ(0, cluster
.mon_command(
7288 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7289 "\", \"tierpool\": \"" + cache_pool_name
+
7290 "\", \"force_nonempty\": \"--force-nonempty\" }",
7292 ASSERT_EQ(0, cluster
.mon_command(
7293 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7294 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7296 ASSERT_EQ(0, cluster
.mon_command(
7297 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7298 "\", \"mode\": \"writeback\"}",
7301 // wait for maps to settle
7302 cluster
.wait_for_latest_osdmap();
7307 bl
.append("hi there");
7308 ObjectWriteOperation op
;
7310 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7313 // verify the object is present in the cache tier
7315 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7316 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7317 ASSERT_TRUE(it
->get_oid() == string("foo"));
7319 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7322 // verify the object is NOT present in the base tier
7324 NObjectIterator it
= ioctx
.nobjects_begin();
7325 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7330 ObjectWriteOperation op
;
7331 std::map
<std::string
, bufferlist
> omap
;
7332 omap
["somekey"] = bufferlist();
7334 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7335 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7336 completion
->wait_for_complete();
7337 ASSERT_EQ(0, completion
->get_return_value());
7338 completion
->release();
7343 ObjectReadOperation op
;
7345 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7346 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7347 "foo", completion
, &op
,
7348 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7349 completion
->wait_for_complete();
7350 ASSERT_NE(0, completion
->get_return_value());
7351 completion
->release();
7356 ObjectReadOperation op
;
7359 std::set
<std::string
> keys
;
7360 keys
.insert("somekey");
7361 std::map
<std::string
, bufferlist
> map
;
7363 op
.omap_get_vals_by_keys(keys
, &map
, &prval
);
7364 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7365 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
, &bl
));
7367 bool completed
= completion
->is_complete();
7369 cache_ioctx
.aio_cancel(completion
);
7370 std::cerr
<< "Most probably test case will hang here, please reset manually" << std::endl
;
7371 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
7373 completion
->release();
7375 // verify still not in base tier
7377 ASSERT_TRUE(ioctx
.nobjects_begin() == ioctx
.nobjects_end());
7381 ObjectWriteOperation op
;
7383 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7387 ObjectReadOperation op
;
7389 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7390 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7391 "foo", completion
, &op
,
7392 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7393 completion
->wait_for_complete();
7394 ASSERT_EQ(0, completion
->get_return_value());
7395 completion
->release();
7399 ObjectReadOperation op
;
7401 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7402 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7403 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7404 completion
->wait_for_complete();
7405 ASSERT_EQ(0, completion
->get_return_value());
7406 completion
->release();
7409 // verify no longer in cache tier
7411 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7412 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7416 NObjectIterator it
= ioctx
.nobjects_begin();
7417 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7421 TEST_F(LibRadosTwoPoolsECPP
, Flush
) {
7424 ASSERT_EQ(0, cluster
.mon_command(
7425 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7426 "\", \"tierpool\": \"" + cache_pool_name
+
7427 "\", \"force_nonempty\": \"--force-nonempty\" }",
7429 ASSERT_EQ(0, cluster
.mon_command(
7430 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7431 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7433 ASSERT_EQ(0, cluster
.mon_command(
7434 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7435 "\", \"mode\": \"writeback\"}",
7438 // wait for maps to settle
7439 cluster
.wait_for_latest_osdmap();
7441 uint64_t user_version
= 0;
7446 bl
.append("hi there");
7447 ObjectWriteOperation op
;
7449 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7452 // verify the object is present in the cache tier
7454 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7455 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7456 ASSERT_TRUE(it
->get_oid() == string("foo"));
7458 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7461 // verify the object is NOT present in the base tier
7463 NObjectIterator it
= ioctx
.nobjects_begin();
7464 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7471 ObjectReadOperation op
;
7472 op
.is_dirty(&dirty
, &r
);
7473 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7476 user_version
= cache_ioctx
.get_last_version();
7481 ObjectWriteOperation op
;
7483 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7484 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7485 completion
->wait_for_complete();
7486 ASSERT_EQ(0, completion
->get_return_value());
7487 completion
->release();
7490 // flush the pinned object with -EPERM
7492 ObjectReadOperation op
;
7493 op
.cache_try_flush();
7494 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7495 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7496 "foo", completion
, &op
,
7497 librados::OPERATION_IGNORE_OVERLAY
|
7498 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7499 completion
->wait_for_complete();
7500 ASSERT_EQ(-EPERM
, completion
->get_return_value());
7501 completion
->release();
7506 ObjectWriteOperation op
;
7508 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7509 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
7510 completion
->wait_for_complete();
7511 ASSERT_EQ(0, completion
->get_return_value());
7512 completion
->release();
7517 ObjectReadOperation op
;
7519 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7520 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7521 "foo", completion
, &op
,
7522 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7523 completion
->wait_for_complete();
7524 ASSERT_EQ(0, completion
->get_return_value());
7525 completion
->release();
7532 ObjectReadOperation op
;
7533 op
.is_dirty(&dirty
, &r
);
7534 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
7535 ASSERT_FALSE(dirty
);
7539 // verify in base tier
7541 NObjectIterator it
= ioctx
.nobjects_begin();
7542 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
7543 ASSERT_TRUE(it
->get_oid() == string("foo"));
7545 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7550 ObjectReadOperation op
;
7552 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7553 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7554 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7555 completion
->wait_for_complete();
7556 ASSERT_EQ(0, completion
->get_return_value());
7557 completion
->release();
7560 // verify no longer in cache tier
7562 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7563 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7566 // read it again and verify the version is consistent
7569 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
7570 ASSERT_EQ(user_version
, cache_ioctx
.get_last_version());
7575 ObjectWriteOperation op
;
7577 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7582 ObjectReadOperation op
;
7584 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7585 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7586 "foo", completion
, &op
,
7587 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7588 completion
->wait_for_complete();
7589 ASSERT_EQ(0, completion
->get_return_value());
7590 completion
->release();
7595 ObjectReadOperation op
;
7597 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7598 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7599 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
7600 completion
->wait_for_complete();
7601 ASSERT_EQ(0, completion
->get_return_value());
7602 completion
->release();
7605 // verify no longer in cache tier
7607 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7608 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7612 NObjectIterator it
= ioctx
.nobjects_begin();
7613 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7617 TEST_F(LibRadosTwoPoolsECPP
, FlushSnap
) {
7620 ASSERT_EQ(0, cluster
.mon_command(
7621 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7622 "\", \"tierpool\": \"" + cache_pool_name
+
7623 "\", \"force_nonempty\": \"--force-nonempty\" }",
7625 ASSERT_EQ(0, cluster
.mon_command(
7626 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7627 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7629 ASSERT_EQ(0, cluster
.mon_command(
7630 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7631 "\", \"mode\": \"writeback\"}",
7634 // wait for maps to settle
7635 cluster
.wait_for_latest_osdmap();
7641 ObjectWriteOperation op
;
7643 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7646 // create a snapshot, clone
7647 vector
<uint64_t> my_snaps(1);
7648 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
7649 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
7654 ObjectWriteOperation op
;
7656 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7661 my_snaps
[1] = my_snaps
[0];
7662 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
7663 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
7668 ObjectWriteOperation op
;
7670 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7673 // verify the object is present in the cache tier
7675 NObjectIterator it
= cache_ioctx
.nobjects_begin();
7676 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
7677 ASSERT_TRUE(it
->get_oid() == string("foo"));
7679 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
7682 // verify the object is NOT present in the base tier
7684 NObjectIterator it
= ioctx
.nobjects_begin();
7685 ASSERT_TRUE(it
== ioctx
.nobjects_end());
7688 // flush on head (should fail)
7689 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7691 ObjectReadOperation op
;
7693 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7694 ASSERT_EQ(0, ioctx
.aio_operate(
7695 "foo", completion
, &op
,
7696 librados::OPERATION_IGNORE_CACHE
, NULL
));
7697 completion
->wait_for_complete();
7698 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
7699 completion
->release();
7701 // flush on recent snap (should fail)
7702 ioctx
.snap_set_read(my_snaps
[0]);
7704 ObjectReadOperation op
;
7706 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7707 ASSERT_EQ(0, ioctx
.aio_operate(
7708 "foo", completion
, &op
,
7709 librados::OPERATION_IGNORE_CACHE
, NULL
));
7710 completion
->wait_for_complete();
7711 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
7712 completion
->release();
7714 // flush on oldest snap
7715 ioctx
.snap_set_read(my_snaps
[1]);
7717 ObjectReadOperation op
;
7719 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7720 ASSERT_EQ(0, ioctx
.aio_operate(
7721 "foo", completion
, &op
,
7722 librados::OPERATION_IGNORE_CACHE
, NULL
));
7723 completion
->wait_for_complete();
7724 ASSERT_EQ(0, completion
->get_return_value());
7725 completion
->release();
7727 // flush on next oldest snap
7728 ioctx
.snap_set_read(my_snaps
[0]);
7730 ObjectReadOperation op
;
7732 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7733 ASSERT_EQ(0, ioctx
.aio_operate(
7734 "foo", completion
, &op
,
7735 librados::OPERATION_IGNORE_CACHE
, NULL
));
7736 completion
->wait_for_complete();
7737 ASSERT_EQ(0, completion
->get_return_value());
7738 completion
->release();
7741 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7743 ObjectReadOperation op
;
7745 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7746 ASSERT_EQ(0, ioctx
.aio_operate(
7747 "foo", completion
, &op
,
7748 librados::OPERATION_IGNORE_CACHE
, NULL
));
7749 completion
->wait_for_complete();
7750 ASSERT_EQ(0, completion
->get_return_value());
7751 completion
->release();
7754 // verify i can read the snaps from the cache pool
7755 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7758 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7759 ASSERT_EQ('c', bl
[0]);
7761 ioctx
.snap_set_read(my_snaps
[0]);
7764 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7765 ASSERT_EQ('b', bl
[0]);
7767 ioctx
.snap_set_read(my_snaps
[1]);
7770 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7771 ASSERT_EQ('a', bl
[0]);
7775 ASSERT_EQ(0, cluster
.mon_command(
7776 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
7780 // wait for maps to settle
7781 cluster
.wait_for_latest_osdmap();
7783 // verify i can read the snaps from the base pool
7784 ioctx
.snap_set_read(librados::SNAP_HEAD
);
7787 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7788 ASSERT_EQ('c', bl
[0]);
7790 ioctx
.snap_set_read(my_snaps
[0]);
7793 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7794 ASSERT_EQ('b', bl
[0]);
7796 ioctx
.snap_set_read(my_snaps
[1]);
7799 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
7800 ASSERT_EQ('a', bl
[0]);
7803 ASSERT_EQ(0, cluster
.mon_command(
7804 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7805 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7807 cluster
.wait_for_latest_osdmap();
7810 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
7813 TEST_F(LibRadosTierECPP
, FlushWriteRaces
) {
7815 std::string pool_name
= get_temp_pool_name();
7816 std::string cache_pool_name
= pool_name
+ "-cache";
7817 ASSERT_EQ("", create_one_pool_pp(pool_name
, cluster
));
7818 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
7820 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
7821 cache_ioctx
.application_enable("rados", true);
7823 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
7827 ASSERT_EQ(0, cluster
.mon_command(
7828 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7829 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
7831 ASSERT_EQ(0, cluster
.mon_command(
7832 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7833 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7835 ASSERT_EQ(0, cluster
.mon_command(
7836 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7837 "\", \"mode\": \"writeback\"}",
7840 // wait for maps to settle
7841 cluster
.wait_for_latest_osdmap();
7843 // create/dirty object
7845 bl
.append("hi there");
7847 ObjectWriteOperation op
;
7849 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7854 ObjectReadOperation op
;
7856 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7857 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7858 "foo", completion
, &op
,
7859 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7861 ObjectWriteOperation op2
;
7863 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
7864 ASSERT_EQ(0, ioctx
.aio_operate(
7865 "foo", completion2
, &op2
, 0));
7867 completion
->wait_for_complete();
7868 completion2
->wait_for_complete();
7869 ASSERT_EQ(0, completion
->get_return_value());
7870 ASSERT_EQ(0, completion2
->get_return_value());
7871 completion
->release();
7872 completion2
->release();
7877 // create/dirty object
7880 bl
.append("hi there");
7881 ObjectWriteOperation op
;
7883 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7886 // try-flush + write
7888 ObjectReadOperation op
;
7889 op
.cache_try_flush();
7890 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7891 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7892 "foo", completion
, &op
,
7893 librados::OPERATION_IGNORE_OVERLAY
|
7894 librados::OPERATION_SKIPRWLOCKS
, NULL
));
7896 ObjectWriteOperation op2
;
7898 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
7899 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion2
, &op2
, 0));
7901 completion
->wait_for_complete();
7902 completion2
->wait_for_complete();
7903 int r
= completion
->get_return_value();
7904 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
7905 ASSERT_EQ(0, completion2
->get_return_value());
7906 completion
->release();
7907 completion2
->release();
7910 cout
<< "didn't get EBUSY, trying again" << std::endl
;
7912 ASSERT_TRUE(--tries
);
7916 ASSERT_EQ(0, cluster
.mon_command(
7917 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
7920 ASSERT_EQ(0, cluster
.mon_command(
7921 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
7922 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
7925 // wait for maps to settle before next test
7926 cluster
.wait_for_latest_osdmap();
7928 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
7929 ASSERT_EQ(0, destroy_one_pool_pp(pool_name
, cluster
));
7932 TEST_F(LibRadosTwoPoolsECPP
, FlushTryFlushRaces
) {
7935 ASSERT_EQ(0, cluster
.mon_command(
7936 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
7937 "\", \"tierpool\": \"" + cache_pool_name
+
7938 "\", \"force_nonempty\": \"--force-nonempty\" }",
7940 ASSERT_EQ(0, cluster
.mon_command(
7941 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
7942 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
7944 ASSERT_EQ(0, cluster
.mon_command(
7945 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
7946 "\", \"mode\": \"writeback\"}",
7949 // wait for maps to settle
7950 cluster
.wait_for_latest_osdmap();
7952 // create/dirty object
7955 bl
.append("hi there");
7956 ObjectWriteOperation op
;
7958 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7963 ObjectReadOperation op
;
7965 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7966 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7967 "foo", completion
, &op
,
7968 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7970 ObjectReadOperation op2
;
7972 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
7973 ASSERT_EQ(0, cache_ioctx
.aio_operate(
7974 "foo", completion2
, &op2
,
7975 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
7977 completion
->wait_for_complete();
7978 completion2
->wait_for_complete();
7979 ASSERT_EQ(0, completion
->get_return_value());
7980 ASSERT_EQ(0, completion2
->get_return_value());
7981 completion
->release();
7982 completion2
->release();
7985 // create/dirty object
7988 bl
.append("hi there");
7989 ObjectWriteOperation op
;
7991 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
7994 // flush + try-flush
7996 ObjectReadOperation op
;
7998 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
7999 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8000 "foo", completion
, &op
,
8001 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
8003 ObjectReadOperation op2
;
8004 op2
.cache_try_flush();
8005 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
8006 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8007 "foo", completion2
, &op2
,
8008 librados::OPERATION_IGNORE_OVERLAY
|
8009 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8011 completion
->wait_for_complete();
8012 completion2
->wait_for_complete();
8013 ASSERT_EQ(0, completion
->get_return_value());
8014 ASSERT_EQ(0, completion2
->get_return_value());
8015 completion
->release();
8016 completion2
->release();
8019 // create/dirty object
8024 bl
.append("hi there");
8025 ObjectWriteOperation op
;
8027 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8030 // try-flush + flush
8031 // (flush will not piggyback on try-flush)
8033 ObjectReadOperation op
;
8034 op
.cache_try_flush();
8035 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8036 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8037 "foo", completion
, &op
,
8038 librados::OPERATION_IGNORE_OVERLAY
|
8039 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8041 ObjectReadOperation op2
;
8043 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
8044 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8045 "foo", completion2
, &op2
,
8046 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
8048 completion
->wait_for_complete();
8049 completion2
->wait_for_complete();
8050 int r
= completion
->get_return_value();
8051 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
8052 ASSERT_EQ(0, completion2
->get_return_value());
8053 completion
->release();
8054 completion2
->release();
8057 cout
<< "didn't get EBUSY, trying again" << std::endl
;
8059 ASSERT_TRUE(--tries
);
8062 // create/dirty object
8065 bl
.append("hi there");
8066 ObjectWriteOperation op
;
8068 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8071 // try-flush + try-flush
8073 ObjectReadOperation op
;
8074 op
.cache_try_flush();
8075 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8076 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8077 "foo", completion
, &op
,
8078 librados::OPERATION_IGNORE_OVERLAY
|
8079 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8081 ObjectReadOperation op2
;
8082 op2
.cache_try_flush();
8083 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
8084 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8085 "foo", completion2
, &op2
,
8086 librados::OPERATION_IGNORE_OVERLAY
|
8087 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8089 completion
->wait_for_complete();
8090 completion2
->wait_for_complete();
8091 ASSERT_EQ(0, completion
->get_return_value());
8092 ASSERT_EQ(0, completion2
->get_return_value());
8093 completion
->release();
8094 completion2
->release();
8098 TEST_F(LibRadosTwoPoolsECPP
, TryFlushReadRace
) {
8101 ASSERT_EQ(0, cluster
.mon_command(
8102 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8103 "\", \"tierpool\": \"" + cache_pool_name
+
8104 "\", \"force_nonempty\": \"--force-nonempty\" }",
8106 ASSERT_EQ(0, cluster
.mon_command(
8107 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8108 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8110 ASSERT_EQ(0, cluster
.mon_command(
8111 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8112 "\", \"mode\": \"writeback\"}",
8115 // wait for maps to settle
8116 cluster
.wait_for_latest_osdmap();
8118 // create/dirty object
8121 bl
.append("hi there");
8122 bufferptr
bp(4000000); // make it big!
8125 ObjectWriteOperation op
;
8127 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8130 // start a continuous stream of reads
8131 read_ioctx
= &ioctx
;
8133 for (int i
= 0; i
< max_reads
; ++i
) {
8140 ObjectReadOperation op
;
8141 op
.cache_try_flush();
8142 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8143 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8144 "foo", completion
, &op
,
8145 librados::OPERATION_IGNORE_OVERLAY
|
8146 librados::OPERATION_SKIPRWLOCKS
, NULL
));
8148 completion
->wait_for_complete();
8149 ASSERT_EQ(0, completion
->get_return_value());
8150 completion
->release();
8153 std::unique_lock locker
{test_lock
};
8155 cond
.wait(locker
, [] { return num_reads
== 0;});
8158 TEST_F(LibRadosTierECPP
, CallForcesPromote
) {
8160 std::string pool_name
= get_temp_pool_name();
8161 std::string cache_pool_name
= pool_name
+ "-cache";
8162 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, cluster
));
8163 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
8165 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
8166 cache_ioctx
.application_enable("rados", true);
8168 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
8172 ASSERT_EQ(0, cluster
.mon_command(
8173 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8174 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8176 ASSERT_EQ(0, cluster
.mon_command(
8177 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8178 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8180 ASSERT_EQ(0, cluster
.mon_command(
8181 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8182 "\", \"mode\": \"writeback\"}",
8185 // set things up such that the op would normally be proxied
8186 ASSERT_EQ(0, cluster
.mon_command(
8187 set_pool_str(cache_pool_name
, "hit_set_count", 2),
8189 ASSERT_EQ(0, cluster
.mon_command(
8190 set_pool_str(cache_pool_name
, "hit_set_period", 600),
8192 ASSERT_EQ(0, cluster
.mon_command(
8193 set_pool_str(cache_pool_name
, "hit_set_type",
8196 ASSERT_EQ(0, cluster
.mon_command(
8197 set_pool_str(cache_pool_name
, "min_read_recency_for_promote",
8201 // wait for maps to settle
8202 cluster
.wait_for_latest_osdmap();
8204 // create/dirty object
8206 bl
.append("hi there");
8208 ObjectWriteOperation op
;
8210 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8215 ObjectReadOperation op
;
8217 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8218 ASSERT_EQ(0, cache_ioctx
.aio_operate(
8219 "foo", completion
, &op
,
8220 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
8221 completion
->wait_for_complete();
8222 ASSERT_EQ(0, completion
->get_return_value());
8223 completion
->release();
8228 ObjectReadOperation op
;
8230 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8231 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
8232 librados::OPERATION_IGNORE_CACHE
,
8234 completion
->wait_for_complete();
8235 ASSERT_EQ(0, completion
->get_return_value());
8236 completion
->release();
8241 ObjectReadOperation op
;
8243 op
.exec("rbd", "get_id", bl
);
8245 // should get EIO (not an rbd object), not -EOPNOTSUPP (we didn't promote)
8246 ASSERT_EQ(-5, ioctx
.operate("foo", &op
, &out
));
8249 // make sure foo is back in the cache tier
8251 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8252 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
8253 ASSERT_TRUE(it
->get_oid() == string("foo"));
8255 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
8259 ASSERT_EQ(0, cluster
.mon_command(
8260 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8263 ASSERT_EQ(0, cluster
.mon_command(
8264 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8265 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8268 // wait for maps to settle before next test
8269 cluster
.wait_for_latest_osdmap();
8271 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
8272 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, cluster
));
8275 TEST_F(LibRadosTierECPP
, HitSetNone
) {
8277 list
< pair
<time_t,time_t> > ls
;
8278 AioCompletion
*c
= librados::Rados::aio_create_completion();
8279 ASSERT_EQ(0, ioctx
.hit_set_list(123, c
, &ls
));
8280 c
->wait_for_complete();
8281 ASSERT_EQ(0, c
->get_return_value());
8282 ASSERT_TRUE(ls
.empty());
8287 AioCompletion
*c
= librados::Rados::aio_create_completion();
8288 ASSERT_EQ(0, ioctx
.hit_set_get(123, c
, 12345, &bl
));
8289 c
->wait_for_complete();
8290 ASSERT_EQ(-ENOENT
, c
->get_return_value());
8295 TEST_F(LibRadosTwoPoolsECPP
, HitSetRead
) {
8298 ASSERT_EQ(0, cluster
.mon_command(
8299 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8300 "\", \"tierpool\": \"" + cache_pool_name
+
8301 "\", \"force_nonempty\": \"--force-nonempty\" }",
8304 // enable hitset tracking for this pool
8305 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", 2),
8307 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", 600),
8309 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type",
8313 // wait for maps to settle
8314 cluster
.wait_for_latest_osdmap();
8316 cache_ioctx
.set_namespace("");
8318 // keep reading until we see our object appear in the HitSet
8319 utime_t start
= ceph_clock_now();
8320 utime_t hard_stop
= start
+ utime_t(600, 0);
8323 utime_t now
= ceph_clock_now();
8324 ASSERT_TRUE(now
< hard_stop
);
8326 string name
= "foo";
8328 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
8329 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
,
8330 cluster
.pool_lookup(cache_pool_name
.c_str()), "");
8333 ASSERT_EQ(-ENOENT
, cache_ioctx
.read("foo", bl
, 1, 0));
8336 AioCompletion
*c
= librados::Rados::aio_create_completion();
8337 ASSERT_EQ(0, cache_ioctx
.hit_set_get(hash
, c
, now
.sec(), &hbl
));
8338 c
->wait_for_complete();
8342 auto p
= hbl
.cbegin();
8345 if (hs
.contains(oid
)) {
8346 cout
<< "ok, hit_set contains " << oid
<< std::endl
;
8349 cout
<< "hmm, not in HitSet yet" << std::endl
;
8351 cout
<< "hmm, no HitSet yet" << std::endl
;
8358 // disable this test until hitset-get reliably works on EC pools
8360 TEST_F(LibRadosTierECPP
, HitSetWrite
) {
8361 int num_pg
= _get_pg_num(cluster
, pool_name
);
8362 ceph_assert(num_pg
> 0);
8364 // enable hitset tracking for this pool
8366 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_count", 8),
8368 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_period", 600),
8370 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_type",
8374 // wait for maps to settle
8375 cluster
.wait_for_latest_osdmap();
8377 ioctx
.set_namespace("");
8379 // do a bunch of writes
8380 for (int i
=0; i
<1000; ++i
) {
8383 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, 1, 0));
8387 std::map
<int,HitSet
> hitsets
;
8388 for (int i
=0; i
<num_pg
; ++i
) {
8389 list
< pair
<time_t,time_t> > ls
;
8390 AioCompletion
*c
= librados::Rados::aio_create_completion();
8391 ASSERT_EQ(0, ioctx
.hit_set_list(i
, c
, &ls
));
8392 c
->wait_for_complete();
8394 std::cout
<< "pg " << i
<< " ls " << ls
<< std::endl
;
8395 ASSERT_FALSE(ls
.empty());
8398 c
= librados::Rados::aio_create_completion();
8400 ASSERT_EQ(0, ioctx
.hit_set_get(i
, c
, ls
.back().first
, &bl
));
8401 c
->wait_for_complete();
8404 //std::cout << "bl len is " << bl.length() << "\n";
8405 //bl.hexdump(std::cout);
8406 //std::cout << std::endl;
8408 auto p
= bl
.cbegin();
8409 decode(hitsets
[i
], p
);
8411 // cope with racing splits by refreshing pg_num
8412 if (i
== num_pg
- 1)
8413 num_pg
= _get_pg_num(cluster
, pool_name
);
8416 for (int i
=0; i
<1000; ++i
) {
8417 string n
= stringify(i
);
8418 uint32_t hash
= ioctx
.get_object_hash_position(n
);
8419 hobject_t
oid(sobject_t(n
, CEPH_NOSNAP
), "", hash
,
8420 cluster
.pool_lookup(pool_name
.c_str()), "");
8421 std::cout
<< "checking for " << oid
<< std::endl
;
8423 for (int p
=0; p
<num_pg
; ++p
) {
8424 if (hitsets
[p
].contains(oid
)) {
8434 TEST_F(LibRadosTwoPoolsECPP
, HitSetTrim
) {
8436 unsigned period
= 3;
8440 ASSERT_EQ(0, cluster
.mon_command(
8441 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8442 "\", \"tierpool\": \"" + cache_pool_name
+
8443 "\", \"force_nonempty\": \"--force-nonempty\" }",
8446 // enable hitset tracking for this pool
8447 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", count
),
8449 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", period
),
8451 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
8453 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_fpp", ".01"),
8456 // wait for maps to settle
8457 cluster
.wait_for_latest_osdmap();
8459 cache_ioctx
.set_namespace("");
8461 // do a bunch of writes and make sure the hitsets rotate
8462 utime_t start
= ceph_clock_now();
8463 utime_t hard_stop
= start
+ utime_t(count
* period
* 50, 0);
8466 int bsize
= alignment
;
8467 char *buf
= (char *)new char[bsize
];
8468 memset(buf
, 'f', bsize
);
8471 string name
= "foo";
8473 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
8474 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
, -1, "");
8477 bl
.append(buf
, bsize
);
8478 ASSERT_EQ(0, cache_ioctx
.append("foo", bl
, bsize
));
8480 list
<pair
<time_t, time_t> > ls
;
8481 AioCompletion
*c
= librados::Rados::aio_create_completion();
8482 ASSERT_EQ(0, cache_ioctx
.hit_set_list(hash
, c
, &ls
));
8483 c
->wait_for_complete();
8486 cout
<< " got ls " << ls
<< std::endl
;
8489 first
= ls
.front().first
;
8490 cout
<< "first is " << first
<< std::endl
;
8492 if (ls
.front().first
!= first
) {
8493 cout
<< "first now " << ls
.front().first
<< ", trimmed" << std::endl
;
8499 utime_t now
= ceph_clock_now();
8500 ASSERT_TRUE(now
< hard_stop
);
8507 TEST_F(LibRadosTwoPoolsECPP
, PromoteOn2ndRead
) {
8509 for (int i
=0; i
<20; ++i
) {
8511 bl
.append("hi there");
8512 ObjectWriteOperation op
;
8514 ASSERT_EQ(0, ioctx
.operate("foo" + stringify(i
), &op
));
8519 ASSERT_EQ(0, cluster
.mon_command(
8520 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8521 "\", \"tierpool\": \"" + cache_pool_name
+
8522 "\", \"force_nonempty\": \"--force-nonempty\" }",
8524 ASSERT_EQ(0, cluster
.mon_command(
8525 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8526 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8528 ASSERT_EQ(0, cluster
.mon_command(
8529 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8530 "\", \"mode\": \"writeback\"}",
8533 // enable hitset tracking for this pool
8534 ASSERT_EQ(0, cluster
.mon_command(
8535 set_pool_str(cache_pool_name
, "hit_set_count", 2),
8537 ASSERT_EQ(0, cluster
.mon_command(
8538 set_pool_str(cache_pool_name
, "hit_set_period", 600),
8540 ASSERT_EQ(0, cluster
.mon_command(
8541 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
8543 ASSERT_EQ(0, cluster
.mon_command(
8544 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
8546 ASSERT_EQ(0, cluster
.mon_command(
8547 set_pool_str(cache_pool_name
, "hit_set_grade_decay_rate", 20),
8549 ASSERT_EQ(0, cluster
.mon_command(
8550 set_pool_str(cache_pool_name
, "hit_set_search_last_n", 1),
8553 // wait for maps to settle
8554 cluster
.wait_for_latest_osdmap();
8556 int fake
= 0; // set this to non-zero to test spurious promotion,
8557 // e.g. from thrashing
8561 // 1st read, don't trigger a promote
8562 obj
= "foo" + stringify(attempt
);
8563 cout
<< obj
<< std::endl
;
8566 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
8569 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
8574 // verify the object is NOT present in the cache tier
8577 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8578 while (it
!= cache_ioctx
.nobjects_end()) {
8579 cout
<< " see " << it
->get_oid() << std::endl
;
8580 if (it
->get_oid() == string(obj
.c_str())) {
8591 ASSERT_LE(attempt
, 20);
8592 cout
<< "hrm, object is present in cache on attempt " << attempt
8593 << ", retrying" << std::endl
;
8596 // Read until the object is present in the cache tier
8597 cout
<< "verifying " << obj
<< " is eventually promoted" << std::endl
;
8600 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
8603 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8604 while (it
!= cache_ioctx
.nobjects_end()) {
8605 if (it
->get_oid() == string(obj
.c_str())) {
8618 ASSERT_EQ(0, cluster
.mon_command(
8619 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8622 ASSERT_EQ(0, cluster
.mon_command(
8623 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8624 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8627 // wait for maps to settle before next test
8628 cluster
.wait_for_latest_osdmap();
8631 TEST_F(LibRadosTwoPoolsECPP
, ProxyRead
) {
8635 bl
.append("hi there");
8636 ObjectWriteOperation op
;
8638 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8643 ASSERT_EQ(0, cluster
.mon_command(
8644 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8645 "\", \"tierpool\": \"" + cache_pool_name
+
8646 "\", \"force_nonempty\": \"--force-nonempty\" }",
8648 ASSERT_EQ(0, cluster
.mon_command(
8649 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8650 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8652 ASSERT_EQ(0, cluster
.mon_command(
8653 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8654 "\", \"mode\": \"readproxy\"}",
8657 // wait for maps to settle
8658 cluster
.wait_for_latest_osdmap();
8660 // read and verify the object
8663 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
8664 ASSERT_EQ('h', bl
[0]);
8667 // Verify 10 times the object is NOT present in the cache tier
8670 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8671 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
8676 ASSERT_EQ(0, cluster
.mon_command(
8677 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8680 ASSERT_EQ(0, cluster
.mon_command(
8681 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8682 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8685 // wait for maps to settle before next test
8686 cluster
.wait_for_latest_osdmap();
8689 TEST_F(LibRadosTwoPoolsECPP
, CachePin
) {
8693 bl
.append("hi there");
8694 ObjectWriteOperation op
;
8696 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8700 bl
.append("hi there");
8701 ObjectWriteOperation op
;
8703 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
8707 bl
.append("hi there");
8708 ObjectWriteOperation op
;
8710 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
8714 bl
.append("hi there");
8715 ObjectWriteOperation op
;
8717 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
8722 ASSERT_EQ(0, cluster
.mon_command(
8723 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8724 "\", \"tierpool\": \"" + cache_pool_name
+
8725 "\", \"force_nonempty\": \"--force-nonempty\" }",
8727 ASSERT_EQ(0, cluster
.mon_command(
8728 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
8729 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
8731 ASSERT_EQ(0, cluster
.mon_command(
8732 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
8733 "\", \"mode\": \"writeback\"}",
8736 // wait for maps to settle
8737 cluster
.wait_for_latest_osdmap();
8739 // read, trigger promote
8742 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
8743 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
8744 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
8745 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
8748 // verify the objects are present in the cache tier
8750 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8751 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
8752 for (uint32_t i
= 0; i
< 4; i
++) {
8753 ASSERT_TRUE(it
->get_oid() == string("foo") ||
8754 it
->get_oid() == string("bar") ||
8755 it
->get_oid() == string("baz") ||
8756 it
->get_oid() == string("bam"));
8759 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
8764 ObjectWriteOperation op
;
8766 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8767 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8768 completion
->wait_for_complete();
8769 ASSERT_EQ(0, completion
->get_return_value());
8770 completion
->release();
8773 ObjectWriteOperation op
;
8775 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8776 ASSERT_EQ(0, cache_ioctx
.aio_operate("baz", completion
, &op
));
8777 completion
->wait_for_complete();
8778 ASSERT_EQ(0, completion
->get_return_value());
8779 completion
->release();
8783 ASSERT_EQ(0, cluster
.mon_command(
8784 set_pool_str(cache_pool_name
, "hit_set_count", 2),
8786 ASSERT_EQ(0, cluster
.mon_command(
8787 set_pool_str(cache_pool_name
, "hit_set_period", 600),
8789 ASSERT_EQ(0, cluster
.mon_command(
8790 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
8792 ASSERT_EQ(0, cluster
.mon_command(
8793 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
8795 ASSERT_EQ(0, cluster
.mon_command(
8796 set_pool_str(cache_pool_name
, "target_max_objects", 1),
8801 // Verify the pinned object 'foo' is not flushed/evicted
8805 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
8808 NObjectIterator it
= cache_ioctx
.nobjects_begin();
8809 while (it
!= cache_ioctx
.nobjects_end()) {
8810 ASSERT_TRUE(it
->get_oid() == string("foo") ||
8811 it
->get_oid() == string("bar") ||
8812 it
->get_oid() == string("baz") ||
8813 it
->get_oid() == string("bam"));
8818 ASSERT_TRUE(it
->get_oid() == string("foo") ||
8819 it
->get_oid() == string("baz"));
8827 ASSERT_EQ(0, cluster
.mon_command(
8828 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
8831 ASSERT_EQ(0, cluster
.mon_command(
8832 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8833 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8836 // wait for maps to settle before next test
8837 cluster
.wait_for_latest_osdmap();
8839 TEST_F(LibRadosTwoPoolsECPP
, SetRedirectRead
) {
8843 bl
.append("hi there");
8844 ObjectWriteOperation op
;
8846 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
8851 ObjectWriteOperation op
;
8853 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
8858 ASSERT_EQ(0, cluster
.mon_command(
8859 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
8860 "\", \"tierpool\": \"" + cache_pool_name
+
8861 "\", \"force_nonempty\": \"--force-nonempty\" }",
8864 // wait for maps to settle
8865 cluster
.wait_for_latest_osdmap();
8868 ObjectWriteOperation op
;
8869 op
.set_redirect("bar", cache_ioctx
, 0);
8870 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8871 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
8872 completion
->wait_for_complete();
8873 ASSERT_EQ(0, completion
->get_return_value());
8874 completion
->release();
8876 // read and verify the object
8879 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
8880 ASSERT_EQ('t', bl
[0]);
8883 ASSERT_EQ(0, cluster
.mon_command(
8884 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
8885 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
8888 // wait for maps to settle before next test
8889 cluster
.wait_for_latest_osdmap();
8892 TEST_F(LibRadosTwoPoolsECPP
, SetChunkRead
) {
8893 // note: require >= mimic
8897 bl
.append("there hi");
8898 ObjectWriteOperation op
;
8900 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
8905 bl
.append("There hi");
8906 ObjectWriteOperation op
;
8908 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
8911 // wait for maps to settle
8912 cluster
.wait_for_latest_osdmap();
8915 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 0, 4, "bar", "foo");
8919 ObjectWriteOperation op
;
8921 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8922 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8923 completion
->wait_for_complete();
8924 ASSERT_EQ(0, completion
->get_return_value());
8925 completion
->release();
8928 // read and verify the object
8931 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
8932 ASSERT_EQ('T', bl
[0]);
8935 // wait for maps to settle before next test
8936 cluster
.wait_for_latest_osdmap();
8939 TEST_F(LibRadosTwoPoolsECPP
, ManifestPromoteRead
) {
8940 // note: require >= mimic
8945 bl
.append("hiaa there");
8946 ObjectWriteOperation op
;
8948 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
8952 bl
.append("base chunk");
8953 ObjectWriteOperation op
;
8955 ASSERT_EQ(0, cache_ioctx
.operate("foo-chunk", &op
));
8959 bl
.append("HIaa there");
8960 ObjectWriteOperation op
;
8962 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
8966 bl
.append("BASE CHUNK");
8967 ObjectWriteOperation op
;
8969 ASSERT_EQ(0, ioctx
.operate("bar-chunk", &op
));
8974 ObjectWriteOperation op
;
8975 op
.set_redirect("bar", ioctx
, 0);
8976 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8977 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8978 completion
->wait_for_complete();
8979 ASSERT_EQ(0, completion
->get_return_value());
8980 completion
->release();
8983 manifest_set_chunk(cluster
, ioctx
, cache_ioctx
, 0, 10, "bar-chunk", "foo-chunk");
8986 ObjectWriteOperation op
;
8988 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
8989 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
8990 completion
->wait_for_complete();
8991 ASSERT_EQ(0, completion
->get_return_value());
8992 completion
->release();
8994 // read and verify the object (redirect)
8997 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
8998 ASSERT_EQ('H', bl
[0]);
9002 ObjectWriteOperation op
;
9004 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9005 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo-chunk", completion
, &op
));
9006 completion
->wait_for_complete();
9007 ASSERT_EQ(0, completion
->get_return_value());
9008 completion
->release();
9010 // read and verify the object
9013 ASSERT_EQ(1, cache_ioctx
.read("foo-chunk", bl
, 1, 0));
9014 ASSERT_EQ('B', bl
[0]);
9017 // wait for maps to settle before next test
9018 cluster
.wait_for_latest_osdmap();
9021 TEST_F(LibRadosTwoPoolsECPP
, TrySetDedupTier
) {
9022 // note: require >= mimic
9025 ASSERT_EQ(-EOPNOTSUPP
, cluster
.mon_command(
9026 set_pool_str(pool_name
, "dedup_tier", cache_pool_name
),
9030 TEST_F(LibRadosTwoPoolsPP
, PropagateBaseTierError
) {
9031 // write object to base tier
9033 encode(static_cast<uint32_t>(0U), omap_bl
);
9035 ObjectWriteOperation op1
;
9036 op1
.omap_set({{"somekey", omap_bl
}});
9037 ASSERT_EQ(0, ioctx
.operate("propagate-base-tier-error", &op1
));
9041 ASSERT_EQ(0, cluster
.mon_command(
9042 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
9043 "\", \"tierpool\": \"" + cache_pool_name
+
9044 "\", \"force_nonempty\": \"--force-nonempty\" }",
9046 ASSERT_EQ(0, cluster
.mon_command(
9047 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
9048 "\", \"mode\": \"writeback\"}",
9050 ASSERT_EQ(0, cluster
.mon_command(
9051 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
9052 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
9055 ASSERT_EQ(0, cluster
.mon_command(
9056 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
9058 ASSERT_EQ(0, cluster
.mon_command(
9059 set_pool_str(cache_pool_name
, "hit_set_count", 1),
9061 ASSERT_EQ(0, cluster
.mon_command(
9062 set_pool_str(cache_pool_name
, "hit_set_period", 600),
9064 ASSERT_EQ(0, cluster
.mon_command(
9065 set_pool_str(cache_pool_name
, "target_max_objects", 250),
9068 // wait for maps to settle
9069 cluster
.wait_for_latest_osdmap();
9071 // guarded op should fail so expect error to propagate to cache tier
9072 bufferlist test_omap_bl
;
9073 encode(static_cast<uint32_t>(1U), test_omap_bl
);
9075 ObjectWriteOperation op2
;
9076 op2
.omap_cmp({{"somekey", {test_omap_bl
, CEPH_OSD_CMPXATTR_OP_EQ
}}}, nullptr);
9077 op2
.omap_set({{"somekey", test_omap_bl
}});
9079 ASSERT_EQ(-ECANCELED
, ioctx
.operate("propagate-base-tier-error", &op2
));
9082 TEST_F(LibRadosTwoPoolsPP
, HelloWriteReturn
) {
9085 ASSERT_EQ(0, cluster
.mon_command(
9086 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
9087 "\", \"tierpool\": \"" + cache_pool_name
+
9088 "\", \"force_nonempty\": \"--force-nonempty\" }",
9090 ASSERT_EQ(0, cluster
.mon_command(
9091 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
9092 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
9094 ASSERT_EQ(0, cluster
.mon_command(
9095 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
9096 "\", \"mode\": \"writeback\"}",
9099 // set things up such that the op would normally be proxied
9100 ASSERT_EQ(0, cluster
.mon_command(
9101 set_pool_str(cache_pool_name
, "hit_set_count", 2),
9103 ASSERT_EQ(0, cluster
.mon_command(
9104 set_pool_str(cache_pool_name
, "hit_set_period", 600),
9106 ASSERT_EQ(0, cluster
.mon_command(
9107 set_pool_str(cache_pool_name
, "hit_set_type",
9110 ASSERT_EQ(0, cluster
.mon_command(
9111 set_pool_str(cache_pool_name
, "min_read_recency_for_promote",
9115 // wait for maps to settle
9116 cluster
.wait_for_latest_osdmap();
9118 // this *will* return data due to the RETURNVEC flag
9122 ObjectWriteOperation o
;
9123 o
.exec("hello", "write_return_data", in
, &out
, &rval
);
9124 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9125 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &o
,
9126 librados::OPERATION_RETURNVEC
));
9127 completion
->wait_for_complete();
9128 ASSERT_EQ(42, completion
->get_return_value());
9129 ASSERT_EQ(42, rval
);
9130 out
.hexdump(std::cout
);
9131 ASSERT_EQ("you might see this", std::string(out
.c_str(), out
.length()));
9134 // this will overflow because the return data is too big
9138 ObjectWriteOperation o
;
9139 o
.exec("hello", "write_too_much_return_data", in
, &out
, &rval
);
9140 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9141 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &o
,
9142 librados::OPERATION_RETURNVEC
));
9143 completion
->wait_for_complete();
9144 ASSERT_EQ(-EOVERFLOW
, completion
->get_return_value());
9145 ASSERT_EQ(-EOVERFLOW
, rval
);
9146 ASSERT_EQ("", std::string(out
.c_str(), out
.length()));
9150 TEST_F(LibRadosTwoPoolsPP
, TierFlushDuringUnsetDedupTier
) {
9151 // skip test if not yet octopus
9152 if (_get_required_osd_release(cluster
) < "octopus") {
9153 cout
<< "cluster is not yet octopus, skipping test" << std::endl
;
9159 // set dedup parameters without dedup_tier
9160 ASSERT_EQ(0, cluster
.mon_command(
9161 set_pool_str(cache_pool_name
, "fingerprint_algorithm", "sha1"),
9163 ASSERT_EQ(0, cluster
.mon_command(
9164 set_pool_str(cache_pool_name
, "dedup_chunk_algorithm", "fastcdc"),
9166 ASSERT_EQ(0, cluster
.mon_command(
9167 set_pool_str(cache_pool_name
, "dedup_cdc_chunk_size", 1024),
9173 generate_buffer(1024*8, &gbl
);
9174 ObjectWriteOperation op
;
9176 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
9180 bl
.append("there hiHI");
9181 ObjectWriteOperation op
;
9183 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
9186 // wait for maps to settle
9187 cluster
.wait_for_latest_osdmap();
9189 // set-chunk to set manifest object
9191 ObjectReadOperation op
;
9192 op
.set_chunk(0, 2, ioctx
, "bar", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
9193 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9194 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
9195 librados::OPERATION_IGNORE_CACHE
, NULL
));
9196 completion
->wait_for_complete();
9197 ASSERT_EQ(0, completion
->get_return_value());
9198 completion
->release();
9201 // flush to check if proper error is returned
9203 ObjectReadOperation op
;
9205 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
9206 ASSERT_EQ(0, cache_ioctx
.aio_operate(
9207 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
9208 completion
->wait_for_complete();
9209 ASSERT_EQ(-EINVAL
, completion
->get_return_value());
9210 completion
->release();