From ffd8ffb956e99bc627a4e54898ab1c809e7c6306 Mon Sep 17 00:00:00 2001 From: Gui Hecheng Date: Wed, 22 Feb 2017 17:16:55 +0800 Subject: [PATCH] librbd: add writesame AioImageRequest Based on pr: https://github.com/ceph/ceph/pull/10019. Signed-off-by: Gui Hecheng Signed-off-by: Mingxin Liu --- src/librbd/cache/ImageCache.h | 3 + src/librbd/cache/ImageWriteback.cc | 18 +++ src/librbd/cache/ImageWriteback.h | 3 + src/librbd/cache/PassthroughImageCache.cc | 14 ++ src/librbd/cache/PassthroughImageCache.h | 3 + src/librbd/io/ImageRequest.cc | 155 ++++++++++++++++++++++ src/librbd/io/ImageRequest.h | 47 +++++++ 7 files changed, 243 insertions(+) diff --git a/src/librbd/cache/ImageCache.h b/src/librbd/cache/ImageCache.h index 859993b0ff9..02a6467aa60 100644 --- a/src/librbd/cache/ImageCache.h +++ b/src/librbd/cache/ImageCache.h @@ -30,6 +30,9 @@ struct ImageCache { virtual void aio_discard(uint64_t offset, uint64_t length, Context *on_finish) = 0; virtual void aio_flush(Context *on_finish) = 0; + virtual void aio_writesame(uint64_t offset, uint64_t length, + ceph::bufferlist&& bl, + int fadvise_flags, Context *on_finish) = 0; /// internal state methods virtual void init(Context *on_finish) = 0; diff --git a/src/librbd/cache/ImageWriteback.cc b/src/librbd/cache/ImageWriteback.cc index 6867eec2552..69b28c3d274 100644 --- a/src/librbd/cache/ImageWriteback.cc +++ b/src/librbd/cache/ImageWriteback.cc @@ -78,6 +78,24 @@ void ImageWriteback::aio_flush(Context *on_finish) { req.send(); } +template +void ImageWriteback::aio_writesame(uint64_t offset, uint64_t length, + ceph::bufferlist&& bl, + int fadvise_flags, Context *on_finish) { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 20) << "offset=" << offset << ", " + << "length=" << length << ", " + << "data_len=" << bl.length() << ", " + << "on_finish=" << on_finish << dendl; + + auto aio_comp = io::AioCompletion::create_and_start(on_finish, &m_image_ctx, + io::AIO_TYPE_WRITESAME); + io::ImageWriteSameRequest req(m_image_ctx, aio_comp, offset, length, + std::move(bl), fadvise_flags); + req.set_bypass_image_cache(); + req.send(); +} + } // namespace cache } // namespace librbd diff --git a/src/librbd/cache/ImageWriteback.h b/src/librbd/cache/ImageWriteback.h index c3737800ecb..29ea713baa8 100644 --- a/src/librbd/cache/ImageWriteback.h +++ b/src/librbd/cache/ImageWriteback.h @@ -32,6 +32,9 @@ public: int fadvise_flags, Context *on_finish); void aio_discard(uint64_t offset, uint64_t length, Context *on_finish); void aio_flush(Context *on_finish); + void aio_writesame(uint64_t offset, uint64_t length, + ceph::bufferlist&& bl, + int fadvise_flags, Context *on_finish); private: ImageCtxT &m_image_ctx; diff --git a/src/librbd/cache/PassthroughImageCache.cc b/src/librbd/cache/PassthroughImageCache.cc index 0ad2f4ef877..62f81aca329 100644 --- a/src/librbd/cache/PassthroughImageCache.cc +++ b/src/librbd/cache/PassthroughImageCache.cc @@ -62,6 +62,20 @@ void PassthroughImageCache::aio_flush(Context *on_finish) { m_image_writeback.aio_flush(on_finish); } +template +void PassthroughImageCache::aio_writesame(uint64_t offset, uint64_t length, + bufferlist&& bl, int fadvise_flags, + Context *on_finish) { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 20) << "offset=" << offset << ", " + << "length=" << length << ", " + << "data_len=" << bl.length() << ", " + << "on_finish=" << on_finish << dendl; + + m_image_writeback.aio_writesame(offset, length, std::move(bl), fadvise_flags, + on_finish); +} + template void PassthroughImageCache::init(Context *on_finish) { CephContext *cct = m_image_ctx.cct; diff --git a/src/librbd/cache/PassthroughImageCache.h b/src/librbd/cache/PassthroughImageCache.h index 9e451d1a7af..2abea0efb77 100644 --- a/src/librbd/cache/PassthroughImageCache.h +++ b/src/librbd/cache/PassthroughImageCache.h @@ -29,6 +29,9 @@ public: void aio_discard(uint64_t offset, uint64_t length, Context *on_finish) override; void aio_flush(Context *on_finish) override; + virtual void aio_writesame(uint64_t offset, uint64_t length, + ceph::bufferlist&& bl, + int fadvise_flags, Context *on_finish); /// internal state methods void init(Context *on_finish) override; diff --git a/src/librbd/io/ImageRequest.cc b/src/librbd/io/ImageRequest.cc index e2b873d0673..44b6ea1813b 100644 --- a/src/librbd/io/ImageRequest.cc +++ b/src/librbd/io/ImageRequest.cc @@ -141,6 +141,15 @@ void ImageRequest::aio_flush(I *ictx, AioCompletion *c) { req.send(); } +template +void ImageRequest::aio_writesame(I *ictx, AioCompletion *c, + uint64_t off, uint64_t len, + bufferlist &&bl, + int op_flags) { + ImageWriteSameRequest req(*ictx, c, off, len, std::move(bl), op_flags); + req.send(); +} + template void ImageRequest::send() { I &image_ctx = this->m_image_ctx; @@ -654,6 +663,151 @@ void ImageFlushRequest::send_image_cache_request() { image_ctx.image_cache->aio_flush(req_comp); } +template +bool ImageWriteSameRequest::assemble_writesame_extent(const ObjectExtent &object_extent, + bufferlist *bl, bool force_write) { + size_t m_data_len = m_data_bl.length(); + + if (!force_write) { + bool may_writesame = true; + + for (auto q = object_extent.buffer_extents.begin(); + q != object_extent.buffer_extents.end(); ++q) { + if (!(q->first % m_data_len == 0 && q->second % m_data_len == 0)) { + may_writesame = false; + break; + } + } + + if (may_writesame) { + bl->append(m_data_bl); + return true; + } + } + + for (auto q = object_extent.buffer_extents.begin(); + q != object_extent.buffer_extents.end(); ++q) { + bufferlist sub_bl; + uint64_t sub_off = q->first % m_data_len; + uint64_t sub_len = m_data_len - sub_off; + uint64_t extent_left = q->second; + while (extent_left >= sub_len) { + sub_bl.substr_of(m_data_bl, sub_off, sub_len); + bl->claim_append(sub_bl); + extent_left -= sub_len; + if (sub_off) { + sub_off = 0; + sub_len = m_data_len; + } + } + if (extent_left) { + sub_bl.substr_of(m_data_bl, sub_off, extent_left); + bl->claim_append(sub_bl); + } + } + return false; +} + +template +uint64_t ImageWriteSameRequest::append_journal_event( + const ObjectRequests &requests, bool synchronous) { + I &image_ctx = this->m_image_ctx; + + uint64_t tid = 0; + assert(!this->m_image_extents.empty()); + for (auto &extent : this->m_image_extents) { + journal::EventEntry event_entry(journal::AioWriteSameEvent(extent.first, + extent.second, + m_data_bl)); + tid = image_ctx.journal->append_io_event(std::move(event_entry), + requests, extent.first, + extent.second, synchronous); + } + + if (image_ctx.object_cacher == NULL) { + AioCompletion *aio_comp = this->m_aio_comp; + aio_comp->associate_journal_event(tid); + } + return tid; +} + +template +void ImageWriteSameRequest::send_image_cache_request() { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.image_cache != nullptr); + + AioCompletion *aio_comp = this->m_aio_comp; + aio_comp->set_request_count(this->m_image_extents.size()); + for (auto &extent : this->m_image_extents) { + C_AioRequest *req_comp = new C_AioRequest(aio_comp); + image_ctx.image_cache->aio_writesame(extent.first, extent.second, + std::move(m_data_bl), m_op_flags, + req_comp); + } +} + +template +void ImageWriteSameRequest::send_object_cache_requests( + const ObjectExtents &object_extents, uint64_t journal_tid) { + I &image_ctx = this->m_image_ctx; + for (auto p = object_extents.begin(); p != object_extents.end(); ++p) { + const ObjectExtent &object_extent = *p; + + bufferlist bl; + assemble_writesame_extent(object_extent, &bl, true); + + AioCompletion *aio_comp = this->m_aio_comp; + C_AioRequest *req_comp = new C_AioRequest(aio_comp); + image_ctx.write_to_cache(object_extent.oid, bl, object_extent.length, + object_extent.offset, req_comp, m_op_flags, + journal_tid); + } +} + +template +void ImageWriteSameRequest::send_object_requests( + const ObjectExtents &object_extents, const ::SnapContext &snapc, + ObjectRequests *object_requests) { + I &image_ctx = this->m_image_ctx; + + // cache handles creating object requests during writeback + if (image_ctx.object_cacher == NULL) { + AbstractImageWriteRequest::send_object_requests(object_extents, snapc, + object_requests); + } +} + +template +ObjectRequestHandle *ImageWriteSameRequest::create_object_request( + const ObjectExtent &object_extent, const ::SnapContext &snapc, + Context *on_finish) { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.object_cacher == NULL); + + bufferlist bl; + ObjectRequest *req; + + if (assemble_writesame_extent(object_extent, &bl, false)) { + req = ObjectRequest::create_writesame( + &image_ctx, object_extent.oid.name, object_extent.objectno, + object_extent.offset, object_extent.length, + bl, snapc, on_finish, m_op_flags); + return req; + } + req = ObjectRequest::create_write( + &image_ctx, object_extent.oid.name, object_extent.objectno, + object_extent.offset, + bl, snapc, on_finish, m_op_flags); + return req; +} + +template +void ImageWriteSameRequest::update_stats(size_t length) { + I &image_ctx = this->m_image_ctx; + image_ctx.perfcounter->inc(l_librbd_wr); + image_ctx.perfcounter->inc(l_librbd_wr_bytes, length); +} + } // namespace io } // namespace librbd @@ -663,3 +817,4 @@ template class librbd::io::AbstractImageWriteRequest; template class librbd::io::ImageWriteRequest; template class librbd::io::ImageDiscardRequest; template class librbd::io::ImageFlushRequest; +template class librbd::io::ImageWriteSameRequest; diff --git a/src/librbd/io/ImageRequest.h b/src/librbd/io/ImageRequest.h index 0bdca22e63b..4c8ae76f5bb 100644 --- a/src/librbd/io/ImageRequest.h +++ b/src/librbd/io/ImageRequest.h @@ -37,6 +37,8 @@ public: static void aio_discard(ImageCtxT *ictx, AioCompletion *c, uint64_t off, uint64_t len); static void aio_flush(ImageCtxT *ictx, AioCompletion *c); + static void aio_writesame(ImageCtxT *ictx, AioCompletion *c, uint64_t off, + uint64_t len, bufferlist &&bl, int op_flags); virtual bool is_write_op() const { return false; @@ -257,6 +259,50 @@ protected: } }; +template +class ImageWriteSameRequest : public AbstractImageWriteRequest { +public: + ImageWriteSameRequest(ImageCtxT &image_ctx, AioCompletion *aio_comp, + uint64_t off, uint64_t len, bufferlist &&bl, + int op_flags) + : AbstractImageWriteRequest(image_ctx, aio_comp, {{off, len}}), + m_data_bl(std::move(bl)), m_op_flags(op_flags) { + } + +protected: + using typename ImageRequest::ObjectRequests; + using typename AbstractImageWriteRequest::ObjectExtents; + + virtual aio_type_t get_aio_type() const { + return AIO_TYPE_WRITESAME; + } + virtual const char *get_request_type() const { + return "aio_writesame"; + } + + bool assemble_writesame_extent(const ObjectExtent &object_extent, + bufferlist *bl, bool force_write); + + virtual void send_image_cache_request() override; + + virtual void send_object_cache_requests(const ObjectExtents &object_extents, + uint64_t journal_tid); + + virtual void send_object_requests(const ObjectExtents &object_extents, + const ::SnapContext &snapc, + ObjectRequests *object_requests); + virtual ObjectRequestHandle *create_object_request( + const ObjectExtent &object_extent, const ::SnapContext &snapc, + Context *on_finish); + + virtual uint64_t append_journal_event(const ObjectRequests &requests, + bool synchronous); + virtual void update_stats(size_t length); +private: + bufferlist m_data_bl; + int m_op_flags; +}; + } // namespace io } // namespace librbd @@ -266,5 +312,6 @@ extern template class librbd::io::AbstractImageWriteRequest; extern template class librbd::io::ImageWriteRequest; extern template class librbd::io::ImageDiscardRequest; extern template class librbd::io::ImageFlushRequest; +extern template class librbd::io::ImageWriteSameRequest; #endif // CEPH_LIBRBD_IO_IMAGE_REQUEST_H -- 2.47.3