__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);
#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"
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();
}
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)));
});
}
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)));
});