]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
osdc/Striper: implemented a lightweight version of file_to_extents
authorJason Dillaman <dillaman@redhat.com>
Wed, 8 May 2019 21:34:02 +0000 (17:34 -0400)
committerJason Dillaman <dillaman@redhat.com>
Mon, 13 May 2019 16:38:13 +0000 (12:38 -0400)
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 <dillaman@redhat.com>
src/osdc/Striper.cc
src/osdc/Striper.h
src/osdc/StriperTypes.h [new file with mode: 0644]

index 2eff69b38cba7db1b098c019f50df3d3fdf9375f..005a4637dc1ef332fadb565ef310d979710c8295 100644 (file)
@@ -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<ObjectExtent>& extents,
                              uint64_t buffer_offset)
 {
-  map<object_t,std::vector<ObjectExtent> > 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_t,std::vector<ObjectExtent> >& 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<ObjectExtent>& 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_t,std::vector<ObjectExtent> >& object_extents,
-  std::vector<ObjectExtent>& 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<pair<uint64_t, uint64_t> >& extents)
index 12278e1f0642e989e4462b068ab7179911a4ea45..b3034d8204ba681d41cc5946bd74130887e5fa54 100644 (file)
@@ -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_t, std::vector<ObjectExtent> >& object_extents,
-      std::vector<ObjectExtent>& 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 (file)
index 0000000..2ce8466
--- /dev/null
@@ -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 <boost/container/small_vector.hpp>
+#include <ios>
+#include <utility>
+
+namespace striper {
+
+// off -> len extents in (striped) buffer being mapped
+typedef std::pair<uint64_t,uint64_t> 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