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>
32 using namespace boost::assign
;
33 using namespace librbd::watch_notify
;
35 void register_test_image_watcher() {
38 class TestImageWatcher
: public TestFixture
{
41 TestImageWatcher() : m_watch_ctx(NULL
)
45 class WatchCtx
: public librados::WatchCtx2
{
47 explicit WatchCtx(TestImageWatcher
&parent
) : m_parent(parent
), m_handle(0) {}
49 int watch(const librbd::ImageCtx
&ictx
) {
50 m_header_oid
= ictx
.header_oid
;
51 return m_parent
.m_ioctx
.watch2(m_header_oid
, &m_handle
, this);
55 return m_parent
.m_ioctx
.unwatch2(m_handle
);
58 void handle_notify(uint64_t notify_id
,
61 bufferlist
& bl
) override
{
65 auto iter
= bl
.cbegin();
66 DECODE_START(1, iter
);
68 iter
.copy_all(payload
);
71 NotifyOp notify_op
= static_cast<NotifyOp
>(op
);
73 std::cout << "NOTIFY: " << notify_op << ", " << notify_id
74 << ", " << cookie << ", " << notifier_id << std::endl;
77 std::lock_guard l
{m_parent
.m_callback_lock
};
78 m_parent
.m_notify_payloads
[notify_op
] = payload
;
81 if (m_parent
.m_notify_acks
.count(notify_op
) > 0) {
82 reply
= m_parent
.m_notify_acks
[notify_op
];
83 m_parent
.m_notifies
+= notify_op
;
84 m_parent
.m_callback_cond
.notify_all();
87 m_parent
.m_ioctx
.notify_ack(m_header_oid
, notify_id
, cookie
, reply
);
93 void handle_error(uint64_t cookie
, int err
) override
{
94 std::cerr
<< "ERROR: " << cookie
<< ", " << cpp_strerror(err
)
98 uint64_t get_handle() const {
103 TestImageWatcher
&m_parent
;
104 std::string m_header_oid
;
108 void TearDown() override
{
109 deregister_image_watch();
110 TestFixture::TearDown();
113 int deregister_image_watch() {
114 if (m_watch_ctx
!= NULL
) {
115 int r
= m_watch_ctx
->unwatch();
117 librados::Rados
rados(m_ioctx
);
127 int register_image_watch(librbd::ImageCtx
&ictx
) {
128 m_watch_ctx
= new WatchCtx(*this);
129 return m_watch_ctx
->watch(ictx
);
132 bool wait_for_notifies(librbd::ImageCtx
&ictx
) {
133 std::unique_lock l
{m_callback_lock
};
134 while (m_notifies
.size() < m_notify_acks
.size()) {
135 if (m_callback_cond
.wait_for(l
, 10s
) == std::cv_status::timeout
) {
139 return (m_notifies
.size() == m_notify_acks
.size());
142 bufferlist
create_response_message(int r
) {
144 encode(ResponseMessage(r
), bl
);
148 bool extract_async_request_id(NotifyOp op
, AsyncRequestId
*id
) {
149 if (m_notify_payloads
.count(op
) == 0) {
153 bufferlist payload
= m_notify_payloads
[op
];
154 auto iter
= payload
.cbegin();
157 case NOTIFY_OP_FLATTEN
:
159 FlattenPayload payload
;
160 payload
.decode(2, iter
);
161 *id
= payload
.async_request_id
;
164 case NOTIFY_OP_RESIZE
:
166 ResizePayload payload
;
167 payload
.decode(2, iter
);
168 *id
= payload
.async_request_id
;
171 case NOTIFY_OP_SNAP_CREATE
:
173 SnapCreatePayload payload
;
174 payload
.decode(7, iter
);
175 *id
= payload
.async_request_id
;
178 case NOTIFY_OP_SNAP_RENAME
:
180 SnapRenamePayload payload
;
181 payload
.decode(7, iter
);
182 *id
= payload
.async_request_id
;
185 case NOTIFY_OP_SNAP_REMOVE
:
187 SnapRemovePayload payload
;
188 payload
.decode(7, iter
);
189 *id
= payload
.async_request_id
;
192 case NOTIFY_OP_SNAP_PROTECT
:
194 SnapProtectPayload payload
;
195 payload
.decode(7, iter
);
196 *id
= payload
.async_request_id
;
199 case NOTIFY_OP_SNAP_UNPROTECT
:
201 SnapUnprotectPayload payload
;
202 payload
.decode(7, iter
);
203 *id
= payload
.async_request_id
;
206 case NOTIFY_OP_RENAME
:
208 RenamePayload payload
;
209 payload
.decode(7, iter
);
210 *id
= payload
.async_request_id
;
213 case NOTIFY_OP_REBUILD_OBJECT_MAP
:
215 RebuildObjectMapPayload payload
;
216 payload
.decode(2, iter
);
217 *id
= payload
.async_request_id
;
226 int notify_async_progress(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
227 uint64_t offset
, uint64_t total
) {
229 encode(NotifyMessage(new AsyncProgressPayload(id
, offset
, total
)), bl
);
230 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
233 int notify_async_complete(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
236 encode(NotifyMessage(new AsyncCompletePayload(id
, r
)), bl
);
237 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
240 typedef std::map
<NotifyOp
, bufferlist
> NotifyOpPayloads
;
241 typedef std::set
<NotifyOp
> NotifyOps
;
243 WatchCtx
*m_watch_ctx
;
245 NotifyOps m_notifies
;
246 NotifyOpPayloads m_notify_payloads
;
247 NotifyOpPayloads m_notify_acks
;
249 AsyncRequestId m_async_request_id
;
251 ceph::mutex m_callback_lock
= ceph::make_mutex("m_callback_lock");
252 ceph::condition_variable m_callback_cond
;
256 struct ProgressContext
: public librbd::ProgressContext
{
257 ceph::mutex mutex
= ceph::make_mutex("ProgressContext::mutex");
258 ceph::condition_variable cond
;
263 ProgressContext() : received(false),
264 offset(0), total(0) {}
266 int update_progress(uint64_t offset_
, uint64_t total_
) override
{
267 std::lock_guard l
{mutex
};
275 bool wait(librbd::ImageCtx
*ictx
, uint64_t offset_
, uint64_t total_
) {
276 std::unique_lock l
{mutex
};
278 if (cond
.wait_for(l
, 10s
) == std::cv_status::timeout
) {
282 return (received
&& offset
== offset_
&& total
== total_
);
287 librbd::ImageCtx
*ictx
;
288 ProgressContext
*progress_context
;
291 FlattenTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
292 : ictx(ictx_
), progress_context(ctx
), result(0) {}
295 std::shared_lock l
{ictx
->owner_lock
};
297 ictx
->image_watcher
->notify_flatten(0, *progress_context
, &ctx
);
303 librbd::ImageCtx
*ictx
;
304 ProgressContext
*progress_context
;
307 ResizeTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
308 : ictx(ictx_
), progress_context(ctx
), result(0) {}
311 std::shared_lock l
{ictx
->owner_lock
};
313 ictx
->image_watcher
->notify_resize(0, 0, true, *progress_context
, &ctx
);
318 struct SnapCreateTask
{
319 librbd::ImageCtx
*ictx
;
320 ProgressContext
*progress_context
;
323 SnapCreateTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
324 : ictx(ictx_
), progress_context(ctx
), result(0) {}
327 std::shared_lock l
{ictx
->owner_lock
};
329 ictx
->image_watcher
->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(),
330 "snap", 0, *progress_context
, &ctx
);
335 struct SnapRenameTask
{
336 librbd::ImageCtx
*ictx
;
339 SnapRenameTask(librbd::ImageCtx
*ictx
)
344 std::shared_lock l
{ictx
->owner_lock
};
346 ictx
->image_watcher
->notify_snap_rename(0, 1, "snap-rename", &ctx
);
351 struct SnapRemoveTask
{
352 librbd::ImageCtx
*ictx
;
355 SnapRemoveTask(librbd::ImageCtx
*ictx
)
360 std::shared_lock l
{ictx
->owner_lock
};
362 ictx
->image_watcher
->notify_snap_remove(
363 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx
);
368 struct SnapProtectTask
{
369 librbd::ImageCtx
*ictx
;
372 SnapProtectTask(librbd::ImageCtx
*ictx
)
377 std::shared_lock l
{ictx
->owner_lock
};
379 ictx
->image_watcher
->notify_snap_protect(
380 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx
);
385 struct SnapUnprotectTask
{
386 librbd::ImageCtx
*ictx
;
389 SnapUnprotectTask(librbd::ImageCtx
*ictx
)
394 std::shared_lock l
{ictx
->owner_lock
};
396 ictx
->image_watcher
->notify_snap_unprotect(
397 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx
);
403 librbd::ImageCtx
*ictx
;
406 RenameTask(librbd::ImageCtx
*ictx
)
411 std::shared_lock l
{ictx
->owner_lock
};
413 ictx
->image_watcher
->notify_rename(0, "new_name", &ctx
);
418 struct RebuildObjectMapTask
{
419 librbd::ImageCtx
*ictx
;
420 ProgressContext
*progress_context
;
423 RebuildObjectMapTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
424 : ictx(ictx_
), progress_context(ctx
), result(0) {}
427 std::shared_lock l
{ictx
->owner_lock
};
429 ictx
->image_watcher
->notify_rebuild_object_map(0, *progress_context
, &ctx
);
434 TEST_F(TestImageWatcher
, NotifyHeaderUpdate
) {
435 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
437 librbd::ImageCtx
*ictx
;
438 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
440 ASSERT_EQ(0, register_image_watch(*ictx
));
442 m_notify_acks
= {{NOTIFY_OP_HEADER_UPDATE
, {}}};
443 ictx
->notify_update();
445 ASSERT_TRUE(wait_for_notifies(*ictx
));
447 NotifyOps expected_notify_ops
;
448 expected_notify_ops
+= NOTIFY_OP_HEADER_UPDATE
;
449 ASSERT_EQ(expected_notify_ops
, m_notifies
);
452 TEST_F(TestImageWatcher
, NotifyFlatten
) {
453 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
455 librbd::ImageCtx
*ictx
;
456 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
458 ASSERT_EQ(0, register_image_watch(*ictx
));
459 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
460 "auto " + stringify(m_watch_ctx
->get_handle())));
462 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
464 ProgressContext progress_context
;
465 FlattenTask
flatten_task(ictx
, &progress_context
);
466 boost::thread
thread(boost::ref(flatten_task
));
468 ASSERT_TRUE(wait_for_notifies(*ictx
));
470 NotifyOps expected_notify_ops
;
471 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
472 ASSERT_EQ(expected_notify_ops
, m_notifies
);
474 AsyncRequestId async_request_id
;
475 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
477 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
478 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
480 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
482 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
483 ASSERT_EQ(0, flatten_task
.result
);
486 TEST_F(TestImageWatcher
, NotifyResize
) {
487 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
489 librbd::ImageCtx
*ictx
;
490 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
492 ASSERT_EQ(0, register_image_watch(*ictx
));
493 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
494 "auto " + stringify(m_watch_ctx
->get_handle())));
496 m_notify_acks
= {{NOTIFY_OP_RESIZE
, create_response_message(0)}};
498 ProgressContext progress_context
;
499 ResizeTask
resize_task(ictx
, &progress_context
);
500 boost::thread
thread(boost::ref(resize_task
));
502 ASSERT_TRUE(wait_for_notifies(*ictx
));
504 NotifyOps expected_notify_ops
;
505 expected_notify_ops
+= NOTIFY_OP_RESIZE
;
506 ASSERT_EQ(expected_notify_ops
, m_notifies
);
508 AsyncRequestId async_request_id
;
509 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RESIZE
, &async_request_id
));
511 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
512 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
514 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
516 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
517 ASSERT_EQ(0, resize_task
.result
);
520 TEST_F(TestImageWatcher
, NotifyRebuildObjectMap
) {
521 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
523 librbd::ImageCtx
*ictx
;
524 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
526 ASSERT_EQ(0, register_image_watch(*ictx
));
527 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
528 "auto " + stringify(m_watch_ctx
->get_handle())));
530 m_notify_acks
= {{NOTIFY_OP_REBUILD_OBJECT_MAP
, create_response_message(0)}};
532 ProgressContext progress_context
;
533 RebuildObjectMapTask
rebuild_task(ictx
, &progress_context
);
534 boost::thread
thread(boost::ref(rebuild_task
));
536 ASSERT_TRUE(wait_for_notifies(*ictx
));
538 NotifyOps expected_notify_ops
;
539 expected_notify_ops
+= NOTIFY_OP_REBUILD_OBJECT_MAP
;
540 ASSERT_EQ(expected_notify_ops
, m_notifies
);
542 AsyncRequestId async_request_id
;
543 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_REBUILD_OBJECT_MAP
,
546 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
547 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
549 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
551 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
552 ASSERT_EQ(0, rebuild_task
.result
);
555 TEST_F(TestImageWatcher
, NotifySnapCreate
) {
556 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
558 librbd::ImageCtx
*ictx
;
559 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
561 ASSERT_EQ(0, register_image_watch(*ictx
));
562 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
563 "auto " + stringify(m_watch_ctx
->get_handle())));
565 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(0)}};
567 ProgressContext progress_context
;
568 SnapCreateTask
snap_create_task(ictx
, &progress_context
);
569 boost::thread
thread(boost::ref(snap_create_task
));
571 ASSERT_TRUE(wait_for_notifies(*ictx
));
573 NotifyOps expected_notify_ops
;
574 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
575 ASSERT_EQ(expected_notify_ops
, m_notifies
);
577 AsyncRequestId async_request_id
;
578 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_CREATE
,
581 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 1, 10));
582 ASSERT_TRUE(progress_context
.wait(ictx
, 1, 10));
584 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
586 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
587 ASSERT_EQ(0, snap_create_task
.result
);
590 TEST_F(TestImageWatcher
, NotifySnapCreateError
) {
591 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
593 librbd::ImageCtx
*ictx
;
594 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
596 ASSERT_EQ(0, register_image_watch(*ictx
));
597 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
598 "auto " + stringify(m_watch_ctx
->get_handle())));
600 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(-EEXIST
)}};
602 std::shared_lock l
{ictx
->owner_lock
};
603 C_SaferCond notify_ctx
;
604 librbd::NoOpProgressContext prog_ctx
;
605 ictx
->image_watcher
->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(),
606 "snap", 0, prog_ctx
, ¬ify_ctx
);
607 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
609 NotifyOps expected_notify_ops
;
610 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
611 ASSERT_EQ(expected_notify_ops
, m_notifies
);
614 TEST_F(TestImageWatcher
, NotifySnapRename
) {
615 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
617 librbd::ImageCtx
*ictx
;
618 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
620 ASSERT_EQ(0, register_image_watch(*ictx
));
621 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
622 "auto " + stringify(m_watch_ctx
->get_handle())));
624 m_notify_acks
= {{NOTIFY_OP_SNAP_RENAME
, create_response_message(0)}};
626 SnapRenameTask
snap_rename_task(ictx
);
627 boost::thread
thread(boost::ref(snap_rename_task
));
629 ASSERT_TRUE(wait_for_notifies(*ictx
));
631 NotifyOps expected_notify_ops
;
632 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
633 ASSERT_EQ(expected_notify_ops
, m_notifies
);
635 AsyncRequestId async_request_id
;
636 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_RENAME
,
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_rename_task
.result
);
645 TEST_F(TestImageWatcher
, NotifySnapRenameError
) {
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_RENAME
, create_response_message(-EEXIST
)}};
657 std::shared_lock l
{ictx
->owner_lock
};
658 C_SaferCond notify_ctx
;
659 ictx
->image_watcher
->notify_snap_rename(0, 1, "snap-rename", ¬ify_ctx
);
660 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
662 NotifyOps expected_notify_ops
;
663 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
664 ASSERT_EQ(expected_notify_ops
, m_notifies
);
667 TEST_F(TestImageWatcher
, NotifySnapRemove
) {
668 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
670 librbd::ImageCtx
*ictx
;
671 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
673 ASSERT_EQ(0, register_image_watch(*ictx
));
674 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
675 "auto " + stringify(m_watch_ctx
->get_handle())));
677 m_notify_acks
= {{NOTIFY_OP_SNAP_REMOVE
, create_response_message(0)}};
679 SnapRemoveTask
snap_remove_task(ictx
);
680 boost::thread
thread(boost::ref(snap_remove_task
));
682 ASSERT_TRUE(wait_for_notifies(*ictx
));
684 NotifyOps expected_notify_ops
;
685 expected_notify_ops
+= NOTIFY_OP_SNAP_REMOVE
;
686 ASSERT_EQ(expected_notify_ops
, m_notifies
);
688 AsyncRequestId async_request_id
;
689 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_REMOVE
,
692 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
694 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
695 ASSERT_EQ(0, snap_remove_task
.result
);
698 TEST_F(TestImageWatcher
, NotifySnapProtect
) {
699 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
701 librbd::ImageCtx
*ictx
;
702 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
704 ASSERT_EQ(0, register_image_watch(*ictx
));
705 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
706 "auto " + stringify(m_watch_ctx
->get_handle())));
708 m_notify_acks
= {{NOTIFY_OP_SNAP_PROTECT
, create_response_message(0)}};
710 SnapProtectTask
snap_protect_task(ictx
);
711 boost::thread
thread(boost::ref(snap_protect_task
));
713 ASSERT_TRUE(wait_for_notifies(*ictx
));
715 NotifyOps expected_notify_ops
;
716 expected_notify_ops
+= NOTIFY_OP_SNAP_PROTECT
;
717 ASSERT_EQ(expected_notify_ops
, m_notifies
);
719 AsyncRequestId async_request_id
;
720 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_PROTECT
,
723 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
725 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
726 ASSERT_EQ(0, snap_protect_task
.result
);
729 TEST_F(TestImageWatcher
, NotifySnapUnprotect
) {
730 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
732 librbd::ImageCtx
*ictx
;
733 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
735 ASSERT_EQ(0, register_image_watch(*ictx
));
736 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
737 "auto " + stringify(m_watch_ctx
->get_handle())));
739 m_notify_acks
= {{NOTIFY_OP_SNAP_UNPROTECT
, create_response_message(0)}};
741 SnapUnprotectTask
snap_unprotect_task(ictx
);
742 boost::thread
thread(boost::ref(snap_unprotect_task
));
744 ASSERT_TRUE(wait_for_notifies(*ictx
));
746 NotifyOps expected_notify_ops
;
747 expected_notify_ops
+= NOTIFY_OP_SNAP_UNPROTECT
;
748 ASSERT_EQ(expected_notify_ops
, m_notifies
);
750 AsyncRequestId async_request_id
;
751 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_UNPROTECT
,
754 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
756 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
757 ASSERT_EQ(0, snap_unprotect_task
.result
);
760 TEST_F(TestImageWatcher
, NotifyRename
) {
761 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
763 librbd::ImageCtx
*ictx
;
764 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
766 ASSERT_EQ(0, register_image_watch(*ictx
));
767 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
768 "auto " + stringify(m_watch_ctx
->get_handle())));
770 m_notify_acks
= {{NOTIFY_OP_RENAME
, create_response_message(0)}};
772 RenameTask
rename_task(ictx
);
773 boost::thread
thread(boost::ref(rename_task
));
775 ASSERT_TRUE(wait_for_notifies(*ictx
));
777 NotifyOps expected_notify_ops
;
778 expected_notify_ops
+= NOTIFY_OP_RENAME
;
779 ASSERT_EQ(expected_notify_ops
, m_notifies
);
781 AsyncRequestId async_request_id
;
782 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RENAME
,
785 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
787 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
788 ASSERT_EQ(0, rename_task
.result
);
791 TEST_F(TestImageWatcher
, NotifyAsyncTimedOut
) {
792 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
794 librbd::ImageCtx
*ictx
;
795 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
797 ASSERT_EQ(0, register_image_watch(*ictx
));
798 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
799 "auto " + stringify(m_watch_ctx
->get_handle())));
801 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, {}}};
803 ProgressContext progress_context
;
804 FlattenTask
flatten_task(ictx
, &progress_context
);
805 boost::thread
thread(boost::ref(flatten_task
));
807 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
808 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);
811 TEST_F(TestImageWatcher
, NotifyAsyncError
) {
812 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
814 librbd::ImageCtx
*ictx
;
815 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
817 ASSERT_EQ(0, register_image_watch(*ictx
));
818 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
819 "auto " + stringify(m_watch_ctx
->get_handle())));
821 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(-EIO
)}};
823 ProgressContext progress_context
;
824 FlattenTask
flatten_task(ictx
, &progress_context
);
825 boost::thread
thread(boost::ref(flatten_task
));
827 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
828 ASSERT_EQ(-EIO
, flatten_task
.result
);
831 TEST_F(TestImageWatcher
, NotifyAsyncCompleteError
) {
832 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
834 librbd::ImageCtx
*ictx
;
835 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
837 ASSERT_EQ(0, register_image_watch(*ictx
));
838 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
839 "auto " + stringify(m_watch_ctx
->get_handle())));
841 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
843 ProgressContext progress_context
;
844 FlattenTask
flatten_task(ictx
, &progress_context
);
845 boost::thread
thread(boost::ref(flatten_task
));
847 ASSERT_TRUE(wait_for_notifies(*ictx
));
849 NotifyOps expected_notify_ops
;
850 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
851 ASSERT_EQ(expected_notify_ops
, m_notifies
);
853 AsyncRequestId async_request_id
;
854 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
856 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, -ESHUTDOWN
));
858 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
859 ASSERT_EQ(-ESHUTDOWN
, flatten_task
.result
);
862 TEST_F(TestImageWatcher
, NotifyAsyncRequestTimedOut
) {
863 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
865 librbd::ImageCtx
*ictx
;
866 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
868 ictx
->config
.set_val("rbd_request_timed_out_seconds", "0");
870 ASSERT_EQ(0, register_image_watch(*ictx
));
871 ASSERT_EQ(0, lock_image(*ictx
, ClsLockType::EXCLUSIVE
,
872 "auto " + stringify(m_watch_ctx
->get_handle())));
874 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
876 ProgressContext progress_context
;
877 FlattenTask
flatten_task(ictx
, &progress_context
);
878 boost::thread
thread(boost::ref(flatten_task
));
880 ASSERT_TRUE(wait_for_notifies(*ictx
));
882 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
883 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);