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"
18 #include "osd/HitSet.h"
25 using namespace librados
;
27 using std::ostringstream
;
30 typedef RadosTestPP LibRadosTierPP
;
31 typedef RadosTestECPP LibRadosTierECPP
;
33 void flush_evict_all(librados::Rados
& cluster
, librados::IoCtx
& cache_ioctx
)
36 cache_ioctx
.set_namespace(all_nspaces
);
37 for (NObjectIterator it
= cache_ioctx
.nobjects_begin();
38 it
!= cache_ioctx
.nobjects_end(); ++it
) {
39 cache_ioctx
.locator_set_key(it
->get_locator());
40 cache_ioctx
.set_namespace(it
->get_nspace());
42 ObjectReadOperation op
;
44 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
45 cache_ioctx
.aio_operate(
46 it
->get_oid(), completion
, &op
,
47 librados::OPERATION_IGNORE_OVERLAY
, NULL
);
48 completion
->wait_for_complete();
49 completion
->get_return_value();
50 completion
->release();
53 ObjectReadOperation op
;
55 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
56 cache_ioctx
.aio_operate(
57 it
->get_oid(), completion
, &op
,
58 librados::OPERATION_IGNORE_OVERLAY
, NULL
);
59 completion
->wait_for_complete();
60 completion
->get_return_value();
61 completion
->release();
66 static string
_get_required_osd_release(Rados
& cluster
)
69 string cmd
= string("{\"prefix\": \"osd dump\",\"format\":\"json\"}");
71 int r
= cluster
.mon_command(cmd
, inbl
, &outbl
, NULL
);
73 string
outstr(outbl
.c_str(), outbl
.length());
75 if (!json_spirit::read(outstr
, v
)) {
76 cerr
<<" unable to parse json " << outstr
<< std::endl
;
80 json_spirit::Object
& o
= v
.get_obj();
81 for (json_spirit::Object::size_type i
=0; i
<o
.size(); i
++) {
82 json_spirit::Pair
& p
= o
[i
];
83 if (p
.name_
== "require_osd_release") {
84 cout
<< "require_osd_release = " << p
.value_
.get_str() << std::endl
;
85 return p
.value_
.get_str();
88 cerr
<< "didn't find require_osd_release in " << outstr
<< std::endl
;
92 class LibRadosTwoPoolsPP
: public RadosTestPP
95 LibRadosTwoPoolsPP() {};
96 ~LibRadosTwoPoolsPP() override
{};
98 static void SetUpTestCase() {
99 pool_name
= get_temp_pool_name();
100 ASSERT_EQ("", create_one_pool_pp(pool_name
, s_cluster
));
102 static void TearDownTestCase() {
103 ASSERT_EQ(0, destroy_one_pool_pp(pool_name
, s_cluster
));
105 static std::string cache_pool_name
;
107 void SetUp() override
{
108 cache_pool_name
= get_temp_pool_name();
109 ASSERT_EQ(0, s_cluster
.pool_create(cache_pool_name
.c_str()));
110 RadosTestPP::SetUp();
112 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
113 cache_ioctx
.application_enable("rados", true);
114 cache_ioctx
.set_namespace(nspace
);
116 void TearDown() override
{
117 // flush + evict cache
118 flush_evict_all(cluster
, cache_ioctx
);
122 ASSERT_EQ(0, cluster
.mon_command(
123 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
126 ASSERT_EQ(0, cluster
.mon_command(
127 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
128 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
131 // wait for maps to settle before next test
132 cluster
.wait_for_latest_osdmap();
134 RadosTestPP::TearDown();
136 cleanup_default_namespace(cache_ioctx
);
137 cleanup_namespace(cache_ioctx
, nspace
);
140 ASSERT_EQ(0, s_cluster
.pool_delete(cache_pool_name
.c_str()));
142 librados::IoCtx cache_ioctx
;
148 Completions() = default;
149 librados::AioCompletion
* getCompletion() {
150 librados::AioCompletion
* comp
= librados::Rados::aio_create_completion();
151 m_completions
.push_back(comp
);
156 for (auto& comp
: m_completions
) {
162 vector
<librados::AioCompletion
*> m_completions
;
165 Completions completions
;
167 std::string
LibRadosTwoPoolsPP::cache_pool_name
;
169 TEST_F(LibRadosTierPP
, Dirty
) {
171 ObjectWriteOperation op
;
173 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still get 0 if it dne
176 ObjectWriteOperation op
;
178 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
183 ObjectReadOperation op
;
184 op
.is_dirty(&dirty
, &r
);
185 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
190 ObjectWriteOperation op
;
192 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
195 ObjectWriteOperation op
;
197 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still 0 if already clean
202 ObjectReadOperation op
;
203 op
.is_dirty(&dirty
, &r
);
204 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
209 ObjectWriteOperation op
;
210 op
.truncate(0); // still a write even tho it is a no-op
211 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
216 ObjectReadOperation op
;
217 op
.is_dirty(&dirty
, &r
);
218 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
224 TEST_F(LibRadosTwoPoolsPP
, Overlay
) {
229 ObjectWriteOperation op
;
231 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
236 ObjectWriteOperation op
;
238 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
243 ASSERT_EQ(0, cluster
.mon_command(
244 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
245 "\", \"tierpool\": \"" + cache_pool_name
+
246 "\", \"force_nonempty\": \"--force-nonempty\" }",
248 ASSERT_EQ(0, cluster
.mon_command(
249 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
250 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
253 // wait for maps to settle
254 cluster
.wait_for_latest_osdmap();
256 // by default, the overlay sends us to cache pool
259 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
260 ASSERT_EQ('c', bl
[0]);
264 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
265 ASSERT_EQ('c', bl
[0]);
268 // unless we say otherwise
271 ObjectReadOperation op
;
272 op
.read(0, 1, &bl
, NULL
);
273 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
274 ASSERT_EQ(0, ioctx
.aio_operate(
275 "foo", completion
, &op
,
276 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
277 completion
->wait_for_complete();
278 ASSERT_EQ(0, completion
->get_return_value());
279 completion
->release();
280 ASSERT_EQ('b', bl
[0]);
284 TEST_F(LibRadosTwoPoolsPP
, Promote
) {
288 bl
.append("hi there");
289 ObjectWriteOperation op
;
291 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
296 ASSERT_EQ(0, cluster
.mon_command(
297 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
298 "\", \"tierpool\": \"" + cache_pool_name
+
299 "\", \"force_nonempty\": \"--force-nonempty\" }",
301 ASSERT_EQ(0, cluster
.mon_command(
302 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
303 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
305 ASSERT_EQ(0, cluster
.mon_command(
306 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
307 "\", \"mode\": \"writeback\"}",
310 // wait for maps to settle
311 cluster
.wait_for_latest_osdmap();
313 // read, trigger a promote
316 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
319 // read, trigger a whiteout
322 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
323 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
326 // verify the object is present in the cache tier
328 NObjectIterator it
= cache_ioctx
.nobjects_begin();
329 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
330 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
332 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
334 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
338 TEST_F(LibRadosTwoPoolsPP
, PromoteSnap
) {
342 bl
.append("hi there");
343 ObjectWriteOperation op
;
345 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
349 bl
.append("hi there");
350 ObjectWriteOperation op
;
352 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
356 bl
.append("hi there");
357 ObjectWriteOperation op
;
359 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
363 bl
.append("hi there");
364 ObjectWriteOperation op
;
366 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
369 // create a snapshot, clone
370 vector
<uint64_t> my_snaps(1);
371 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
372 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
377 ObjectWriteOperation op
;
379 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
384 ObjectWriteOperation op
;
386 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
389 ObjectWriteOperation op
;
391 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
396 ObjectWriteOperation op
;
398 ASSERT_EQ(0, ioctx
.operate("bam", &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 on the head
423 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
424 ASSERT_EQ('c', bl
[0]);
428 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
429 ASSERT_EQ('c', bl
[0]);
432 ioctx
.snap_set_read(my_snaps
[0]);
437 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
438 ASSERT_EQ('h', bl
[0]);
444 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
445 ASSERT_EQ('h', bl
[0]);
451 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
452 ASSERT_EQ('h', bl
[0]);
455 ioctx
.snap_set_read(librados::SNAP_HEAD
);
460 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
461 ASSERT_EQ('c', bl
[0]);
467 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
468 ASSERT_EQ('c', bl
[0]);
474 ASSERT_EQ(-ENOENT
, ioctx
.read("baz", bl
, 1, 0));
478 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
481 TEST_F(LibRadosTwoPoolsPP
, PromoteSnapScrub
) {
485 for (int i
=0; i
<num
; ++i
) {
487 bl
.append("hi there");
488 ObjectWriteOperation op
;
490 ASSERT_EQ(0, ioctx
.operate(string("foo") + stringify(i
), &op
));
493 vector
<uint64_t> my_snaps
;
494 for (int snap
=0; snap
<4; ++snap
) {
495 // create a snapshot, clone
496 vector
<uint64_t> ns(1);
497 ns
.insert(ns
.end(), my_snaps
.begin(), my_snaps
.end());
499 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
500 cout
<< "my_snaps " << my_snaps
<< std::endl
;
501 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
503 for (int i
=0; i
<num
; ++i
) {
505 bl
.append(string("ciao! snap") + stringify(snap
));
506 ObjectWriteOperation op
;
508 ASSERT_EQ(0, ioctx
.operate(string("foo") + stringify(i
), &op
));
514 ASSERT_EQ(0, cluster
.mon_command(
515 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
516 "\", \"tierpool\": \"" + cache_pool_name
+
517 "\", \"force_nonempty\": \"--force-nonempty\" }",
519 ASSERT_EQ(0, cluster
.mon_command(
520 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
521 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
523 ASSERT_EQ(0, cluster
.mon_command(
524 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
525 "\", \"mode\": \"writeback\"}",
528 // wait for maps to settle
529 cluster
.wait_for_latest_osdmap();
531 // read, trigger a promote on _some_ heads to make sure we handle cases
532 // where snaps are present and where they are not.
533 cout
<< "promoting some heads" << std::endl
;
534 for (int i
=0; i
<num
; ++i
) {
535 if (i
% 5 == 0 || i
> num
- 3) {
537 ASSERT_EQ(1, ioctx
.read(string("foo") + stringify(i
), bl
, 1, 0));
538 ASSERT_EQ('c', bl
[0]);
542 for (unsigned snap
= 0; snap
< my_snaps
.size(); ++snap
) {
543 cout
<< "promoting from clones for snap " << my_snaps
[snap
] << std::endl
;
544 ioctx
.snap_set_read(my_snaps
[snap
]);
546 // read some snaps, semi-randomly
547 for (int i
=0; i
<50; ++i
) {
549 string o
= string("foo") + stringify((snap
* i
* 137) % 80);
550 //cout << o << std::endl;
551 ASSERT_EQ(1, ioctx
.read(o
, bl
, 1, 0));
555 // ok, stop and scrub this pool (to make sure scrub can handle
556 // missing clones in the cache tier).
559 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
560 for (int i
=0; i
<10; ++i
) {
563 ss
<< "{\"prefix\": \"pg scrub\", \"pgid\": \""
564 << cache_ioctx
.get_id() << "." << i
566 int r
= cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
567 if (r
== -ENOENT
|| // in case mgr osdmap is stale
575 // give it a few seconds to go. this is sloppy but is usually enough time
576 cout
<< "waiting for scrubs..." << std::endl
;
578 cout
<< "done waiting" << std::endl
;
581 ioctx
.snap_set_read(librados::SNAP_HEAD
);
584 for (unsigned snap
= 0; snap
< my_snaps
.size(); ++snap
) {
585 ioctx
.selfmanaged_snap_remove(my_snaps
[snap
]);
589 TEST_F(LibRadosTwoPoolsPP
, PromoteSnapTrimRace
) {
593 bl
.append("hi there");
594 ObjectWriteOperation op
;
596 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
599 // create a snapshot, clone
600 vector
<uint64_t> my_snaps(1);
601 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
602 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
607 ObjectWriteOperation op
;
609 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
614 ASSERT_EQ(0, cluster
.mon_command(
615 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
616 "\", \"tierpool\": \"" + cache_pool_name
+
617 "\", \"force_nonempty\": \"--force-nonempty\" }",
619 ASSERT_EQ(0, cluster
.mon_command(
620 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
621 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
623 ASSERT_EQ(0, cluster
.mon_command(
624 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
625 "\", \"mode\": \"writeback\"}",
628 // wait for maps to settle
629 cluster
.wait_for_latest_osdmap();
632 ASSERT_EQ(0, ioctx
.selfmanaged_snap_remove(my_snaps
[0]));
634 ioctx
.snap_set_read(my_snaps
[0]);
636 // read foo snap. the OSD may or may not realize that this snap has
637 // been logically deleted; either response is valid.
640 int r
= ioctx
.read("foo", bl
, 1, 0);
641 ASSERT_TRUE(r
== 1 || r
== -ENOENT
);
645 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
648 TEST_F(LibRadosTwoPoolsPP
, Whiteout
) {
652 bl
.append("hi there");
653 ObjectWriteOperation op
;
655 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
660 ASSERT_EQ(0, cluster
.mon_command(
661 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
662 "\", \"tierpool\": \"" + cache_pool_name
+
663 "\", \"force_nonempty\": \"--force-nonempty\" }",
665 ASSERT_EQ(0, cluster
.mon_command(
666 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
667 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
669 ASSERT_EQ(0, cluster
.mon_command(
670 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
671 "\", \"mode\": \"writeback\"}",
674 // wait for maps to settle
675 cluster
.wait_for_latest_osdmap();
677 // create some whiteouts, verify they behave
679 ObjectWriteOperation op
;
682 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
686 ObjectWriteOperation op
;
689 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
692 ObjectWriteOperation op
;
695 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
698 // verify the whiteouts are there in the cache tier
700 NObjectIterator it
= cache_ioctx
.nobjects_begin();
701 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
702 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
704 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
706 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
709 // delete a whiteout and verify it goes away
710 ASSERT_EQ(-ENOENT
, ioctx
.remove("foo"));
712 ObjectWriteOperation op
;
714 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
715 ASSERT_EQ(0, ioctx
.aio_operate("bar", completion
, &op
,
716 librados::OPERATION_IGNORE_CACHE
));
717 completion
->wait_for_complete();
718 ASSERT_EQ(0, completion
->get_return_value());
719 completion
->release();
721 NObjectIterator it
= cache_ioctx
.nobjects_begin();
722 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
723 ASSERT_TRUE(it
->get_oid() == string("foo"));
725 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
728 // recreate an object and verify we can read it
731 bl
.append("hi there");
732 ObjectWriteOperation op
;
734 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
738 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
739 ASSERT_EQ('h', bl
[0]);
743 TEST_F(LibRadosTwoPoolsPP
, WhiteoutDeleteCreate
) {
746 ASSERT_EQ(0, cluster
.mon_command(
747 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
748 "\", \"tierpool\": \"" + cache_pool_name
+
749 "\", \"force_nonempty\": \"--force-nonempty\" }",
751 ASSERT_EQ(0, cluster
.mon_command(
752 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
753 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
755 ASSERT_EQ(0, cluster
.mon_command(
756 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
757 "\", \"mode\": \"writeback\"}",
760 // wait for maps to settle
761 cluster
.wait_for_latest_osdmap();
767 ASSERT_EQ(0, ioctx
.write_full("foo", bl
));
770 // do delete + create operation
772 ObjectWriteOperation op
;
777 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
780 // verify it still "exists" (w/ new content)
783 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
784 ASSERT_EQ('b', bl
[0]);
788 TEST_F(LibRadosTwoPoolsPP
, Evict
) {
792 bl
.append("hi there");
793 ObjectWriteOperation op
;
795 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
800 ASSERT_EQ(0, cluster
.mon_command(
801 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
802 "\", \"tierpool\": \"" + cache_pool_name
+
803 "\", \"force_nonempty\": \"--force-nonempty\" }",
805 ASSERT_EQ(0, cluster
.mon_command(
806 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
807 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
809 ASSERT_EQ(0, cluster
.mon_command(
810 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
811 "\", \"mode\": \"writeback\"}",
814 // wait for maps to settle
815 cluster
.wait_for_latest_osdmap();
817 // read, trigger a promote
820 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
823 // read, trigger a whiteout, and a dirty object
826 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
827 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
828 ASSERT_EQ(0, ioctx
.write("bar", bl
, bl
.length(), 0));
831 // verify the object is present in the cache tier
833 NObjectIterator it
= cache_ioctx
.nobjects_begin();
834 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
835 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
837 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
839 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
844 ObjectWriteOperation op
;
846 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
847 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
848 completion
->wait_for_complete();
849 ASSERT_EQ(0, completion
->get_return_value());
850 completion
->release();
853 // evict the pinned object with -EPERM
855 ObjectReadOperation op
;
857 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
858 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
859 librados::OPERATION_IGNORE_CACHE
,
861 completion
->wait_for_complete();
862 ASSERT_EQ(-EPERM
, completion
->get_return_value());
863 completion
->release();
868 ObjectWriteOperation op
;
870 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
871 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
872 completion
->wait_for_complete();
873 ASSERT_EQ(0, completion
->get_return_value());
874 completion
->release();
879 ObjectReadOperation op
;
881 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
882 ASSERT_EQ(0, cache_ioctx
.aio_operate(
883 "foo", completion
, &op
,
884 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
885 completion
->wait_for_complete();
886 ASSERT_EQ(0, completion
->get_return_value());
887 completion
->release();
894 ObjectReadOperation op
;
895 op
.is_dirty(&dirty
, &r
);
896 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
903 ObjectReadOperation op
;
905 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
906 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
907 librados::OPERATION_IGNORE_CACHE
,
909 completion
->wait_for_complete();
910 ASSERT_EQ(0, completion
->get_return_value());
911 completion
->release();
914 ObjectReadOperation op
;
916 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
917 ASSERT_EQ(0, cache_ioctx
.aio_operate(
918 "foo", completion
, &op
,
919 librados::OPERATION_IGNORE_CACHE
, NULL
));
920 completion
->wait_for_complete();
921 ASSERT_EQ(0, completion
->get_return_value());
922 completion
->release();
925 ObjectReadOperation op
;
927 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
928 ASSERT_EQ(0, cache_ioctx
.aio_operate(
929 "bar", completion
, &op
,
930 librados::OPERATION_IGNORE_CACHE
, NULL
));
931 completion
->wait_for_complete();
932 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
933 completion
->release();
937 TEST_F(LibRadosTwoPoolsPP
, EvictSnap
) {
941 bl
.append("hi there");
942 ObjectWriteOperation op
;
944 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
948 bl
.append("hi there");
949 ObjectWriteOperation op
;
951 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
955 bl
.append("hi there");
956 ObjectWriteOperation op
;
958 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
962 bl
.append("hi there");
963 ObjectWriteOperation op
;
965 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
968 // create a snapshot, clone
969 vector
<uint64_t> my_snaps(1);
970 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
971 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
976 ObjectWriteOperation op
;
978 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
983 ObjectWriteOperation op
;
985 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
988 ObjectWriteOperation op
;
990 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
995 ObjectWriteOperation op
;
997 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
1002 ASSERT_EQ(0, cluster
.mon_command(
1003 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1004 "\", \"tierpool\": \"" + cache_pool_name
+
1005 "\", \"force_nonempty\": \"--force-nonempty\" }",
1007 ASSERT_EQ(0, cluster
.mon_command(
1008 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1009 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1011 ASSERT_EQ(0, cluster
.mon_command(
1012 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1013 "\", \"mode\": \"writeback\"}",
1016 // wait for maps to settle
1017 cluster
.wait_for_latest_osdmap();
1019 // read, trigger a promote on the head
1022 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1023 ASSERT_EQ('c', bl
[0]);
1027 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
1028 ASSERT_EQ('c', bl
[0]);
1033 ObjectReadOperation op
;
1035 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1036 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1037 "bam", completion
, &op
,
1038 librados::OPERATION_IGNORE_CACHE
, NULL
));
1039 completion
->wait_for_complete();
1040 ASSERT_EQ(0, completion
->get_return_value());
1041 completion
->release();
1045 ObjectReadOperation op
;
1046 op
.read(1, 0, &bl
, NULL
);
1047 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1048 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1049 "bam", completion
, &op
,
1050 librados::OPERATION_IGNORE_CACHE
, NULL
));
1051 completion
->wait_for_complete();
1052 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1053 completion
->release();
1057 ioctx
.snap_set_read(my_snaps
[0]);
1060 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1061 ASSERT_EQ('h', bl
[0]);
1066 ObjectReadOperation op
;
1068 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1069 ASSERT_EQ(0, ioctx
.aio_operate(
1070 "foo", completion
, &op
,
1071 librados::OPERATION_IGNORE_CACHE
, NULL
));
1072 completion
->wait_for_complete();
1073 ASSERT_EQ(0, completion
->get_return_value());
1074 completion
->release();
1079 ObjectReadOperation op
;
1080 op
.read(1, 0, &bl
, NULL
);
1081 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1082 ASSERT_EQ(0, ioctx
.aio_operate(
1083 "foo", completion
, &op
,
1084 librados::OPERATION_IGNORE_CACHE
, NULL
));
1085 completion
->wait_for_complete();
1086 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1087 completion
->release();
1089 // head is still there...
1090 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1093 ObjectReadOperation op
;
1094 op
.read(1, 0, &bl
, NULL
);
1095 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1096 ASSERT_EQ(0, ioctx
.aio_operate(
1097 "foo", completion
, &op
,
1098 librados::OPERATION_IGNORE_CACHE
, NULL
));
1099 completion
->wait_for_complete();
1100 ASSERT_EQ(0, completion
->get_return_value());
1101 completion
->release();
1104 // promote head + snap of bar
1105 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1108 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
1109 ASSERT_EQ('c', bl
[0]);
1111 ioctx
.snap_set_read(my_snaps
[0]);
1114 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
1115 ASSERT_EQ('h', bl
[0]);
1118 // evict bar head (fail)
1119 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1121 ObjectReadOperation op
;
1123 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1124 ASSERT_EQ(0, ioctx
.aio_operate(
1125 "bar", completion
, &op
,
1126 librados::OPERATION_IGNORE_CACHE
, NULL
));
1127 completion
->wait_for_complete();
1128 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
1129 completion
->release();
1133 ioctx
.snap_set_read(my_snaps
[0]);
1135 ObjectReadOperation op
;
1137 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1138 ASSERT_EQ(0, ioctx
.aio_operate(
1139 "bar", completion
, &op
,
1140 librados::OPERATION_IGNORE_CACHE
, NULL
));
1141 completion
->wait_for_complete();
1142 ASSERT_EQ(0, completion
->get_return_value());
1143 completion
->release();
1146 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1149 ObjectReadOperation op
;
1150 op
.read(1, 0, &bl
, NULL
);
1151 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1152 ASSERT_EQ(0, ioctx
.aio_operate(
1153 "bar", completion
, &op
,
1154 librados::OPERATION_IGNORE_CACHE
, NULL
));
1155 completion
->wait_for_complete();
1156 ASSERT_EQ(0, completion
->get_return_value());
1157 completion
->release();
1160 ObjectReadOperation op
;
1162 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1163 ASSERT_EQ(0, ioctx
.aio_operate(
1164 "bar", completion
, &op
,
1165 librados::OPERATION_IGNORE_CACHE
, NULL
));
1166 completion
->wait_for_complete();
1167 ASSERT_EQ(0, completion
->get_return_value());
1168 completion
->release();
1172 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
1175 // this test case reproduces http://tracker.ceph.com/issues/8629
1176 TEST_F(LibRadosTwoPoolsPP
, EvictSnap2
) {
1180 bl
.append("hi there");
1181 ObjectWriteOperation op
;
1183 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1185 // create a snapshot, clone
1186 vector
<uint64_t> my_snaps(1);
1187 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1188 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1193 ObjectWriteOperation op
;
1195 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1199 ASSERT_EQ(0, cluster
.mon_command(
1200 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1201 "\", \"tierpool\": \"" + cache_pool_name
+
1202 "\", \"force_nonempty\": \"--force-nonempty\" }",
1204 ASSERT_EQ(0, cluster
.mon_command(
1205 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1206 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1208 ASSERT_EQ(0, cluster
.mon_command(
1209 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1210 "\", \"mode\": \"writeback\"}",
1213 // wait for maps to settle
1214 cluster
.wait_for_latest_osdmap();
1216 // read, trigger a promote on the head
1219 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1220 ASSERT_EQ('c', bl
[0]);
1225 ObjectReadOperation op
;
1227 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1228 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1229 "foo", completion
, &op
,
1230 librados::OPERATION_IGNORE_CACHE
, NULL
));
1231 completion
->wait_for_complete();
1232 ASSERT_EQ(0, completion
->get_return_value());
1233 completion
->release();
1236 // verify the snapdir is not present in the cache pool
1238 ObjectReadOperation op
;
1239 librados::snap_set_t snapset
;
1240 op
.list_snaps(&snapset
, NULL
);
1241 ioctx
.snap_set_read(librados::SNAP_DIR
);
1242 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1243 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
,
1244 librados::OPERATION_IGNORE_CACHE
, NULL
));
1245 completion
->wait_for_complete();
1246 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1247 completion
->release();
1251 //This test case reproduces http://tracker.ceph.com/issues/17445
1252 TEST_F(LibRadosTwoPoolsPP
, ListSnap
){
1256 bl
.append("hi there");
1257 ObjectWriteOperation op
;
1259 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1263 bl
.append("hi there");
1264 ObjectWriteOperation op
;
1266 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
1270 bl
.append("hi there");
1271 ObjectWriteOperation op
;
1273 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
1277 bl
.append("hi there");
1278 ObjectWriteOperation op
;
1280 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
1283 // Create a snapshot, clone
1284 vector
<uint64_t> my_snaps(1);
1285 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1286 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1291 ObjectWriteOperation op
;
1293 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1298 ObjectWriteOperation op
;
1300 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
1303 ObjectWriteOperation op
;
1305 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
1310 ObjectWriteOperation op
;
1312 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
1317 ASSERT_EQ(0, cluster
.mon_command(
1318 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1319 "\", \"tierpool\": \"" + cache_pool_name
+
1320 "\", \"force_nonempty\": \"--force-nonempty\" }",
1322 ASSERT_EQ(0, cluster
.mon_command(
1323 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1324 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1326 ASSERT_EQ(0, cluster
.mon_command(
1327 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1328 "\", \"mode\": \"writeback\"}",
1331 // Wait for maps to settle
1332 cluster
.wait_for_latest_osdmap();
1334 // Read, trigger a promote on the head
1337 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1338 ASSERT_EQ('c', bl
[0]);
1342 ioctx
.snap_set_read(my_snaps
[0]);
1345 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1346 ASSERT_EQ('h', bl
[0]);
1351 ObjectReadOperation op
;
1353 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1354 ASSERT_EQ(0, ioctx
.aio_operate(
1355 "foo", completion
, &op
,
1356 librados::OPERATION_IGNORE_CACHE
, NULL
));
1357 completion
->wait_for_complete();
1358 ASSERT_EQ(0, completion
->get_return_value());
1359 completion
->release();
1364 ObjectReadOperation op
;
1365 op
.read(1, 0, &bl
, NULL
);
1366 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1367 ASSERT_EQ(0, ioctx
.aio_operate(
1368 "foo", completion
, &op
,
1369 librados::OPERATION_IGNORE_CACHE
, NULL
));
1370 completion
->wait_for_complete();
1371 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
1372 completion
->release();
1376 ioctx
.snap_set_read(CEPH_SNAPDIR
);
1378 snap_set_t snap_set
;
1380 ObjectReadOperation op
;
1381 op
.list_snaps(&snap_set
, &snap_ret
);
1382 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1383 ASSERT_EQ(0, ioctx
.aio_operate(
1384 "foo", completion
, &op
,
1386 completion
->wait_for_complete();
1387 ASSERT_EQ(0, snap_ret
);
1388 ASSERT_LT(0u, snap_set
.clones
.size());
1389 for (vector
<librados::clone_info_t
>::const_iterator r
= snap_set
.clones
.begin();
1390 r
!= snap_set
.clones
.end();
1392 if (r
->cloneid
!= librados::SNAP_HEAD
) {
1393 ASSERT_LT(0u, r
->snaps
.size());
1399 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
1402 TEST_F(LibRadosTwoPoolsPP
, TryFlush
) {
1405 ASSERT_EQ(0, cluster
.mon_command(
1406 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1407 "\", \"tierpool\": \"" + cache_pool_name
+
1408 "\", \"force_nonempty\": \"--force-nonempty\" }",
1410 ASSERT_EQ(0, cluster
.mon_command(
1411 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1412 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1414 ASSERT_EQ(0, cluster
.mon_command(
1415 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1416 "\", \"mode\": \"writeback\"}",
1419 // wait for maps to settle
1420 cluster
.wait_for_latest_osdmap();
1425 bl
.append("hi there");
1426 ObjectWriteOperation op
;
1428 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1431 // verify the object is present in the cache tier
1433 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1434 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
1435 ASSERT_TRUE(it
->get_oid() == string("foo"));
1437 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1440 // verify the object is NOT present in the base tier
1442 NObjectIterator it
= ioctx
.nobjects_begin();
1443 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1450 ObjectReadOperation op
;
1451 op
.is_dirty(&dirty
, &r
);
1452 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1459 ObjectWriteOperation op
;
1461 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1462 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1463 completion
->wait_for_complete();
1464 ASSERT_EQ(0, completion
->get_return_value());
1465 completion
->release();
1468 // flush the pinned object with -EPERM
1470 ObjectReadOperation op
;
1471 op
.cache_try_flush();
1472 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1473 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1474 "foo", completion
, &op
,
1475 librados::OPERATION_IGNORE_OVERLAY
|
1476 librados::OPERATION_SKIPRWLOCKS
, NULL
));
1477 completion
->wait_for_complete();
1478 ASSERT_EQ(-EPERM
, completion
->get_return_value());
1479 completion
->release();
1484 ObjectWriteOperation op
;
1486 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1487 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1488 completion
->wait_for_complete();
1489 ASSERT_EQ(0, completion
->get_return_value());
1490 completion
->release();
1495 ObjectReadOperation op
;
1496 op
.cache_try_flush();
1497 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1498 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1499 "foo", completion
, &op
,
1500 librados::OPERATION_IGNORE_OVERLAY
|
1501 librados::OPERATION_SKIPRWLOCKS
, NULL
));
1502 completion
->wait_for_complete();
1503 ASSERT_EQ(0, completion
->get_return_value());
1504 completion
->release();
1511 ObjectReadOperation op
;
1512 op
.is_dirty(&dirty
, &r
);
1513 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1514 ASSERT_FALSE(dirty
);
1518 // verify in base tier
1520 NObjectIterator it
= ioctx
.nobjects_begin();
1521 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
1522 ASSERT_TRUE(it
->get_oid() == string("foo"));
1524 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1529 ObjectReadOperation op
;
1531 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1532 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1533 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
1534 completion
->wait_for_complete();
1535 ASSERT_EQ(0, completion
->get_return_value());
1536 completion
->release();
1539 // verify no longer in cache tier
1541 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1542 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1546 TEST_F(LibRadosTwoPoolsPP
, Flush
) {
1549 ASSERT_EQ(0, cluster
.mon_command(
1550 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1551 "\", \"tierpool\": \"" + cache_pool_name
+
1552 "\", \"force_nonempty\": \"--force-nonempty\" }",
1554 ASSERT_EQ(0, cluster
.mon_command(
1555 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1556 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1558 ASSERT_EQ(0, cluster
.mon_command(
1559 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1560 "\", \"mode\": \"writeback\"}",
1563 // wait for maps to settle
1564 cluster
.wait_for_latest_osdmap();
1566 uint64_t user_version
= 0;
1571 bl
.append("hi there");
1572 ObjectWriteOperation op
;
1574 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1577 // verify the object is present in the cache tier
1579 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1580 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
1581 ASSERT_TRUE(it
->get_oid() == string("foo"));
1583 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1586 // verify the object is NOT present in the base tier
1588 NObjectIterator it
= ioctx
.nobjects_begin();
1589 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1596 ObjectReadOperation op
;
1597 op
.is_dirty(&dirty
, &r
);
1598 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1601 user_version
= cache_ioctx
.get_last_version();
1606 ObjectWriteOperation op
;
1608 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1609 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1610 completion
->wait_for_complete();
1611 ASSERT_EQ(0, completion
->get_return_value());
1612 completion
->release();
1615 // flush the pinned object with -EPERM
1617 ObjectReadOperation op
;
1618 op
.cache_try_flush();
1619 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1620 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1621 "foo", completion
, &op
,
1622 librados::OPERATION_IGNORE_OVERLAY
|
1623 librados::OPERATION_SKIPRWLOCKS
, NULL
));
1624 completion
->wait_for_complete();
1625 ASSERT_EQ(-EPERM
, completion
->get_return_value());
1626 completion
->release();
1631 ObjectWriteOperation op
;
1633 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1634 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
1635 completion
->wait_for_complete();
1636 ASSERT_EQ(0, completion
->get_return_value());
1637 completion
->release();
1642 ObjectReadOperation op
;
1644 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1645 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1646 "foo", completion
, &op
,
1647 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
1648 completion
->wait_for_complete();
1649 ASSERT_EQ(0, completion
->get_return_value());
1650 completion
->release();
1657 ObjectReadOperation op
;
1658 op
.is_dirty(&dirty
, &r
);
1659 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
1660 ASSERT_FALSE(dirty
);
1664 // verify in base tier
1666 NObjectIterator it
= ioctx
.nobjects_begin();
1667 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
1668 ASSERT_TRUE(it
->get_oid() == string("foo"));
1670 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1675 ObjectReadOperation op
;
1677 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1678 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1679 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
1680 completion
->wait_for_complete();
1681 ASSERT_EQ(0, completion
->get_return_value());
1682 completion
->release();
1685 // verify no longer in cache tier
1687 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1688 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1691 // read it again and verify the version is consistent
1694 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
1695 ASSERT_EQ(user_version
, cache_ioctx
.get_last_version());
1700 ObjectWriteOperation op
;
1702 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1707 ObjectReadOperation op
;
1709 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1710 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1711 "foo", completion
, &op
,
1712 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
1713 completion
->wait_for_complete();
1714 ASSERT_EQ(0, completion
->get_return_value());
1715 completion
->release();
1720 ObjectReadOperation op
;
1722 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1723 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1724 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
1725 completion
->wait_for_complete();
1726 ASSERT_EQ(0, completion
->get_return_value());
1727 completion
->release();
1730 // verify no longer in cache tier
1732 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1733 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1737 NObjectIterator it
= ioctx
.nobjects_begin();
1738 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1742 TEST_F(LibRadosTwoPoolsPP
, FlushSnap
) {
1745 ASSERT_EQ(0, cluster
.mon_command(
1746 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1747 "\", \"tierpool\": \"" + cache_pool_name
+
1748 "\", \"force_nonempty\": \"--force-nonempty\" }",
1750 ASSERT_EQ(0, cluster
.mon_command(
1751 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1752 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1754 ASSERT_EQ(0, cluster
.mon_command(
1755 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1756 "\", \"mode\": \"writeback\"}",
1759 // wait for maps to settle
1760 cluster
.wait_for_latest_osdmap();
1766 ObjectWriteOperation op
;
1768 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1771 // create a snapshot, clone
1772 vector
<uint64_t> my_snaps(1);
1773 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1774 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1779 ObjectWriteOperation op
;
1781 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1786 my_snaps
[1] = my_snaps
[0];
1787 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
1788 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
1793 ObjectWriteOperation op
;
1795 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1798 // verify the object is present in the cache tier
1800 NObjectIterator it
= cache_ioctx
.nobjects_begin();
1801 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
1802 ASSERT_TRUE(it
->get_oid() == string("foo"));
1804 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
1807 // verify the object is NOT present in the base tier
1809 NObjectIterator it
= ioctx
.nobjects_begin();
1810 ASSERT_TRUE(it
== ioctx
.nobjects_end());
1813 // flush on head (should fail)
1814 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1816 ObjectReadOperation op
;
1818 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1819 ASSERT_EQ(0, ioctx
.aio_operate(
1820 "foo", completion
, &op
,
1821 librados::OPERATION_IGNORE_CACHE
, NULL
));
1822 completion
->wait_for_complete();
1823 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
1824 completion
->release();
1826 // flush on recent snap (should fail)
1827 ioctx
.snap_set_read(my_snaps
[0]);
1829 ObjectReadOperation op
;
1831 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1832 ASSERT_EQ(0, ioctx
.aio_operate(
1833 "foo", completion
, &op
,
1834 librados::OPERATION_IGNORE_CACHE
, NULL
));
1835 completion
->wait_for_complete();
1836 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
1837 completion
->release();
1839 // flush on oldest snap
1840 ioctx
.snap_set_read(my_snaps
[1]);
1842 ObjectReadOperation op
;
1844 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1845 ASSERT_EQ(0, ioctx
.aio_operate(
1846 "foo", completion
, &op
,
1847 librados::OPERATION_IGNORE_CACHE
, NULL
));
1848 completion
->wait_for_complete();
1849 ASSERT_EQ(0, completion
->get_return_value());
1850 completion
->release();
1852 // flush on next oldest snap
1853 ioctx
.snap_set_read(my_snaps
[0]);
1855 ObjectReadOperation op
;
1857 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1858 ASSERT_EQ(0, ioctx
.aio_operate(
1859 "foo", completion
, &op
,
1860 librados::OPERATION_IGNORE_CACHE
, NULL
));
1861 completion
->wait_for_complete();
1862 ASSERT_EQ(0, completion
->get_return_value());
1863 completion
->release();
1866 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1868 ObjectReadOperation op
;
1870 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1871 ASSERT_EQ(0, ioctx
.aio_operate(
1872 "foo", completion
, &op
,
1873 librados::OPERATION_IGNORE_CACHE
, NULL
));
1874 completion
->wait_for_complete();
1875 ASSERT_EQ(0, completion
->get_return_value());
1876 completion
->release();
1879 // verify i can read the snaps from the cache pool
1880 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1883 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1884 ASSERT_EQ('c', bl
[0]);
1886 ioctx
.snap_set_read(my_snaps
[0]);
1889 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1890 ASSERT_EQ('b', bl
[0]);
1892 ioctx
.snap_set_read(my_snaps
[1]);
1895 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1896 ASSERT_EQ('a', bl
[0]);
1900 ASSERT_EQ(0, cluster
.mon_command(
1901 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
1905 // wait for maps to settle
1906 cluster
.wait_for_latest_osdmap();
1908 // verify i can read the snaps from the base pool
1909 ioctx
.snap_set_read(librados::SNAP_HEAD
);
1912 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1913 ASSERT_EQ('c', bl
[0]);
1915 ioctx
.snap_set_read(my_snaps
[0]);
1918 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1919 ASSERT_EQ('b', bl
[0]);
1921 ioctx
.snap_set_read(my_snaps
[1]);
1924 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
1925 ASSERT_EQ('a', bl
[0]);
1928 ASSERT_EQ(0, cluster
.mon_command(
1929 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1930 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1934 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
1937 TEST_F(LibRadosTierPP
, FlushWriteRaces
) {
1939 std::string pool_name
= get_temp_pool_name();
1940 std::string cache_pool_name
= pool_name
+ "-cache";
1941 ASSERT_EQ("", create_one_pool_pp(pool_name
, cluster
));
1942 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
1944 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
1945 cache_ioctx
.application_enable("rados", true);
1947 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
1951 ASSERT_EQ(0, cluster
.mon_command(
1952 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
1953 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
1955 ASSERT_EQ(0, cluster
.mon_command(
1956 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
1957 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
1959 ASSERT_EQ(0, cluster
.mon_command(
1960 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
1961 "\", \"mode\": \"writeback\"}",
1964 // wait for maps to settle
1965 cluster
.wait_for_latest_osdmap();
1967 // create/dirty object
1969 bl
.append("hi there");
1971 ObjectWriteOperation op
;
1973 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
1978 ObjectReadOperation op
;
1980 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
1981 ASSERT_EQ(0, cache_ioctx
.aio_operate(
1982 "foo", completion
, &op
,
1983 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
1985 ObjectWriteOperation op2
;
1987 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
1988 ASSERT_EQ(0, ioctx
.aio_operate(
1989 "foo", completion2
, &op2
, 0));
1991 completion
->wait_for_complete();
1992 completion2
->wait_for_complete();
1993 ASSERT_EQ(0, completion
->get_return_value());
1994 ASSERT_EQ(0, completion2
->get_return_value());
1995 completion
->release();
1996 completion2
->release();
2001 // create/dirty object
2004 bl
.append("hi there");
2005 ObjectWriteOperation op
;
2007 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2010 // try-flush + write
2012 ObjectReadOperation op
;
2013 op
.cache_try_flush();
2014 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2015 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2016 "foo", completion
, &op
,
2017 librados::OPERATION_IGNORE_OVERLAY
|
2018 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2020 ObjectWriteOperation op2
;
2022 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2023 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion2
, &op2
, 0));
2025 completion
->wait_for_complete();
2026 completion2
->wait_for_complete();
2027 int r
= completion
->get_return_value();
2028 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
2029 ASSERT_EQ(0, completion2
->get_return_value());
2030 completion
->release();
2031 completion2
->release();
2034 cout
<< "didn't get EBUSY, trying again" << std::endl
;
2036 ASSERT_TRUE(--tries
);
2040 ASSERT_EQ(0, cluster
.mon_command(
2041 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
2044 ASSERT_EQ(0, cluster
.mon_command(
2045 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
2046 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2049 // wait for maps to settle before next test
2050 cluster
.wait_for_latest_osdmap();
2052 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
2053 ASSERT_EQ(0, destroy_one_pool_pp(pool_name
, cluster
));
2056 TEST_F(LibRadosTwoPoolsPP
, FlushTryFlushRaces
) {
2059 ASSERT_EQ(0, cluster
.mon_command(
2060 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2061 "\", \"tierpool\": \"" + cache_pool_name
+
2062 "\", \"force_nonempty\": \"--force-nonempty\" }",
2064 ASSERT_EQ(0, cluster
.mon_command(
2065 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2066 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2068 ASSERT_EQ(0, cluster
.mon_command(
2069 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2070 "\", \"mode\": \"writeback\"}",
2073 // wait for maps to settle
2074 cluster
.wait_for_latest_osdmap();
2076 // create/dirty object
2079 bl
.append("hi there");
2080 ObjectWriteOperation op
;
2082 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2087 ObjectReadOperation op
;
2089 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2090 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2091 "foo", completion
, &op
,
2092 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2094 ObjectReadOperation op2
;
2096 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2097 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2098 "foo", completion2
, &op2
,
2099 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2101 completion
->wait_for_complete();
2102 completion2
->wait_for_complete();
2103 ASSERT_EQ(0, completion
->get_return_value());
2104 ASSERT_EQ(0, completion2
->get_return_value());
2105 completion
->release();
2106 completion2
->release();
2109 // create/dirty object
2112 bl
.append("hi there");
2113 ObjectWriteOperation op
;
2115 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2118 // flush + try-flush
2120 ObjectReadOperation op
;
2122 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2123 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2124 "foo", completion
, &op
,
2125 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2127 ObjectReadOperation op2
;
2128 op2
.cache_try_flush();
2129 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2130 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2131 "foo", completion2
, &op2
,
2132 librados::OPERATION_IGNORE_OVERLAY
|
2133 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2135 completion
->wait_for_complete();
2136 completion2
->wait_for_complete();
2137 ASSERT_EQ(0, completion
->get_return_value());
2138 ASSERT_EQ(0, completion2
->get_return_value());
2139 completion
->release();
2140 completion2
->release();
2143 // create/dirty object
2148 bl
.append("hi there");
2149 ObjectWriteOperation op
;
2151 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2154 // try-flush + flush
2155 // (flush will not piggyback on try-flush)
2157 ObjectReadOperation op
;
2158 op
.cache_try_flush();
2159 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2160 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2161 "foo", completion
, &op
,
2162 librados::OPERATION_IGNORE_OVERLAY
|
2163 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2165 ObjectReadOperation op2
;
2167 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2168 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2169 "foo", completion2
, &op2
,
2170 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
2172 completion
->wait_for_complete();
2173 completion2
->wait_for_complete();
2174 int r
= completion
->get_return_value();
2175 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
2176 ASSERT_EQ(0, completion2
->get_return_value());
2177 completion
->release();
2178 completion2
->release();
2181 cout
<< "didn't get EBUSY, trying again" << std::endl
;
2183 ASSERT_TRUE(--tries
);
2186 // create/dirty object
2189 bl
.append("hi there");
2190 ObjectWriteOperation op
;
2192 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2195 // try-flush + try-flush
2197 ObjectReadOperation op
;
2198 op
.cache_try_flush();
2199 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2200 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2201 "foo", completion
, &op
,
2202 librados::OPERATION_IGNORE_OVERLAY
|
2203 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2205 ObjectReadOperation op2
;
2206 op2
.cache_try_flush();
2207 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
2208 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2209 "foo", completion2
, &op2
,
2210 librados::OPERATION_IGNORE_OVERLAY
|
2211 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2213 completion
->wait_for_complete();
2214 completion2
->wait_for_complete();
2215 ASSERT_EQ(0, completion
->get_return_value());
2216 ASSERT_EQ(0, completion2
->get_return_value());
2217 completion
->release();
2218 completion2
->release();
2223 IoCtx
*read_ioctx
= 0;
2224 ceph::mutex test_lock
= ceph::make_mutex("FlushReadRaces::lock");
2225 ceph::condition_variable cond
;
2226 int max_reads
= 100;
2227 int num_reads
= 0; // in progress
2229 void flush_read_race_cb(completion_t cb
, void *arg
);
2231 void start_flush_read()
2233 //cout << " starting read" << std::endl;
2234 ObjectReadOperation op
;
2235 op
.stat(NULL
, NULL
, NULL
);
2236 librados::AioCompletion
*completion
= completions
.getCompletion();
2237 completion
->set_complete_callback(0, flush_read_race_cb
);
2238 read_ioctx
->aio_operate("foo", completion
, &op
, NULL
);
2241 void flush_read_race_cb(completion_t cb
, void *arg
)
2243 //cout << " finished read" << std::endl;
2244 std::lock_guard l
{test_lock
};
2245 if (num_reads
> max_reads
) {
2253 TEST_F(LibRadosTwoPoolsPP
, TryFlushReadRace
) {
2256 ASSERT_EQ(0, cluster
.mon_command(
2257 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2258 "\", \"tierpool\": \"" + cache_pool_name
+
2259 "\", \"force_nonempty\": \"--force-nonempty\" }",
2261 ASSERT_EQ(0, cluster
.mon_command(
2262 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2263 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2265 ASSERT_EQ(0, cluster
.mon_command(
2266 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2267 "\", \"mode\": \"writeback\"}",
2270 // wait for maps to settle
2271 cluster
.wait_for_latest_osdmap();
2273 // create/dirty object
2276 bl
.append("hi there");
2277 bufferptr
bp(4000000); // make it big!
2280 ObjectWriteOperation op
;
2282 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2285 // start a continuous stream of reads
2286 read_ioctx
= &ioctx
;
2288 for (int i
= 0; i
< max_reads
; ++i
) {
2295 ObjectReadOperation op
;
2296 op
.cache_try_flush();
2297 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2298 ASSERT_EQ(0, cache_ioctx
.aio_operate(
2299 "foo", completion
, &op
,
2300 librados::OPERATION_IGNORE_OVERLAY
|
2301 librados::OPERATION_SKIPRWLOCKS
, NULL
));
2303 completion
->wait_for_complete();
2304 ASSERT_EQ(0, completion
->get_return_value());
2305 completion
->release();
2308 std::unique_lock locker
{test_lock
};
2310 cond
.wait(locker
, [] { return num_reads
== 0;});
2313 TEST_F(LibRadosTierPP
, HitSetNone
) {
2315 list
< pair
<time_t,time_t> > ls
;
2316 AioCompletion
*c
= librados::Rados::aio_create_completion();
2317 ASSERT_EQ(0, ioctx
.hit_set_list(123, c
, &ls
));
2318 c
->wait_for_complete();
2319 ASSERT_EQ(0, c
->get_return_value());
2320 ASSERT_TRUE(ls
.empty());
2325 AioCompletion
*c
= librados::Rados::aio_create_completion();
2326 ASSERT_EQ(0, ioctx
.hit_set_get(123, c
, 12345, &bl
));
2327 c
->wait_for_complete();
2328 ASSERT_EQ(-ENOENT
, c
->get_return_value());
2333 string
set_pool_str(string pool
, string var
, string val
)
2335 return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
2336 + string("\",\"var\": \"") + var
+ string("\",\"val\": \"")
2337 + val
+ string("\"}");
2340 string
set_pool_str(string pool
, string var
, int val
)
2342 return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
2343 + string("\",\"var\": \"") + var
+ string("\",\"val\": \"")
2344 + stringify(val
) + string("\"}");
2347 TEST_F(LibRadosTwoPoolsPP
, HitSetRead
) {
2350 ASSERT_EQ(0, cluster
.mon_command(
2351 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2352 "\", \"tierpool\": \"" + cache_pool_name
+
2353 "\", \"force_nonempty\": \"--force-nonempty\" }",
2356 // enable hitset tracking for this pool
2357 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", 2),
2359 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", 600),
2361 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type",
2365 // wait for maps to settle
2366 cluster
.wait_for_latest_osdmap();
2368 cache_ioctx
.set_namespace("");
2370 // keep reading until we see our object appear in the HitSet
2371 utime_t start
= ceph_clock_now();
2372 utime_t hard_stop
= start
+ utime_t(600, 0);
2375 utime_t now
= ceph_clock_now();
2376 ASSERT_TRUE(now
< hard_stop
);
2378 string name
= "foo";
2380 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
2381 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
,
2382 cluster
.pool_lookup(cache_pool_name
.c_str()), "");
2385 ASSERT_EQ(-ENOENT
, cache_ioctx
.read("foo", bl
, 1, 0));
2388 AioCompletion
*c
= librados::Rados::aio_create_completion();
2389 ASSERT_EQ(0, cache_ioctx
.hit_set_get(hash
, c
, now
.sec(), &hbl
));
2390 c
->wait_for_complete();
2394 auto p
= hbl
.cbegin();
2397 if (hs
.contains(oid
)) {
2398 cout
<< "ok, hit_set contains " << oid
<< std::endl
;
2401 cout
<< "hmm, not in HitSet yet" << std::endl
;
2403 cout
<< "hmm, no HitSet yet" << std::endl
;
2410 static int _get_pg_num(Rados
& cluster
, string pool_name
)
2413 string cmd
= string("{\"prefix\": \"osd pool get\",\"pool\":\"")
2415 + string("\",\"var\": \"pg_num\",\"format\": \"json\"}");
2417 int r
= cluster
.mon_command(cmd
, inbl
, &outbl
, NULL
);
2418 ceph_assert(r
>= 0);
2419 string
outstr(outbl
.c_str(), outbl
.length());
2420 json_spirit::Value v
;
2421 if (!json_spirit::read(outstr
, v
)) {
2422 cerr
<<" unable to parse json " << outstr
<< std::endl
;
2426 json_spirit::Object
& o
= v
.get_obj();
2427 for (json_spirit::Object::size_type i
=0; i
<o
.size(); i
++) {
2428 json_spirit::Pair
& p
= o
[i
];
2429 if (p
.name_
== "pg_num") {
2430 cout
<< "pg_num = " << p
.value_
.get_int() << std::endl
;
2431 return p
.value_
.get_int();
2434 cerr
<< "didn't find pg_num in " << outstr
<< std::endl
;
2438 TEST_F(LibRadosTwoPoolsPP
, HitSetWrite
) {
2439 int num_pg
= _get_pg_num(cluster
, pool_name
);
2440 ceph_assert(num_pg
> 0);
2444 ASSERT_EQ(0, cluster
.mon_command(
2445 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2446 "\", \"tierpool\": \"" + cache_pool_name
+
2447 "\", \"force_nonempty\": \"--force-nonempty\" }",
2450 // enable hitset tracking for this pool
2451 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", 8),
2453 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", 600),
2455 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type",
2459 // wait for maps to settle
2460 cluster
.wait_for_latest_osdmap();
2462 cache_ioctx
.set_namespace("");
2466 // do a bunch of writes
2467 for (int i
=0; i
<num
; ++i
) {
2470 ASSERT_EQ(0, cache_ioctx
.write(stringify(i
), bl
, 1, 0));
2474 std::map
<int,HitSet
> hitsets
;
2475 for (int i
=0; i
<num_pg
; ++i
) {
2476 list
< pair
<time_t,time_t> > ls
;
2477 AioCompletion
*c
= librados::Rados::aio_create_completion();
2478 ASSERT_EQ(0, cache_ioctx
.hit_set_list(i
, c
, &ls
));
2479 c
->wait_for_complete();
2481 std::cout
<< "pg " << i
<< " ls " << ls
<< std::endl
;
2482 ASSERT_FALSE(ls
.empty());
2485 c
= librados::Rados::aio_create_completion();
2487 ASSERT_EQ(0, cache_ioctx
.hit_set_get(i
, c
, ls
.back().first
, &bl
));
2488 c
->wait_for_complete();
2492 auto p
= bl
.cbegin();
2493 decode(hitsets
[i
], p
);
2495 catch (buffer::error
& e
) {
2496 std::cout
<< "failed to decode hit set; bl len is " << bl
.length() << "\n";
2497 bl
.hexdump(std::cout
);
2498 std::cout
<< std::endl
;
2502 // cope with racing splits by refreshing pg_num
2503 if (i
== num_pg
- 1)
2504 num_pg
= _get_pg_num(cluster
, cache_pool_name
);
2507 for (int i
=0; i
<num
; ++i
) {
2508 string n
= stringify(i
);
2510 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(n
, &hash
));
2511 hobject_t
oid(sobject_t(n
, CEPH_NOSNAP
), "", hash
,
2512 cluster
.pool_lookup(cache_pool_name
.c_str()), "");
2513 std::cout
<< "checking for " << oid
<< std::endl
;
2515 for (int p
=0; p
<num_pg
; ++p
) {
2516 if (hitsets
[p
].contains(oid
)) {
2525 TEST_F(LibRadosTwoPoolsPP
, HitSetTrim
) {
2527 unsigned period
= 3;
2531 ASSERT_EQ(0, cluster
.mon_command(
2532 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2533 "\", \"tierpool\": \"" + cache_pool_name
+
2534 "\", \"force_nonempty\": \"--force-nonempty\" }",
2537 // enable hitset tracking for this pool
2538 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", count
),
2540 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", period
),
2542 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
2544 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_fpp", ".01"),
2547 // wait for maps to settle
2548 cluster
.wait_for_latest_osdmap();
2550 cache_ioctx
.set_namespace("");
2552 // do a bunch of writes and make sure the hitsets rotate
2553 utime_t start
= ceph_clock_now();
2554 utime_t hard_stop
= start
+ utime_t(count
* period
* 50, 0);
2558 string name
= "foo";
2560 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
2561 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
, -1, "");
2565 ASSERT_EQ(0, cache_ioctx
.write("foo", bl
, 1, 0));
2567 list
<pair
<time_t, time_t> > ls
;
2568 AioCompletion
*c
= librados::Rados::aio_create_completion();
2569 ASSERT_EQ(0, cache_ioctx
.hit_set_list(hash
, c
, &ls
));
2570 c
->wait_for_complete();
2573 cout
<< " got ls " << ls
<< std::endl
;
2576 first
= ls
.front().first
;
2577 cout
<< "first is " << first
<< std::endl
;
2579 if (ls
.front().first
!= first
) {
2580 cout
<< "first now " << ls
.front().first
<< ", trimmed" << std::endl
;
2586 utime_t now
= ceph_clock_now();
2587 ASSERT_TRUE(now
< hard_stop
);
2593 TEST_F(LibRadosTwoPoolsPP
, PromoteOn2ndRead
) {
2595 for (int i
=0; i
<20; ++i
) {
2597 bl
.append("hi there");
2598 ObjectWriteOperation op
;
2600 ASSERT_EQ(0, ioctx
.operate("foo" + stringify(i
), &op
));
2605 ASSERT_EQ(0, cluster
.mon_command(
2606 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2607 "\", \"tierpool\": \"" + cache_pool_name
+
2608 "\", \"force_nonempty\": \"--force-nonempty\" }",
2610 ASSERT_EQ(0, cluster
.mon_command(
2611 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2612 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2614 ASSERT_EQ(0, cluster
.mon_command(
2615 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2616 "\", \"mode\": \"writeback\"}",
2619 // enable hitset tracking for this pool
2620 ASSERT_EQ(0, cluster
.mon_command(
2621 set_pool_str(cache_pool_name
, "hit_set_count", 2),
2623 ASSERT_EQ(0, cluster
.mon_command(
2624 set_pool_str(cache_pool_name
, "hit_set_period", 600),
2626 ASSERT_EQ(0, cluster
.mon_command(
2627 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
2629 ASSERT_EQ(0, cluster
.mon_command(
2630 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
2632 ASSERT_EQ(0, cluster
.mon_command(
2633 set_pool_str(cache_pool_name
, "hit_set_grade_decay_rate", 20),
2635 ASSERT_EQ(0, cluster
.mon_command(
2636 set_pool_str(cache_pool_name
, "hit_set_search_last_n", 1),
2639 // wait for maps to settle
2640 cluster
.wait_for_latest_osdmap();
2642 int fake
= 0; // set this to non-zero to test spurious promotion,
2643 // e.g. from thrashing
2647 // 1st read, don't trigger a promote
2648 obj
= "foo" + stringify(attempt
);
2649 cout
<< obj
<< std::endl
;
2652 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
2655 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
2660 // verify the object is NOT present in the cache tier
2663 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2664 while (it
!= cache_ioctx
.nobjects_end()) {
2665 cout
<< " see " << it
->get_oid() << std::endl
;
2666 if (it
->get_oid() == string(obj
.c_str())) {
2677 ASSERT_LE(attempt
, 20);
2678 cout
<< "hrm, object is present in cache on attempt " << attempt
2679 << ", retrying" << std::endl
;
2682 // Read until the object is present in the cache tier
2683 cout
<< "verifying " << obj
<< " is eventually promoted" << std::endl
;
2686 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
2689 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2690 while (it
!= cache_ioctx
.nobjects_end()) {
2691 if (it
->get_oid() == string(obj
.c_str())) {
2704 ASSERT_EQ(0, cluster
.mon_command(
2705 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
2708 ASSERT_EQ(0, cluster
.mon_command(
2709 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
2710 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2713 // wait for maps to settle before next test
2714 cluster
.wait_for_latest_osdmap();
2717 TEST_F(LibRadosTwoPoolsPP
, ProxyRead
) {
2721 bl
.append("hi there");
2722 ObjectWriteOperation op
;
2724 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2729 ASSERT_EQ(0, cluster
.mon_command(
2730 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2731 "\", \"tierpool\": \"" + cache_pool_name
+
2732 "\", \"force_nonempty\": \"--force-nonempty\" }",
2734 ASSERT_EQ(0, cluster
.mon_command(
2735 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2736 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2738 ASSERT_EQ(0, cluster
.mon_command(
2739 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2740 "\", \"mode\": \"readproxy\"}",
2743 // wait for maps to settle
2744 cluster
.wait_for_latest_osdmap();
2746 // read and verify the object
2749 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2750 ASSERT_EQ('h', bl
[0]);
2753 // Verify 10 times the object is NOT present in the cache tier
2756 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2757 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
2762 ASSERT_EQ(0, cluster
.mon_command(
2763 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
2766 ASSERT_EQ(0, cluster
.mon_command(
2767 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
2768 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2771 // wait for maps to settle before next test
2772 cluster
.wait_for_latest_osdmap();
2775 TEST_F(LibRadosTwoPoolsPP
, CachePin
) {
2779 bl
.append("hi there");
2780 ObjectWriteOperation op
;
2782 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2786 bl
.append("hi there");
2787 ObjectWriteOperation op
;
2789 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
2793 bl
.append("hi there");
2794 ObjectWriteOperation op
;
2796 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
2800 bl
.append("hi there");
2801 ObjectWriteOperation op
;
2803 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
2808 ASSERT_EQ(0, cluster
.mon_command(
2809 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2810 "\", \"tierpool\": \"" + cache_pool_name
+
2811 "\", \"force_nonempty\": \"--force-nonempty\" }",
2813 ASSERT_EQ(0, cluster
.mon_command(
2814 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
2815 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
2817 ASSERT_EQ(0, cluster
.mon_command(
2818 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
2819 "\", \"mode\": \"writeback\"}",
2822 // wait for maps to settle
2823 cluster
.wait_for_latest_osdmap();
2825 // read, trigger promote
2828 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2829 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
2830 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
2831 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
2834 // verify the objects are present in the cache tier
2836 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2837 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
2838 for (uint32_t i
= 0; i
< 4; i
++) {
2839 ASSERT_TRUE(it
->get_oid() == string("foo") ||
2840 it
->get_oid() == string("bar") ||
2841 it
->get_oid() == string("baz") ||
2842 it
->get_oid() == string("bam"));
2845 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
2850 ObjectWriteOperation op
;
2852 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2853 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
2854 completion
->wait_for_complete();
2855 ASSERT_EQ(0, completion
->get_return_value());
2856 completion
->release();
2859 ObjectWriteOperation op
;
2861 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2862 ASSERT_EQ(0, cache_ioctx
.aio_operate("baz", completion
, &op
));
2863 completion
->wait_for_complete();
2864 ASSERT_EQ(0, completion
->get_return_value());
2865 completion
->release();
2869 ASSERT_EQ(0, cluster
.mon_command(
2870 set_pool_str(cache_pool_name
, "hit_set_count", 2),
2872 ASSERT_EQ(0, cluster
.mon_command(
2873 set_pool_str(cache_pool_name
, "hit_set_period", 600),
2875 ASSERT_EQ(0, cluster
.mon_command(
2876 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
2878 ASSERT_EQ(0, cluster
.mon_command(
2879 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
2881 ASSERT_EQ(0, cluster
.mon_command(
2882 set_pool_str(cache_pool_name
, "target_max_objects", 1),
2887 // Verify the pinned object 'foo' is not flushed/evicted
2891 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
2894 NObjectIterator it
= cache_ioctx
.nobjects_begin();
2895 while (it
!= cache_ioctx
.nobjects_end()) {
2896 ASSERT_TRUE(it
->get_oid() == string("foo") ||
2897 it
->get_oid() == string("bar") ||
2898 it
->get_oid() == string("baz") ||
2899 it
->get_oid() == string("bam"));
2904 ASSERT_TRUE(it
->get_oid() == string("foo") ||
2905 it
->get_oid() == string("baz"));
2913 ASSERT_EQ(0, cluster
.mon_command(
2914 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
2917 ASSERT_EQ(0, cluster
.mon_command(
2918 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
2919 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2922 // wait for maps to settle before next test
2923 cluster
.wait_for_latest_osdmap();
2926 TEST_F(LibRadosTwoPoolsPP
, SetRedirectRead
) {
2930 bl
.append("hi there");
2931 ObjectWriteOperation op
;
2933 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2938 ObjectWriteOperation op
;
2940 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
2945 ASSERT_EQ(0, cluster
.mon_command(
2946 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
2947 "\", \"tierpool\": \"" + cache_pool_name
+
2948 "\", \"force_nonempty\": \"--force-nonempty\" }",
2951 // wait for maps to settle
2952 cluster
.wait_for_latest_osdmap();
2955 ObjectWriteOperation op
;
2956 op
.set_redirect("bar", cache_ioctx
, 0);
2957 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
2958 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
2959 completion
->wait_for_complete();
2960 ASSERT_EQ(0, completion
->get_return_value());
2961 completion
->release();
2963 // read and verify the object
2966 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
2967 ASSERT_EQ('t', bl
[0]);
2970 ASSERT_EQ(0, cluster
.mon_command(
2971 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
2972 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
2975 // wait for maps to settle before next test
2976 cluster
.wait_for_latest_osdmap();
2979 TEST_F(LibRadosTwoPoolsPP
, SetChunkRead
) {
2980 // skip test if not yet mimic
2981 if (_get_required_osd_release(cluster
) < "mimic") {
2982 GTEST_SKIP() << "cluster is not yet mimic, skipping test";
2987 ObjectWriteOperation op
;
2989 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
2993 bl
.append("hi there");
2994 ObjectWriteOperation op
;
2996 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3001 ASSERT_EQ(0, cluster
.mon_command(
3002 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
3003 "\", \"tierpool\": \"" + cache_pool_name
+
3004 "\", \"force_nonempty\": \"--force-nonempty\" }",
3007 // wait for maps to settle
3008 cluster
.wait_for_latest_osdmap();
3012 ObjectWriteOperation op
;
3013 int len
= strlen("hi there");
3014 for (int i
= 0; i
< len
; i
+=2) {
3015 op
.set_chunk(i
, 2, cache_ioctx
, "bar", i
);
3017 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3018 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3019 completion
->wait_for_complete();
3020 ASSERT_EQ(0, completion
->get_return_value());
3021 completion
->release();
3024 // make all chunks dirty --> full flush --> all chunks are evicted
3027 bl
.append("There hi");
3028 ObjectWriteOperation op
;
3030 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3033 // read and verify the object
3036 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3037 ASSERT_EQ('T', bl
[0]);
3040 ASSERT_EQ(0, cluster
.mon_command(
3041 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
3042 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
3045 // wait for maps to settle before next test
3046 cluster
.wait_for_latest_osdmap();
3049 TEST_F(LibRadosTwoPoolsPP
, ManifestPromoteRead
) {
3050 // skip test if not yet mimic
3051 if (_get_required_osd_release(cluster
) < "mimic") {
3052 GTEST_SKIP() << "cluster is not yet mimic, skipping test";
3058 bl
.append("hi there");
3059 ObjectWriteOperation op
;
3061 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3065 bl
.append("base chunk");
3066 ObjectWriteOperation op
;
3068 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3073 ObjectWriteOperation op
;
3075 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3080 ObjectWriteOperation op
;
3082 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3087 ASSERT_EQ(0, cluster
.mon_command(
3088 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
3089 "\", \"tierpool\": \"" + cache_pool_name
+
3090 "\", \"force_nonempty\": \"--force-nonempty\" }",
3093 // wait for maps to settle
3094 cluster
.wait_for_latest_osdmap();
3098 ObjectWriteOperation op
;
3099 op
.set_redirect("bar", cache_ioctx
, 0);
3100 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3101 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3102 completion
->wait_for_complete();
3103 ASSERT_EQ(0, completion
->get_return_value());
3104 completion
->release();
3108 ObjectWriteOperation op
;
3109 op
.set_chunk(0, 2, cache_ioctx
, "bar-chunk", 0);
3110 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3111 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3112 completion
->wait_for_complete();
3113 ASSERT_EQ(0, completion
->get_return_value());
3114 completion
->release();
3118 ObjectWriteOperation op
;
3120 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3121 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3122 completion
->wait_for_complete();
3123 ASSERT_EQ(0, completion
->get_return_value());
3124 completion
->release();
3126 // read and verify the object (redirect)
3129 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3130 ASSERT_EQ('t', bl
[0]);
3134 ObjectWriteOperation op
;
3136 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3137 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3138 completion
->wait_for_complete();
3139 ASSERT_EQ(0, completion
->get_return_value());
3140 completion
->release();
3142 // read and verify the object
3145 ASSERT_EQ(1, ioctx
.read("foo-chunk", bl
, 1, 0));
3146 ASSERT_EQ('C', bl
[0]);
3149 ASSERT_EQ(0, cluster
.mon_command(
3150 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
3151 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
3154 // wait for maps to settle before next test
3155 cluster
.wait_for_latest_osdmap();
3158 TEST_F(LibRadosTwoPoolsPP
, ManifestRefRead
) {
3159 // note: require >= mimic
3164 bl
.append("hi there");
3165 ObjectWriteOperation op
;
3167 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3171 bl
.append("base chunk");
3172 ObjectWriteOperation op
;
3174 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3179 ObjectWriteOperation op
;
3181 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3186 ObjectWriteOperation op
;
3188 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3191 // wait for maps to settle
3192 cluster
.wait_for_latest_osdmap();
3196 ObjectWriteOperation op
;
3197 op
.set_redirect("bar", cache_ioctx
, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3198 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3199 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3200 completion
->wait_for_complete();
3201 ASSERT_EQ(0, completion
->get_return_value());
3202 completion
->release();
3206 ObjectWriteOperation op
;
3207 op
.set_chunk(0, 2, cache_ioctx
, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3208 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3209 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3210 completion
->wait_for_complete();
3211 ASSERT_EQ(0, completion
->get_return_value());
3212 completion
->release();
3214 // redirect's refcount
3217 cache_ioctx
.exec("bar", "cas", "chunk_read", in
, out
);
3218 cls_chunk_refcount_read_ret read_ret
;
3220 auto iter
= out
.cbegin();
3221 decode(read_ret
, iter
);
3222 } catch (buffer::error
& err
) {
3225 ASSERT_EQ(1U, read_ret
.refs
.size());
3230 cache_ioctx
.exec("bar-chunk", "cas", "chunk_read", in
, out
);
3231 cls_chunk_refcount_read_ret read_ret
;
3233 auto iter
= out
.cbegin();
3234 decode(read_ret
, iter
);
3235 } catch (buffer::error
& err
) {
3238 ASSERT_EQ(1u, read_ret
.refs
.size());
3241 // wait for maps to settle before next test
3242 cluster
.wait_for_latest_osdmap();
3245 TEST_F(LibRadosTwoPoolsPP
, ManifestUnset
) {
3246 // skip test if not yet nautilus
3247 if (_get_required_osd_release(cluster
) < "nautilus") {
3248 GTEST_SKIP() << "cluster is not yet nautilus, skipping test";
3254 bl
.append("hi there");
3255 ObjectWriteOperation op
;
3257 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3261 bl
.append("base chunk");
3262 ObjectWriteOperation op
;
3264 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3269 ObjectWriteOperation op
;
3271 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3276 ObjectWriteOperation op
;
3278 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3281 // wait for maps to settle
3282 cluster
.wait_for_latest_osdmap();
3286 ObjectWriteOperation op
;
3287 op
.set_redirect("bar", cache_ioctx
, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3288 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3289 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3290 completion
->wait_for_complete();
3291 ASSERT_EQ(0, completion
->get_return_value());
3292 completion
->release();
3296 ObjectWriteOperation op
;
3297 op
.set_chunk(0, 2, cache_ioctx
, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3298 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3299 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3300 completion
->wait_for_complete();
3301 ASSERT_EQ(0, completion
->get_return_value());
3302 completion
->release();
3304 // redirect's refcount
3307 cache_ioctx
.exec("bar", "cas", "chunk_read", in
, out
);
3308 cls_chunk_refcount_read_ret read_ret
;
3310 auto iter
= out
.cbegin();
3311 decode(read_ret
, iter
);
3312 } catch (buffer::error
& err
) {
3315 ASSERT_EQ(1u, read_ret
.refs
.size());
3320 cache_ioctx
.exec("bar-chunk", "cas", "chunk_read", in
, out
);
3321 cls_chunk_refcount_read_ret read_ret
;
3323 auto iter
= out
.cbegin();
3324 decode(read_ret
, iter
);
3325 } catch (buffer::error
& err
) {
3328 ASSERT_EQ(1u, read_ret
.refs
.size());
3331 // unset-manifest for set-redirect
3333 ObjectWriteOperation op
;
3334 op
.unset_manifest();
3335 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3336 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3337 completion
->wait_for_complete();
3338 ASSERT_EQ(0, completion
->get_return_value());
3339 completion
->release();
3342 // unset-manifest for set-chunk
3344 ObjectWriteOperation op
;
3345 op
.unset_manifest();
3346 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3347 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3348 completion
->wait_for_complete();
3349 ASSERT_EQ(0, completion
->get_return_value());
3350 completion
->release();
3352 // redirect's refcount
3355 cache_ioctx
.exec("bar", "cas", "chunk_read", in
, out
);
3356 if (out
.length() != 0U) {
3357 ObjectWriteOperation op
;
3358 op
.unset_manifest();
3359 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3360 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3361 completion
->wait_for_complete();
3362 ASSERT_EQ(-EOPNOTSUPP
, completion
->get_return_value());
3363 completion
->release();
3369 cache_ioctx
.exec("bar-chunk", "cas", "chunk_read", in
, out
);
3370 if (out
.length() != 0U) {
3371 ObjectWriteOperation op
;
3372 op
.unset_manifest();
3373 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3374 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3375 completion
->wait_for_complete();
3376 ASSERT_EQ(-EOPNOTSUPP
, completion
->get_return_value());
3377 completion
->release();
3381 // wait for maps to settle before next test
3382 cluster
.wait_for_latest_osdmap();
3385 #include "common/ceph_crypto.h"
3386 using ceph::crypto::SHA1
;
3387 #include "rgw/rgw_common.h"
3388 TEST_F(LibRadosTwoPoolsPP
, ManifestDedupRefRead
) {
3389 // skip test if not yet nautilus
3390 if (_get_required_osd_release(cluster
) < "nautilus") {
3391 GTEST_SKIP() << "cluster is not yet nautilus, skipping test";
3395 ASSERT_EQ(0, cluster
.mon_command(
3396 set_pool_str(pool_name
, "fingerprint_algorithm", "sha1"),
3398 cluster
.wait_for_latest_osdmap();
3403 bl
.append("hi there");
3404 ObjectWriteOperation op
;
3406 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3410 bl
.append("hi there");
3411 ObjectWriteOperation op
;
3413 ASSERT_EQ(0, ioctx
.operate("foo-dedup", &op
));
3418 ObjectWriteOperation op
;
3420 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
3425 ObjectWriteOperation op
;
3427 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3430 // wait for maps to settle
3431 cluster
.wait_for_latest_osdmap();
3433 // set-chunk (dedup)
3435 ObjectWriteOperation op
;
3436 int len
= strlen("hi there");
3437 op
.set_chunk(0, len
, cache_ioctx
, "bar-chunk", 0,
3438 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3439 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3440 ASSERT_EQ(0, ioctx
.aio_operate("foo-dedup", completion
, &op
));
3441 completion
->wait_for_complete();
3442 ASSERT_EQ(0, completion
->get_return_value());
3443 completion
->release();
3445 // set-chunk (dedup)
3447 ObjectWriteOperation op
;
3448 int len
= strlen("hi there");
3449 op
.set_chunk(0, len
, cache_ioctx
, "bar", 0,
3450 CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3451 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3452 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
3453 completion
->wait_for_complete();
3454 ASSERT_EQ(0, completion
->get_return_value());
3455 completion
->release();
3457 // make all chunks dirty --> flush
3459 // make a dirty chunks
3461 bl
.append("There hi");
3462 ObjectWriteOperation op
;
3464 ASSERT_EQ(0, ioctx
.operate("foo-dedup", &op
));
3469 bl
.append("There hi");
3470 ObjectWriteOperation op
;
3472 ASSERT_EQ(0, ioctx
.operate("foo-dedup", &op
));
3475 // make a dirty chunks
3477 bl
.append("There hi");
3478 ObjectWriteOperation op
;
3480 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3485 bl
.append("There hi");
3486 ObjectWriteOperation op
;
3488 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3494 int size
= strlen("There hi");
3495 unsigned char fingerprint
[CEPH_CRYPTO_SHA1_DIGESTSIZE
+ 1];
3496 char p_str
[CEPH_CRYPTO_SHA1_DIGESTSIZE
*2+1] = {0};
3497 sha1_gen
.Update((const unsigned char *)"There hi", size
);
3498 sha1_gen
.Final(fingerprint
);
3499 buf_to_hex(fingerprint
, CEPH_CRYPTO_SHA1_DIGESTSIZE
, p_str
);
3500 cache_ioctx
.exec(p_str
, "cas", "chunk_read", in
, out
);
3501 cls_chunk_refcount_read_ret read_ret
;
3503 auto iter
= out
.cbegin();
3504 decode(read_ret
, iter
);
3505 } catch (buffer::error
& err
) {
3508 ASSERT_EQ(2u, read_ret
.refs
.size());
3511 // wait for maps to settle before next test
3512 cluster
.wait_for_latest_osdmap();
3515 TEST_F(LibRadosTwoPoolsPP
, ManifestFlushRead
) {
3516 // skip test if not yet octopus
3517 if (_get_required_osd_release(cluster
) < "octopus") {
3518 GTEST_SKIP() << "cluster is not yet octopus, skipping test";
3524 bl
.append("base chunk");
3525 ObjectWriteOperation op
;
3527 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3531 bl
.append("CHUNKS");
3532 ObjectWriteOperation op
;
3534 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
3539 ASSERT_EQ(0, cluster
.mon_command(
3540 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
3541 "\", \"tierpool\": \"" + cache_pool_name
+
3542 "\", \"force_nonempty\": \"--force-nonempty\" }",
3545 // wait for maps to settle
3546 cluster
.wait_for_latest_osdmap();
3550 ObjectWriteOperation op
;
3551 op
.set_chunk(0, 2, cache_ioctx
, "bar-chunk", 0);
3552 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3553 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3554 completion
->wait_for_complete();
3555 ASSERT_EQ(0, completion
->get_return_value());
3556 completion
->release();
3560 ObjectWriteOperation op
;
3561 op
.set_chunk(2, 2, cache_ioctx
, "bar-chunk", 2);
3562 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3563 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3564 completion
->wait_for_complete();
3565 ASSERT_EQ(0, completion
->get_return_value());
3566 completion
->release();
3568 // make chunked object dirty
3572 ObjectWriteOperation op
;
3574 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
3578 ObjectWriteOperation op
;
3580 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3581 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
3582 completion
->wait_for_complete();
3583 ASSERT_EQ(0, completion
->get_return_value());
3584 completion
->release();
3586 // read and verify the chunked object
3589 ASSERT_EQ(1, cache_ioctx
.read("bar-chunk", bl
, 1, 0));
3590 ASSERT_EQ('D', bl
[0]);
3593 ASSERT_EQ(0, cluster
.mon_command(
3594 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
3595 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
3598 // wait for maps to settle before next test
3599 cluster
.wait_for_latest_osdmap();
3602 class LibRadosTwoPoolsECPP
: public RadosTestECPP
3605 LibRadosTwoPoolsECPP() {};
3606 ~LibRadosTwoPoolsECPP() override
{};
3608 static void SetUpTestCase() {
3609 pool_name
= get_temp_pool_name();
3610 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, s_cluster
));
3612 static void TearDownTestCase() {
3613 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, s_cluster
));
3615 static std::string cache_pool_name
;
3617 void SetUp() override
{
3618 cache_pool_name
= get_temp_pool_name();
3619 ASSERT_EQ(0, s_cluster
.pool_create(cache_pool_name
.c_str()));
3620 RadosTestECPP::SetUp();
3622 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
3623 cache_ioctx
.application_enable("rados", true);
3624 cache_ioctx
.set_namespace(nspace
);
3626 void TearDown() override
{
3627 // flush + evict cache
3628 flush_evict_all(cluster
, cache_ioctx
);
3632 ASSERT_EQ(0, cluster
.mon_command(
3633 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
3636 ASSERT_EQ(0, cluster
.mon_command(
3637 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
3638 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
3641 // wait for maps to settle before next test
3642 cluster
.wait_for_latest_osdmap();
3644 RadosTestECPP::TearDown();
3646 cleanup_default_namespace(cache_ioctx
);
3647 cleanup_namespace(cache_ioctx
, nspace
);
3649 cache_ioctx
.close();
3650 ASSERT_EQ(0, s_cluster
.pool_delete(cache_pool_name
.c_str()));
3653 librados::IoCtx cache_ioctx
;
3656 std::string
LibRadosTwoPoolsECPP::cache_pool_name
;
3658 TEST_F(LibRadosTierECPP
, Dirty
) {
3660 ObjectWriteOperation op
;
3662 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still get 0 if it dne
3665 ObjectWriteOperation op
;
3667 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3672 ObjectReadOperation op
;
3673 op
.is_dirty(&dirty
, &r
);
3674 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
3679 ObjectWriteOperation op
;
3681 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3684 ObjectWriteOperation op
;
3686 ASSERT_EQ(0, ioctx
.operate("foo", &op
)); // still 0 if already clean
3691 ObjectReadOperation op
;
3692 op
.is_dirty(&dirty
, &r
);
3693 ASSERT_EQ(0, ioctx
.operate("foo", &op
, NULL
));
3694 ASSERT_FALSE(dirty
);
3698 // ObjectWriteOperation op;
3699 // op.truncate(0); // still a write even tho it is a no-op
3700 // ASSERT_EQ(0, ioctx.operate("foo", &op));
3703 // bool dirty = false;
3705 // ObjectReadOperation op;
3706 // op.is_dirty(&dirty, &r);
3707 // ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
3708 // ASSERT_TRUE(dirty);
3713 TEST_F(LibRadosTwoPoolsECPP
, Overlay
) {
3718 ObjectWriteOperation op
;
3720 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3725 ObjectWriteOperation op
;
3727 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
));
3732 ASSERT_EQ(0, cluster
.mon_command(
3733 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
3734 "\", \"tierpool\": \"" + cache_pool_name
+
3735 "\", \"force_nonempty\": \"--force-nonempty\" }",
3737 ASSERT_EQ(0, cluster
.mon_command(
3738 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
3739 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
3742 // wait for maps to settle
3743 cluster
.wait_for_latest_osdmap();
3745 // by default, the overlay sends us to cache pool
3748 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3749 ASSERT_EQ('c', bl
[0]);
3753 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
3754 ASSERT_EQ('c', bl
[0]);
3757 // unless we say otherwise
3760 ObjectReadOperation op
;
3761 op
.read(0, 1, &bl
, NULL
);
3762 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
3763 ASSERT_EQ(0, ioctx
.aio_operate(
3764 "foo", completion
, &op
,
3765 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
3766 completion
->wait_for_complete();
3767 ASSERT_EQ(0, completion
->get_return_value());
3768 completion
->release();
3769 ASSERT_EQ('b', bl
[0]);
3773 TEST_F(LibRadosTwoPoolsECPP
, Promote
) {
3777 bl
.append("hi there");
3778 ObjectWriteOperation op
;
3780 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3785 ASSERT_EQ(0, cluster
.mon_command(
3786 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
3787 "\", \"tierpool\": \"" + cache_pool_name
+
3788 "\", \"force_nonempty\": \"--force-nonempty\" }",
3790 ASSERT_EQ(0, cluster
.mon_command(
3791 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
3792 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
3794 ASSERT_EQ(0, cluster
.mon_command(
3795 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
3796 "\", \"mode\": \"writeback\"}",
3799 // wait for maps to settle
3800 cluster
.wait_for_latest_osdmap();
3802 // read, trigger a promote
3805 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3808 // read, trigger a whiteout
3811 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
3812 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
3815 // verify the object is present in the cache tier
3817 NObjectIterator it
= cache_ioctx
.nobjects_begin();
3818 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
3819 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
3821 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
3823 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
3827 TEST_F(LibRadosTwoPoolsECPP
, PromoteSnap
) {
3831 bl
.append("hi there");
3832 ObjectWriteOperation op
;
3834 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3838 bl
.append("hi there");
3839 ObjectWriteOperation op
;
3841 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
3845 bl
.append("hi there");
3846 ObjectWriteOperation op
;
3848 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
3852 bl
.append("hi there");
3853 ObjectWriteOperation op
;
3855 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
3858 // create a snapshot, clone
3859 vector
<uint64_t> my_snaps(1);
3860 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
3861 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
3866 ObjectWriteOperation op
;
3868 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
3873 ObjectWriteOperation op
;
3875 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
3878 ObjectWriteOperation op
;
3880 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
3885 ObjectWriteOperation op
;
3887 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
3892 ASSERT_EQ(0, cluster
.mon_command(
3893 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
3894 "\", \"tierpool\": \"" + cache_pool_name
+
3895 "\", \"force_nonempty\": \"--force-nonempty\" }",
3897 ASSERT_EQ(0, cluster
.mon_command(
3898 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
3899 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
3901 ASSERT_EQ(0, cluster
.mon_command(
3902 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
3903 "\", \"mode\": \"writeback\"}",
3906 // wait for maps to settle
3907 cluster
.wait_for_latest_osdmap();
3909 // read, trigger a promote on the head
3912 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3913 ASSERT_EQ('c', bl
[0]);
3917 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
3918 ASSERT_EQ('c', bl
[0]);
3921 ioctx
.snap_set_read(my_snaps
[0]);
3923 // stop and scrub this pg (to make sure scrub can handle missing
3924 // clones in the cache tier)
3925 // This test requires cache tier and base tier to have the same pg_num/pgp_num
3927 for (int tries
= 0; tries
< 5; ++tries
) {
3929 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
3931 ASSERT_EQ(0, ioctx
.get_object_pg_hash_position2("foo", &hash
));
3933 ss
<< "{\"prefix\": \"pg scrub\", \"pgid\": \""
3934 << cache_ioctx
.get_id() << "."
3937 int r
= cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
3939 r
== -ENOENT
) { // in case mgr osdmap is a bit stale
3946 // give it a few seconds to go. this is sloppy but is usually enough time
3947 cout
<< "waiting for scrub..." << std::endl
;
3949 cout
<< "done waiting" << std::endl
;
3955 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3956 ASSERT_EQ('h', bl
[0]);
3962 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
3963 ASSERT_EQ('h', bl
[0]);
3969 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
3970 ASSERT_EQ('h', bl
[0]);
3973 ioctx
.snap_set_read(librados::SNAP_HEAD
);
3978 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
3979 ASSERT_EQ('c', bl
[0]);
3985 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
3986 ASSERT_EQ('c', bl
[0]);
3992 ASSERT_EQ(-ENOENT
, ioctx
.read("baz", bl
, 1, 0));
3996 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
3999 TEST_F(LibRadosTwoPoolsECPP
, PromoteSnapTrimRace
) {
4003 bl
.append("hi there");
4004 ObjectWriteOperation op
;
4006 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4009 // create a snapshot, clone
4010 vector
<uint64_t> my_snaps(1);
4011 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4012 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4017 ObjectWriteOperation op
;
4019 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4024 ASSERT_EQ(0, cluster
.mon_command(
4025 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
4026 "\", \"tierpool\": \"" + cache_pool_name
+
4027 "\", \"force_nonempty\": \"--force-nonempty\" }",
4029 ASSERT_EQ(0, cluster
.mon_command(
4030 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
4031 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
4033 ASSERT_EQ(0, cluster
.mon_command(
4034 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
4035 "\", \"mode\": \"writeback\"}",
4038 // wait for maps to settle
4039 cluster
.wait_for_latest_osdmap();
4042 ASSERT_EQ(0, ioctx
.selfmanaged_snap_remove(my_snaps
[0]));
4044 ioctx
.snap_set_read(my_snaps
[0]);
4046 // read foo snap. the OSD may or may not realize that this snap has
4047 // been logically deleted; either response is valid.
4050 int r
= ioctx
.read("foo", bl
, 1, 0);
4051 ASSERT_TRUE(r
== 1 || r
== -ENOENT
);
4055 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
4058 TEST_F(LibRadosTwoPoolsECPP
, Whiteout
) {
4062 bl
.append("hi there");
4063 ObjectWriteOperation op
;
4065 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4070 ASSERT_EQ(0, cluster
.mon_command(
4071 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
4072 "\", \"tierpool\": \"" + cache_pool_name
+
4073 "\", \"force_nonempty\": \"--force-nonempty\" }",
4075 ASSERT_EQ(0, cluster
.mon_command(
4076 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
4077 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
4079 ASSERT_EQ(0, cluster
.mon_command(
4080 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
4081 "\", \"mode\": \"writeback\"}",
4084 // wait for maps to settle
4085 cluster
.wait_for_latest_osdmap();
4087 // create some whiteouts, verify they behave
4089 ObjectWriteOperation op
;
4092 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4096 ObjectWriteOperation op
;
4099 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
4102 ObjectWriteOperation op
;
4105 ASSERT_EQ(-ENOENT
, ioctx
.operate("bar", &op
));
4108 // verify the whiteouts are there in the cache tier
4110 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4111 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
4112 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
4114 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
4116 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4119 // delete a whiteout and verify it goes away
4120 ASSERT_EQ(-ENOENT
, ioctx
.remove("foo"));
4122 ObjectWriteOperation op
;
4124 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4125 ASSERT_EQ(0, ioctx
.aio_operate("bar", completion
, &op
,
4126 librados::OPERATION_IGNORE_CACHE
));
4127 completion
->wait_for_complete();
4128 ASSERT_EQ(0, completion
->get_return_value());
4129 completion
->release();
4131 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4132 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
4133 ASSERT_TRUE(it
->get_oid() == string("foo"));
4135 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4138 // recreate an object and verify we can read it
4141 bl
.append("hi there");
4142 ObjectWriteOperation op
;
4144 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4148 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
4149 ASSERT_EQ('h', bl
[0]);
4153 TEST_F(LibRadosTwoPoolsECPP
, Evict
) {
4157 bl
.append("hi there");
4158 ObjectWriteOperation op
;
4160 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4165 ASSERT_EQ(0, cluster
.mon_command(
4166 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
4167 "\", \"tierpool\": \"" + cache_pool_name
+
4168 "\", \"force_nonempty\": \"--force-nonempty\" }",
4170 ASSERT_EQ(0, cluster
.mon_command(
4171 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
4172 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
4174 ASSERT_EQ(0, cluster
.mon_command(
4175 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
4176 "\", \"mode\": \"writeback\"}",
4179 // wait for maps to settle
4180 cluster
.wait_for_latest_osdmap();
4182 // read, trigger a promote
4185 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
4188 // read, trigger a whiteout, and a dirty object
4191 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
4192 ASSERT_EQ(-ENOENT
, ioctx
.read("bar", bl
, 1, 0));
4193 ASSERT_EQ(0, ioctx
.write("bar", bl
, bl
.length(), 0));
4196 // verify the object is present in the cache tier
4198 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4199 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
4200 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
4202 ASSERT_TRUE(it
->get_oid() == string("foo") || it
->get_oid() == string("bar"));
4204 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4209 ObjectWriteOperation op
;
4211 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4212 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
4213 completion
->wait_for_complete();
4214 ASSERT_EQ(0, completion
->get_return_value());
4215 completion
->release();
4218 // evict the pinned object with -EPERM
4220 ObjectReadOperation op
;
4222 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4223 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
4224 librados::OPERATION_IGNORE_CACHE
,
4226 completion
->wait_for_complete();
4227 ASSERT_EQ(-EPERM
, completion
->get_return_value());
4228 completion
->release();
4233 ObjectWriteOperation op
;
4235 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4236 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
4237 completion
->wait_for_complete();
4238 ASSERT_EQ(0, completion
->get_return_value());
4239 completion
->release();
4244 ObjectReadOperation op
;
4246 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4247 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4248 "foo", completion
, &op
,
4249 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4250 completion
->wait_for_complete();
4251 ASSERT_EQ(0, completion
->get_return_value());
4252 completion
->release();
4259 ObjectReadOperation op
;
4260 op
.is_dirty(&dirty
, &r
);
4261 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
4262 ASSERT_FALSE(dirty
);
4268 ObjectReadOperation op
;
4270 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4271 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
4272 librados::OPERATION_IGNORE_CACHE
,
4274 completion
->wait_for_complete();
4275 ASSERT_EQ(0, completion
->get_return_value());
4276 completion
->release();
4279 ObjectReadOperation op
;
4281 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4282 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4283 "foo", completion
, &op
,
4284 librados::OPERATION_IGNORE_CACHE
, NULL
));
4285 completion
->wait_for_complete();
4286 ASSERT_EQ(0, completion
->get_return_value());
4287 completion
->release();
4290 ObjectReadOperation op
;
4292 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4293 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4294 "bar", completion
, &op
,
4295 librados::OPERATION_IGNORE_CACHE
, NULL
));
4296 completion
->wait_for_complete();
4297 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
4298 completion
->release();
4302 TEST_F(LibRadosTwoPoolsECPP
, EvictSnap
) {
4306 bl
.append("hi there");
4307 ObjectWriteOperation op
;
4309 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4313 bl
.append("hi there");
4314 ObjectWriteOperation op
;
4316 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
4320 bl
.append("hi there");
4321 ObjectWriteOperation op
;
4323 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
4327 bl
.append("hi there");
4328 ObjectWriteOperation op
;
4330 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
4333 // create a snapshot, clone
4334 vector
<uint64_t> my_snaps(1);
4335 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
4336 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
4341 ObjectWriteOperation op
;
4343 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4348 ObjectWriteOperation op
;
4350 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
4353 ObjectWriteOperation op
;
4355 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
4360 ObjectWriteOperation op
;
4362 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
4367 ASSERT_EQ(0, cluster
.mon_command(
4368 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
4369 "\", \"tierpool\": \"" + cache_pool_name
+
4370 "\", \"force_nonempty\": \"--force-nonempty\" }",
4372 ASSERT_EQ(0, cluster
.mon_command(
4373 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
4374 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
4376 ASSERT_EQ(0, cluster
.mon_command(
4377 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
4378 "\", \"mode\": \"writeback\"}",
4381 // wait for maps to settle
4382 cluster
.wait_for_latest_osdmap();
4384 // read, trigger a promote on the head
4387 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
4388 ASSERT_EQ('c', bl
[0]);
4392 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
4393 ASSERT_EQ('c', bl
[0]);
4398 ObjectReadOperation op
;
4400 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4401 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4402 "bam", completion
, &op
,
4403 librados::OPERATION_IGNORE_CACHE
, NULL
));
4404 completion
->wait_for_complete();
4405 ASSERT_EQ(0, completion
->get_return_value());
4406 completion
->release();
4410 ObjectReadOperation op
;
4411 op
.read(1, 0, &bl
, NULL
);
4412 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4413 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4414 "bam", completion
, &op
,
4415 librados::OPERATION_IGNORE_CACHE
, NULL
));
4416 completion
->wait_for_complete();
4417 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
4418 completion
->release();
4422 ioctx
.snap_set_read(my_snaps
[0]);
4425 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
4426 ASSERT_EQ('h', bl
[0]);
4431 ObjectReadOperation op
;
4433 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4434 ASSERT_EQ(0, ioctx
.aio_operate(
4435 "foo", completion
, &op
,
4436 librados::OPERATION_IGNORE_CACHE
, NULL
));
4437 completion
->wait_for_complete();
4438 ASSERT_EQ(0, completion
->get_return_value());
4439 completion
->release();
4444 ObjectReadOperation op
;
4445 op
.read(1, 0, &bl
, NULL
);
4446 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4447 ASSERT_EQ(0, ioctx
.aio_operate(
4448 "foo", completion
, &op
,
4449 librados::OPERATION_IGNORE_CACHE
, NULL
));
4450 completion
->wait_for_complete();
4451 ASSERT_EQ(-ENOENT
, completion
->get_return_value());
4452 completion
->release();
4454 // head is still there...
4455 ioctx
.snap_set_read(librados::SNAP_HEAD
);
4458 ObjectReadOperation op
;
4459 op
.read(1, 0, &bl
, NULL
);
4460 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4461 ASSERT_EQ(0, ioctx
.aio_operate(
4462 "foo", completion
, &op
,
4463 librados::OPERATION_IGNORE_CACHE
, NULL
));
4464 completion
->wait_for_complete();
4465 ASSERT_EQ(0, completion
->get_return_value());
4466 completion
->release();
4469 // promote head + snap of bar
4470 ioctx
.snap_set_read(librados::SNAP_HEAD
);
4473 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
4474 ASSERT_EQ('c', bl
[0]);
4476 ioctx
.snap_set_read(my_snaps
[0]);
4479 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
4480 ASSERT_EQ('h', bl
[0]);
4483 // evict bar head (fail)
4484 ioctx
.snap_set_read(librados::SNAP_HEAD
);
4486 ObjectReadOperation op
;
4488 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4489 ASSERT_EQ(0, ioctx
.aio_operate(
4490 "bar", completion
, &op
,
4491 librados::OPERATION_IGNORE_CACHE
, NULL
));
4492 completion
->wait_for_complete();
4493 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
4494 completion
->release();
4498 ioctx
.snap_set_read(my_snaps
[0]);
4500 ObjectReadOperation op
;
4502 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4503 ASSERT_EQ(0, ioctx
.aio_operate(
4504 "bar", completion
, &op
,
4505 librados::OPERATION_IGNORE_CACHE
, NULL
));
4506 completion
->wait_for_complete();
4507 ASSERT_EQ(0, completion
->get_return_value());
4508 completion
->release();
4511 ioctx
.snap_set_read(librados::SNAP_HEAD
);
4514 ObjectReadOperation op
;
4515 op
.read(1, 0, &bl
, NULL
);
4516 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4517 ASSERT_EQ(0, ioctx
.aio_operate(
4518 "bar", completion
, &op
,
4519 librados::OPERATION_IGNORE_CACHE
, NULL
));
4520 completion
->wait_for_complete();
4521 ASSERT_EQ(0, completion
->get_return_value());
4522 completion
->release();
4525 ObjectReadOperation op
;
4527 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4528 ASSERT_EQ(0, ioctx
.aio_operate(
4529 "bar", completion
, &op
,
4530 librados::OPERATION_IGNORE_CACHE
, NULL
));
4531 completion
->wait_for_complete();
4532 ASSERT_EQ(0, completion
->get_return_value());
4533 completion
->release();
4537 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
4540 TEST_F(LibRadosTwoPoolsECPP
, TryFlush
) {
4543 ASSERT_EQ(0, cluster
.mon_command(
4544 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
4545 "\", \"tierpool\": \"" + cache_pool_name
+
4546 "\", \"force_nonempty\": \"--force-nonempty\" }",
4548 ASSERT_EQ(0, cluster
.mon_command(
4549 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
4550 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
4552 ASSERT_EQ(0, cluster
.mon_command(
4553 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
4554 "\", \"mode\": \"writeback\"}",
4557 // wait for maps to settle
4558 cluster
.wait_for_latest_osdmap();
4563 bl
.append("hi there");
4564 ObjectWriteOperation op
;
4566 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4569 // verify the object is present in the cache tier
4571 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4572 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
4573 ASSERT_TRUE(it
->get_oid() == string("foo"));
4575 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4578 // verify the object is NOT present in the base tier
4580 NObjectIterator it
= ioctx
.nobjects_begin();
4581 ASSERT_TRUE(it
== ioctx
.nobjects_end());
4588 ObjectReadOperation op
;
4589 op
.is_dirty(&dirty
, &r
);
4590 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
4597 ObjectWriteOperation op
;
4599 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4600 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
4601 completion
->wait_for_complete();
4602 ASSERT_EQ(0, completion
->get_return_value());
4603 completion
->release();
4606 // flush the pinned object with -EPERM
4608 ObjectReadOperation op
;
4609 op
.cache_try_flush();
4610 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4611 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4612 "foo", completion
, &op
,
4613 librados::OPERATION_IGNORE_OVERLAY
|
4614 librados::OPERATION_SKIPRWLOCKS
, NULL
));
4615 completion
->wait_for_complete();
4616 ASSERT_EQ(-EPERM
, completion
->get_return_value());
4617 completion
->release();
4622 ObjectWriteOperation op
;
4624 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4625 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
4626 completion
->wait_for_complete();
4627 ASSERT_EQ(0, completion
->get_return_value());
4628 completion
->release();
4633 ObjectReadOperation op
;
4634 op
.cache_try_flush();
4635 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4636 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4637 "foo", completion
, &op
,
4638 librados::OPERATION_IGNORE_OVERLAY
|
4639 librados::OPERATION_SKIPRWLOCKS
, NULL
));
4640 completion
->wait_for_complete();
4641 ASSERT_EQ(0, completion
->get_return_value());
4642 completion
->release();
4649 ObjectReadOperation op
;
4650 op
.is_dirty(&dirty
, &r
);
4651 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
4652 ASSERT_FALSE(dirty
);
4656 // verify in base tier
4658 NObjectIterator it
= ioctx
.nobjects_begin();
4659 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
4660 ASSERT_TRUE(it
->get_oid() == string("foo"));
4662 ASSERT_TRUE(it
== ioctx
.nobjects_end());
4667 ObjectReadOperation op
;
4669 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4670 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4671 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
4672 completion
->wait_for_complete();
4673 ASSERT_EQ(0, completion
->get_return_value());
4674 completion
->release();
4677 // verify no longer in cache tier
4679 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4680 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4684 TEST_F(LibRadosTwoPoolsECPP
, FailedFlush
) {
4687 ASSERT_EQ(0, cluster
.mon_command(
4688 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
4689 "\", \"tierpool\": \"" + cache_pool_name
+
4690 "\", \"force_nonempty\": \"--force-nonempty\" }",
4692 ASSERT_EQ(0, cluster
.mon_command(
4693 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
4694 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
4696 ASSERT_EQ(0, cluster
.mon_command(
4697 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
4698 "\", \"mode\": \"writeback\"}",
4701 // wait for maps to settle
4702 cluster
.wait_for_latest_osdmap();
4707 bl
.append("hi there");
4708 ObjectWriteOperation op
;
4710 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4713 // verify the object is present in the cache tier
4715 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4716 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
4717 ASSERT_TRUE(it
->get_oid() == string("foo"));
4719 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4722 // verify the object is NOT present in the base tier
4724 NObjectIterator it
= ioctx
.nobjects_begin();
4725 ASSERT_TRUE(it
== ioctx
.nobjects_end());
4730 ObjectWriteOperation op
;
4731 std::map
<std::string
, bufferlist
> omap
;
4732 omap
["somekey"] = bufferlist();
4734 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4735 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
4736 completion
->wait_for_complete();
4737 ASSERT_EQ(0, completion
->get_return_value());
4738 completion
->release();
4743 ObjectReadOperation op
;
4745 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4746 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4747 "foo", completion
, &op
,
4748 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4749 completion
->wait_for_complete();
4750 ASSERT_NE(0, completion
->get_return_value());
4751 completion
->release();
4756 ObjectReadOperation op
;
4759 std::set
<std::string
> keys
;
4760 keys
.insert("somekey");
4761 std::map
<std::string
, bufferlist
> map
;
4763 op
.omap_get_vals_by_keys(keys
, &map
, &prval
);
4764 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4765 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
, &bl
));
4767 bool completed
= completion
->is_complete();
4769 cache_ioctx
.aio_cancel(completion
);
4770 std::cerr
<< "Most probably test case will hang here, please reset manually" << std::endl
;
4771 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
4773 completion
->release();
4775 // verify still not in base tier
4777 ASSERT_TRUE(ioctx
.nobjects_begin() == ioctx
.nobjects_end());
4781 ObjectWriteOperation op
;
4783 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4787 ObjectReadOperation op
;
4789 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4790 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4791 "foo", completion
, &op
,
4792 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4793 completion
->wait_for_complete();
4794 ASSERT_EQ(0, completion
->get_return_value());
4795 completion
->release();
4799 ObjectReadOperation op
;
4801 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4802 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4803 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
4804 completion
->wait_for_complete();
4805 ASSERT_EQ(0, completion
->get_return_value());
4806 completion
->release();
4809 // verify no longer in cache tier
4811 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4812 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4816 NObjectIterator it
= ioctx
.nobjects_begin();
4817 ASSERT_TRUE(it
== ioctx
.nobjects_end());
4821 TEST_F(LibRadosTwoPoolsECPP
, Flush
) {
4824 ASSERT_EQ(0, cluster
.mon_command(
4825 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
4826 "\", \"tierpool\": \"" + cache_pool_name
+
4827 "\", \"force_nonempty\": \"--force-nonempty\" }",
4829 ASSERT_EQ(0, cluster
.mon_command(
4830 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
4831 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
4833 ASSERT_EQ(0, cluster
.mon_command(
4834 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
4835 "\", \"mode\": \"writeback\"}",
4838 // wait for maps to settle
4839 cluster
.wait_for_latest_osdmap();
4841 uint64_t user_version
= 0;
4846 bl
.append("hi there");
4847 ObjectWriteOperation op
;
4849 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4852 // verify the object is present in the cache tier
4854 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4855 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
4856 ASSERT_TRUE(it
->get_oid() == string("foo"));
4858 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4861 // verify the object is NOT present in the base tier
4863 NObjectIterator it
= ioctx
.nobjects_begin();
4864 ASSERT_TRUE(it
== ioctx
.nobjects_end());
4871 ObjectReadOperation op
;
4872 op
.is_dirty(&dirty
, &r
);
4873 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
4876 user_version
= cache_ioctx
.get_last_version();
4881 ObjectWriteOperation op
;
4883 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4884 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
4885 completion
->wait_for_complete();
4886 ASSERT_EQ(0, completion
->get_return_value());
4887 completion
->release();
4890 // flush the pinned object with -EPERM
4892 ObjectReadOperation op
;
4893 op
.cache_try_flush();
4894 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4895 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4896 "foo", completion
, &op
,
4897 librados::OPERATION_IGNORE_OVERLAY
|
4898 librados::OPERATION_SKIPRWLOCKS
, NULL
));
4899 completion
->wait_for_complete();
4900 ASSERT_EQ(-EPERM
, completion
->get_return_value());
4901 completion
->release();
4906 ObjectWriteOperation op
;
4908 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4909 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
4910 completion
->wait_for_complete();
4911 ASSERT_EQ(0, completion
->get_return_value());
4912 completion
->release();
4917 ObjectReadOperation op
;
4919 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4920 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4921 "foo", completion
, &op
,
4922 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4923 completion
->wait_for_complete();
4924 ASSERT_EQ(0, completion
->get_return_value());
4925 completion
->release();
4932 ObjectReadOperation op
;
4933 op
.is_dirty(&dirty
, &r
);
4934 ASSERT_EQ(0, cache_ioctx
.operate("foo", &op
, NULL
));
4935 ASSERT_FALSE(dirty
);
4939 // verify in base tier
4941 NObjectIterator it
= ioctx
.nobjects_begin();
4942 ASSERT_TRUE(it
!= ioctx
.nobjects_end());
4943 ASSERT_TRUE(it
->get_oid() == string("foo"));
4945 ASSERT_TRUE(it
== ioctx
.nobjects_end());
4950 ObjectReadOperation op
;
4952 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4953 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4954 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
4955 completion
->wait_for_complete();
4956 ASSERT_EQ(0, completion
->get_return_value());
4957 completion
->release();
4960 // verify no longer in cache tier
4962 NObjectIterator it
= cache_ioctx
.nobjects_begin();
4963 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
4966 // read it again and verify the version is consistent
4969 ASSERT_EQ(1, cache_ioctx
.read("foo", bl
, 1, 0));
4970 ASSERT_EQ(user_version
, cache_ioctx
.get_last_version());
4975 ObjectWriteOperation op
;
4977 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
4982 ObjectReadOperation op
;
4984 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4985 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4986 "foo", completion
, &op
,
4987 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
4988 completion
->wait_for_complete();
4989 ASSERT_EQ(0, completion
->get_return_value());
4990 completion
->release();
4995 ObjectReadOperation op
;
4997 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
4998 ASSERT_EQ(0, cache_ioctx
.aio_operate(
4999 "foo", completion
, &op
, librados::OPERATION_IGNORE_CACHE
, NULL
));
5000 completion
->wait_for_complete();
5001 ASSERT_EQ(0, completion
->get_return_value());
5002 completion
->release();
5005 // verify no longer in cache tier
5007 NObjectIterator it
= cache_ioctx
.nobjects_begin();
5008 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
5012 NObjectIterator it
= ioctx
.nobjects_begin();
5013 ASSERT_TRUE(it
== ioctx
.nobjects_end());
5017 TEST_F(LibRadosTwoPoolsECPP
, FlushSnap
) {
5020 ASSERT_EQ(0, cluster
.mon_command(
5021 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5022 "\", \"tierpool\": \"" + cache_pool_name
+
5023 "\", \"force_nonempty\": \"--force-nonempty\" }",
5025 ASSERT_EQ(0, cluster
.mon_command(
5026 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
5027 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
5029 ASSERT_EQ(0, cluster
.mon_command(
5030 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
5031 "\", \"mode\": \"writeback\"}",
5034 // wait for maps to settle
5035 cluster
.wait_for_latest_osdmap();
5041 ObjectWriteOperation op
;
5043 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5046 // create a snapshot, clone
5047 vector
<uint64_t> my_snaps(1);
5048 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5049 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5054 ObjectWriteOperation op
;
5056 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5061 my_snaps
[1] = my_snaps
[0];
5062 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&my_snaps
[0]));
5063 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(my_snaps
[0],
5068 ObjectWriteOperation op
;
5070 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5073 // verify the object is present in the cache tier
5075 NObjectIterator it
= cache_ioctx
.nobjects_begin();
5076 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
5077 ASSERT_TRUE(it
->get_oid() == string("foo"));
5079 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
5082 // verify the object is NOT present in the base tier
5084 NObjectIterator it
= ioctx
.nobjects_begin();
5085 ASSERT_TRUE(it
== ioctx
.nobjects_end());
5088 // flush on head (should fail)
5089 ioctx
.snap_set_read(librados::SNAP_HEAD
);
5091 ObjectReadOperation op
;
5093 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5094 ASSERT_EQ(0, ioctx
.aio_operate(
5095 "foo", completion
, &op
,
5096 librados::OPERATION_IGNORE_CACHE
, NULL
));
5097 completion
->wait_for_complete();
5098 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
5099 completion
->release();
5101 // flush on recent snap (should fail)
5102 ioctx
.snap_set_read(my_snaps
[0]);
5104 ObjectReadOperation op
;
5106 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5107 ASSERT_EQ(0, ioctx
.aio_operate(
5108 "foo", completion
, &op
,
5109 librados::OPERATION_IGNORE_CACHE
, NULL
));
5110 completion
->wait_for_complete();
5111 ASSERT_EQ(-EBUSY
, completion
->get_return_value());
5112 completion
->release();
5114 // flush on oldest snap
5115 ioctx
.snap_set_read(my_snaps
[1]);
5117 ObjectReadOperation op
;
5119 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5120 ASSERT_EQ(0, ioctx
.aio_operate(
5121 "foo", completion
, &op
,
5122 librados::OPERATION_IGNORE_CACHE
, NULL
));
5123 completion
->wait_for_complete();
5124 ASSERT_EQ(0, completion
->get_return_value());
5125 completion
->release();
5127 // flush on next oldest snap
5128 ioctx
.snap_set_read(my_snaps
[0]);
5130 ObjectReadOperation op
;
5132 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5133 ASSERT_EQ(0, ioctx
.aio_operate(
5134 "foo", completion
, &op
,
5135 librados::OPERATION_IGNORE_CACHE
, NULL
));
5136 completion
->wait_for_complete();
5137 ASSERT_EQ(0, completion
->get_return_value());
5138 completion
->release();
5141 ioctx
.snap_set_read(librados::SNAP_HEAD
);
5143 ObjectReadOperation op
;
5145 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5146 ASSERT_EQ(0, ioctx
.aio_operate(
5147 "foo", completion
, &op
,
5148 librados::OPERATION_IGNORE_CACHE
, NULL
));
5149 completion
->wait_for_complete();
5150 ASSERT_EQ(0, completion
->get_return_value());
5151 completion
->release();
5154 // verify i can read the snaps from the cache pool
5155 ioctx
.snap_set_read(librados::SNAP_HEAD
);
5158 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5159 ASSERT_EQ('c', bl
[0]);
5161 ioctx
.snap_set_read(my_snaps
[0]);
5164 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5165 ASSERT_EQ('b', bl
[0]);
5167 ioctx
.snap_set_read(my_snaps
[1]);
5170 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5171 ASSERT_EQ('a', bl
[0]);
5175 ASSERT_EQ(0, cluster
.mon_command(
5176 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
5180 // wait for maps to settle
5181 cluster
.wait_for_latest_osdmap();
5183 // verify i can read the snaps from the base pool
5184 ioctx
.snap_set_read(librados::SNAP_HEAD
);
5187 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5188 ASSERT_EQ('c', bl
[0]);
5190 ioctx
.snap_set_read(my_snaps
[0]);
5193 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5194 ASSERT_EQ('b', bl
[0]);
5196 ioctx
.snap_set_read(my_snaps
[1]);
5199 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
5200 ASSERT_EQ('a', bl
[0]);
5203 ASSERT_EQ(0, cluster
.mon_command(
5204 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
5205 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
5207 cluster
.wait_for_latest_osdmap();
5210 ioctx
.selfmanaged_snap_remove(my_snaps
[0]);
5213 TEST_F(LibRadosTierECPP
, FlushWriteRaces
) {
5215 std::string pool_name
= get_temp_pool_name();
5216 std::string cache_pool_name
= pool_name
+ "-cache";
5217 ASSERT_EQ("", create_one_pool_pp(pool_name
, cluster
));
5218 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
5220 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
5221 cache_ioctx
.application_enable("rados", true);
5223 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
5227 ASSERT_EQ(0, cluster
.mon_command(
5228 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5229 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
5231 ASSERT_EQ(0, cluster
.mon_command(
5232 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
5233 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
5235 ASSERT_EQ(0, cluster
.mon_command(
5236 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
5237 "\", \"mode\": \"writeback\"}",
5240 // wait for maps to settle
5241 cluster
.wait_for_latest_osdmap();
5243 // create/dirty object
5245 bl
.append("hi there");
5247 ObjectWriteOperation op
;
5249 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5254 ObjectReadOperation op
;
5256 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5257 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5258 "foo", completion
, &op
,
5259 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
5261 ObjectWriteOperation op2
;
5263 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
5264 ASSERT_EQ(0, ioctx
.aio_operate(
5265 "foo", completion2
, &op2
, 0));
5267 completion
->wait_for_complete();
5268 completion2
->wait_for_complete();
5269 ASSERT_EQ(0, completion
->get_return_value());
5270 ASSERT_EQ(0, completion2
->get_return_value());
5271 completion
->release();
5272 completion2
->release();
5277 // create/dirty object
5280 bl
.append("hi there");
5281 ObjectWriteOperation op
;
5283 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5286 // try-flush + write
5288 ObjectReadOperation op
;
5289 op
.cache_try_flush();
5290 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5291 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5292 "foo", completion
, &op
,
5293 librados::OPERATION_IGNORE_OVERLAY
|
5294 librados::OPERATION_SKIPRWLOCKS
, NULL
));
5296 ObjectWriteOperation op2
;
5298 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
5299 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion2
, &op2
, 0));
5301 completion
->wait_for_complete();
5302 completion2
->wait_for_complete();
5303 int r
= completion
->get_return_value();
5304 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
5305 ASSERT_EQ(0, completion2
->get_return_value());
5306 completion
->release();
5307 completion2
->release();
5310 cout
<< "didn't get EBUSY, trying again" << std::endl
;
5312 ASSERT_TRUE(--tries
);
5316 ASSERT_EQ(0, cluster
.mon_command(
5317 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
5320 ASSERT_EQ(0, cluster
.mon_command(
5321 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
5322 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
5325 // wait for maps to settle before next test
5326 cluster
.wait_for_latest_osdmap();
5328 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
5329 ASSERT_EQ(0, destroy_one_pool_pp(pool_name
, cluster
));
5332 TEST_F(LibRadosTwoPoolsECPP
, FlushTryFlushRaces
) {
5335 ASSERT_EQ(0, cluster
.mon_command(
5336 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5337 "\", \"tierpool\": \"" + cache_pool_name
+
5338 "\", \"force_nonempty\": \"--force-nonempty\" }",
5340 ASSERT_EQ(0, cluster
.mon_command(
5341 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
5342 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
5344 ASSERT_EQ(0, cluster
.mon_command(
5345 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
5346 "\", \"mode\": \"writeback\"}",
5349 // wait for maps to settle
5350 cluster
.wait_for_latest_osdmap();
5352 // create/dirty object
5355 bl
.append("hi there");
5356 ObjectWriteOperation op
;
5358 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5363 ObjectReadOperation op
;
5365 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5366 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5367 "foo", completion
, &op
,
5368 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
5370 ObjectReadOperation op2
;
5372 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
5373 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5374 "foo", completion2
, &op2
,
5375 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
5377 completion
->wait_for_complete();
5378 completion2
->wait_for_complete();
5379 ASSERT_EQ(0, completion
->get_return_value());
5380 ASSERT_EQ(0, completion2
->get_return_value());
5381 completion
->release();
5382 completion2
->release();
5385 // create/dirty object
5388 bl
.append("hi there");
5389 ObjectWriteOperation op
;
5391 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5394 // flush + try-flush
5396 ObjectReadOperation op
;
5398 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5399 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5400 "foo", completion
, &op
,
5401 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
5403 ObjectReadOperation op2
;
5404 op2
.cache_try_flush();
5405 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
5406 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5407 "foo", completion2
, &op2
,
5408 librados::OPERATION_IGNORE_OVERLAY
|
5409 librados::OPERATION_SKIPRWLOCKS
, NULL
));
5411 completion
->wait_for_complete();
5412 completion2
->wait_for_complete();
5413 ASSERT_EQ(0, completion
->get_return_value());
5414 ASSERT_EQ(0, completion2
->get_return_value());
5415 completion
->release();
5416 completion2
->release();
5419 // create/dirty object
5424 bl
.append("hi there");
5425 ObjectWriteOperation op
;
5427 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5430 // try-flush + flush
5431 // (flush will not piggyback on try-flush)
5433 ObjectReadOperation op
;
5434 op
.cache_try_flush();
5435 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5436 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5437 "foo", completion
, &op
,
5438 librados::OPERATION_IGNORE_OVERLAY
|
5439 librados::OPERATION_SKIPRWLOCKS
, NULL
));
5441 ObjectReadOperation op2
;
5443 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
5444 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5445 "foo", completion2
, &op2
,
5446 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
5448 completion
->wait_for_complete();
5449 completion2
->wait_for_complete();
5450 int r
= completion
->get_return_value();
5451 ASSERT_TRUE(r
== -EBUSY
|| r
== 0);
5452 ASSERT_EQ(0, completion2
->get_return_value());
5453 completion
->release();
5454 completion2
->release();
5457 cout
<< "didn't get EBUSY, trying again" << std::endl
;
5459 ASSERT_TRUE(--tries
);
5462 // create/dirty object
5465 bl
.append("hi there");
5466 ObjectWriteOperation op
;
5468 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5471 // try-flush + try-flush
5473 ObjectReadOperation op
;
5474 op
.cache_try_flush();
5475 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5476 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5477 "foo", completion
, &op
,
5478 librados::OPERATION_IGNORE_OVERLAY
|
5479 librados::OPERATION_SKIPRWLOCKS
, NULL
));
5481 ObjectReadOperation op2
;
5482 op2
.cache_try_flush();
5483 librados::AioCompletion
*completion2
= cluster
.aio_create_completion();
5484 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5485 "foo", completion2
, &op2
,
5486 librados::OPERATION_IGNORE_OVERLAY
|
5487 librados::OPERATION_SKIPRWLOCKS
, NULL
));
5489 completion
->wait_for_complete();
5490 completion2
->wait_for_complete();
5491 ASSERT_EQ(0, completion
->get_return_value());
5492 ASSERT_EQ(0, completion2
->get_return_value());
5493 completion
->release();
5494 completion2
->release();
5498 TEST_F(LibRadosTwoPoolsECPP
, TryFlushReadRace
) {
5501 ASSERT_EQ(0, cluster
.mon_command(
5502 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5503 "\", \"tierpool\": \"" + cache_pool_name
+
5504 "\", \"force_nonempty\": \"--force-nonempty\" }",
5506 ASSERT_EQ(0, cluster
.mon_command(
5507 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
5508 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
5510 ASSERT_EQ(0, cluster
.mon_command(
5511 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
5512 "\", \"mode\": \"writeback\"}",
5515 // wait for maps to settle
5516 cluster
.wait_for_latest_osdmap();
5518 // create/dirty object
5521 bl
.append("hi there");
5522 bufferptr
bp(4000000); // make it big!
5525 ObjectWriteOperation op
;
5527 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5530 // start a continuous stream of reads
5531 read_ioctx
= &ioctx
;
5533 for (int i
= 0; i
< max_reads
; ++i
) {
5540 ObjectReadOperation op
;
5541 op
.cache_try_flush();
5542 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5543 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5544 "foo", completion
, &op
,
5545 librados::OPERATION_IGNORE_OVERLAY
|
5546 librados::OPERATION_SKIPRWLOCKS
, NULL
));
5548 completion
->wait_for_complete();
5549 ASSERT_EQ(0, completion
->get_return_value());
5550 completion
->release();
5553 std::unique_lock locker
{test_lock
};
5555 cond
.wait(locker
, [] { return num_reads
== 0;});
5558 TEST_F(LibRadosTierECPP
, CallForcesPromote
) {
5560 std::string pool_name
= get_temp_pool_name();
5561 std::string cache_pool_name
= pool_name
+ "-cache";
5562 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, cluster
));
5563 ASSERT_EQ(0, cluster
.pool_create(cache_pool_name
.c_str()));
5565 ASSERT_EQ(0, cluster
.ioctx_create(cache_pool_name
.c_str(), cache_ioctx
));
5566 cache_ioctx
.application_enable("rados", true);
5568 ASSERT_EQ(0, cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
5572 ASSERT_EQ(0, cluster
.mon_command(
5573 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5574 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
5576 ASSERT_EQ(0, cluster
.mon_command(
5577 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
5578 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
5580 ASSERT_EQ(0, cluster
.mon_command(
5581 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
5582 "\", \"mode\": \"writeback\"}",
5585 // set things up such that the op would normally be proxied
5586 ASSERT_EQ(0, cluster
.mon_command(
5587 set_pool_str(cache_pool_name
, "hit_set_count", 2),
5589 ASSERT_EQ(0, cluster
.mon_command(
5590 set_pool_str(cache_pool_name
, "hit_set_period", 600),
5592 ASSERT_EQ(0, cluster
.mon_command(
5593 set_pool_str(cache_pool_name
, "hit_set_type",
5596 ASSERT_EQ(0, cluster
.mon_command(
5597 set_pool_str(cache_pool_name
, "min_read_recency_for_promote",
5601 // wait for maps to settle
5602 cluster
.wait_for_latest_osdmap();
5604 // create/dirty object
5606 bl
.append("hi there");
5608 ObjectWriteOperation op
;
5610 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
5615 ObjectReadOperation op
;
5617 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5618 ASSERT_EQ(0, cache_ioctx
.aio_operate(
5619 "foo", completion
, &op
,
5620 librados::OPERATION_IGNORE_OVERLAY
, NULL
));
5621 completion
->wait_for_complete();
5622 ASSERT_EQ(0, completion
->get_return_value());
5623 completion
->release();
5628 ObjectReadOperation op
;
5630 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
5631 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
,
5632 librados::OPERATION_IGNORE_CACHE
,
5634 completion
->wait_for_complete();
5635 ASSERT_EQ(0, completion
->get_return_value());
5636 completion
->release();
5641 ObjectReadOperation op
;
5643 op
.exec("rbd", "get_id", bl
);
5645 // should get EIO (not an rbd object), not -EOPNOTSUPP (we didn't promote)
5646 ASSERT_EQ(-5, ioctx
.operate("foo", &op
, &out
));
5649 // make sure foo is back in the cache tier
5651 NObjectIterator it
= cache_ioctx
.nobjects_begin();
5652 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
5653 ASSERT_TRUE(it
->get_oid() == string("foo"));
5655 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
5659 ASSERT_EQ(0, cluster
.mon_command(
5660 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
5663 ASSERT_EQ(0, cluster
.mon_command(
5664 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
5665 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
5668 // wait for maps to settle before next test
5669 cluster
.wait_for_latest_osdmap();
5671 ASSERT_EQ(0, cluster
.pool_delete(cache_pool_name
.c_str()));
5672 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, cluster
));
5675 TEST_F(LibRadosTierECPP
, HitSetNone
) {
5677 list
< pair
<time_t,time_t> > ls
;
5678 AioCompletion
*c
= librados::Rados::aio_create_completion();
5679 ASSERT_EQ(0, ioctx
.hit_set_list(123, c
, &ls
));
5680 c
->wait_for_complete();
5681 ASSERT_EQ(0, c
->get_return_value());
5682 ASSERT_TRUE(ls
.empty());
5687 AioCompletion
*c
= librados::Rados::aio_create_completion();
5688 ASSERT_EQ(0, ioctx
.hit_set_get(123, c
, 12345, &bl
));
5689 c
->wait_for_complete();
5690 ASSERT_EQ(-ENOENT
, c
->get_return_value());
5695 TEST_F(LibRadosTwoPoolsECPP
, HitSetRead
) {
5698 ASSERT_EQ(0, cluster
.mon_command(
5699 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5700 "\", \"tierpool\": \"" + cache_pool_name
+
5701 "\", \"force_nonempty\": \"--force-nonempty\" }",
5704 // enable hitset tracking for this pool
5705 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", 2),
5707 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", 600),
5709 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type",
5713 // wait for maps to settle
5714 cluster
.wait_for_latest_osdmap();
5716 cache_ioctx
.set_namespace("");
5718 // keep reading until we see our object appear in the HitSet
5719 utime_t start
= ceph_clock_now();
5720 utime_t hard_stop
= start
+ utime_t(600, 0);
5723 utime_t now
= ceph_clock_now();
5724 ASSERT_TRUE(now
< hard_stop
);
5726 string name
= "foo";
5728 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
5729 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
,
5730 cluster
.pool_lookup(cache_pool_name
.c_str()), "");
5733 ASSERT_EQ(-ENOENT
, cache_ioctx
.read("foo", bl
, 1, 0));
5736 AioCompletion
*c
= librados::Rados::aio_create_completion();
5737 ASSERT_EQ(0, cache_ioctx
.hit_set_get(hash
, c
, now
.sec(), &hbl
));
5738 c
->wait_for_complete();
5742 auto p
= hbl
.cbegin();
5745 if (hs
.contains(oid
)) {
5746 cout
<< "ok, hit_set contains " << oid
<< std::endl
;
5749 cout
<< "hmm, not in HitSet yet" << std::endl
;
5751 cout
<< "hmm, no HitSet yet" << std::endl
;
5758 // disable this test until hitset-get reliably works on EC pools
5760 TEST_F(LibRadosTierECPP
, HitSetWrite
) {
5761 int num_pg
= _get_pg_num(cluster
, pool_name
);
5762 ceph_assert(num_pg
> 0);
5764 // enable hitset tracking for this pool
5766 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_count", 8),
5768 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_period", 600),
5770 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(pool_name
, "hit_set_type",
5774 // wait for maps to settle
5775 cluster
.wait_for_latest_osdmap();
5777 ioctx
.set_namespace("");
5779 // do a bunch of writes
5780 for (int i
=0; i
<1000; ++i
) {
5783 ASSERT_EQ(0, ioctx
.write(stringify(i
), bl
, 1, 0));
5787 std::map
<int,HitSet
> hitsets
;
5788 for (int i
=0; i
<num_pg
; ++i
) {
5789 list
< pair
<time_t,time_t> > ls
;
5790 AioCompletion
*c
= librados::Rados::aio_create_completion();
5791 ASSERT_EQ(0, ioctx
.hit_set_list(i
, c
, &ls
));
5792 c
->wait_for_complete();
5794 std::cout
<< "pg " << i
<< " ls " << ls
<< std::endl
;
5795 ASSERT_FALSE(ls
.empty());
5798 c
= librados::Rados::aio_create_completion();
5800 ASSERT_EQ(0, ioctx
.hit_set_get(i
, c
, ls
.back().first
, &bl
));
5801 c
->wait_for_complete();
5804 //std::cout << "bl len is " << bl.length() << "\n";
5805 //bl.hexdump(std::cout);
5806 //std::cout << std::endl;
5808 auto p
= bl
.cbegin();
5809 decode(hitsets
[i
], p
);
5811 // cope with racing splits by refreshing pg_num
5812 if (i
== num_pg
- 1)
5813 num_pg
= _get_pg_num(cluster
, pool_name
);
5816 for (int i
=0; i
<1000; ++i
) {
5817 string n
= stringify(i
);
5818 uint32_t hash
= ioctx
.get_object_hash_position(n
);
5819 hobject_t
oid(sobject_t(n
, CEPH_NOSNAP
), "", hash
,
5820 cluster
.pool_lookup(pool_name
.c_str()), "");
5821 std::cout
<< "checking for " << oid
<< std::endl
;
5823 for (int p
=0; p
<num_pg
; ++p
) {
5824 if (hitsets
[p
].contains(oid
)) {
5834 TEST_F(LibRadosTwoPoolsECPP
, HitSetTrim
) {
5836 unsigned period
= 3;
5840 ASSERT_EQ(0, cluster
.mon_command(
5841 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5842 "\", \"tierpool\": \"" + cache_pool_name
+
5843 "\", \"force_nonempty\": \"--force-nonempty\" }",
5846 // enable hitset tracking for this pool
5847 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_count", count
),
5849 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_period", period
),
5851 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
5853 ASSERT_EQ(0, cluster
.mon_command(set_pool_str(cache_pool_name
, "hit_set_fpp", ".01"),
5856 // wait for maps to settle
5857 cluster
.wait_for_latest_osdmap();
5859 cache_ioctx
.set_namespace("");
5861 // do a bunch of writes and make sure the hitsets rotate
5862 utime_t start
= ceph_clock_now();
5863 utime_t hard_stop
= start
+ utime_t(count
* period
* 50, 0);
5866 int bsize
= alignment
;
5867 char *buf
= (char *)new char[bsize
];
5868 memset(buf
, 'f', bsize
);
5871 string name
= "foo";
5873 ASSERT_EQ(0, cache_ioctx
.get_object_hash_position2(name
, &hash
));
5874 hobject_t
oid(sobject_t(name
, CEPH_NOSNAP
), "", hash
, -1, "");
5877 bl
.append(buf
, bsize
);
5878 ASSERT_EQ(0, cache_ioctx
.append("foo", bl
, bsize
));
5880 list
<pair
<time_t, time_t> > ls
;
5881 AioCompletion
*c
= librados::Rados::aio_create_completion();
5882 ASSERT_EQ(0, cache_ioctx
.hit_set_list(hash
, c
, &ls
));
5883 c
->wait_for_complete();
5886 cout
<< " got ls " << ls
<< std::endl
;
5889 first
= ls
.front().first
;
5890 cout
<< "first is " << first
<< std::endl
;
5892 if (ls
.front().first
!= first
) {
5893 cout
<< "first now " << ls
.front().first
<< ", trimmed" << std::endl
;
5899 utime_t now
= ceph_clock_now();
5900 ASSERT_TRUE(now
< hard_stop
);
5907 TEST_F(LibRadosTwoPoolsECPP
, PromoteOn2ndRead
) {
5909 for (int i
=0; i
<20; ++i
) {
5911 bl
.append("hi there");
5912 ObjectWriteOperation op
;
5914 ASSERT_EQ(0, ioctx
.operate("foo" + stringify(i
), &op
));
5919 ASSERT_EQ(0, cluster
.mon_command(
5920 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
5921 "\", \"tierpool\": \"" + cache_pool_name
+
5922 "\", \"force_nonempty\": \"--force-nonempty\" }",
5924 ASSERT_EQ(0, cluster
.mon_command(
5925 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
5926 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
5928 ASSERT_EQ(0, cluster
.mon_command(
5929 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
5930 "\", \"mode\": \"writeback\"}",
5933 // enable hitset tracking for this pool
5934 ASSERT_EQ(0, cluster
.mon_command(
5935 set_pool_str(cache_pool_name
, "hit_set_count", 2),
5937 ASSERT_EQ(0, cluster
.mon_command(
5938 set_pool_str(cache_pool_name
, "hit_set_period", 600),
5940 ASSERT_EQ(0, cluster
.mon_command(
5941 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
5943 ASSERT_EQ(0, cluster
.mon_command(
5944 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
5946 ASSERT_EQ(0, cluster
.mon_command(
5947 set_pool_str(cache_pool_name
, "hit_set_grade_decay_rate", 20),
5949 ASSERT_EQ(0, cluster
.mon_command(
5950 set_pool_str(cache_pool_name
, "hit_set_search_last_n", 1),
5953 // wait for maps to settle
5954 cluster
.wait_for_latest_osdmap();
5956 int fake
= 0; // set this to non-zero to test spurious promotion,
5957 // e.g. from thrashing
5961 // 1st read, don't trigger a promote
5962 obj
= "foo" + stringify(attempt
);
5963 cout
<< obj
<< std::endl
;
5966 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
5969 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
5974 // verify the object is NOT present in the cache tier
5977 NObjectIterator it
= cache_ioctx
.nobjects_begin();
5978 while (it
!= cache_ioctx
.nobjects_end()) {
5979 cout
<< " see " << it
->get_oid() << std::endl
;
5980 if (it
->get_oid() == string(obj
.c_str())) {
5991 ASSERT_LE(attempt
, 20);
5992 cout
<< "hrm, object is present in cache on attempt " << attempt
5993 << ", retrying" << std::endl
;
5996 // Read until the object is present in the cache tier
5997 cout
<< "verifying " << obj
<< " is eventually promoted" << std::endl
;
6000 ASSERT_EQ(1, ioctx
.read(obj
.c_str(), bl
, 1, 0));
6003 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6004 while (it
!= cache_ioctx
.nobjects_end()) {
6005 if (it
->get_oid() == string(obj
.c_str())) {
6018 ASSERT_EQ(0, cluster
.mon_command(
6019 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
6022 ASSERT_EQ(0, cluster
.mon_command(
6023 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6024 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6027 // wait for maps to settle before next test
6028 cluster
.wait_for_latest_osdmap();
6031 TEST_F(LibRadosTwoPoolsECPP
, ProxyRead
) {
6035 bl
.append("hi there");
6036 ObjectWriteOperation op
;
6038 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6043 ASSERT_EQ(0, cluster
.mon_command(
6044 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6045 "\", \"tierpool\": \"" + cache_pool_name
+
6046 "\", \"force_nonempty\": \"--force-nonempty\" }",
6048 ASSERT_EQ(0, cluster
.mon_command(
6049 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6050 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6052 ASSERT_EQ(0, cluster
.mon_command(
6053 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6054 "\", \"mode\": \"readproxy\"}",
6057 // wait for maps to settle
6058 cluster
.wait_for_latest_osdmap();
6060 // read and verify the object
6063 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6064 ASSERT_EQ('h', bl
[0]);
6067 // Verify 10 times the object is NOT present in the cache tier
6070 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6071 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6076 ASSERT_EQ(0, cluster
.mon_command(
6077 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
6080 ASSERT_EQ(0, cluster
.mon_command(
6081 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6082 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6085 // wait for maps to settle before next test
6086 cluster
.wait_for_latest_osdmap();
6089 TEST_F(LibRadosTwoPoolsECPP
, CachePin
) {
6093 bl
.append("hi there");
6094 ObjectWriteOperation op
;
6096 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6100 bl
.append("hi there");
6101 ObjectWriteOperation op
;
6103 ASSERT_EQ(0, ioctx
.operate("bar", &op
));
6107 bl
.append("hi there");
6108 ObjectWriteOperation op
;
6110 ASSERT_EQ(0, ioctx
.operate("baz", &op
));
6114 bl
.append("hi there");
6115 ObjectWriteOperation op
;
6117 ASSERT_EQ(0, ioctx
.operate("bam", &op
));
6122 ASSERT_EQ(0, cluster
.mon_command(
6123 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6124 "\", \"tierpool\": \"" + cache_pool_name
+
6125 "\", \"force_nonempty\": \"--force-nonempty\" }",
6127 ASSERT_EQ(0, cluster
.mon_command(
6128 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6129 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6131 ASSERT_EQ(0, cluster
.mon_command(
6132 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6133 "\", \"mode\": \"writeback\"}",
6136 // wait for maps to settle
6137 cluster
.wait_for_latest_osdmap();
6139 // read, trigger promote
6142 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6143 ASSERT_EQ(1, ioctx
.read("bar", bl
, 1, 0));
6144 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
6145 ASSERT_EQ(1, ioctx
.read("bam", bl
, 1, 0));
6148 // verify the objects are present in the cache tier
6150 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6151 ASSERT_TRUE(it
!= cache_ioctx
.nobjects_end());
6152 for (uint32_t i
= 0; i
< 4; i
++) {
6153 ASSERT_TRUE(it
->get_oid() == string("foo") ||
6154 it
->get_oid() == string("bar") ||
6155 it
->get_oid() == string("baz") ||
6156 it
->get_oid() == string("bam"));
6159 ASSERT_TRUE(it
== cache_ioctx
.nobjects_end());
6164 ObjectWriteOperation op
;
6166 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6167 ASSERT_EQ(0, cache_ioctx
.aio_operate("foo", completion
, &op
));
6168 completion
->wait_for_complete();
6169 ASSERT_EQ(0, completion
->get_return_value());
6170 completion
->release();
6173 ObjectWriteOperation op
;
6175 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6176 ASSERT_EQ(0, cache_ioctx
.aio_operate("baz", completion
, &op
));
6177 completion
->wait_for_complete();
6178 ASSERT_EQ(0, completion
->get_return_value());
6179 completion
->release();
6183 ASSERT_EQ(0, cluster
.mon_command(
6184 set_pool_str(cache_pool_name
, "hit_set_count", 2),
6186 ASSERT_EQ(0, cluster
.mon_command(
6187 set_pool_str(cache_pool_name
, "hit_set_period", 600),
6189 ASSERT_EQ(0, cluster
.mon_command(
6190 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
6192 ASSERT_EQ(0, cluster
.mon_command(
6193 set_pool_str(cache_pool_name
, "min_read_recency_for_promote", 1),
6195 ASSERT_EQ(0, cluster
.mon_command(
6196 set_pool_str(cache_pool_name
, "target_max_objects", 1),
6201 // Verify the pinned object 'foo' is not flushed/evicted
6205 ASSERT_EQ(1, ioctx
.read("baz", bl
, 1, 0));
6208 NObjectIterator it
= cache_ioctx
.nobjects_begin();
6209 while (it
!= cache_ioctx
.nobjects_end()) {
6210 ASSERT_TRUE(it
->get_oid() == string("foo") ||
6211 it
->get_oid() == string("bar") ||
6212 it
->get_oid() == string("baz") ||
6213 it
->get_oid() == string("bam"));
6218 ASSERT_TRUE(it
->get_oid() == string("foo") ||
6219 it
->get_oid() == string("baz"));
6227 ASSERT_EQ(0, cluster
.mon_command(
6228 "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name
+
6231 ASSERT_EQ(0, cluster
.mon_command(
6232 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6233 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6236 // wait for maps to settle before next test
6237 cluster
.wait_for_latest_osdmap();
6239 TEST_F(LibRadosTwoPoolsECPP
, SetRedirectRead
) {
6243 bl
.append("hi there");
6244 ObjectWriteOperation op
;
6246 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6251 ObjectWriteOperation op
;
6253 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
6258 ASSERT_EQ(0, cluster
.mon_command(
6259 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6260 "\", \"tierpool\": \"" + cache_pool_name
+
6261 "\", \"force_nonempty\": \"--force-nonempty\" }",
6264 // wait for maps to settle
6265 cluster
.wait_for_latest_osdmap();
6268 ObjectWriteOperation op
;
6269 op
.set_redirect("bar", cache_ioctx
, 0);
6270 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6271 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
6272 completion
->wait_for_complete();
6273 ASSERT_EQ(0, completion
->get_return_value());
6274 completion
->release();
6276 // read and verify the object
6279 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6280 ASSERT_EQ('t', bl
[0]);
6283 ASSERT_EQ(0, cluster
.mon_command(
6284 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6285 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6288 // wait for maps to settle before next test
6289 cluster
.wait_for_latest_osdmap();
6292 TEST_F(LibRadosTwoPoolsECPP
, SetChunkRead
) {
6293 // note: require >= mimic
6297 ObjectWriteOperation op
;
6299 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6303 bl
.append("hi there");
6304 ObjectWriteOperation op
;
6306 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
6311 ASSERT_EQ(0, cluster
.mon_command(
6312 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6313 "\", \"tierpool\": \"" + cache_pool_name
+
6314 "\", \"force_nonempty\": \"--force-nonempty\" }",
6317 // wait for maps to settle
6318 cluster
.wait_for_latest_osdmap();
6322 ObjectWriteOperation op
;
6323 op
.set_chunk(0, 8, cache_ioctx
, "bar", 0);
6324 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6325 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
6326 completion
->wait_for_complete();
6327 ASSERT_EQ(0, completion
->get_return_value());
6328 completion
->release();
6331 // make all chunks dirty --> full flush --> all chunks are evicted
6334 bl
.append("There hi");
6335 ObjectWriteOperation op
;
6337 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6340 // read and verify the object
6343 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6344 ASSERT_EQ('T', bl
[0]);
6347 ASSERT_EQ(0, cluster
.mon_command(
6348 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6349 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6352 // wait for maps to settle before next test
6353 cluster
.wait_for_latest_osdmap();
6356 TEST_F(LibRadosTwoPoolsECPP
, ManifestPromoteRead
) {
6357 // note: require >= mimic
6362 bl
.append("hi there");
6363 ObjectWriteOperation op
;
6365 ASSERT_EQ(0, ioctx
.operate("foo", &op
));
6368 ObjectWriteOperation op
;
6370 ASSERT_EQ(0, ioctx
.operate("foo-chunk", &op
));
6374 bl
.append("HI there");
6375 ObjectWriteOperation op
;
6377 ASSERT_EQ(0, cache_ioctx
.operate("bar", &op
));
6381 bl
.append("BASE CHUNK");
6382 ObjectWriteOperation op
;
6384 ASSERT_EQ(0, cache_ioctx
.operate("bar-chunk", &op
));
6389 ASSERT_EQ(0, cluster
.mon_command(
6390 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6391 "\", \"tierpool\": \"" + cache_pool_name
+
6392 "\", \"force_nonempty\": \"--force-nonempty\" }",
6395 // wait for maps to settle
6396 cluster
.wait_for_latest_osdmap();
6400 ObjectWriteOperation op
;
6401 op
.set_redirect("bar", cache_ioctx
, 0);
6402 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6403 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
6404 completion
->wait_for_complete();
6405 ASSERT_EQ(0, completion
->get_return_value());
6406 completion
->release();
6410 ObjectWriteOperation op
;
6411 op
.set_chunk(0, 10, cache_ioctx
, "bar-chunk", 0);
6412 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6413 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
6414 completion
->wait_for_complete();
6415 ASSERT_EQ(0, completion
->get_return_value());
6416 completion
->release();
6420 ObjectWriteOperation op
;
6422 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6423 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &op
));
6424 completion
->wait_for_complete();
6425 ASSERT_EQ(0, completion
->get_return_value());
6426 completion
->release();
6428 // read and verify the object (redirect)
6431 ASSERT_EQ(1, ioctx
.read("foo", bl
, 1, 0));
6432 ASSERT_EQ('H', bl
[0]);
6436 ObjectWriteOperation op
;
6438 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6439 ASSERT_EQ(0, ioctx
.aio_operate("foo-chunk", completion
, &op
));
6440 completion
->wait_for_complete();
6441 ASSERT_EQ(0, completion
->get_return_value());
6442 completion
->release();
6444 // read and verify the object
6447 ASSERT_EQ(1, ioctx
.read("foo-chunk", bl
, 1, 0));
6448 ASSERT_EQ('B', bl
[0]);
6451 ASSERT_EQ(0, cluster
.mon_command(
6452 "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name
+
6453 "\", \"tierpool\": \"" + cache_pool_name
+ "\"}",
6456 // wait for maps to settle before next test
6457 cluster
.wait_for_latest_osdmap();
6460 TEST_F(LibRadosTwoPoolsPP
, PropagateBaseTierError
) {
6461 // write object to base tier
6463 encode(static_cast<uint32_t>(0U), omap_bl
);
6465 ObjectWriteOperation op1
;
6466 op1
.omap_set({{"somekey", omap_bl
}});
6467 ASSERT_EQ(0, ioctx
.operate("propagate-base-tier-error", &op1
));
6471 ASSERT_EQ(0, cluster
.mon_command(
6472 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6473 "\", \"tierpool\": \"" + cache_pool_name
+
6474 "\", \"force_nonempty\": \"--force-nonempty\" }",
6476 ASSERT_EQ(0, cluster
.mon_command(
6477 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6478 "\", \"mode\": \"writeback\"}",
6480 ASSERT_EQ(0, cluster
.mon_command(
6481 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6482 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6485 ASSERT_EQ(0, cluster
.mon_command(
6486 set_pool_str(cache_pool_name
, "hit_set_type", "bloom"),
6488 ASSERT_EQ(0, cluster
.mon_command(
6489 set_pool_str(cache_pool_name
, "hit_set_count", 1),
6491 ASSERT_EQ(0, cluster
.mon_command(
6492 set_pool_str(cache_pool_name
, "hit_set_period", 600),
6494 ASSERT_EQ(0, cluster
.mon_command(
6495 set_pool_str(cache_pool_name
, "target_max_objects", 250),
6498 // wait for maps to settle
6499 cluster
.wait_for_latest_osdmap();
6501 // guarded op should fail so expect error to propagate to cache tier
6502 bufferlist test_omap_bl
;
6503 encode(static_cast<uint32_t>(1U), test_omap_bl
);
6505 ObjectWriteOperation op2
;
6506 op2
.omap_cmp({{"somekey", {test_omap_bl
, CEPH_OSD_CMPXATTR_OP_EQ
}}}, nullptr);
6507 op2
.omap_set({{"somekey", test_omap_bl
}});
6509 ASSERT_EQ(-ECANCELED
, ioctx
.operate("propagate-base-tier-error", &op2
));
6512 TEST_F(LibRadosTwoPoolsPP
, HelloWriteReturn
) {
6515 ASSERT_EQ(0, cluster
.mon_command(
6516 "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name
+
6517 "\", \"tierpool\": \"" + cache_pool_name
+
6518 "\", \"force_nonempty\": \"--force-nonempty\" }",
6520 ASSERT_EQ(0, cluster
.mon_command(
6521 "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name
+
6522 "\", \"overlaypool\": \"" + cache_pool_name
+ "\"}",
6524 ASSERT_EQ(0, cluster
.mon_command(
6525 "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name
+
6526 "\", \"mode\": \"writeback\"}",
6529 // set things up such that the op would normally be proxied
6530 ASSERT_EQ(0, cluster
.mon_command(
6531 set_pool_str(cache_pool_name
, "hit_set_count", 2),
6533 ASSERT_EQ(0, cluster
.mon_command(
6534 set_pool_str(cache_pool_name
, "hit_set_period", 600),
6536 ASSERT_EQ(0, cluster
.mon_command(
6537 set_pool_str(cache_pool_name
, "hit_set_type",
6540 ASSERT_EQ(0, cluster
.mon_command(
6541 set_pool_str(cache_pool_name
, "min_read_recency_for_promote",
6545 // wait for maps to settle
6546 cluster
.wait_for_latest_osdmap();
6548 // this *will* return data due to the RETURNVEC flag
6552 ObjectWriteOperation o
;
6553 o
.exec("hello", "write_return_data", in
, &out
, &rval
);
6554 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6555 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &o
,
6556 librados::OPERATION_RETURNVEC
));
6557 completion
->wait_for_complete();
6558 ASSERT_EQ(42, completion
->get_return_value());
6559 ASSERT_EQ(42, rval
);
6560 out
.hexdump(std::cout
);
6561 ASSERT_EQ("you might see this", std::string(out
.c_str(), out
.length()));
6564 // this will overflow because the return data is too big
6568 ObjectWriteOperation o
;
6569 o
.exec("hello", "write_too_much_return_data", in
, &out
, &rval
);
6570 librados::AioCompletion
*completion
= cluster
.aio_create_completion();
6571 ASSERT_EQ(0, ioctx
.aio_operate("foo", completion
, &o
,
6572 librados::OPERATION_RETURNVEC
));
6573 completion
->wait_for_complete();
6574 ASSERT_EQ(-EOVERFLOW
, completion
->get_return_value());
6575 ASSERT_EQ(-EOVERFLOW
, rval
);
6576 ASSERT_EQ("", std::string(out
.c_str(), out
.length()));