if (r < 0) {
m_ret_val = r;
lderr(cct) << "failed to allocate tag: " << cpp_strerror(r) << dendl;
+ shut_down();
+ return;
+ }
+
+ m_tag_tid = m_tag.tid;
+ append_event();
+}
+
+template <typename I>
+void PromoteRequest<I>::append_event() {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ EventEntry event_entry{DemotePromoteEvent{}, {}};
+ bufferlist event_entry_bl;
+ ::encode(event_entry, event_entry_bl);
+
+ m_journaler->start_append(0, 0, 0);
+ m_future = m_journaler->append(m_tag_tid, event_entry_bl);
+
+ auto ctx = create_context_callback<
+ PromoteRequest<I>, &PromoteRequest<I>::handle_append_event>(this);
+ m_future.flush(ctx);
+}
+
+template <typename I>
+void PromoteRequest<I>::handle_append_event(int r) {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 20) << "r=" << r << dendl;
+
+ if (r < 0) {
+ m_ret_val = r;
+ lderr(cct) << "failed to append promotion journal event: "
+ << cpp_strerror(r) << dendl;
+ stop_append();
+ return;
+ }
+
+ commit_event();
+}
+
+template <typename I>
+void PromoteRequest<I>::commit_event() {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ m_journaler->committed(m_future);
+
+ auto ctx = create_context_callback<
+ PromoteRequest<I>, &PromoteRequest<I>::handle_commit_event>(this);
+ m_journaler->flush_commit_position(ctx);
+}
+
+template <typename I>
+void PromoteRequest<I>::handle_commit_event(int r) {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 20) << "r=" << r << dendl;
+
+ if (r < 0) {
+ m_ret_val = r;
+ lderr(cct) << "failed to flush promote commit position: "
+ << cpp_strerror(r) << dendl;
+ }
+
+ stop_append();
+}
+
+template <typename I>
+void PromoteRequest<I>::stop_append() {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ auto ctx = create_context_callback<
+ PromoteRequest<I>, &PromoteRequest<I>::handle_stop_append>(this);
+ m_journaler->stop_append(ctx);
+}
+
+template <typename I>
+void PromoteRequest<I>::handle_stop_append(int r) {
+ CephContext *cct = m_image_ctx->cct;
+ ldout(cct, 20) << "r=" << r << dendl;
+
+ if (r < 0) {
+ if (m_ret_val == 0) {
+ m_ret_val = r;
+ }
+ lderr(cct) << "failed to stop journal append: " << cpp_strerror(r) << dendl;
}
shut_down();
template <>
struct TypeTraits<MockTestImageCtx> {
typedef ::journal::MockJournalerProxy Journaler;
+ typedef ::journal::MockFutureProxy Future;
};
template <>
namespace journal {
using ::testing::_;
+using ::testing::A;
using ::testing::InSequence;
+using ::testing::Return;
using ::testing::WithArg;
class TestMockJournalPromoteRequest : public TestMockFixture {
.WillOnce(WithArg<3>(CompleteContext(r, static_cast<ContextWQ*>(NULL))));
}
+ void expect_append_journaler(::journal::MockJournaler &mock_journaler) {
+ EXPECT_CALL(mock_journaler, append(_, _))
+ .WillOnce(Return(::journal::MockFutureProxy()));
+ }
+
+ void expect_future_flush(::journal::MockFuture &mock_future, int r) {
+ EXPECT_CALL(mock_future, flush(_))
+ .WillOnce(CompleteContext(r, static_cast<ContextWQ*>(NULL)));
+ }
+
+ void expect_future_committed(::journal::MockJournaler &mock_journaler) {
+ EXPECT_CALL(mock_journaler, committed(A<const ::journal::MockFutureProxy &>()));
+ }
+
+ void expect_flush_commit_position(::journal::MockJournaler &mock_journaler,
+ int r) {
+ EXPECT_CALL(mock_journaler, flush_commit_position(_))
+ .WillOnce(CompleteContext(r, static_cast<ContextWQ*>(NULL)));
+ }
+
+ void expect_start_append(::journal::MockJournaler &mock_journaler) {
+ EXPECT_CALL(mock_journaler, start_append(_, _, _));
+ }
+
+ void expect_stop_append(::journal::MockJournaler &mock_journaler, int r) {
+ EXPECT_CALL(mock_journaler, stop_append(_))
+ .WillOnce(CompleteContext(r, static_cast<ContextWQ*>(NULL)));
+ }
+
void expect_shut_down_journaler(::journal::MockJournaler &mock_journaler,
int r) {
EXPECT_CALL(mock_journaler, shut_down(_))
expect_open_journaler(mock_image_ctx, mock_open_request, 0);
expect_allocate_tag(mock_journaler,
{Journal<>::ORPHAN_MIRROR_UUID, true, 567, 1}, 0);
+
+ ::journal::MockFuture mock_future;
+ expect_start_append(mock_journaler);
+ expect_append_journaler(mock_journaler);
+ expect_future_flush(mock_future, 0);
+ expect_future_committed(mock_journaler);
+ expect_flush_commit_position(mock_journaler, 0);
+ expect_stop_append(mock_journaler, 0);
+
expect_shut_down_journaler(mock_journaler, 0);
C_SaferCond ctx;
expect_open_journaler(mock_image_ctx, mock_open_request, 0);
expect_allocate_tag(mock_journaler,
{Journal<>::LOCAL_MIRROR_UUID, true, 567, 0}, 0);
+
+ ::journal::MockFuture mock_future;
+ expect_start_append(mock_journaler);
+ expect_append_journaler(mock_journaler);
+ expect_future_flush(mock_future, 0);
+ expect_future_committed(mock_journaler);
+ expect_flush_commit_position(mock_journaler, 0);
+ expect_stop_append(mock_journaler, 0);
+
expect_shut_down_journaler(mock_journaler, 0);
C_SaferCond ctx;
ASSERT_EQ(-EBADMSG, ctx.wait());
}
+TEST_F(TestMockJournalPromoteRequest, AppendEventError) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ ::journal::MockJournaler mock_journaler;
+ MockOpenRequest mock_open_request;
+
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_construct_journaler(mock_journaler);
+ expect_open_journaler(mock_image_ctx, mock_open_request, 0);
+ expect_allocate_tag(mock_journaler,
+ {Journal<>::ORPHAN_MIRROR_UUID, true, 567, 1}, 0);
+
+ ::journal::MockFuture mock_future;
+ expect_start_append(mock_journaler);
+ expect_append_journaler(mock_journaler);
+ expect_future_flush(mock_future, -EPERM);
+ expect_stop_append(mock_journaler, 0);
+
+ expect_shut_down_journaler(mock_journaler, 0);
+
+ C_SaferCond ctx;
+ auto req = MockPromoteRequest::create(&mock_image_ctx, false, &ctx);
+ req->send();
+ ASSERT_EQ(-EPERM, ctx.wait());
+}
+
+TEST_F(TestMockJournalPromoteRequest, CommitEventError) {
+ REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ ::journal::MockJournaler mock_journaler;
+ MockOpenRequest mock_open_request;
+
+ expect_op_work_queue(mock_image_ctx);
+
+ InSequence seq;
+ expect_construct_journaler(mock_journaler);
+ expect_open_journaler(mock_image_ctx, mock_open_request, 0);
+ expect_allocate_tag(mock_journaler,
+ {Journal<>::ORPHAN_MIRROR_UUID, true, 567, 1}, 0);
+
+ ::journal::MockFuture mock_future;
+ expect_start_append(mock_journaler);
+ expect_append_journaler(mock_journaler);
+ expect_future_flush(mock_future, 0);
+ expect_future_committed(mock_journaler);
+ expect_flush_commit_position(mock_journaler, -EINVAL);
+ expect_stop_append(mock_journaler, 0);
+
+ expect_shut_down_journaler(mock_journaler, 0);
+
+ C_SaferCond ctx;
+ auto req = MockPromoteRequest::create(&mock_image_ctx, false, &ctx);
+ req->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
TEST_F(TestMockJournalPromoteRequest, ShutDownError) {
REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
expect_open_journaler(mock_image_ctx, mock_open_request, 0);
expect_allocate_tag(mock_journaler,
{Journal<>::LOCAL_MIRROR_UUID, true, 567, 0}, 0);
+
+ ::journal::MockFuture mock_future;
+ expect_start_append(mock_journaler);
+ expect_append_journaler(mock_journaler);
+ expect_future_flush(mock_future, 0);
+ expect_future_committed(mock_journaler);
+ expect_flush_commit_position(mock_journaler, 0);
+ expect_stop_append(mock_journaler, 0);
+
expect_shut_down_journaler(mock_journaler, -EINVAL);
C_SaferCond ctx;