]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson: handle hot CaynStore exceptions without throwing.
authorRadoslaw Zarzynski <rzarzyns@redhat.com>
Thu, 25 Apr 2019 14:39:56 +0000 (16:39 +0200)
committerKefu Chai <kchai@redhat.com>
Tue, 7 May 2019 09:47:45 +0000 (17:47 +0800)
Signed-off-by: Radoslaw Zarzynski <rzarzyns@redhat.com>
src/crimson/os/cyan_store.cc
src/crimson/os/cyan_store.h
src/crimson/osd/pg_backend.cc

index 0cb7160a57a130f314b233fe6a7eab5a2ab7d858..493b4a8da61f0ed5cd8947c45f2a83e8b98504ed 100644 (file)
@@ -164,7 +164,8 @@ seastar::future<ceph::bufferptr> CyanStore::get_attr(CollectionRef c,
                 __func__, c->cid, oid);
   auto o = c->get_object(oid);
   if (!o) {
-    throw std::runtime_error(fmt::format("object does not exist: {}", oid));
+    return seastar::make_exception_future<ceph::bufferptr>(
+      EnoentException(fmt::format("object does not exist: {}", oid)));
   }
   if (auto found = o->xattr.find(name); found != o->xattr.end()) {
     return seastar::make_ready_future<ceph::bufferptr>(found->second);
index 4315650667de51e59b848f16dfacded4e09db077..56ab6d9abb753cff62c11ed5977357c9db719f77 100644 (file)
@@ -6,8 +6,11 @@
 #include <string>
 #include <unordered_map>
 #include <map>
+#include <typeinfo>
 #include <vector>
+
 #include <seastar/core/future.hh>
+
 #include "osd/osd_types.h"
 #include "include/uuid.h"
 
@@ -26,6 +29,33 @@ class CyanStore {
   uuid_d osd_fsid;
 
 public:
+  template <class ConcreteExceptionT>
+  class Exception : public std::logic_error {
+  public:
+    using std::logic_error::logic_error;
+
+    // Throwing an exception isn't the sole way to signalize an error
+    // with it. This approach nicely fits cold, infrequent issues but
+    // when applied to a hot one (like ENOENT on write path), it will
+    // likely hurt performance.
+    // Alternative approach for hot errors is to create exception_ptr
+    // on our own and place it in the future via make_exception_future.
+    // When ::handle_exception is called, handler would inspect stored
+    // exception whether it's hot-or-cold before rethrowing it.
+    // The main advantage is both types flow through very similar path
+    // based on future::handle_exception.
+    static bool is_class_of(const std::exception_ptr& ep) {
+      // Seastar offers hacks for making throwing lock-less but stack
+      // unwinding still can be a problem so painful to justify going
+      // with non-standard, obscure things like this one.
+      return *ep.__cxa_exception_type() == typeid(ConcreteExceptionT);
+    }
+  };
+
+  struct EnoentException : public Exception<EnoentException> {
+    using Exception<EnoentException>::Exception;
+  };
+
   CyanStore(const std::string& path);
   ~CyanStore();
 
index ec1aa3495bf7e9449df906b0f3476a8527757faf..813f84b4f3b5ba5613539dcdb55375086579ecdc 100644 (file)
@@ -98,11 +98,19 @@ PGBackend::_load_oi(const hobject_t& oid)
   }
   return store->get_attr(coll,
                          ghobject_t{oid, ghobject_t::NO_GEN, shard},
-                         OI_ATTR).then([oid, this](auto bp) {
+                         OI_ATTR).then_wrapped([oid, this](auto fut) {
     auto oi = std::make_unique<object_info_t>();
-    bufferlist bl;
-    bl.push_back(std::move(bp));
-    oi->decode(bl);
+    if (fut.failed()) {
+      auto ep = std::move(fut).get_exception();
+      if (!ceph::os::CyanStore::EnoentException::is_class_of(ep)) {
+        std::rethrow_exception(ep);
+      }
+    } else {
+      // decode existing OI_ATTR's value
+      ceph::bufferlist bl;
+      bl.push_back(std::move(fut).get0());
+      oi->decode(bl);
+    }
     return seastar::make_ready_future<cached_oi_t>(
       oi_cache.insert(oid, std::move(oi)));
   });
@@ -116,10 +124,21 @@ PGBackend::_load_ss(const hobject_t& oid)
   }
   return store->get_attr(coll,
                          ghobject_t{oid, ghobject_t::NO_GEN, shard},
-                         SS_ATTR).then([oid, this](auto bp) {
-    bufferlist bl;
-    bl.push_back(std::move(bp));
-    auto snapset = std::make_unique<SnapSet>(bl);
+                         SS_ATTR).then_wrapped([oid, this](auto fut) {
+    std::unique_ptr<SnapSet> snapset;
+    if (fut.failed()) {
+      auto ep = std::move(fut).get_exception();
+      if (!ceph::os::CyanStore::EnoentException::is_class_of(ep)) {
+        std::rethrow_exception(ep);
+      } else {
+        snapset = std::make_unique<SnapSet>();
+      }
+    } else {
+      // decode existing SS_ATTR's value
+      ceph::bufferlist bl;
+      bl.push_back(std::move(fut).get0());
+      snapset = std::make_unique<SnapSet>(bl);
+    }
     return seastar::make_ready_future<cached_ss_t>(
       ss_cache.insert(oid, std::move(snapset)));
   });