Skip to content

Commit

Permalink
crimson: handle hot CaynStore exceptions without throwing.
Browse files Browse the repository at this point in the history
Signed-off-by: Radoslaw Zarzynski <[email protected]>
  • Loading branch information
rzarzynski authored and tchaikov committed May 7, 2019
1 parent 5d31861 commit c3473cd
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 9 deletions.
3 changes: 2 additions & 1 deletion src/crimson/os/cyan_store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
30 changes: 30 additions & 0 deletions src/crimson/os/cyan_store.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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();

Expand Down
35 changes: 27 additions & 8 deletions src/crimson/osd/pg_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
});
Expand All @@ -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)));
});
Expand Down

0 comments on commit c3473cd

Please sign in to comment.