Currently, Striper supports assembling results representing a single object extent.
Recently, the object dispatch API was extended allowing to read multiple object extents per rados operation.
This commit enables the Striper to correctly un-sparsify the results of the new read extents API.
Signed-off-by: Or Ozeri <oro@il.ibm.com>
#include "librbd/cache/ObjectCacherWriteback.h"
#include "librbd/io/ObjectDispatchSpec.h"
#include "librbd/io/ObjectDispatcherInterface.h"
+#include "librbd/io/ReadResult.h"
#include "librbd/io/Types.h"
#include "librbd/io/Utils.h"
#include "osd/osd_types.h"
template <typename I>
bool ObjectCacherObjectDispatch<I>::read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
- int* object_dispatch_flags, io::DispatchResult* dispatch_result,
- Context** on_finish, Context* on_dispatched) {
+ uint64_t* version, int* object_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
// IO chained in reverse order
auto cct = m_image_ctx->cct;
- ldout(cct, 20) << "object_no=" << object_no << " " << extents << dendl;
+ ldout(cct, 20) << "object_no=" << object_no << " " << *extents << dendl;
+
+ if (extents->size() == 0) {
+ ldout(cct, 20) << "no extents to read" << dendl;
+ return false;
+ }
- if (version != nullptr || extents.size() != 1) {
+ if (version != nullptr) {
// we currently don't cache read versions
// and don't support reading more than one extent
return false;
}
- auto [object_off, object_len] = extents.front();
// ensure we aren't holding the cache lock post-read
on_dispatched = util::create_async_context_callback(*m_image_ctx,
((read_flags << ObjectCacherWriteback::READ_FLAGS_SHIFT) &
ObjectCacherWriteback::READ_FLAGS_MASK));
+ ceph::bufferlist* bl;
+ if (extents->size() > 1) {
+ auto req = new io::ReadResult::C_ObjectReadMergedExtents(
+ cct, extents, on_dispatched);
+ on_dispatched = req;
+ bl = &req->bl;
+ } else {
+ bl = &extents->front().bl;
+ }
+
m_image_ctx->image_lock.lock_shared();
auto rd = m_object_cacher->prepare_read(
- io_context->read_snap().value_or(CEPH_NOSNAP), read_data, op_flags);
+ io_context->read_snap().value_or(CEPH_NOSNAP), bl, op_flags);
m_image_ctx->image_lock.unlock_shared();
- ObjectExtent extent(data_object_name(m_image_ctx, object_no), object_no,
- object_off, object_len, 0);
- extent.oloc.pool = m_image_ctx->data_ctx.get_id();
- extent.buffer_extents.push_back({0, object_len});
- rd->extents.push_back(extent);
+ uint64_t off = 0;
+ for (auto& read_extent: *extents) {
+ ObjectExtent extent(data_object_name(m_image_ctx, object_no), object_no,
+ read_extent.offset, read_extent.length, 0);
+ extent.oloc.pool = m_image_ctx->data_ctx.get_id();
+ extent.buffer_extents.push_back({off, read_extent.length});
+ rd->extents.push_back(extent);
+ off += read_extent.length;
+ }
ZTracer::Trace trace(parent_trace);
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
void shut_down(Context* on_finish) override;
bool read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) override;
aio_comp->set_request_count(1);
auto req_comp = new io::ReadResult::C_ObjectReadRequest(
- aio_comp, off, len, {{0, len}});
+ aio_comp, {{off, len, {{0, len}}}});
auto io_context = m_ictx->duplicate_data_io_context();
if (snapid != CEPH_NOSNAP) {
op_flags &= ~READ_FLAGS_MASK;
auto req = io::ObjectDispatchSpec::create_read(
- m_ictx, io::OBJECT_DISPATCH_LAYER_CACHE, object_no, {{off, len}},
- io_context, op_flags, read_flags, trace, &req_comp->bl,
- &req_comp->extent_map, nullptr, req_comp);
+ m_ictx, io::OBJECT_DISPATCH_LAYER_CACHE, object_no, &req_comp->extents,
+ io_context, op_flags, read_flags, trace, nullptr, req_comp);
req->send();
}
template <typename I>
bool ParentCacheObjectDispatch<I>::read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
- int* object_dispatch_flags, io::DispatchResult* dispatch_result,
- Context** on_finish, Context* on_dispatched) {
+ uint64_t* version, int* object_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
auto cct = m_image_ctx->cct;
- ldout(cct, 20) << "object_no=" << object_no << " " << extents << dendl;
+ ldout(cct, 20) << "object_no=" << object_no << " " << *extents << dendl;
- if (version != nullptr || extents.size() != 1) {
+ if (version != nullptr) {
// we currently don't cache read versions
- // and don't support reading more than one extent
return false;
}
- auto [object_off, object_len] = extents.front();
-
string oid = data_object_name(m_image_ctx, object_no);
/* if RO daemon still don't startup, or RO daemon crash,
CacheGenContextURef ctx = make_gen_lambda_context<ObjectCacheRequest*,
std::function<void(ObjectCacheRequest*)>>
- ([this, read_data, dispatch_result, on_dispatched, object_no,
- object_off = object_off, object_len = object_len, io_context,
- &parent_trace]
+ ([this, extents, dispatch_result, on_dispatched, object_no, io_context,
+ &parent_trace]
(ObjectCacheRequest* ack) {
- handle_read_cache(ack, object_no, object_off, object_len, io_context,
- parent_trace, read_data, dispatch_result,
- on_dispatched);
+ handle_read_cache(ack, object_no, extents, io_context, parent_trace,
+ dispatch_result, on_dispatched);
});
m_cache_client->lookup_object(m_image_ctx->data_ctx.get_namespace(),
template <typename I>
void ParentCacheObjectDispatch<I>::handle_read_cache(
- ObjectCacheRequest* ack, uint64_t object_no, uint64_t read_off,
- uint64_t read_len, IOContext io_context,
- const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
+ ObjectCacheRequest* ack, uint64_t object_no, io::ReadExtents* extents,
+ IOContext io_context, const ZTracer::Trace &parent_trace,
io::DispatchResult* dispatch_result, Context* on_dispatched) {
auto cct = m_image_ctx->cct;
ldout(cct, 20) << dendl;
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
on_dispatched->complete(r);
});
- m_plugin_api.read_parent(m_image_ctx, object_no, {{read_off, read_len}},
+ m_plugin_api.read_parent(m_image_ctx, object_no, extents,
io_context->read_snap().value_or(CEPH_NOSNAP),
- parent_trace, read_data, ctx);
+ parent_trace, ctx);
return;
}
- // try to read from parent image cache
- int r = read_object(file_path, read_data, read_off, read_len, on_dispatched);
- if(r < 0) {
- // cache read error, fall back to read rados
- *dispatch_result = io::DISPATCH_RESULT_CONTINUE;
- on_dispatched->complete(0);
- return;
+ int read_len = 0;
+ for (auto& extent: *extents) {
+ // try to read from parent image cache
+ int r = read_object(file_path, &extent.bl, extent.offset, extent.length,
+ on_dispatched);
+ if (r < 0) {
+ // cache read error, fall back to read rados
+ for (auto& read_extent: *extents) {
+ // clear read bufferlists
+ if (&read_extent == &extent) {
+ break;
+ }
+ read_extent.bl.clear();
+ }
+ *dispatch_result = io::DISPATCH_RESULT_CONTINUE;
+ on_dispatched->complete(0);
+ return;
+ }
+
+ read_len += r;
}
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
- on_dispatched->complete(r);
+ on_dispatched->complete(read_len);
}
template <typename I>
}
bool read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) override;
int read_object(std::string file_path, ceph::bufferlist* read_data,
uint64_t offset, uint64_t length, Context *on_finish);
void handle_read_cache(ceph::immutable_obj_cache::ObjectCacheRequest* ack,
- uint64_t object_no, uint64_t read_off,
- uint64_t read_len, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents,
+ IOContext io_context,
const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data,
io::DispatchResult* dispatch_result,
Context* on_dispatched);
int handle_register_client(bool reg);
template <typename I>
bool WriteAroundObjectDispatch<I>::read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
- int* object_dispatch_flags, io::DispatchResult* dispatch_result,
- Context** on_finish, Context* on_dispatched) {
- auto [object_off, object_len] = extents.front();
- return dispatch_unoptimized_io(object_no, object_off, object_len,
- dispatch_result, on_dispatched);
+ uint64_t* version, int* object_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ bool handled = false;
+ for (auto& extent: *extents) {
+ handled |= dispatch_unoptimized_io(object_no, extent.offset, extent.length,
+ dispatch_result, on_dispatched);
+ }
+ return handled;
}
template <typename I>
void shut_down(Context* on_finish) override;
bool read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) override;
I* image_ctx;
CryptoInterface* crypto;
uint64_t object_no;
- uint64_t object_off;
- ceph::bufferlist* read_data;
+ io::ReadExtents* extents;
Context* onfinish;
- io::ReadResult::C_ObjectReadRequest* req_comp;
io::ObjectDispatchSpec* req;
C_EncryptedObjectReadRequest(
I* image_ctx, CryptoInterface* crypto, uint64_t object_no,
- uint64_t object_off, uint64_t object_len, IOContext io_context,
+ io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, int* object_dispatch_flags,
+ uint64_t* version, int* object_dispatch_flags,
Context** on_finish,
Context* on_dispatched) : image_ctx(image_ctx),
crypto(crypto),
object_no(object_no),
- object_off(object_off),
- read_data(read_data),
+ extents(extents),
onfinish(on_dispatched) {
*on_finish = util::create_context_callback<
Context, &Context::complete>(*on_finish, crypto);
- auto aio_comp = io::AioCompletion::create_and_start(
- (Context*)this, util::get_image_ctx(image_ctx),
- io::AIO_TYPE_READ);
- aio_comp->read_result = io::ReadResult{read_data};
- aio_comp->set_request_count(1);
-
- auto req_comp = new io::ReadResult::C_ObjectReadRequest(
- aio_comp, object_off, object_len, {{0, object_len}});
-
req = io::ObjectDispatchSpec::create_read(
image_ctx, io::OBJECT_DISPATCH_LAYER_CRYPTO, object_no,
- {{object_off, object_len}}, io_context, op_flags, read_flags,
- parent_trace, &req_comp->bl, &req_comp->extent_map, nullptr,
- req_comp);
+ extents, io_context, op_flags, read_flags, parent_trace,
+ version, this);
}
void send() {
}
void finish(int r) override {
- ldout(image_ctx->cct, 20) << "r=" << r << dendl;
- if (r > 0) {
- auto crypto_ret = crypto->decrypt(
- read_data,
- Striper::get_file_offset(
- image_ctx->cct, &image_ctx->layout, object_no,
- object_off));
- if (crypto_ret != 0) {
- ceph_assert(crypto_ret < 0);
- r = crypto_ret;
+ auto cct = image_ctx->cct;
+ ldout(cct, 20) << "r=" << r << dendl;
+ if (r == 0) {
+ for (auto& extent: *extents) {
+ io::util::unsparsify(cct, &extent.bl, extent.extent_map,
+ extent.offset, extent.length);
+
+ auto crypto_ret = crypto->decrypt(
+ &extent.bl,
+ Striper::get_file_offset(
+ cct, &image_ctx->layout, object_no,
+ extent.offset));
+ if (crypto_ret != 0) {
+ ceph_assert(crypto_ret < 0);
+ r = crypto_ret;
+ break;
+ }
+
+ r += extent.length;
}
}
onfinish->complete(r);
template <typename I>
bool CryptoObjectDispatch<I>::read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map, uint64_t* version,
- int* object_dispatch_flags, io::DispatchResult* dispatch_result,
- Context** on_finish, Context* on_dispatched) {
+ uint64_t* version, int* object_dispatch_flags,
+ io::DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
auto cct = m_image_ctx->cct;
ldout(cct, 20) << data_object_name(m_image_ctx, object_no) << " "
- << extents << dendl;
+ << *extents << dendl;
ceph_assert(m_crypto != nullptr);
- if (version != nullptr || extents.size() != 1) {
- // there's currently no need to support multiple extents
- // as well as returning object version
- return false;
- }
-
- auto [object_off, object_len] = extents.front();
-
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
auto req = new C_EncryptedObjectReadRequest<I>(
- m_image_ctx, m_crypto, object_no, object_off, object_len, io_context,
- op_flags, read_flags, parent_trace, read_data, object_dispatch_flags,
+ m_image_ctx, m_crypto, object_no, extents, io_context,
+ op_flags, read_flags, parent_trace, version, object_dispatch_flags,
on_finish, on_dispatched);
req->send();
return true;
void shut_down(Context* on_finish) override;
bool read(
- uint64_t object_no, const io::Extents &extents,
- IOContext io_context, int op_flags, int read_flags,
- const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
- io::Extents* extent_map, uint64_t* version, int* object_dispatch_flags,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
+ uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) override;
struct C_RBD_Readahead : public Context {
I *ictx;
uint64_t object_no;
- uint64_t offset;
- uint64_t length;
-
- bufferlist read_data;
- io::Extents extent_map;
+ io::ReadExtents extents;
C_RBD_Readahead(I *ictx, uint64_t object_no, uint64_t offset, uint64_t length)
- : ictx(ictx), object_no(object_no), offset(offset), length(length) {
+ : ictx(ictx), object_no(object_no), extents({{offset, length}}) {
ictx->readahead.inc_pending();
}
void finish(int r) override {
+ ceph_assert(extents.size() == 1);
+ auto& extent = extents.front();
ldout(ictx->cct, 20) << "C_RBD_Readahead on "
<< data_object_name(ictx, object_no) << ": "
- << offset << "~" << length << dendl;
+ << extent.offset << "~" << extent.length << dendl;
ictx->readahead.dec_pending();
}
};
object_extent.length);
auto req = io::ObjectDispatchSpec::create_read(
ictx, io::OBJECT_DISPATCH_LAYER_NONE, object_extent.object_no,
- {{object_extent.offset, object_extent.length}}, io_context, 0, 0, {},
- &req_comp->read_data, &req_comp->extent_map, nullptr, req_comp);
+ &req_comp->extents, io_context, 0, 0, {}, nullptr, req_comp);
req->send();
}
<< oe.buffer_extents << dendl;
auto req_comp = new io::ReadResult::C_ObjectReadRequest(
- aio_comp, oe.offset, oe.length, std::move(oe.buffer_extents));
+ aio_comp, {{oe.offset, oe.length, std::move(oe.buffer_extents)}});
auto req = ObjectDispatchSpec::create_read(
&image_ctx, OBJECT_DISPATCH_LAYER_NONE, oe.object_no,
- {{oe.offset, oe.length}}, this->m_io_context, m_op_flags, m_read_flags,
- this->m_trace, &req_comp->bl, &req_comp->extent_map, nullptr, req_comp);
+ &req_comp->extents, this->m_io_context, m_op_flags, m_read_flags,
+ this->m_trace, nullptr, req_comp);
req->send();
}
template <typename I>
bool ObjectDispatch<I>::read(
- uint64_t object_no, const Extents &extents, IOContext io_context,
+ uint64_t object_no, ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
- int* object_dispatch_flags, DispatchResult* dispatch_result,
- Context** on_finish, Context* on_dispatched) {
+ uint64_t* version, int* object_dispatch_flags,
+ DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
auto cct = m_image_ctx->cct;
- ldout(cct, 20) << "object_no=" << object_no << " " << extents << dendl;
+ ldout(cct, 20) << "object_no=" << object_no << " " << *extents << dendl;
*dispatch_result = DISPATCH_RESULT_COMPLETE;
auto req = new ObjectReadRequest<I>(m_image_ctx, object_no, extents,
io_context, op_flags, read_flags,
- parent_trace, read_data, extent_map,
- version, on_dispatched);
+ parent_trace, version, on_dispatched);
req->send();
return true;
}
void shut_down(Context* on_finish) override;
bool read(
- uint64_t object_no, const Extents &extents, IOContext io_context,
+ uint64_t object_no, ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) override;
virtual void shut_down(Context* on_finish) = 0;
virtual bool read(
- uint64_t object_no, const Extents &extents,
- IOContext io_context, int op_flags, int read_flags,
- const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
- Extents* extent_map, uint64_t* version, int* object_dispatch_flags,
+ uint64_t object_no, ReadExtents* extents, IOContext io_context,
+ int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
+ uint64_t* version, int* object_dispatch_flags,
DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) = 0;
};
struct ReadRequest : public RequestBase {
- const Extents extents;
+ ReadExtents* extents;
int read_flags;
- ceph::bufferlist* read_data;
- Extents* extent_map;
uint64_t* version;
- ReadRequest(uint64_t object_no, const Extents &extents,
- int read_flags, ceph::bufferlist* read_data,
- Extents* extent_map, uint64_t* version)
+ ReadRequest(uint64_t object_no, ReadExtents* extents, int read_flags,
+ uint64_t* version)
: RequestBase(object_no), extents(extents), read_flags(read_flags),
- read_data(read_data), extent_map(extent_map), version(version) {
+ version(version) {
}
};
template <typename ImageCtxT>
static ObjectDispatchSpec* create_read(
ImageCtxT* image_ctx, ObjectDispatchLayer object_dispatch_layer,
- uint64_t object_no, const Extents &extents, IOContext io_context,
+ uint64_t object_no, ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
- Context* on_finish) {
+ uint64_t* version, Context* on_finish) {
return new ObjectDispatchSpec(image_ctx->io_object_dispatcher,
object_dispatch_layer,
ReadRequest{object_no, extents,
- read_flags, read_data, extent_map,
- version},
+ read_flags, version},
io_context, op_flags, parent_trace,
on_finish);
}
return object_dispatch->read(
read.object_no, read.extents, object_dispatch_spec->io_context,
object_dispatch_spec->op_flags, read.read_flags,
- object_dispatch_spec->parent_trace,
- read.read_data, read.extent_map, read.version,
+ object_dispatch_spec->parent_trace, read.version,
&object_dispatch_spec->object_dispatch_flags,
&object_dispatch_spec->dispatch_result,
&object_dispatch_spec->dispatcher_ctx.on_finish,
template <typename I>
ObjectReadRequest<I>::ObjectReadRequest(
- I *ictx, uint64_t objectno, const Extents &extents,
+ I *ictx, uint64_t objectno, ReadExtents* extents,
IOContext io_context, int op_flags, int read_flags,
- const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
- Extents* extent_map, uint64_t* version, Context *completion)
- : ObjectRequest<I>(ictx, objectno, io_context, "read",
- parent_trace, completion),
- m_extents(extents), m_op_flags(op_flags), m_read_flags(read_flags),
- m_read_data(read_data), m_extent_map(extent_map), m_version(version) {
+ const ZTracer::Trace &parent_trace, uint64_t* version,
+ Context *completion)
+ : ObjectRequest<I>(ictx, objectno, io_context, "read", parent_trace,
+ completion),
+ m_extents(extents), m_op_flags(op_flags),m_read_flags(read_flags),
+ m_version(version) {
}
template <typename I>
ldout(image_ctx->cct, 20) << dendl;
neorados::ReadOp read_op;
- m_extent_results.reserve(this->m_extents.size());
- for (auto [object_off, object_len]: this->m_extents) {
- m_extent_results.emplace_back();
- auto& extent_result = m_extent_results.back();
- if (object_len >= image_ctx->sparse_read_threshold_bytes) {
- read_op.sparse_read(object_off, object_len, &(extent_result.first),
- &(extent_result.second));
+ for (auto& extent: *this->m_extents) {
+ if (extent.length >= image_ctx->sparse_read_threshold_bytes) {
+ read_op.sparse_read(extent.offset, extent.length, &extent.bl,
+ &extent.extent_map);
} else {
- read_op.read(object_off, object_len, &(extent_result.first));
+ read_op.read(extent.offset, extent.length, &extent.bl);
}
}
util::apply_op_flags(
return;
}
- // merge ExtentResults to a single sparse bufferlist
- int pos = 0;
- uint64_t object_off = 0;
- for (auto& [read_data, extent_map] : m_extent_results) {
- if (extent_map.size() == 0) {
- extent_map.push_back(std::make_pair(m_extents[pos].first,
- read_data.length()));
- }
-
- uint64_t total_extents_len = 0;
- for (auto& [extent_off, extent_len] : extent_map) {
- ceph_assert(extent_off >= object_off);
- object_off = extent_off + extent_len;
- m_extent_map->push_back(std::make_pair(extent_off, extent_len));
- total_extents_len += extent_len;
- }
- ceph_assert(total_extents_len == read_data.length());
-
- m_read_data->claim_append(read_data);
- ++pos;
- }
-
this->finish(0);
}
io::util::read_parent<I>(
image_ctx, this->m_object_no, this->m_extents,
this->m_io_context->read_snap().value_or(CEPH_NOSNAP), this->m_trace,
- m_read_data, ctx);
+ ctx);
}
template <typename I>
return;
}
- if (this->m_extents.size() > 1) {
- m_extent_map->insert(m_extent_map->end(),
- m_extents.begin(), m_extents.end());
- }
-
copyup();
}
class ObjectReadRequest : public ObjectRequest<ImageCtxT> {
public:
static ObjectReadRequest* create(
- ImageCtxT *ictx, uint64_t objectno, const Extents &extents,
+ ImageCtxT *ictx, uint64_t objectno, ReadExtents* extents,
IOContext io_context, int op_flags, int read_flags,
- const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
- Extents* extent_map, uint64_t* version, Context *completion) {
+ const ZTracer::Trace &parent_trace, uint64_t* version,
+ Context *completion) {
return new ObjectReadRequest(ictx, objectno, extents, io_context, op_flags,
- read_flags, parent_trace, read_data,
- extent_map, version, completion);
+ read_flags, parent_trace, version, completion);
}
ObjectReadRequest(
- ImageCtxT *ictx, uint64_t objectno, const Extents &extents,
+ ImageCtxT *ictx, uint64_t objectno, ReadExtents* extents,
IOContext io_context, int op_flags, int read_flags,
- const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data,
- Extents* extent_map, uint64_t* version, Context *completion);
+ const ZTracer::Trace &parent_trace, uint64_t* version,
+ Context *completion);
void send() override;
* @endverbatim
*/
- const Extents m_extents;
-
- typedef std::pair<ceph::bufferlist, Extents> ExtentResult;
- typedef std::vector<ExtentResult> ExtentResults;
- ExtentResults m_extent_results;
+ ReadExtents* m_extents;
int m_op_flags;
int m_read_flags;
-
- ceph::bufferlist* m_read_data;
- Extents* m_extent_map;
uint64_t* m_version;
void read_object();
}
ReadResult::C_ObjectReadRequest::C_ObjectReadRequest(
- AioCompletion *aio_completion, uint64_t object_off, uint64_t object_len,
- LightweightBufferExtents&& buffer_extents)
- : aio_completion(aio_completion), object_off(object_off),
- object_len(object_len), buffer_extents(std::move(buffer_extents)) {
+ AioCompletion *aio_completion, ReadExtents&& extents)
+ : aio_completion(aio_completion), extents(std::move(extents)) {
aio_completion->add_request();
}
r = 0;
}
if (r >= 0) {
- ldout(cct, 10) << " got " << extent_map
- << " for " << buffer_extents
- << " bl " << bl.length() << dendl;
+ uint64_t object_len = 0;
aio_completion->lock.lock();
- if (!extent_map.empty()) {
+ for (auto& extent: extents) {
+ ldout(cct, 10) << " got " << extent.extent_map
+ << " for " << extent.buffer_extents
+ << " bl " << extent.bl.length() << dendl;
+
aio_completion->read_result.m_destriper.add_partial_sparse_result(
- cct, bl, extent_map, object_off, buffer_extents);
- } else {
- // handle the case where a sparse-read wasn't issued
- aio_completion->read_result.m_destriper.add_partial_result(
- cct, std::move(bl), buffer_extents);
+ cct, std::move(extent.bl), extent.extent_map, extent.offset,
+ extent.buffer_extents);
+
+ object_len += extent.length;
}
aio_completion->lock.unlock();
-
r = object_len;
}
aio_completion->complete_request(r);
}
+ReadResult::C_ObjectReadMergedExtents::C_ObjectReadMergedExtents(
+ CephContext* cct, ReadExtents* extents, Context* on_finish)
+ : cct(cct), extents(extents), on_finish(on_finish) {
+}
+
+void ReadResult::C_ObjectReadMergedExtents::finish(int r) {
+ if (r >= 0) {
+ for (auto& extent: *extents) {
+ if (bl.length() < extent.length) {
+ lderr(cct) << "Merged extents length is less than expected" << dendl;
+ r = -EIO;
+ break;
+ }
+ bl.splice(0, extent.length, &extent.bl);
+ }
+ if (bl.length() != 0) {
+ lderr(cct) << "Merged extents length is greater than expected" << dendl;
+ r = -EIO;
+ }
+ }
+ on_finish->complete(r);
+}
+
ReadResult::ReadResult() : m_buffer(Empty()) {
}
struct C_ObjectReadRequest : public Context {
AioCompletion *aio_completion;
- uint64_t object_off;
- uint64_t object_len;
- LightweightBufferExtents buffer_extents;
+ ReadExtents extents;
- bufferlist bl;
- Extents extent_map;
-
- C_ObjectReadRequest(AioCompletion *aio_completion, uint64_t object_off,
- uint64_t object_len,
- LightweightBufferExtents&& buffer_extents);
+ C_ObjectReadRequest(AioCompletion *aio_completion, ReadExtents&& extents);
void finish(int r) override;
};
+ struct C_ObjectReadMergedExtents : public Context {
+ CephContext* cct;
+ ReadExtents* extents;
+ Context *on_finish;
+ bufferlist bl;
+
+ C_ObjectReadMergedExtents(CephContext* cct, ReadExtents* extents,
+ Context* on_finish);
+
+ void finish(int r) override;
+ };
+
ReadResult();
ReadResult(char *buf, size_t buf_len);
ReadResult(const struct iovec *iov, int iov_count);
template <typename I>
bool SimpleSchedulerObjectDispatch<I>::read(
- uint64_t object_no, const Extents &extents, IOContext io_context,
+ uint64_t object_no, ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
- int* object_dispatch_flags, DispatchResult* dispatch_result,
- Context** on_finish, Context* on_dispatched) {
+ uint64_t* version, int* object_dispatch_flags,
+ DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
auto cct = m_image_ctx->cct;
ldout(cct, 20) << data_object_name(m_image_ctx, object_no) << " " << extents
<< dendl;
std::lock_guard locker{m_lock};
- for (auto [object_off, object_len] : extents) {
- if (intersects(object_no, object_off, object_len)) {
+ for (auto& extent : *extents) {
+ if (intersects(object_no, extent.offset, extent.length)) {
dispatch_delayed_requests(object_no);
break;
}
void shut_down(Context* on_finish) override;
bool read(
- uint64_t object_no, const Extents &extents, IOContext io_context,
+ uint64_t object_no, ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) override;
typedef std::pair<uint64_t,uint64_t> Extent;
typedef std::vector<Extent> Extents;
+struct ReadExtent {
+ const uint64_t offset;
+ const uint64_t length;
+ const LightweightBufferExtents buffer_extents;
+ ceph::bufferlist bl;
+ Extents extent_map;
+
+ ReadExtent(uint64_t offset,
+ uint64_t length) : offset(offset), length(length) {};
+ ReadExtent(uint64_t offset,
+ uint64_t length,
+ const LightweightBufferExtents&& buffer_extents)
+ : offset(offset),
+ length(length),
+ buffer_extents(buffer_extents) {}
+ ReadExtent(uint64_t offset,
+ uint64_t length,
+ const LightweightBufferExtents&& buffer_extents,
+ ceph::bufferlist&& bl,
+ Extents&& extent_map) : offset(offset),
+ length(length),
+ buffer_extents(buffer_extents),
+ bl(bl),
+ extent_map(extent_map) {};
+
+ friend inline std::ostream& operator<<(
+ std::ostream& os,
+ const ReadExtent &extent) {
+ os << "offset=" << extent.offset << ", "
+ << "length=" << extent.length << ", "
+ << "buffer_extents=" << extent.buffer_extents << ", "
+ << "bl.length=" << extent.bl.length() << ", "
+ << "extent_map=" << extent.extent_map;
+ return os;
+ }
+};
+
+typedef std::vector<ReadExtent> ReadExtents;
+
typedef std::map<uint64_t, uint64_t> ExtentMap;
} // namespace io
}
template <typename I>
-void read_parent(I *image_ctx, uint64_t object_no, const Extents &extents,
+void read_parent(I *image_ctx, uint64_t object_no, ReadExtents* extents,
librados::snap_t snap_id, const ZTracer::Trace &trace,
- ceph::bufferlist* data, Context* on_finish) {
+ Context* on_finish) {
auto cct = image_ctx->cct;
// calculate reverse mapping onto the image
Extents parent_extents;
- for (auto [object_off, object_len]: extents) {
- Striper::extent_to_file(cct, &image_ctx->layout, object_no, object_off,
- object_len, parent_extents);
+ for (auto& extent: *extents) {
+ Striper::extent_to_file(cct, &image_ctx->layout, object_no, extent.offset,
+ extent.length, parent_extents);
}
uint64_t parent_overlap = 0;
ldout(cct, 20) << dendl;
+ ceph::bufferlist* parent_read_bl;
+ if (extents->size() > 1) {
+ auto parent_comp = new ReadResult::C_ObjectReadMergedExtents(
+ cct, extents, on_finish);
+ parent_read_bl = &parent_comp->bl;
+ on_finish = parent_comp;
+ } else {
+ parent_read_bl = &extents->front().bl;
+ }
+
auto comp = AioCompletion::create_and_start(on_finish, image_ctx->parent,
AIO_TYPE_READ);
ldout(cct, 20) << "completion " << comp << ", extents " << parent_extents
<< dendl;
ImageRequest<I>::aio_read(
- image_ctx->parent, comp, std::move(parent_extents), ReadResult{data},
+ image_ctx->parent, comp, std::move(parent_extents),
+ ReadResult{parent_read_bl},
image_ctx->parent->get_data_io_context(), 0, 0, trace);
}
return total_bytes;
}
+void unsparsify(CephContext* cct, ceph::bufferlist* bl,
+ const Extents& extent_map, uint64_t bl_off,
+ uint64_t out_bl_len) {
+ Striper::StripedReadResult destriper;
+ bufferlist out_bl;
+
+ destriper.add_partial_sparse_result(cct, std::move(*bl), extent_map, bl_off,
+ {{0, out_bl_len}});
+ destriper.assemble_result(cct, out_bl, true);
+ *bl = out_bl;
+}
+
} // namespace util
} // namespace io
} // namespace librbd
template void librbd::io::util::read_parent(
- librbd::ImageCtx *image_ctx, uint64_t object_no, const Extents &extents,
- librados::snap_t snap_id, const ZTracer::Trace &trace,
- ceph::bufferlist* data, Context* on_finish);
+ librbd::ImageCtx *image_ctx, uint64_t object_no, ReadExtents* extents,
+ librados::snap_t snap_id, const ZTracer::Trace &trace, Context* on_finish);
template int librbd::io::util::clip_request(
librbd::ImageCtx *image_ctx, Extents *image_extents);
bool force_write);
template <typename ImageCtxT = librbd::ImageCtx>
-void read_parent(ImageCtxT *image_ctx, uint64_t object_no, const Extents &extents,
- librados::snap_t snap_id, const ZTracer::Trace &trace,
- ceph::bufferlist* data, Context* on_finish);
+void read_parent(ImageCtxT *image_ctx, uint64_t object_no,
+ ReadExtents* extents, librados::snap_t snap_id,
+ const ZTracer::Trace &trace, Context* on_finish);
template <typename ImageCtxT = librbd::ImageCtx>
int clip_request(ImageCtxT *image_ctx, Extents *image_extents);
uint64_t extents_length(Extents &extents);
+void unsparsify(CephContext* cct, ceph::bufferlist* bl,
+ const Extents& extent_map, uint64_t bl_off,
+ uint64_t out_bl_len);
+
} // namespace util
} // namespace io
} // namespace librbd
void shut_down(Context* on_finish) override;
bool read(
- uint64_t object_no, const io::Extents &extents, IOContext io_context,
+ uint64_t object_no, io::ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace &parent_trace,
- ceph::bufferlist* read_data, io::Extents* extent_map,
uint64_t* version, int* object_dispatch_flags,
io::DispatchResult* dispatch_result, Context** on_finish,
Context* on_dispatched) {
template <typename I>
void Api<I>::read_parent(
- I *image_ctx, uint64_t object_no, const Extents &extents,
+ I *image_ctx, uint64_t object_no, io::ReadExtents* extents,
librados::snap_t snap_id, const ZTracer::Trace &trace,
- ceph::bufferlist* data, Context* on_finish) {
- io::util::read_parent<I>(image_ctx, object_no, extents, snap_id, trace, data,
+ Context* on_finish) {
+ io::util::read_parent<I>(image_ctx, object_no, extents, snap_id, trace,
on_finish);
}
virtual ~Api() {}
virtual void read_parent(
- ImageCtxT *image_ctx, uint64_t object_no, const Extents &extents,
+ ImageCtxT *image_ctx, uint64_t object_no, io::ReadExtents* extents,
librados::snap_t snap_id, const ZTracer::Trace &trace,
- ceph::bufferlist* data, Context* on_finish);
+ Context* on_finish);
};
ldout(cct, 10) << "add_partial_sparse_result(" << this << ") " << bl.length()
<< " covering " << bl_map << " (offset " << bl_off << ")"
<< " to " << buffer_extents << dendl;
+
+ if (bl_map.empty()) {
+ add_partial_result(cct, bl, buffer_extents);
+ return;
+ }
+
auto s = bl_map.cbegin();
for (auto& be : buffer_extents) {
::add_partial_sparse_result(cct, &partial, &total_intended_len, bl, &s,
}
void Striper::StripedReadResult::add_partial_sparse_result(
- CephContext *cct, ceph::buffer::list& bl,
+ CephContext *cct, ceph::buffer::list&& bl,
const std::vector<std::pair<uint64_t, uint64_t>>& bl_map, uint64_t bl_off,
const striper::LightweightBufferExtents& buffer_extents) {
ldout(cct, 10) << "add_partial_sparse_result(" << this << ") " << bl.length()
<< " covering " << bl_map << " (offset " << bl_off << ")"
<< " to " << buffer_extents << dendl;
+
+ if (bl_map.empty()) {
+ add_partial_result(cct, std::move(bl), buffer_extents);
+ return;
+ }
+
auto s = bl_map.cbegin();
for (auto& be : buffer_extents) {
::add_partial_sparse_result(cct, &partial, &total_intended_len, bl, &s,
const std::map<uint64_t, uint64_t>& bl_map, uint64_t bl_off,
const std::vector<std::pair<uint64_t,uint64_t> >& buffer_extents);
void add_partial_sparse_result(
- CephContext *cct, ceph::buffer::list& bl,
+ CephContext *cct, ceph::buffer::list&& bl,
const std::vector<std::pair<uint64_t, uint64_t>>& bl_map,
uint64_t bl_off,
const striper::LightweightBufferExtents& buffer_extents);
template <>
struct Api<MockParentImageCacheImageCtx> {
- MOCK_METHOD7(read_parent, void(MockParentImageCacheImageCtx*, uint64_t,
- const librbd::io::Extents &, librados::snap_t,
- const ZTracer::Trace &, ceph::bufferlist*,
- Context*));
+ MOCK_METHOD6(read_parent, void(MockParentImageCacheImageCtx*, uint64_t,
+ librbd::io::ReadExtents*, librados::snap_t,
+ const ZTracer::Trace &, Context*));
};
} // namespace plugin
}
void expect_read_parent(MockPluginApi &mock_plugin_api, uint64_t object_no,
- const io::Extents &extents, librados::snap_t snap_id,
+ io::ReadExtents* extents, librados::snap_t snap_id,
int r) {
EXPECT_CALL(mock_plugin_api,
- read_parent(_, object_no, extents, snap_id, _, _, _))
- .WillOnce(WithArg<6>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr))));
+ read_parent(_, object_no, extents, snap_id, _, _))
+ .WillOnce(WithArg<5>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr))));
}
void expect_cache_close(MockParentImageCache& mparent_image_cache, int ret_val) {
C_SaferCond on_dispatched;
io::DispatchResult dispatch_result;
- ceph::bufferlist read_data;
+ io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
mock_parent_image_cache->read(
- 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, 0, {}, &read_data,
- nullptr, nullptr, nullptr, &dispatch_result, nullptr, &on_dispatched);
+ 0, &extents, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
+ nullptr, &dispatch_result, nullptr, &on_dispatched);
ASSERT_EQ(0, on_dispatched.wait());
mock_parent_image_cache->get_cache_client()->close();
expect_cache_lookup_object(*mock_parent_image_cache, "");
- expect_read_parent(mock_plugin_api, 0, {{0, 4096}}, CEPH_NOSNAP, 0);
+ io::ReadExtents extents = {{0, 4096}};
+ expect_read_parent(mock_plugin_api, 0, &extents, CEPH_NOSNAP, 0);
C_SaferCond on_dispatched;
io::DispatchResult dispatch_result;
mock_parent_image_cache->read(
- 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
- nullptr, nullptr, nullptr, &dispatch_result, nullptr, &on_dispatched);
+ 0, &extents, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
+ nullptr, &dispatch_result, nullptr, &on_dispatched);
ASSERT_EQ(0, on_dispatched.wait());
mock_parent_image_cache->get_cache_client()->close();
EXPECT_CALL(*crypto, encrypt(_, _)).Times(count);
}
- void expect_decrypt() {
- EXPECT_CALL(*crypto, decrypt(_, _));
+ void expect_decrypt(int count = 1) {
+ EXPECT_CALL(*crypto, decrypt(_, _)).Times(count);
}
};
TEST_F(TestMockCryptoCryptoObjectDispatch, ReadFail) {
expect_object_read();
+ io::ReadExtents extents = {{0, 4096}};
ASSERT_TRUE(mock_crypto_object_dispatch->read(
- 0, {{0, 4096}}, mock_image_ctx->get_data_io_context(), 0, 0, {}, &data,
- &extent_map, nullptr, &object_dispatch_flags, &dispatch_result,
+ 0, &extents, mock_image_ctx->get_data_io_context(), 0, 0, {},
+ nullptr, &object_dispatch_flags, &dispatch_result,
&on_finish, on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish, &finished_cond);
TEST_F(TestMockCryptoCryptoObjectDispatch, Read) {
expect_object_read();
+ io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
ASSERT_TRUE(mock_crypto_object_dispatch->read(
- 0, {{0, 4096}}, mock_image_ctx->get_data_io_context(), 0, 0, {},
- &data, &extent_map, nullptr, &object_dispatch_flags, &dispatch_result,
+ 0, &extents, mock_image_ctx->get_data_io_context(), 0, 0, {},
+ nullptr, &object_dispatch_flags, &dispatch_result,
&on_finish, on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish, &finished_cond);
ASSERT_EQ(ETIMEDOUT, dispatched_cond.wait_for(0));
- expect_decrypt();
+ expect_decrypt(2);
dispatcher_ctx->complete(0);
- ASSERT_EQ(4096, dispatched_cond.wait());
+ ASSERT_EQ(8192, dispatched_cond.wait());
}
TEST_F(TestMockCryptoCryptoObjectDispatch, Write) {
s_instance = this;
}
- MOCK_METHOD7(read_parent,
- void(librbd::MockTestImageCtx *, uint64_t, const Extents &,
- librados::snap_t, const ZTracer::Trace &, ceph::bufferlist*,
- Context*));
+ MOCK_METHOD6(read_parent,
+ void(librbd::MockTestImageCtx *, uint64_t, ReadExtents*,
+ librados::snap_t, const ZTracer::Trace &, Context*));
};
Mock *Mock::s_instance = nullptr;
template<> void read_parent(
librbd::MockTestImageCtx *image_ctx, uint64_t object_no,
- const Extents &extents, librados::snap_t snap_id,
- const ZTracer::Trace &trace, ceph::bufferlist* data,
- Context* on_finish) {
+ ReadExtents* extents, librados::snap_t snap_id,
+ const ZTracer::Trace &trace, Context* on_finish) {
Mock::s_instance->read_parent(image_ctx, object_no, extents, snap_id, trace,
- data, on_finish);
+ on_finish);
}
} // namespace util
}
void expect_read_parent(MockUtils &mock_utils, uint64_t object_no,
- const Extents &extents, librados::snap_t snap_id,
+ ReadExtents* extents, librados::snap_t snap_id,
int r) {
EXPECT_CALL(mock_utils,
- read_parent(_, object_no, extents, snap_id, _, _, _))
- .WillOnce(WithArg<6>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr))));
+ read_parent(_, object_no, extents, snap_id, _, _))
+ .WillOnce(WithArg<5>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr))));
}
void expect_copyup(MockCopyupRequest& mock_copyup_request, int r) {
expect_read(mock_image_ctx, ictx->get_object_name(0), 8192, 4096,
std::string(4096, '2'), 0);
- bufferlist bl;
- Extents extent_map;
C_SaferCond ctx;
uint64_t version;
+ ReadExtents extents = {{0, 4096}, {8192, 4096}};
auto req = MockObjectReadRequest::create(
- &mock_image_ctx, 0, {{0, 4096}, {8192, 4096}},
+ &mock_image_ctx, 0, &extents,
mock_image_ctx.get_data_io_context(), 0, 0, {},
- &bl, &extent_map, &version, &ctx);
+ &version, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
- bufferlist expected_bl;
- expected_bl.append(std::string(4096, '1'));
- expected_bl.append(std::string(4096, '2'));
- Extents exepected_extent_map = {{0, 4096}, {8192, 4096}};
+ bufferlist expected_bl1;
+ expected_bl1.append(std::string(4096, '1'));
+ bufferlist expected_bl2;
+ expected_bl2.append(std::string(4096, '2'));
- ASSERT_TRUE(expected_bl.contents_equal(bl));
- ASSERT_EQ(exepected_extent_map.size(), extent_map.size());
- ASSERT_TRUE(std::equal(extent_map.begin(), extent_map.end(),
- exepected_extent_map.begin()));
+ ASSERT_EQ(extents[0].extent_map.size(), 0);
+ ASSERT_EQ(extents[1].extent_map.size(), 0);
+ ASSERT_TRUE(extents[0].bl.contents_equal(expected_bl1));
+ ASSERT_TRUE(extents[1].bl.contents_equal(expected_bl2));
}
TEST_F(TestMockIoObjectRequest, SparseReadThreshold) {
ictx->sparse_read_threshold_bytes,
std::string(ictx->sparse_read_threshold_bytes, '1'), 0);
- bufferlist bl;
- Extents extent_map;
C_SaferCond ctx;
+
+ ReadExtents extents = {{0, ictx->sparse_read_threshold_bytes}};
auto req = MockObjectReadRequest::create(
- &mock_image_ctx, 0,
- {{0, ictx->sparse_read_threshold_bytes}},
- mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl,
- &extent_map, nullptr, &ctx);
+ &mock_image_ctx, 0, &extents,
+ mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -EPERM);
- bufferlist bl;
- Extents extent_map;
C_SaferCond ctx;
+ ReadExtents extents = {{0, 4096}};
auto req = MockObjectReadRequest::create(
- &mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
+ &mock_image_ctx, 0, &extents,
+ mock_image_ctx.get_data_io_context(), 0, 0, {},
nullptr, &ctx);
req->send();
ASSERT_EQ(-EPERM, ctx.wait());
expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
MockUtils mock_utils;
- expect_read_parent(mock_utils, 0, {{0, 4096}}, CEPH_NOSNAP, 0);
+ ReadExtents extents = {{0, 4096}};
+ expect_read_parent(mock_utils, 0, &extents, CEPH_NOSNAP, 0);
- bufferlist bl;
- Extents extent_map;
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
- &mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
+ &mock_image_ctx, 0, &extents,
+ mock_image_ctx.get_data_io_context(), 0, 0, {},
nullptr, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
MockUtils mock_utils;
- expect_read_parent(mock_utils, 0, {{0, 4096}}, CEPH_NOSNAP, -EPERM);
+ ReadExtents extents = {{0, 4096}};
+ expect_read_parent(mock_utils, 0, &extents, CEPH_NOSNAP, -EPERM);
- bufferlist bl;
- Extents extent_map;
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
- &mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
+ &mock_image_ctx, 0, &extents,
+ mock_image_ctx.get_data_io_context(), 0, 0, {},
nullptr, &ctx);
req->send();
ASSERT_EQ(-EPERM, ctx.wait());
expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
- bufferlist bl;
- Extents extent_map;
+ ReadExtents extents = {{0, 4096}};
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
- &mock_image_ctx, 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0,
- READ_FLAG_DISABLE_READ_FROM_PARENT, {}, &bl, &extent_map,
- nullptr, &ctx);
+ &mock_image_ctx, 0, &extents, mock_image_ctx.get_data_io_context(), 0,
+ READ_FLAG_DISABLE_READ_FROM_PARENT, {}, nullptr, &ctx);
req->send();
ASSERT_EQ(-ENOENT, ctx.wait());
}
expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
MockUtils mock_utils;
- expect_read_parent(mock_utils, 0, {{0, 4096}}, CEPH_NOSNAP, 0);
+ ReadExtents extents = {{0, 4096}};
+ expect_read_parent(mock_utils, 0, &extents, CEPH_NOSNAP, 0);
MockCopyupRequest mock_copyup_request;
expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
expect_copyup(mock_copyup_request, 0);
- bufferlist bl;
- Extents extent_map;
C_SaferCond ctx;
auto req = MockObjectReadRequest::create(
- &mock_image_ctx, 0, {{0, 4096}},
- mock_image_ctx.get_data_io_context(), 0, 0, {}, &bl, &extent_map,
+ &mock_image_ctx, 0, &extents,
+ mock_image_ctx.get_data_io_context(), 0, 0, {},
nullptr, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
C_SaferCond cond;
Context *on_finish = &cond;
+ io::ReadExtents extents = {{0, 4096}, {8192, 4096}};
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.read(
- 0, {{0, 4096}}, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
- nullptr, nullptr, nullptr, nullptr, &on_finish, nullptr));
+ 0, &extents, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr,
+ nullptr, nullptr, &on_finish, nullptr));
ASSERT_EQ(on_finish, &cond); // not modified
on_finish->complete(0);
ASSERT_EQ(0, cond.wait());
MOCK_METHOD1(shut_down, void(Context*));
- MOCK_METHOD8(execute_read,
- bool(uint64_t, const Extents&, IOContext io_context,
- ceph::bufferlist*, Extents*, uint64_t*,
+ MOCK_METHOD6(execute_read,
+ bool(uint64_t, ReadExtents*, IOContext io_context, uint64_t*,
DispatchResult*, Context*));
bool read(
- uint64_t object_no, const Extents& extents, IOContext io_context,
+ uint64_t object_no, ReadExtents* extents, IOContext io_context,
int op_flags, int read_flags, const ZTracer::Trace& parent_trace,
- ceph::bufferlist* read_data, Extents* extent_map, uint64_t* version,
- int* dispatch_flags, DispatchResult* dispatch_result,
- Context** on_finish, Context* on_dispatched) {
- return execute_read(object_no, extents, io_context, read_data, extent_map,
- version, dispatch_result, on_dispatched);
+ uint64_t* version, int* dispatch_flags,
+ DispatchResult* dispatch_result, Context** on_finish,
+ Context* on_dispatched) {
+ return execute_read(object_no, extents, io_context, version,
+ dispatch_result, on_dispatched);
}
MOCK_METHOD9(execute_discard,