From: Jason Dillaman Date: Wed, 8 May 2019 21:34:02 +0000 (-0400) Subject: osdc/Striper: implemented a lightweight version of file_to_extents X-Git-Tag: v15.1.0~2664^2~5 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=a3448eda332fccc4299001e0c249eda6a8aee805;p=ceph-ci.git osdc/Striper: implemented a lightweight version of file_to_extents The previous versions of file_to_extents resulted in numerous heap allocations for maps, vectors, and strings -- in addition to using a CPU inefficient oid name formater. librbd doesn't require the use of object_t and it would be better to avoid any heap allocations on the IO path for the common case. Signed-off-by: Jason Dillaman --- diff --git a/src/osdc/Striper.cc b/src/osdc/Striper.cc index 2eff69b38cb..005a4637dc1 100644 --- a/src/osdc/Striper.cc +++ b/src/osdc/Striper.cc @@ -31,6 +31,27 @@ using std::pair; using ceph::bufferlist; +namespace { + +object_t format_oid(const char* object_format, uint64_t object_no) { + char buf[strlen(object_format) + 32]; + snprintf(buf, sizeof(buf), object_format, (long long unsigned)object_no); + return object_t(buf); +} + +struct OrderByObject { + constexpr bool operator()(uint64_t object_no, + const striper::LightweightObjectExtent& rhs) const { + return object_no < rhs.object_no; + } + constexpr bool operator()(const striper::LightweightObjectExtent& lhs, + uint64_t object_no) const { + return lhs.object_no < object_no; + } +}; + +} // anonymous namespace + void Striper::file_to_extents(CephContext *cct, const char *object_format, const file_layout_t *layout, uint64_t offset, uint64_t len, @@ -38,10 +59,27 @@ void Striper::file_to_extents(CephContext *cct, const char *object_format, std::vector& extents, uint64_t buffer_offset) { - map > object_extents; - file_to_extents(cct, object_format, layout, offset, len, trunc_size, - object_extents, buffer_offset); - assimilate_extents(object_extents, extents); + striper::LightweightObjectExtents lightweight_object_extents; + file_to_extents(cct, layout, offset, len, trunc_size, buffer_offset, + &lightweight_object_extents); + + // convert lightweight object extents to heavyweight version + extents.reserve(lightweight_object_extents.size()); + for (auto& lightweight_object_extent : lightweight_object_extents) { + auto& object_extent = extents.emplace_back( + object_t(format_oid(object_format, lightweight_object_extent.object_no)), + lightweight_object_extent.object_no, + lightweight_object_extent.offset, lightweight_object_extent.length, + lightweight_object_extent.truncate_size); + + object_extent.oloc = OSDMap::file_to_object_locator(*layout); + object_extent.buffer_extents.reserve( + lightweight_object_extent.buffer_extents.size()); + object_extent.buffer_extents.insert( + object_extent.buffer_extents.end(), + lightweight_object_extent.buffer_extents.begin(), + lightweight_object_extent.buffer_extents.end()); + } } void Striper::file_to_extents( @@ -52,15 +90,39 @@ void Striper::file_to_extents( map >& object_extents, uint64_t buffer_offset) { - ldout(cct, 10) << "file_to_extents " << offset << "~" << len - << " format " << object_format - << dendl; + striper::LightweightObjectExtents lightweight_object_extents; + file_to_extents(cct, layout, offset, len, trunc_size, buffer_offset, + &lightweight_object_extents); + + // convert lightweight object extents to heavyweight version + for (auto& lightweight_object_extent : lightweight_object_extents) { + auto oid = format_oid(object_format, lightweight_object_extent.object_no); + auto& object_extent = object_extents[oid].emplace_back( + oid, lightweight_object_extent.object_no, + lightweight_object_extent.offset, lightweight_object_extent.length, + lightweight_object_extent.truncate_size); + + object_extent.oloc = OSDMap::file_to_object_locator(*layout); + object_extent.buffer_extents.reserve( + lightweight_object_extent.buffer_extents.size()); + object_extent.buffer_extents.insert( + object_extent.buffer_extents.end(), + lightweight_object_extent.buffer_extents.begin(), + lightweight_object_extent.buffer_extents.end()); + } +} + +void Striper::file_to_extents( + CephContext *cct, const file_layout_t *layout, uint64_t offset, + uint64_t len, uint64_t trunc_size, uint64_t buffer_offset, + striper::LightweightObjectExtents* object_extents) { + ldout(cct, 10) << "file_to_extents " << offset << "~" << len << dendl; ceph_assert(len > 0); /* * we want only one extent per object! this means that each extent * we read may map into different bits of the final read - * buffer.. hence ObjectExtent.buffer_extents + * buffer.. hence buffer_extents */ __u32 object_size = layout->object_size; @@ -90,11 +152,6 @@ void Striper::file_to_extents( // object id uint64_t objectno = objectsetno * stripe_count + stripepos; - // find oid, extent - char buf[strlen(object_format) + 32]; - snprintf(buf, sizeof(buf), object_format, (long long unsigned)objectno); - object_t oid = buf; - // map range into object uint64_t block_start = (stripeno % stripes_per_object) * su; uint64_t block_off = cur % su; @@ -114,32 +171,29 @@ void Striper::file_to_extents( << block_off << " " << x_offset << "~" << x_len << dendl; - ObjectExtent *ex = 0; - std::vector& exv = object_extents[oid]; - if (exv.empty() || exv.back().offset + exv.back().length != x_offset) { - exv.resize(exv.size() + 1); - ex = &exv.back(); - ex->oid = oid; - ex->objectno = objectno; - ex->oloc = OSDMap::file_to_object_locator(*layout); - - ex->offset = x_offset; - ex->length = x_len; - ex->truncate_size = object_truncate_size(cct, layout, objectno, - trunc_size); - - ldout(cct, 20) << " added new " << *ex << dendl; + striper::LightweightObjectExtent* ex = nullptr; + auto it = std::upper_bound(object_extents->begin(), object_extents->end(), + objectno, OrderByObject()); + striper::LightweightObjectExtents::reverse_iterator rev_it(it); + if (rev_it == object_extents->rend() || + rev_it->object_no != objectno || + rev_it->offset + rev_it->length != x_offset) { + // expect up to "stripe-width - 1" vector shifts in the worst-case + ex = &(*object_extents->emplace( + it, objectno, x_offset, x_len, + object_truncate_size(cct, layout, objectno, trunc_size))); + ldout(cct, 20) << " added new " << *ex << dendl; } else { - // add to extent - ex = &exv.back(); + ex = &(*rev_it); + ceph_assert(ex->offset + ex->length == x_offset); + ldout(cct, 20) << " adding in to " << *ex << dendl; ex->length += x_len; } - ex->buffer_extents.push_back(make_pair(cur - offset + buffer_offset, - x_len)); - ldout(cct, 15) << "file_to_extents " << *ex << " in " << ex->oloc - << dendl; + ex->buffer_extents.emplace_back(cur - offset + buffer_offset, x_len); + + ldout(cct, 15) << "file_to_extents " << *ex << dendl; // ldout(cct, 0) << "map: ino " << ino << " oid " << ex.oid << " osd " // << ex.osd << " offset " << ex.offset << " len " << ex.len // << " ... left " << left << dendl; @@ -149,18 +203,6 @@ void Striper::file_to_extents( } } -void Striper::assimilate_extents( - map >& object_extents, - std::vector& extents) -{ - // make final list - for (auto it = object_extents.cbegin(); it != object_extents.cend(); ++it) { - for (auto p = it->second.begin(); p != it->second.end(); ++p) { - extents.push_back(*p); - } - } -} - void Striper::extent_to_file(CephContext *cct, file_layout_t *layout, uint64_t objectno, uint64_t off, uint64_t len, std::vector >& extents) diff --git a/src/osdc/Striper.h b/src/osdc/Striper.h index 12278e1f064..b3034d8204b 100644 --- a/src/osdc/Striper.h +++ b/src/osdc/Striper.h @@ -17,6 +17,7 @@ #include "include/types.h" #include "osd/osd_types.h" +#include "osdc/StriperTypes.h" class CephContext; @@ -24,6 +25,11 @@ class CephContext; class Striper { public: + static void file_to_extents( + CephContext *cct, const file_layout_t *layout, uint64_t offset, + uint64_t len, uint64_t trunc_size, uint64_t buffer_offset, + striper::LightweightObjectExtents* object_extents); + /* * std::map (ino, layout, offset, len) to a (list of) ObjectExtents (byte * ranges in objects on (primary) osds) @@ -54,10 +60,6 @@ class CephContext; file_to_extents(cct, buf, layout, offset, len, trunc_size, extents); } - static void assimilate_extents( - std::map >& object_extents, - std::vector& extents); - /** * reverse std::map an object extent to file extents */ diff --git a/src/osdc/StriperTypes.h b/src/osdc/StriperTypes.h new file mode 100644 index 00000000000..2ce8466a8a3 --- /dev/null +++ b/src/osdc/StriperTypes.h @@ -0,0 +1,48 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_OSDC_STRIPER_TYPES_H +#define CEPH_OSDC_STRIPER_TYPES_H + +#include "include/types.h" +#include +#include +#include + +namespace striper { + +// off -> len extents in (striped) buffer being mapped +typedef std::pair BufferExtent; +typedef boost::container::small_vector< + BufferExtent, 4> LightweightBufferExtents; + +struct LightweightObjectExtent { + LightweightObjectExtent() = delete; + LightweightObjectExtent(uint64_t object_no, uint64_t offset, + uint64_t length, uint64_t truncate_size) + : object_no(object_no), offset(offset), length(length), + truncate_size(truncate_size) { + } + + uint64_t object_no; + uint64_t offset; // in-object + uint64_t length; // in-object + uint64_t truncate_size; // in-object + LightweightBufferExtents buffer_extents; +}; + +typedef boost::container::small_vector< + LightweightObjectExtent, 4> LightweightObjectExtents; + +inline std::ostream& operator<<(std::ostream& os, + const LightweightObjectExtent& ex) { + return os << "extent(" + << ex.object_no << " " + << ex.offset << "~" << ex.length + << " -> " << ex.buffer_extents + << ")"; +} + +} // namespace striper + +#endif // CEPH_OSDC_STRIPER_TYPES_H