]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
osdc: reduce ObjectCacher's memory fragments
authorYan, Zheng <zyan@redhat.com>
Thu, 27 Sep 2018 05:10:55 +0000 (13:10 +0800)
committerYan, Zheng <zyan@redhat.com>
Wed, 10 Oct 2018 00:53:09 +0000 (08:53 +0800)
Fixes: http://tracker.ceph.com/issues/36192
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
src/common/buffer.cc
src/include/buffer.h
src/osdc/ObjectCacher.cc
src/osdc/ObjectCacher.h

index 3b44f505c8fd3411406ddcc2a0c1af8b5ee831a6..147dba5d0d56e2237c779abb83b3245e0df91329 100644 (file)
@@ -1402,6 +1402,32 @@ using namespace ceph;
     }
   }
 
+  uint64_t buffer::list::get_wasted_space() const
+  {
+    if (_buffers.size() == 1)
+      return _buffers.back().wasted();
+
+    std::vector<const raw*> raw_vec;
+    raw_vec.reserve(_buffers.size());
+    for (const auto& p : _buffers)
+      raw_vec.push_back(p.get_raw());
+    std::sort(raw_vec.begin(), raw_vec.end());
+
+    uint64_t total = 0;
+    const raw *last = nullptr;
+    for (const auto r : raw_vec) {
+      if (r == last)
+       continue;
+      last = r;
+      total += r->len;
+    }
+    // If multiple buffers are sharing the same raw buffer and they overlap
+    // with each other, the wasted space will be underestimated.
+    if (total <= length())
+      return 0;
+    return total - length();
+  }
+
   void buffer::list::rebuild()
   {
     if (_len == 0) {
index 80599c9b2589902390d4de9ec57d940b9064c84f..65146478e523ede5e19c6a57ff50bc32a89cf310 100644 (file)
@@ -728,6 +728,7 @@ namespace buffer CEPH_BUFFER_API {
       return *this;
     }
 
+    uint64_t get_wasted_space() const;
     unsigned get_num_buffers() const { return _buffers.size(); }
     const ptr& front() const { return _buffers.front(); }
     const ptr& back() const { return _buffers.back(); }
index 7ecfdb556fa206474fa8c9cef953845f6d71ddbb..491a905255d554f917bcb34bece6c4fe1e879401 100644 (file)
@@ -12,7 +12,7 @@
 #include "include/ceph_assert.h"
 
 #define MAX_FLUSH_UNDER_LOCK 20  ///< max bh's we start writeback on
-#define BUFFER_MEMORY_WEIGHT 12   // memory usage of BufferHead, count in (1<<n)
+#define BUFFER_MEMORY_WEIGHT CEPH_PAGE_SHIFT  // memory usage of BufferHead, count in (1<<n)
 
 using std::chrono::seconds;
                                 /// while holding the lock
@@ -230,6 +230,20 @@ void ObjectCacher::Object::try_merge_bh(BufferHead *bh)
   ++p;
   if (p != data.end() && can_merge_bh(bh, p->second))
     merge_left(bh, p->second);
+
+  maybe_rebuild_buffer(bh);
+}
+
+void ObjectCacher::Object::maybe_rebuild_buffer(BufferHead *bh)
+{
+  auto& bl = bh->bl;
+  if (bl.get_num_buffers() <= 1)
+    return;
+
+  auto wasted = bl.get_wasted_space();
+  if (wasted * 2 > bl.length() &&
+      wasted > (1U << BUFFER_MEMORY_WEIGHT))
+    bl.rebuild();
 }
 
 /*
@@ -454,15 +468,18 @@ ObjectCacher::BufferHead *ObjectCacher::Object::map_write(ObjectExtent &ex,
         if (cur + max >= bh->end()) {
           // we want right bit (one splice)
           final = split(bh, cur);   // just split it, take right half.
+          maybe_rebuild_buffer(bh);
           replace_journal_tid(final, tid);
           ++p;
           ceph_assert(p->second == final);
         } else {
           // we want middle bit (two splices)
           final = split(bh, cur);
+          maybe_rebuild_buffer(bh);
           ++p;
           ceph_assert(p->second == final);
-          split(final, cur+max);
+          auto right = split(final, cur+max);
+          maybe_rebuild_buffer(right);
           replace_journal_tid(final, tid);
         }
       } else {
@@ -471,7 +488,8 @@ ObjectCacher::BufferHead *ObjectCacher::Object::map_write(ObjectExtent &ex,
           // whole bufferhead, piece of cake.
         } else {
           // we want left bit (one splice)
-          split(bh, cur + max);        // just split
+          auto right = split(bh, cur + max);        // just split
+          maybe_rebuild_buffer(right);
         }
         if (final) {
           oc->mark_dirty(bh);
@@ -549,6 +567,7 @@ void ObjectCacher::Object::truncate(loff_t s)
     // split bh at truncation point?
     if (bh->start() < s) {
       split(bh, s);
+      maybe_rebuild_buffer(bh);
       continue;
     }
 
@@ -586,13 +605,15 @@ void ObjectCacher::Object::discard(loff_t off, loff_t len,
     // split bh at truncation point?
     if (bh->start() < off) {
       split(bh, off);
+      maybe_rebuild_buffer(bh);
       ++p;
       continue;
     }
 
     ceph_assert(bh->start() >= off);
     if (bh->end() > off + len) {
-      split(bh, off + len);
+      auto right = split(bh, off + len);
+      maybe_rebuild_buffer(right);
     }
 
     ++p;
index e2ea93b42cf9b709a6c8c0106e5ddb529b414079..a976f082e37097b6a8d94e9774dfee6cc5cabae6 100644 (file)
@@ -343,6 +343,7 @@ class ObjectCacher {
     void merge_left(BufferHead *left, BufferHead *right);
     bool can_merge_bh(BufferHead *left, BufferHead *right);
     void try_merge_bh(BufferHead *bh);
+    void maybe_rebuild_buffer(BufferHead *bh);
 
     bool is_cached(loff_t off, loff_t len) const;
     bool include_all_cached_data(loff_t off, loff_t len);