// vim: ts=8 sw=2 smarttab
#include "librbd/api/Config.h"
-#include "cls/rbd/cls_rbd_client.h"
#include "common/dout.h"
#include "common/errno.h"
+#include "common/Cond.h"
#include "librbd/ImageCtx.h"
#include "librbd/Utils.h"
#include "librbd/api/PoolMetadata.h"
+#include "librbd/image/GetMetadataRequest.h"
+#include <algorithm>
#include <boost/algorithm/string/predicate.hpp>
#define dout_subsys ceph_subsys_rbd
return r;
}
- std::string last_key = ImageCtx::METADATA_CONF_PREFIX;
- bool more_results = true;
+ std::map<std::string, bufferlist> pairs;
+ C_SaferCond ctx;
+ auto req = image::GetMetadataRequest<I>::create(
+ image_ctx->md_ctx, image_ctx->header_oid, ImageCtx::METADATA_CONF_PREFIX,
+ ImageCtx::METADATA_CONF_PREFIX, 0U, &pairs, &ctx);
+ req->send();
- while (more_results) {
- std::map<std::string, bufferlist> pairs;
-
- r = cls_client::metadata_list(&image_ctx->md_ctx, image_ctx->header_oid,
- last_key, MAX_KEYS, &pairs);
- if (r < 0) {
- lderr(cct) << "failed reading image metadata: " << cpp_strerror(r)
- << dendl;
- return r;
- }
+ r = ctx.wait();
+ if (r < 0) {
+ lderr(cct) << "failed reading image metadata: " << cpp_strerror(r)
+ << dendl;
+ return r;
+ }
- if (pairs.empty()) {
+ for (auto kv : pairs) {
+ std::string key;
+ if (!util::is_metadata_config_override(kv.first, &key)) {
break;
}
-
- more_results = (pairs.size() == MAX_KEYS);
- last_key = pairs.rbegin()->first;
-
- for (auto kv : pairs) {
- std::string key;
- if (!util::is_metadata_config_override(kv.first, &key)) {
- more_results = false;
- break;
- }
- auto it = opts.find(key);
- if (it != opts.end()) {
- it->second = {{kv.second.c_str(), kv.second.length()},
- RBD_CONFIG_SOURCE_IMAGE};
- }
+ auto it = opts.find(key);
+ if (it != opts.end()) {
+ it->second = {{kv.second.c_str(), kv.second.length()},
+ RBD_CONFIG_SOURCE_IMAGE};
}
}
#include "cls/rbd/cls_rbd_client.h"
#include "common/dout.h"
#include "common/errno.h"
+#include "common/Cond.h"
#include "librbd/Utils.h"
#include "librbd/api/Config.h"
+#include "librbd/image/GetMetadataRequest.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
std::map<std::string, ceph::bufferlist> *pairs) {
CephContext *cct = (CephContext *)io_ctx.cct();
- int r = cls_client::metadata_list(&io_ctx, RBD_INFO, start, max, pairs);
- if (r == -ENOENT) {
- r = 0;
- } else if (r < 0) {
+ pairs->clear();
+ C_SaferCond ctx;
+ auto req = image::GetMetadataRequest<I>::create(
+ io_ctx, RBD_INFO, "", start, max, pairs, &ctx);
+ req->send();
+
+ int r = ctx.wait();
+ if (r < 0) {
lderr(cct) << "failed listing metadata: " << cpp_strerror(r)
<< dendl;
return r;
}
-
return 0;
}
#include "common/errno.h"
#include "cls/rbd/cls_rbd_client.h"
#include "librbd/Utils.h"
+#include "librbd/image/GetMetadataRequest.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
} // anonymous namespace
+using librbd::util::create_context_callback;
using librbd::util::create_rados_callback;
template <typename I>
void MetadataCopyRequest<I>::list_src_metadata() {
ldout(m_cct, 20) << "start_key=" << m_last_metadata_key << dendl;
- librados::ObjectReadOperation op;
- librbd::cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
-
- librados::AioCompletion *aio_comp = create_rados_callback<
+ m_metadata.clear();
+ auto ctx = create_context_callback<
MetadataCopyRequest<I>,
&MetadataCopyRequest<I>::handle_list_src_metadata>(this);
- m_out_bl.clear();
- m_src_image_ctx->md_ctx.aio_operate(m_src_image_ctx->header_oid,
- aio_comp, &op, &m_out_bl);
- aio_comp->release();
+ auto req = image::GetMetadataRequest<I>::create(
+ m_src_image_ctx->md_ctx, m_src_image_ctx->header_oid, "",
+ m_last_metadata_key, MAX_METADATA_ITEMS, &m_metadata, ctx);
+ req->send();
}
template <typename I>
void MetadataCopyRequest<I>::handle_list_src_metadata(int r) {
ldout(m_cct, 20) << "r=" << r << dendl;
- Metadata metadata;
- if (r == 0) {
- auto it = m_out_bl.cbegin();
- r = librbd::cls_client::metadata_list_finish(&it, &metadata);
- }
-
if (r < 0) {
lderr(m_cct) << "failed to retrieve metadata: " << cpp_strerror(r) << dendl;
finish(r);
return;
}
- if (metadata.empty()) {
+ if (m_metadata.empty()) {
finish(0);
return;
}
- m_last_metadata_key = metadata.rbegin()->first;
- m_more_metadata = (metadata.size() >= MAX_METADATA_ITEMS);
- set_dst_metadata(metadata);
+ m_last_metadata_key = m_metadata.rbegin()->first;
+ m_more_metadata = (m_metadata.size() >= MAX_METADATA_ITEMS);
+ set_dst_metadata();
}
template <typename I>
-void MetadataCopyRequest<I>::set_dst_metadata(const Metadata& metadata) {
- ldout(m_cct, 20) << "count=" << metadata.size() << dendl;
+void MetadataCopyRequest<I>::set_dst_metadata() {
+ ldout(m_cct, 20) << "count=" << m_metadata.size() << dendl;
librados::ObjectWriteOperation op;
- librbd::cls_client::metadata_set(&op, metadata);
+ librbd::cls_client::metadata_set(&op, m_metadata);
librados::AioCompletion *aio_comp = create_rados_callback<
MetadataCopyRequest<I>,
CephContext *m_cct;
bufferlist m_out_bl;
+ std::map<std::string, bufferlist> m_metadata;
std::string m_last_metadata_key;
bool m_more_metadata = false;
void list_src_metadata();
void handle_list_src_metadata(int r);
- void set_dst_metadata(const Metadata& metadata);
+ void set_dst_metadata();
void handle_set_dst_metadata(int r);
void finish(int r);
#include "include/ceph_assert.h"
#include "librbd/ImageState.h"
#include "librbd/Utils.h"
+#include "librbd/deep_copy/MetadataCopyRequest.h"
#include "librbd/image/AttachChildRequest.h"
#include "librbd/image/AttachParentRequest.h"
#include "librbd/image/CloneRequest.h"
return;
}
- metadata_list();
+ copy_metadata();
}
template <typename I>
-void CloneRequest<I>::metadata_list() {
- ldout(m_cct, 15) << "start_key=" << m_last_metadata_key << dendl;
-
- librados::ObjectReadOperation op;
- cls_client::metadata_list_start(&op, m_last_metadata_key, 0);
-
- using klass = CloneRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_metadata_list>(this);
- m_out_bl.clear();
- m_parent_image_ctx->md_ctx.aio_operate(m_parent_image_ctx->header_oid,
- comp, &op, &m_out_bl);
- comp->release();
-}
-
-template <typename I>
-void CloneRequest<I>::handle_metadata_list(int r) {
- ldout(m_cct, 15) << "r=" << r << dendl;
-
- map<string, bufferlist> metadata;
- if (r == 0) {
- auto it = m_out_bl.cbegin();
- r = cls_client::metadata_list_finish(&it, &metadata);
- }
-
- if (r < 0) {
- if (r == -EOPNOTSUPP || r == -EIO) {
- ldout(m_cct, 10) << "config metadata not supported by OSD" << dendl;
- get_mirror_mode();
- } else {
- lderr(m_cct) << "couldn't list metadata: " << cpp_strerror(r) << dendl;
- m_r_saved = r;
- close_child();
- }
- return;
- }
-
- if (!metadata.empty()) {
- m_pairs.insert(metadata.begin(), metadata.end());
- m_last_metadata_key = m_pairs.rbegin()->first;
- }
-
- if (metadata.size() == MAX_KEYS) {
- metadata_list();
- } else {
- metadata_set();
- }
-}
-
-template <typename I>
-void CloneRequest<I>::metadata_set() {
- if (m_pairs.empty()) {
- get_mirror_mode();
- return;
- }
-
+void CloneRequest<I>::copy_metadata() {
ldout(m_cct, 15) << dendl;
- librados::ObjectWriteOperation op;
- cls_client::metadata_set(&op, m_pairs);
-
- using klass = CloneRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_metadata_set>(this);
- int r = m_ioctx.aio_operate(m_imctx->header_oid, comp, &op);
- ceph_assert(r == 0);
- comp->release();
+ auto ctx = create_context_callback<
+ CloneRequest<I>, &CloneRequest<I>::handle_copy_metadata>(this);
+ auto req = deep_copy::MetadataCopyRequest<I>::create(
+ m_parent_image_ctx, m_imctx, ctx);
+ req->send();
}
template <typename I>
-void CloneRequest<I>::handle_metadata_set(int r) {
+void CloneRequest<I>::handle_copy_metadata(int r) {
ldout(m_cct, 15) << "r=" << r << dendl;
if (r < 0) {
- lderr(m_cct) << "couldn't set metadata: " << cpp_strerror(r) << dendl;
+ lderr(m_cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
m_r_saved = r;
close_child();
- } else {
- get_mirror_mode();
+ return;
}
+
+ get_mirror_mode();
}
template <typename I>
* ATTACH CHILD * * * * * * * * * * * *
* | *
* v *
- * GET PARENT META * * * * * * * * * ^
- * | *
- * v (skip if not needed) *
- * SET CHILD META * * * * * * * * * * ^
+ * COPY META DATA * * * * * * * * * * ^
* | *
* v (skip if not needed) *
* GET MIRROR MODE * * * * * * * * * ^
uint64_t m_clone_format = 2;
bool m_use_p_features;
uint64_t m_features;
- map<string, bufferlist> m_pairs;
- std::string m_last_metadata_key;
bufferlist m_out_bl;
uint64_t m_size;
int m_r_saved = 0;
void attach_child();
void handle_attach_child(int r);
- void metadata_list();
- void handle_metadata_list(int r);
-
- void metadata_set();
- void handle_metadata_set(int r);
+ void copy_metadata();
+ void handle_copy_metadata(int r);
void get_mirror_mode();
void handle_get_mirror_mode(int r);
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
-#include <boost/algorithm/string/predicate.hpp>
#include "include/ceph_assert.h"
#include "librbd/image/RefreshRequest.h"
#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
#include "librbd/deep_copy/Utils.h"
+#include "librbd/image/GetMetadataRequest.h"
#include "librbd/image/RefreshParentRequest.h"
#include "librbd/io/AioCompletion.h"
#include "librbd/io/ImageDispatchSpec.h"
template <typename I>
void RefreshRequest<I>::send_v2_get_metadata() {
CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << ": "
- << "start_key=" << m_last_metadata_key << dendl;
-
- librados::ObjectReadOperation op;
- cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
+ ldout(cct, 10) << this << " " << __func__ << dendl;
- using klass = RefreshRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_v2_get_metadata>(this);
- m_out_bl.clear();
- m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
- &m_out_bl);
- comp->release();
+ auto ctx = create_context_callback<
+ RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_metadata>(this);
+ auto req = GetMetadataRequest<I>::create(
+ m_image_ctx.md_ctx, m_image_ctx.header_oid,
+ ImageCtx::METADATA_CONF_PREFIX, ImageCtx::METADATA_CONF_PREFIX, 0U,
+ &m_metadata, ctx);
+ req->send();
}
template <typename I>
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
- std::map<std::string, bufferlist> metadata;
- if (*result == 0) {
- auto it = m_out_bl.cbegin();
- *result = cls_client::metadata_list_finish(&it, &metadata);
- }
-
if (*result < 0) {
lderr(cct) << "failed to retrieve metadata: " << cpp_strerror(*result)
<< dendl;
return m_on_finish;
}
- if (!metadata.empty()) {
- m_metadata.insert(metadata.begin(), metadata.end());
- m_last_metadata_key = metadata.rbegin()->first;
- if (boost::starts_with(m_last_metadata_key,
- ImageCtx::METADATA_CONF_PREFIX)) {
- send_v2_get_metadata();
- return nullptr;
- }
- }
-
- m_last_metadata_key.clear();
send_v2_get_pool_metadata();
return nullptr;
}
template <typename I>
void RefreshRequest<I>::send_v2_get_pool_metadata() {
CephContext *cct = m_image_ctx.cct;
- ldout(cct, 10) << this << " " << __func__ << ": "
- << "start_key=" << m_last_metadata_key << dendl;
-
- librados::ObjectReadOperation op;
- cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS);
+ ldout(cct, 10) << this << " " << __func__ << dendl;
- using klass = RefreshRequest<I>;
- librados::AioCompletion *comp =
- create_rados_callback<klass, &klass::handle_v2_get_pool_metadata>(this);
- m_out_bl.clear();
- m_pool_metadata_io_ctx.aio_operate(RBD_INFO, comp, &op, &m_out_bl);
- comp->release();
+ auto ctx = create_context_callback<
+ RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_pool_metadata>(this);
+ auto req = GetMetadataRequest<I>::create(
+ m_pool_metadata_io_ctx, RBD_INFO, ImageCtx::METADATA_CONF_PREFIX,
+ ImageCtx::METADATA_CONF_PREFIX, 0U, &m_metadata, ctx);
+ req->send();
}
template <typename I>
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
- std::map<std::string, bufferlist> metadata;
- if (*result == 0) {
- auto it = m_out_bl.cbegin();
- *result = cls_client::metadata_list_finish(&it, &metadata);
- }
-
- if (*result == -EOPNOTSUPP || *result == -ENOENT) {
- ldout(cct, 10) << "pool metadata not supported by OSD" << dendl;
- } else if (*result < 0) {
+ if (*result < 0) {
lderr(cct) << "failed to retrieve pool metadata: " << cpp_strerror(*result)
<< dendl;
return m_on_finish;
}
- if (!metadata.empty()) {
- m_metadata.insert(metadata.begin(), metadata.end());
- m_last_metadata_key = metadata.rbegin()->first;
- if (boost::starts_with(m_last_metadata_key,
- ImageCtx::METADATA_CONF_PREFIX)) {
- send_v2_get_pool_metadata();
- return nullptr;
- }
- }
-
bool thread_safe = m_image_ctx.image_watcher->is_unregistered();
m_image_ctx.apply_metadata(m_metadata, thread_safe);
uint64_t m_op_features = 0;
librados::IoCtx m_pool_metadata_io_ctx;
- std::string m_last_metadata_key;
std::map<std::string, bufferlist> m_metadata;
std::string m_object_prefix;
#include "librbd/api/Image.h"
#include "librbd/exclusive_lock/AutomaticPolicy.h"
#include "librbd/exclusive_lock/StandardPolicy.h"
+#include "librbd/deep_copy/MetadataCopyRequest.h"
#include "librbd/image/CloneRequest.h"
#include "librbd/image/CreateRequest.h"
+#include "librbd/image/GetMetadataRequest.h"
#include "librbd/io/AioCompletion.h"
#include "librbd/io/ImageRequest.h"
#include "librbd/io/ImageRequestWQ.h"
<< dest_size << dendl;
return -EINVAL;
}
- int r;
- const uint32_t MAX_KEYS = 64;
- map<string, bufferlist> pairs;
- std::string last_key = "";
- bool more_results = true;
-
- while (more_results) {
- r = cls_client::metadata_list(&src->md_ctx, src->header_oid, last_key, 0, &pairs);
- if (r < 0 && r != -EOPNOTSUPP && r != -EIO) {
- lderr(cct) << "couldn't list metadata: " << cpp_strerror(r) << dendl;
- return r;
- } else if (r == 0 && !pairs.empty()) {
- r = cls_client::metadata_set(&dest->md_ctx, dest->header_oid, pairs);
- if (r < 0) {
- lderr(cct) << "couldn't set metadata: " << cpp_strerror(r) << dendl;
- return r;
- }
- last_key = pairs.rbegin()->first;
- }
+ C_SaferCond ctx;
+ auto req = deep_copy::MetadataCopyRequest<>::create(
+ src, dest, &ctx);
+ req->send();
- more_results = (pairs.size() == MAX_KEYS);
- pairs.clear();
+ int r = ctx.wait();
+ if (r < 0) {
+ lderr(cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
+ return r;
}
ZTracer::Trace trace;
return r;
}
- return cls_client::metadata_list(&ictx->md_ctx, ictx->header_oid, start, max, pairs);
+ C_SaferCond ctx;
+ auto req = image::GetMetadataRequest<>::create(
+ ictx->md_ctx, ictx->header_oid, "", start, max, pairs, &ctx);
+ req->send();
+
+ return ctx.wait();
}
int list_watchers(ImageCtx *ictx,
#include "include/stringify.h"
#include "librbd/ImageCtx.h"
#include "librbd/deep_copy/MetadataCopyRequest.h"
+#include "librbd/image/GetMetadataRequest.h"
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
#include "test/librbd/mock/MockImageCtx.h"
#include "test/librbd/test_support.h"
};
} // anonymous namespace
+
+namespace image {
+
+template <>
+struct GetMetadataRequest<MockTestImageCtx> {
+ std::map<std::string, bufferlist>* pairs = nullptr;
+ Context* on_finish = nullptr;
+
+ static GetMetadataRequest* s_instance;
+ static GetMetadataRequest* create(librados::IoCtx&,
+ const std::string& oid,
+ const std::string& filter,
+ const std::string& last_key,
+ uint32_t max_results,
+ std::map<std::string, bufferlist>* pairs,
+ Context* on_finish) {
+ ceph_assert(s_instance != nullptr);
+ s_instance->pairs = pairs;
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ GetMetadataRequest() {
+ s_instance = this;
+ }
+
+ MOCK_METHOD0(send, void());
+};
+
+GetMetadataRequest<MockTestImageCtx>* GetMetadataRequest<MockTestImageCtx>::s_instance = nullptr;
+
+} // namspace image
} // namespace librbd
// template definitions
using ::testing::_;
using ::testing::DoAll;
using ::testing::InSequence;
+using ::testing::Invoke;
using ::testing::Return;
using ::testing::StrEq;
using ::testing::WithArg;
class TestMockDeepCopyMetadataCopyRequest : public TestMockFixture {
public:
typedef MetadataCopyRequest<librbd::MockTestImageCtx> MockMetadataCopyRequest;
+ typedef image::GetMetadataRequest<MockTestImageCtx> MockGetMetadataRequest;
typedef std::map<std::string, bufferlist> Metadata;
librbd::ImageCtx *m_src_image_ctx;
&m_thread_pool, &m_work_queue);
}
- void expect_metadata_list(librbd::MockTestImageCtx &mock_image_ctx,
- const Metadata& metadata, int r) {
- bufferlist out_bl;
- encode(metadata, out_bl);
-
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
- StrEq("metadata_list"), _, _, _))
- .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(out_bl)),
- Return(r)));
+ void expect_get_metadata(MockGetMetadataRequest& mock_request,
+ const Metadata& metadata, int r) {
+ EXPECT_CALL(mock_request, send())
+ .WillOnce(Invoke([this, &mock_request, metadata, r]() {
+ *mock_request.pairs = metadata;
+ m_work_queue->queue(mock_request.on_finish, r);
+ }));
}
void expect_metadata_set(librbd::MockTestImageCtx &mock_image_ctx,
}
InSequence seq;
- expect_metadata_list(mock_src_image_ctx, key_values_1, 0);
+ MockGetMetadataRequest mock_request;
+ expect_get_metadata(mock_request, key_values_1, 0);
expect_metadata_set(mock_dst_image_ctx, key_values_1, 0);
- expect_metadata_list(mock_src_image_ctx, key_values_2, 0);
+ expect_get_metadata(mock_request, key_values_2, 0);
expect_metadata_set(mock_dst_image_ctx, key_values_2, 0);
C_SaferCond ctx;
Metadata key_values;
InSequence seq;
- expect_metadata_list(mock_src_image_ctx, key_values, 0);
+ MockGetMetadataRequest mock_request;
+ expect_get_metadata(mock_request, key_values, 0);
C_SaferCond ctx;
auto request = MockMetadataCopyRequest::create(&mock_src_image_ctx,
Metadata key_values;
InSequence seq;
- expect_metadata_list(mock_src_image_ctx, key_values, -EINVAL);
+ MockGetMetadataRequest mock_request;
+ expect_get_metadata(mock_request, key_values, -EINVAL);
C_SaferCond ctx;
auto request = MockMetadataCopyRequest::create(&mock_src_image_ctx,
key_values.emplace("key", bl);
InSequence seq;
- expect_metadata_list(mock_src_image_ctx, key_values, 0);
+ MockGetMetadataRequest mock_request;
+ expect_get_metadata(mock_request, key_values, 0);
expect_metadata_set(mock_dst_image_ctx, key_values, -EINVAL);
C_SaferCond ctx;
#include "test/librados_test_stub/MockTestMemRadosClient.h"
#include "librbd/ImageState.h"
#include "librbd/Operations.h"
+#include "librbd/deep_copy/MetadataCopyRequest.h"
#include "librbd/image/TypeTraits.h"
#include "librbd/image/AttachChildRequest.h"
#include "librbd/image/AttachParentRequest.h"
} // anonymous namespace
+namespace deep_copy {
+
+template <>
+struct MetadataCopyRequest<MockTestImageCtx> {
+ Context* on_finish = nullptr;
+
+ static MetadataCopyRequest* s_instance;
+ static MetadataCopyRequest* create(MockTestImageCtx* src_image_ctx,
+ MockTestImageCtx* dst_image_ctx,
+ Context* on_finish) {
+ ceph_assert(s_instance != nullptr);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ MetadataCopyRequest() {
+ s_instance = this;
+ }
+
+ MOCK_METHOD0(send, void());
+};
+
+MetadataCopyRequest<MockTestImageCtx>* MetadataCopyRequest<MockTestImageCtx>::s_instance = nullptr;
+
+} // namespace deep_copy
+
namespace image {
template <>
typedef AttachParentRequest<MockTestImageCtx> MockAttachParentRequest;
typedef CreateRequest<MockTestImageCtx> MockCreateRequest;
typedef RemoveRequest<MockTestImageCtx> MockRemoveRequest;
+ typedef deep_copy::MetadataCopyRequest<MockTestImageCtx> MockMetadataCopyRequest;
typedef mirror::EnableRequest<MockTestImageCtx> MockMirrorEnableRequest;
void SetUp() override {
}));
}
- void expect_metadata_list(MockTestImageCtx &mock_image_ctx,
- const std::map<std::string, bufferlist>& metadata,
- int r) {
- bufferlist out_bl;
- encode(metadata, out_bl);
-
- EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("metadata_list"), _, _, _))
- .WillOnce(WithArg<5>(Invoke([out_bl, r](bufferlist *out) {
- *out = out_bl;
- return r;
- })));
- }
-
- void expect_metadata_set(librados::IoCtx& io_ctx,
- MockTestImageCtx& mock_image_ctx,
- const std::map<std::string, bufferlist>& metadata,
- int r) {
- bufferlist in_bl;
- encode(metadata, in_bl);
-
- EXPECT_CALL(get_mock_io_ctx(io_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("metadata_set"),
- ContentsEqual(in_bl), _, _))
- .WillOnce(Return(r));
+ void expect_metadata_copy(MockMetadataCopyRequest& mock_request, int r) {
+ EXPECT_CALL(mock_request, send())
+ .WillOnce(Invoke([this, &mock_request, r]() {
+ image_ctx->op_work_queue->queue(mock_request.on_finish, r);
+ }));
}
void expect_test_features(MockTestImageCtx &mock_image_ctx,
MockAttachChildRequest mock_attach_child_request;
expect_attach_child(mock_attach_child_request, 1, 0);
- expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
- expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, 0);
+ MockMetadataCopyRequest mock_request;
+ expect_metadata_copy(mock_request, 0);
MockMirrorEnableRequest mock_mirror_enable_request;
if (is_feature_enabled(RBD_FEATURE_JOURNALING)) {
MockAttachChildRequest mock_attach_child_request;
expect_attach_child(mock_attach_child_request, 2, 0);
- expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
- expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, 0);
+ MockMetadataCopyRequest mock_request;
+ expect_metadata_copy(mock_request, 0);
MockMirrorEnableRequest mock_mirror_enable_request;
if (is_feature_enabled(RBD_FEATURE_JOURNALING)) {
MockAttachChildRequest mock_attach_child_request;
expect_attach_child(mock_attach_child_request, 2, 0);
- expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
- expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, 0);
+ MockMetadataCopyRequest mock_request;
+ expect_metadata_copy(mock_request, 0);
MockMirrorEnableRequest mock_mirror_enable_request;
if (is_feature_enabled(RBD_FEATURE_JOURNALING)) {
ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockImageCloneRequest, MetadataListError) {
- REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
-
- MockTestImageCtx mock_image_ctx(*image_ctx);
- expect_op_work_queue(mock_image_ctx);
-
- InSequence seq;
- expect_open(mock_image_ctx, 0);
-
- expect_get_image_size(mock_image_ctx, mock_image_ctx.snaps.front(), 123);
- expect_is_snap_protected(mock_image_ctx, true, 0);
-
- MockCreateRequest mock_create_request;
- expect_create(mock_create_request, 0);
-
- expect_open(mock_image_ctx, 0);
-
- MockAttachParentRequest mock_attach_parent_request;
- expect_attach_parent(mock_attach_parent_request, 0);
-
- MockAttachChildRequest mock_attach_child_request;
- expect_attach_child(mock_attach_child_request, 2, 0);
-
- expect_metadata_list(mock_image_ctx, {{"key", {}}}, -EINVAL);
-
- expect_close(mock_image_ctx, 0);
-
- MockRemoveRequest mock_remove_request;
- expect_remove(mock_remove_request, 0);
-
- expect_close(mock_image_ctx, 0);
-
- C_SaferCond ctx;
- ImageOptions clone_opts;
- auto req = new MockCloneRequest(m_cct->_conf, m_ioctx, "parent id", "", {}, 123,
- m_ioctx, "clone name", "clone id", clone_opts,
- cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "", "",
- image_ctx->op_work_queue, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-TEST_F(TestMockImageCloneRequest, MetadataSetError) {
+TEST_F(TestMockImageCloneRequest, MetadataCopyError) {
REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
MockTestImageCtx mock_image_ctx(*image_ctx);
MockAttachChildRequest mock_attach_child_request;
expect_attach_child(mock_attach_child_request, 2, 0);
- expect_metadata_list(mock_image_ctx, {{"key", {}}}, 0);
- expect_metadata_set(m_ioctx, mock_image_ctx, {{"key", {}}}, -EINVAL);
+ MockMetadataCopyRequest mock_request;
+ expect_metadata_copy(mock_request, -EINVAL);
expect_close(mock_image_ctx, 0);
MockAttachChildRequest mock_attach_child_request;
expect_attach_child(mock_attach_child_request, 2, 0);
- expect_metadata_list(mock_image_ctx, {}, 0);
+ MockMetadataCopyRequest mock_request;
+ expect_metadata_copy(mock_request, 0);
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
expect_mirror_mode_get(mock_image_ctx, cls::rbd::MIRROR_MODE_POOL, -EINVAL);
MockAttachChildRequest mock_attach_child_request;
expect_attach_child(mock_attach_child_request, 2, 0);
- expect_metadata_list(mock_image_ctx, {}, 0);
+ MockMetadataCopyRequest mock_request;
+ expect_metadata_copy(mock_request, 0);
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, true);
expect_mirror_mode_get(mock_image_ctx, cls::rbd::MIRROR_MODE_POOL, 0);
MockAttachChildRequest mock_attach_child_request;
expect_attach_child(mock_attach_child_request, 2, 0);
- expect_metadata_list(mock_image_ctx, {}, 0);
+ MockMetadataCopyRequest mock_request;
+ expect_metadata_copy(mock_request, 0);
+
expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
expect_close(mock_image_ctx, -EINVAL);
#include "librbd/internal.h"
#include "librbd/Operations.h"
#include "librbd/api/Image.h"
+#include "librbd/image/GetMetadataRequest.h"
#include "librbd/image/RefreshRequest.h"
#include "librbd/image/RefreshParentRequest.h"
#include "librbd/io/ImageDispatchSpec.h"
namespace image {
+template <>
+struct GetMetadataRequest<MockRefreshImageCtx> {
+ std::string oid;
+ std::map<std::string, bufferlist>* pairs = nullptr;
+ Context* on_finish = nullptr;
+
+ static GetMetadataRequest* s_instance;
+ static GetMetadataRequest* create(librados::IoCtx&,
+ const std::string& oid,
+ const std::string& filter,
+ const std::string& last_key,
+ uint32_t max_results,
+ std::map<std::string, bufferlist>* pairs,
+ Context* on_finish) {
+ ceph_assert(s_instance != nullptr);
+ EXPECT_EQ("conf_", filter);
+ EXPECT_EQ("conf_", last_key);
+ s_instance->oid = oid;
+ s_instance->pairs = pairs;
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ GetMetadataRequest() {
+ s_instance = this;
+ }
+
+ MOCK_METHOD0(send, void());
+};
+
template <>
struct RefreshParentRequest<MockRefreshImageCtx> {
static RefreshParentRequest* s_instance;
MOCK_METHOD1(finalize, void(Context *));
};
+GetMetadataRequest<MockRefreshImageCtx>* GetMetadataRequest<MockRefreshImageCtx>::s_instance = nullptr;
RefreshParentRequest<MockRefreshImageCtx>* RefreshParentRequest<MockRefreshImageCtx>::s_instance = nullptr;
} // namespace image
class TestMockImageRefreshRequest : public TestMockFixture {
public:
+ typedef GetMetadataRequest<MockRefreshImageCtx> MockGetMetadataRequest;
typedef RefreshRequest<MockRefreshImageCtx> MockRefreshRequest;
typedef RefreshParentRequest<MockRefreshImageCtx> MockRefreshParentRequest;
typedef io::ImageDispatchSpec<librbd::MockRefreshImageCtx> MockIoImageDispatchSpec;
+ typedef std::map<std::string, bufferlist> Metadata;
void set_v1_migration_header(ImageCtx *ictx) {
bufferlist hdr;
}
}
- void expect_get_metadata(MockRefreshImageCtx &mock_image_ctx, int r) {
- auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
- exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("metadata_list"), _, _, _));
- if (r < 0) {
- expect.WillOnce(Return(r));
- } else {
- expect.WillOnce(DoDefault());
- EXPECT_CALL(*mock_image_ctx.image_watcher, is_unregistered())
- .WillOnce(Return(false));
- }
+ void expect_get_metadata(MockRefreshImageCtx& mock_image_ctx,
+ MockGetMetadataRequest& mock_request,
+ const std::string& oid,
+ const Metadata& metadata, int r) {
+ EXPECT_CALL(mock_request, send())
+ .WillOnce(Invoke([&mock_image_ctx, &mock_request, oid, metadata, r]() {
+ ASSERT_EQ(oid, mock_request.oid);
+ *mock_request.pairs = metadata;
+ mock_image_ctx.image_ctx->op_work_queue->queue(
+ mock_request.on_finish, r);
+ }));
}
void expect_get_flags(MockRefreshImageCtx &mock_image_ctx, int r) {
void expect_apply_metadata(MockRefreshImageCtx &mock_image_ctx,
int r) {
+ EXPECT_CALL(*mock_image_ctx.image_watcher, is_unregistered())
+ .WillOnce(Return(false));
EXPECT_CALL(mock_image_ctx, apply_metadata(_, false))
.WillOnce(Return(r));
}
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_get_snapshots(mock_image_ctx, false, 0);
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, -EOPNOTSUPP);
expect_get_parent_legacy(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_get_snapshots(mock_image_ctx, true, -EOPNOTSUPP);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_get_snapshots(mock_image_ctx, false, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx2->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_op_features(mock_image_ctx, RBD_OPERATION_FEATURE_CLONE_CHILD, 0);
expect_get_group(mock_image_ctx, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx2->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_op_features(mock_image_ctx, RBD_OPERATION_FEATURE_CLONE_CHILD, 0);
expect_get_group(mock_image_ctx, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, mock_image_ctx.features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_op_features(mock_image_ctx, 4096, 0);
expect_get_group(mock_image_ctx, 0);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, 0);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);
InSequence seq;
expect_get_mutable_metadata(mock_image_ctx, ictx->features, 0);
expect_get_parent(mock_image_ctx, 0);
- expect_get_metadata(mock_image_ctx, 0);
+ MockGetMetadataRequest mock_get_metadata_request;
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request,
+ mock_image_ctx.header_oid, {}, 0);
+ expect_get_metadata(mock_image_ctx, mock_get_metadata_request, RBD_INFO, {},
+ 0);
expect_apply_metadata(mock_image_ctx, -EINVAL);
expect_get_group(mock_image_ctx, 0);
expect_refresh_parent_is_required(mock_refresh_parent_request, false);