1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "test/librbd/test_fixture.h"
4 #include "test/librbd/test_support.h"
5 #include "include/int_types.h"
6 #include "include/stringify.h"
7 #include "include/rados/librados.h"
8 #include "include/rbd/librbd.hpp"
9 #include "common/Cond.h"
10 #include "common/ceph_mutex.h"
11 #include "common/errno.h"
12 #include "cls/lock/cls_lock_client.h"
13 #include "cls/lock/cls_lock_types.h"
14 #include "librbd/internal.h"
15 #include "librbd/ImageCtx.h"
16 #include "librbd/ImageWatcher.h"
17 #include "librbd/WatchNotifyTypes.h"
18 #include "librbd/io/AioCompletion.h"
19 #include "test/librados/test.h"
20 #include "gtest/gtest.h"
21 #include <boost/assign/std/set.hpp>
22 #include <boost/assign/std/map.hpp>
23 #include <boost/scope_exit.hpp>
24 #include <boost/thread/thread.hpp>
31 using namespace std::chrono_literals
;
33 using namespace boost::assign
;
34 using namespace librbd::watch_notify
;
36 void register_test_image_watcher() {
39 class TestImageWatcher
: public TestFixture
{
42 TestImageWatcher() : m_watch_ctx(NULL
)
46 class WatchCtx
: public librados::WatchCtx2
{
48 explicit WatchCtx(TestImageWatcher
&parent
) : m_parent(parent
), m_handle(0) {}
50 int watch(const librbd::ImageCtx
&ictx
) {
51 m_header_oid
= ictx
.header_oid
;
52 return m_parent
.m_ioctx
.watch2(m_header_oid
, &m_handle
, this);
56 return m_parent
.m_ioctx
.unwatch2(m_handle
);
59 void handle_notify(uint64_t notify_id
,
62 bufferlist
& bl
) override
{
66 auto iter
= bl
.cbegin();
67 DECODE_START(1, iter
);
69 iter
.copy_all(payload
);
72 NotifyOp notify_op
= static_cast<NotifyOp
>(op
);
74 std::cout << "NOTIFY: " << notify_op << ", " << notify_id
75 << ", " << cookie << ", " << notifier_id << std::endl;
78 std::lock_guard l
{m_parent
.m_callback_lock
};
79 m_parent
.m_notify_payloads
[notify_op
] = payload
;
82 if (m_parent
.m_notify_acks
.count(notify_op
) > 0) {
83 reply
= m_parent
.m_notify_acks
[notify_op
];
84 m_parent
.m_notifies
+= notify_op
;
85 m_parent
.m_callback_cond
.notify_all();
88 m_parent
.m_ioctx
.notify_ack(m_header_oid
, notify_id
, cookie
, reply
);
94 void handle_error(uint64_t cookie
, int err
) override
{
95 std::cerr
<< "ERROR: " << cookie
<< ", " << cpp_strerror(err
)
99 uint64_t get_handle() const {
104 TestImageWatcher
&m_parent
;
105 std::string m_header_oid
;
109 void TearDown() override
{
110 deregister_image_watch();
111 TestFixture::TearDown();
114 int deregister_image_watch() {
115 if (m_watch_ctx
!= NULL
) {
116 int r
= m_watch_ctx
->unwatch();
118 librados::Rados
rados(m_ioctx
);
128 int register_image_watch(librbd::ImageCtx
&ictx
) {
129 m_watch_ctx
= new WatchCtx(*this);
130 return m_watch_ctx
->watch(ictx
);
133 bool wait_for_notifies(librbd::ImageCtx
&ictx
) {
134 std::unique_lock l
{m_callback_lock
};
135 while (m_notifies
.size() < m_notify_acks
.size()) {
136 if (m_callback_cond
.wait_for(l
, 10s
) == std::cv_status::timeout
) {
140 return (m_notifies
.size() == m_notify_acks
.size());
143 bufferlist
create_response_message(int r
) {
145 encode(ResponseMessage(r
), bl
);
149 bool extract_async_request_id(NotifyOp op
, AsyncRequestId
*id
) {
150 if (m_notify_payloads
.count(op
) == 0) {
154 bufferlist payload
= m_notify_payloads
[op
];
155 auto iter
= payload
.cbegin();
158 case NOTIFY_OP_FLATTEN
:
160 FlattenPayload payload
;
161 payload
.decode(2, iter
);
162 *id
= payload
.async_request_id
;
165 case NOTIFY_OP_RESIZE
:
167 ResizePayload payload
;
168 payload
.decode(2, iter
);
169 *id
= payload
.async_request_id
;
172 case NOTIFY_OP_SNAP_CREATE
:
174 SnapCreatePayload payload
;
175 payload
.decode(7, iter
);
176 *id
= payload
.async_request_id
;
179 case NOTIFY_OP_SNAP_RENAME
:
181 SnapRenamePayload payload
;
182 payload
.decode(7, iter
);
183 *id
= payload
.async_request_id
;
186 case NOTIFY_OP_SNAP_REMOVE
:
188 SnapRemovePayload payload
;
189 payload
.decode(7, iter
);
190 *id
= payload
.async_request_id
;
193 case NOTIFY_OP_SNAP_PROTECT
:
195 SnapProtectPayload payload
;
196 payload
.decode(7, iter
);
197 *id
= payload
.async_request_id
;
200 case NOTIFY_OP_SNAP_UNPROTECT
:
202 SnapUnprotectPayload payload
;
203 payload
.decode(7, iter
);
204 *id
= payload
.async_request_id
;
207 case NOTIFY_OP_RENAME
:
209 RenamePayload payload
;
210 payload
.decode(7, iter
);
211 *id
= payload
.async_request_id
;
214 case NOTIFY_OP_REBUILD_OBJECT_MAP
:
216 RebuildObjectMapPayload payload
;
217 payload
.decode(2, iter
);
218 *id
= payload
.async_request_id
;
221 case NOTIFY_OP_UPDATE_FEATURES
:
223 UpdateFeaturesPayload payload
;
224 payload
.decode(7, iter
);
225 *id
= payload
.async_request_id
;
234 int notify_async_progress(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
235 uint64_t offset
, uint64_t total
) {
237 encode(NotifyMessage(new AsyncProgressPayload(id
, offset
, total
)), bl
);
238 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
241 int notify_async_complete(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
244 encode(NotifyMessage(new AsyncCompletePayload(id
, r
)), bl
);
245 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
248 typedef std::map
<NotifyOp
, bufferlist
> NotifyOpPayloads
;
249 typedef std::set
<NotifyOp
> NotifyOps
;
251 WatchCtx
*m_watch_ctx
;
253 NotifyOps m_notifies
;
254 NotifyOpPayloads m_notify_payloads
;
255 NotifyOpPayloads m_notify_acks
;
257 AsyncRequestId m_async_request_id
;
259 ceph::mutex m_callback_lock
= ceph::make_mutex("m_callback_lock");
260 ceph::condition_variable m_callback_cond
;
264 struct ProgressContext
: public librbd::ProgressContext
{
265 ceph::mutex mutex
= ceph::make_mutex("ProgressContext::mutex");
266 ceph::condition_variable cond
;
271 ProgressContext() : received(false),
272 offset(0), total(0) {}
274 int update_progress(uint64_t offset_
, uint64_t total_
) override
{
275 std::lock_guard l
{mutex
};
283 bool wait(librbd::ImageCtx
*ictx
, uint64_t offset_
, uint64_t total_
) {
284 std::unique_lock l
{mutex
};
286 if (cond
.wait_for(l
, 10s
) == std::cv_status::timeout
) {
290 return (received
&& offset
== offset_
&& total
== total_
);
295 librbd::ImageCtx
*ictx
;
296 ProgressContext
*progress_context
;
299 FlattenTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
300 : ictx(ictx_
), progress_context(ctx
), result(0) {}
303 std::shared_lock l
{ictx
->owner_lock
};
305 ictx
->image_watcher
->notify_flatten(0, *progress_context
, &ctx
);
311 librbd::ImageCtx
*ictx
;
312 ProgressContext
*progress_context
;
315 ResizeTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
316 : ictx(ictx_
), progress_context(ctx
), result(0) {}
319 std::shared_lock l
{ictx
->owner_lock
};
321 ictx
->image_watcher
->notify_resize(0, 0, true, *progress_context
, &ctx
);
326 struct SnapCreateTask
{
327 librbd::ImageCtx
*ictx
;
328 ProgressContext
*progress_context
;
331 SnapCreateTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
332 : ictx(ictx_
), progress_context(ctx
), result(0) {}
335 std::shared_lock l
{ictx
->owner_lock
};
337 ictx
->image_watcher
->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(),
338 "snap", 0, *progress_context
, &ctx
);
343 struct SnapRenameTask
{
344 librbd::ImageCtx
*ictx
;
347 SnapRenameTask(librbd::ImageCtx
*ictx
)
352 std::shared_lock l
{ictx
->owner_lock
};
354 ictx
->image_watcher
->notify_snap_rename(0, 1, "snap-rename", &ctx
);
359 struct SnapRemoveTask
{
360 librbd::ImageCtx
*ictx
;
363 SnapRemoveTask(librbd::ImageCtx
*ictx
)
368 std::shared_lock l
{ictx
->owner_lock
};
370 ictx
->image_watcher
->notify_snap_remove(
371 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx
);
376 struct SnapProtectTask
{
377 librbd::ImageCtx
*ictx
;
380 SnapProtectTask(librbd::ImageCtx
*ictx
)
385 std::shared_lock l
{ictx
->owner_lock
};
387 ictx
->image_watcher
->notify_snap_protect(
388 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx
);
393 struct SnapUnprotectTask
{
394 librbd::ImageCtx
*ictx
;
397 SnapUnprotectTask(librbd::ImageCtx
*ictx
)
402 std::shared_lock l
{ictx
->owner_lock
};
404 ictx
->image_watcher
->notify_snap_unprotect(
405 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx
);
411 librbd::ImageCtx
*ictx
;
414 RenameTask(librbd::ImageCtx
*ictx
)
419 std::shared_lock l
{ictx
->owner_lock
};
421 ictx
->image_watcher
->notify_rename(0, "new_name", &ctx
);
426 struct RebuildObjectMapTask
{
427 librbd::ImageCtx
*ictx
;
428 ProgressContext
*progress_context
;
431 RebuildObjectMapTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
432 : ictx(ictx_
), progress_context(ctx
), result(0) {}
435 std::shared_lock l
{ictx
->owner_lock
};
437 ictx
->image_watcher
->notify_rebuild_object_map(0, *progress_context
, &ctx
);
442 struct UpdateFeaturesTask
{
443 librbd::ImageCtx
*ictx
;
446 UpdateFeaturesTask(librbd::ImageCtx
*ictx
)
447 : ictx(ictx
), result(0) {}
450 std::shared_lock l
{ictx
->owner_lock
};
452 uint64_t features
= 24;
454 ictx
->image_watcher
->notify_update_features(0, features
, enabled
, &ctx
);
459 TEST_F(TestImageWatcher
, NotifyHeaderUpdate
) {
460 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
462 librbd::ImageCtx
*ictx
;
463 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
465 ASSERT_EQ(0, register_image_watch(*ictx
));
467 m_notify_acks
= {{NOTIFY_OP_HEADER_UPDATE
, {}}};
468 ictx
->notify_update();
470 ASSERT_TRUE(wait_for_notifies(*ictx
));
472 NotifyOps expected_notify_ops
;
473 expected_notify_ops
+= NOTIFY_OP_HEADER_UPDATE
;
474 ASSERT_EQ(expected_notify_ops
, m_notifies
);
477 TEST_F(TestImageWatcher
, NotifyFlatten
) {
478 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
480 librbd::ImageCtx
*ictx
;
481 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
483 ASSERT_EQ(0, register_image_watch(*ictx
));
484 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
485 "auto " + stringify(m_watch_ctx
->get_handle())));
487 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
489 ProgressContext progress_context
;
490 FlattenTask
flatten_task(ictx
, &progress_context
);
491 boost::thread
thread(boost::ref(flatten_task
));
493 ASSERT_TRUE(wait_for_notifies(*ictx
));
495 NotifyOps expected_notify_ops
;
496 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
497 ASSERT_EQ(expected_notify_ops
, m_notifies
);
499 AsyncRequestId async_request_id
;
500 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
502 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
503 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
505 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
507 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
508 ASSERT_EQ(0, flatten_task
.result
);
511 TEST_F(TestImageWatcher
, NotifyResize
) {
512 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
514 librbd::ImageCtx
*ictx
;
515 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
517 ASSERT_EQ(0, register_image_watch(*ictx
));
518 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
519 "auto " + stringify(m_watch_ctx
->get_handle())));
521 m_notify_acks
= {{NOTIFY_OP_RESIZE
, create_response_message(0)}};
523 ProgressContext progress_context
;
524 ResizeTask
resize_task(ictx
, &progress_context
);
525 boost::thread
thread(boost::ref(resize_task
));
527 ASSERT_TRUE(wait_for_notifies(*ictx
));
529 NotifyOps expected_notify_ops
;
530 expected_notify_ops
+= NOTIFY_OP_RESIZE
;
531 ASSERT_EQ(expected_notify_ops
, m_notifies
);
533 AsyncRequestId async_request_id
;
534 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RESIZE
, &async_request_id
));
536 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
537 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
539 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
541 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
542 ASSERT_EQ(0, resize_task
.result
);
545 TEST_F(TestImageWatcher
, NotifyRebuildObjectMap
) {
546 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
548 librbd::ImageCtx
*ictx
;
549 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
551 ASSERT_EQ(0, register_image_watch(*ictx
));
552 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
553 "auto " + stringify(m_watch_ctx
->get_handle())));
555 m_notify_acks
= {{NOTIFY_OP_REBUILD_OBJECT_MAP
, create_response_message(0)}};
557 ProgressContext progress_context
;
558 RebuildObjectMapTask
rebuild_task(ictx
, &progress_context
);
559 boost::thread
thread(boost::ref(rebuild_task
));
561 ASSERT_TRUE(wait_for_notifies(*ictx
));
563 NotifyOps expected_notify_ops
;
564 expected_notify_ops
+= NOTIFY_OP_REBUILD_OBJECT_MAP
;
565 ASSERT_EQ(expected_notify_ops
, m_notifies
);
567 AsyncRequestId async_request_id
;
568 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_REBUILD_OBJECT_MAP
,
571 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
572 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
574 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
576 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
577 ASSERT_EQ(0, rebuild_task
.result
);
580 TEST_F(TestImageWatcher
, NotifyUpdateFeatures
) {
581 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
583 librbd::ImageCtx
*ictx
;
584 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
586 ASSERT_EQ(0, register_image_watch(*ictx
));
587 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
588 "auto " + stringify(m_watch_ctx
->get_handle())));
590 m_notify_acks
= {{NOTIFY_OP_UPDATE_FEATURES
, create_response_message(0)}};
592 UpdateFeaturesTask
update_features_task(ictx
);
593 boost::thread
thread(boost::ref(update_features_task
));
595 ASSERT_TRUE(wait_for_notifies(*ictx
));
597 NotifyOps expected_notify_ops
;
598 expected_notify_ops
+= NOTIFY_OP_UPDATE_FEATURES
;
599 ASSERT_EQ(expected_notify_ops
, m_notifies
);
601 AsyncRequestId async_request_id
;
602 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_UPDATE_FEATURES
,
605 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
606 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
607 ASSERT_EQ(0, update_features_task
.result
);
610 TEST_F(TestImageWatcher
, NotifySnapCreate
) {
611 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
613 librbd::ImageCtx
*ictx
;
614 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
616 ASSERT_EQ(0, register_image_watch(*ictx
));
617 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
618 "auto " + stringify(m_watch_ctx
->get_handle())));
620 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(0)}};
622 ProgressContext progress_context
;
623 SnapCreateTask
snap_create_task(ictx
, &progress_context
);
624 boost::thread
thread(boost::ref(snap_create_task
));
626 ASSERT_TRUE(wait_for_notifies(*ictx
));
628 NotifyOps expected_notify_ops
;
629 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
630 ASSERT_EQ(expected_notify_ops
, m_notifies
);
632 AsyncRequestId async_request_id
;
633 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_CREATE
,
636 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 1, 10));
637 ASSERT_TRUE(progress_context
.wait(ictx
, 1, 10));
639 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
641 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
642 ASSERT_EQ(0, snap_create_task
.result
);
645 TEST_F(TestImageWatcher
, NotifySnapCreateError
) {
646 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
648 librbd::ImageCtx
*ictx
;
649 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
651 ASSERT_EQ(0, register_image_watch(*ictx
));
652 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
653 "auto " + stringify(m_watch_ctx
->get_handle())));
655 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(-EEXIST
)}};
657 std::shared_lock l
{ictx
->owner_lock
};
658 C_SaferCond notify_ctx
;
659 librbd::NoOpProgressContext prog_ctx
;
660 ictx
->image_watcher
->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(),
661 "snap", 0, prog_ctx
, ¬ify_ctx
);
662 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
664 NotifyOps expected_notify_ops
;
665 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
666 ASSERT_EQ(expected_notify_ops
, m_notifies
);
669 TEST_F(TestImageWatcher
, NotifySnapRename
) {
670 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
672 librbd::ImageCtx
*ictx
;
673 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
675 ASSERT_EQ(0, register_image_watch(*ictx
));
676 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
677 "auto " + stringify(m_watch_ctx
->get_handle())));
679 m_notify_acks
= {{NOTIFY_OP_SNAP_RENAME
, create_response_message(0)}};
681 SnapRenameTask
snap_rename_task(ictx
);
682 boost::thread
thread(boost::ref(snap_rename_task
));
684 ASSERT_TRUE(wait_for_notifies(*ictx
));
686 NotifyOps expected_notify_ops
;
687 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
688 ASSERT_EQ(expected_notify_ops
, m_notifies
);
690 AsyncRequestId async_request_id
;
691 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_RENAME
,
694 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
696 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
697 ASSERT_EQ(0, snap_rename_task
.result
);
700 TEST_F(TestImageWatcher
, NotifySnapRenameError
) {
701 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
703 librbd::ImageCtx
*ictx
;
704 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
706 ASSERT_EQ(0, register_image_watch(*ictx
));
707 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
708 "auto " + stringify(m_watch_ctx
->get_handle())));
710 m_notify_acks
= {{NOTIFY_OP_SNAP_RENAME
, create_response_message(-EEXIST
)}};
712 std::shared_lock l
{ictx
->owner_lock
};
713 C_SaferCond notify_ctx
;
714 ictx
->image_watcher
->notify_snap_rename(0, 1, "snap-rename", ¬ify_ctx
);
715 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
717 NotifyOps expected_notify_ops
;
718 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
719 ASSERT_EQ(expected_notify_ops
, m_notifies
);
722 TEST_F(TestImageWatcher
, NotifySnapRemove
) {
723 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
725 librbd::ImageCtx
*ictx
;
726 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
728 ASSERT_EQ(0, register_image_watch(*ictx
));
729 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
730 "auto " + stringify(m_watch_ctx
->get_handle())));
732 m_notify_acks
= {{NOTIFY_OP_SNAP_REMOVE
, create_response_message(0)}};
734 SnapRemoveTask
snap_remove_task(ictx
);
735 boost::thread
thread(boost::ref(snap_remove_task
));
737 ASSERT_TRUE(wait_for_notifies(*ictx
));
739 NotifyOps expected_notify_ops
;
740 expected_notify_ops
+= NOTIFY_OP_SNAP_REMOVE
;
741 ASSERT_EQ(expected_notify_ops
, m_notifies
);
743 AsyncRequestId async_request_id
;
744 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_REMOVE
,
747 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
749 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
750 ASSERT_EQ(0, snap_remove_task
.result
);
753 TEST_F(TestImageWatcher
, NotifySnapProtect
) {
754 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
756 librbd::ImageCtx
*ictx
;
757 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
759 ASSERT_EQ(0, register_image_watch(*ictx
));
760 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
761 "auto " + stringify(m_watch_ctx
->get_handle())));
763 m_notify_acks
= {{NOTIFY_OP_SNAP_PROTECT
, create_response_message(0)}};
765 SnapProtectTask
snap_protect_task(ictx
);
766 boost::thread
thread(boost::ref(snap_protect_task
));
768 ASSERT_TRUE(wait_for_notifies(*ictx
));
770 NotifyOps expected_notify_ops
;
771 expected_notify_ops
+= NOTIFY_OP_SNAP_PROTECT
;
772 ASSERT_EQ(expected_notify_ops
, m_notifies
);
774 AsyncRequestId async_request_id
;
775 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_PROTECT
,
778 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
780 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
781 ASSERT_EQ(0, snap_protect_task
.result
);
784 TEST_F(TestImageWatcher
, NotifySnapUnprotect
) {
785 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
787 librbd::ImageCtx
*ictx
;
788 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
790 ASSERT_EQ(0, register_image_watch(*ictx
));
791 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
792 "auto " + stringify(m_watch_ctx
->get_handle())));
794 m_notify_acks
= {{NOTIFY_OP_SNAP_UNPROTECT
, create_response_message(0)}};
796 SnapUnprotectTask
snap_unprotect_task(ictx
);
797 boost::thread
thread(boost::ref(snap_unprotect_task
));
799 ASSERT_TRUE(wait_for_notifies(*ictx
));
801 NotifyOps expected_notify_ops
;
802 expected_notify_ops
+= NOTIFY_OP_SNAP_UNPROTECT
;
803 ASSERT_EQ(expected_notify_ops
, m_notifies
);
805 AsyncRequestId async_request_id
;
806 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_UNPROTECT
,
809 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
811 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
812 ASSERT_EQ(0, snap_unprotect_task
.result
);
815 TEST_F(TestImageWatcher
, NotifyRename
) {
816 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
818 librbd::ImageCtx
*ictx
;
819 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
821 ASSERT_EQ(0, register_image_watch(*ictx
));
822 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
823 "auto " + stringify(m_watch_ctx
->get_handle())));
825 m_notify_acks
= {{NOTIFY_OP_RENAME
, create_response_message(0)}};
827 RenameTask
rename_task(ictx
);
828 boost::thread
thread(boost::ref(rename_task
));
830 ASSERT_TRUE(wait_for_notifies(*ictx
));
832 NotifyOps expected_notify_ops
;
833 expected_notify_ops
+= NOTIFY_OP_RENAME
;
834 ASSERT_EQ(expected_notify_ops
, m_notifies
);
836 AsyncRequestId async_request_id
;
837 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RENAME
,
840 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
842 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
843 ASSERT_EQ(0, rename_task
.result
);
846 TEST_F(TestImageWatcher
, NotifyAsyncTimedOut
) {
847 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
849 librbd::ImageCtx
*ictx
;
850 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
852 ASSERT_EQ(0, register_image_watch(*ictx
));
853 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
854 "auto " + stringify(m_watch_ctx
->get_handle())));
856 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, {}}};
858 ProgressContext progress_context
;
859 FlattenTask
flatten_task(ictx
, &progress_context
);
860 boost::thread
thread(boost::ref(flatten_task
));
862 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
863 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);
866 TEST_F(TestImageWatcher
, NotifyAsyncError
) {
867 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
869 librbd::ImageCtx
*ictx
;
870 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
872 ASSERT_EQ(0, register_image_watch(*ictx
));
873 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
874 "auto " + stringify(m_watch_ctx
->get_handle())));
876 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(-EIO
)}};
878 ProgressContext progress_context
;
879 FlattenTask
flatten_task(ictx
, &progress_context
);
880 boost::thread
thread(boost::ref(flatten_task
));
882 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
883 ASSERT_EQ(-EIO
, flatten_task
.result
);
886 TEST_F(TestImageWatcher
, NotifyAsyncCompleteError
) {
887 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
889 librbd::ImageCtx
*ictx
;
890 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
892 ASSERT_EQ(0, register_image_watch(*ictx
));
893 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
894 "auto " + stringify(m_watch_ctx
->get_handle())));
896 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
898 ProgressContext progress_context
;
899 FlattenTask
flatten_task(ictx
, &progress_context
);
900 boost::thread
thread(boost::ref(flatten_task
));
902 ASSERT_TRUE(wait_for_notifies(*ictx
));
904 NotifyOps expected_notify_ops
;
905 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
906 ASSERT_EQ(expected_notify_ops
, m_notifies
);
908 AsyncRequestId async_request_id
;
909 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
911 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, -ESHUTDOWN
));
913 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
914 ASSERT_EQ(-ESHUTDOWN
, flatten_task
.result
);
917 TEST_F(TestImageWatcher
, NotifyAsyncRequestTimedOut
) {
918 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
920 librbd::ImageCtx
*ictx
;
921 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
923 ictx
->config
.set_val("rbd_request_timed_out_seconds", "0");
925 ASSERT_EQ(0, register_image_watch(*ictx
));
926 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
927 "auto " + stringify(m_watch_ctx
->get_handle())));
929 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
931 ProgressContext progress_context
;
932 FlattenTask
flatten_task(ictx
, &progress_context
);
933 boost::thread
thread(boost::ref(flatten_task
));
935 ASSERT_TRUE(wait_for_notifies(*ictx
));
937 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
938 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);