1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/io/ReadResult.h"
5 #include "include/buffer.h"
6 #include "common/dout.h"
7 #include "librbd/io/AioCompletion.h"
8 #include "librbd/io/Utils.h"
9 #include <boost/variant/apply_visitor.hpp>
10 #include <boost/variant/static_visitor.hpp>
12 #define dout_subsys ceph_subsys_rbd
14 #define dout_prefix *_dout << "librbd::io::ReadResult: " << this \
15 << " " << __func__ << ": "
20 struct ReadResult::SetImageExtentsVisitor
: public boost::static_visitor
<void> {
21 Extents image_extents
;
23 explicit SetImageExtentsVisitor(const Extents
& image_extents
)
24 : image_extents(image_extents
) {
27 void operator()(Linear
&linear
) const {
28 uint64_t length
= util::get_extents_length(image_extents
);
30 ceph_assert(length
<= linear
.buf_len
);
31 linear
.buf_len
= length
;
34 void operator()(SparseBufferlist
&sbl
) const {
35 sbl
.image_extents
= image_extents
;
39 void operator()(T
&t
) const {
43 struct ReadResult::AssembleResultVisitor
: public boost::static_visitor
<void> {
45 Striper::StripedReadResult
&destriper
;
47 AssembleResultVisitor(CephContext
*cct
, Striper::StripedReadResult
&destriper
)
48 : cct(cct
), destriper(destriper
) {
51 void operator()(Empty
&empty
) const {
52 ldout(cct
, 20) << "dropping read result" << dendl
;
55 void operator()(Linear
&linear
) const {
56 ldout(cct
, 20) << "copying resulting bytes to "
57 << reinterpret_cast<void*>(linear
.buf
) << dendl
;
58 destriper
.assemble_result(cct
, linear
.buf
, linear
.buf_len
);
61 void operator()(Vector
&vector
) const {
63 destriper
.assemble_result(cct
, bl
, true);
65 ldout(cct
, 20) << "copying resulting " << bl
.length() << " bytes to iovec "
66 << reinterpret_cast<const void*>(vector
.iov
) << dendl
;
68 bufferlist::iterator it
= bl
.begin();
69 size_t length
= bl
.length();
72 for (; offset
< length
&& idx
< vector
.iov_count
; idx
++) {
73 size_t len
= std::min(vector
.iov
[idx
].iov_len
, length
- offset
);
74 it
.copy(len
, static_cast<char *>(vector
.iov
[idx
].iov_base
));
77 ceph_assert(offset
== bl
.length());
80 void operator()(Bufferlist
&bufferlist
) const {
81 bufferlist
.bl
->clear();
82 destriper
.assemble_result(cct
, *bufferlist
.bl
, true);
84 ldout(cct
, 20) << "moved resulting " << bufferlist
.bl
->length() << " "
85 << "bytes to bl " << reinterpret_cast<void*>(bufferlist
.bl
)
89 void operator()(SparseBufferlist
&sparse_bufferlist
) const {
90 sparse_bufferlist
.bl
->clear();
92 ExtentMap buffer_extent_map
;
93 auto buffer_extents_length
= destriper
.assemble_result(
94 cct
, &buffer_extent_map
, sparse_bufferlist
.bl
);
96 ldout(cct
, 20) << "image_extents="
97 << sparse_bufferlist
.image_extents
<< ", "
98 << "buffer_extent_map=" << buffer_extent_map
<< dendl
;
100 sparse_bufferlist
.extent_map
->clear();
101 sparse_bufferlist
.extent_map
->reserve(buffer_extent_map
.size());
103 // The extent-map is logically addressed by buffer-extents not image- or
104 // object-extents. Translate this address mapping to image-extent
105 // logical addressing since it's tied to an image-extent read
106 uint64_t buffer_offset
= 0;
107 auto bem_it
= buffer_extent_map
.begin();
108 for (auto [image_offset
, image_length
] : sparse_bufferlist
.image_extents
) {
109 while (bem_it
!= buffer_extent_map
.end()) {
110 auto [buffer_extent_offset
, buffer_extent_length
] = *bem_it
;
112 if (buffer_offset
+ image_length
<= buffer_extent_offset
) {
113 // skip any image extent that is not included in the results
117 // current buffer-extent should be within the current image-extent
118 ceph_assert(buffer_offset
<= buffer_extent_offset
&&
119 buffer_offset
+ image_length
>=
120 buffer_extent_offset
+ buffer_extent_length
);
121 auto image_extent_offset
=
122 image_offset
+ (buffer_extent_offset
- buffer_offset
);
123 ldout(cct
, 20) << "mapping buffer extent " << buffer_extent_offset
124 << "~" << buffer_extent_length
<< " to image extent "
125 << image_extent_offset
<< "~" << buffer_extent_length
127 sparse_bufferlist
.extent_map
->emplace_back(
128 image_extent_offset
, buffer_extent_length
);
132 buffer_offset
+= image_length
;
134 ceph_assert(buffer_offset
== buffer_extents_length
);
135 ceph_assert(bem_it
== buffer_extent_map
.end());
137 ldout(cct
, 20) << "moved resulting " << *sparse_bufferlist
.extent_map
138 << " extents of total " << sparse_bufferlist
.bl
->length()
140 << reinterpret_cast<void*>(sparse_bufferlist
.bl
) << dendl
;
144 ReadResult::C_ImageReadRequest::C_ImageReadRequest(
145 AioCompletion
*aio_completion
, uint64_t buffer_offset
,
146 const Extents image_extents
)
147 : aio_completion(aio_completion
), buffer_offset(buffer_offset
),
148 image_extents(image_extents
) {
149 aio_completion
->add_request();
152 void ReadResult::C_ImageReadRequest::finish(int r
) {
153 CephContext
*cct
= aio_completion
->ictx
->cct
;
154 ldout(cct
, 10) << "C_ImageReadRequest: r=" << r
156 if (r
>= 0 || (ignore_enoent
&& r
== -ENOENT
)) {
157 striper::LightweightBufferExtents buffer_extents
;
159 for (auto &image_extent
: image_extents
) {
160 buffer_extents
.emplace_back(buffer_offset
+ length
, image_extent
.second
);
161 length
+= image_extent
.second
;
163 ceph_assert(r
== -ENOENT
|| length
== bl
.length());
165 aio_completion
->lock
.lock();
166 aio_completion
->read_result
.m_destriper
.add_partial_result(
167 cct
, std::move(bl
), buffer_extents
);
168 aio_completion
->lock
.unlock();
172 aio_completion
->complete_request(r
);
175 ReadResult::C_ObjectReadRequest::C_ObjectReadRequest(
176 AioCompletion
*aio_completion
, ReadExtents
&& extents
)
177 : aio_completion(aio_completion
), extents(std::move(extents
)) {
178 aio_completion
->add_request();
181 void ReadResult::C_ObjectReadRequest::finish(int r
) {
182 CephContext
*cct
= aio_completion
->ictx
->cct
;
183 ldout(cct
, 10) << "C_ObjectReadRequest: r=" << r
190 uint64_t object_len
= 0;
191 aio_completion
->lock
.lock();
192 for (auto& extent
: extents
) {
193 ldout(cct
, 10) << " got " << extent
.extent_map
194 << " for " << extent
.buffer_extents
195 << " bl " << extent
.bl
.length() << dendl
;
197 aio_completion
->read_result
.m_destriper
.add_partial_sparse_result(
198 cct
, std::move(extent
.bl
), extent
.extent_map
, extent
.offset
,
199 extent
.buffer_extents
);
201 object_len
+= extent
.length
;
203 aio_completion
->lock
.unlock();
207 aio_completion
->complete_request(r
);
210 ReadResult::C_ObjectReadMergedExtents::C_ObjectReadMergedExtents(
211 CephContext
* cct
, ReadExtents
* extents
, Context
* on_finish
)
212 : cct(cct
), extents(extents
), on_finish(on_finish
) {
215 void ReadResult::C_ObjectReadMergedExtents::finish(int r
) {
217 for (auto& extent
: *extents
) {
218 if (bl
.length() < extent
.length
) {
219 lderr(cct
) << "Merged extents length is less than expected" << dendl
;
223 bl
.splice(0, extent
.length
, &extent
.bl
);
225 if (bl
.length() != 0) {
226 lderr(cct
) << "Merged extents length is greater than expected" << dendl
;
230 on_finish
->complete(r
);
233 ReadResult::ReadResult() : m_buffer(Empty()) {
236 ReadResult::ReadResult(char *buf
, size_t buf_len
)
237 : m_buffer(Linear(buf
, buf_len
)) {
240 ReadResult::ReadResult(const struct iovec
*iov
, int iov_count
)
241 : m_buffer(Vector(iov
, iov_count
)) {
244 ReadResult::ReadResult(ceph::bufferlist
*bl
)
245 : m_buffer(Bufferlist(bl
)) {
248 ReadResult::ReadResult(Extents
* extent_map
, ceph::bufferlist
* bl
)
249 : m_buffer(SparseBufferlist(extent_map
, bl
)) {
252 void ReadResult::set_image_extents(const Extents
& image_extents
) {
253 boost::apply_visitor(SetImageExtentsVisitor(image_extents
), m_buffer
);
256 void ReadResult::assemble_result(CephContext
*cct
) {
257 boost::apply_visitor(AssembleResultVisitor(cct
, m_destriper
), m_buffer
);
261 } // namespace librbd