From 382a649fa03626c6cdb40a400af3f5f45fa17a18 Mon Sep 17 00:00:00 2001 From: Samuel Just Date: Wed, 29 May 2019 17:31:53 -0700 Subject: [PATCH] crimson/os/cyan_store: add some omap machinery Adds transaction methods for PeeringState. Mainly omap_set, but also a stub for collection hint and the other omap update methods. Also adds omap_get and debugging to dump the transaction upon encountering a problem. Also fixes up std and ceph::bufferlist namespace qualifications. Signed-off-by: Samuel Just --- src/crimson/os/cyan_store.cc | 261 ++++++++++++++++++++++++++++------- src/crimson/os/cyan_store.h | 38 ++++- 2 files changed, 247 insertions(+), 52 deletions(-) diff --git a/src/crimson/os/cyan_store.cc b/src/crimson/os/cyan_store.cc index 147799b9deb51..eb8aeaf9a9bdb 100644 --- a/src/crimson/os/cyan_store.cc +++ b/src/crimson/os/cyan_store.cc @@ -27,9 +27,9 @@ CyanStore::~CyanStore() = default; seastar::future<> CyanStore::mount() { - bufferlist bl; - string fn = path + "/collections"; - string err; + ceph::bufferlist bl; + std::string fn = path + "/collections"; + std::string err; if (int r = bl.read_file(fn.c_str(), &err); r < 0) { throw std::runtime_error("read_file"); } @@ -39,8 +39,8 @@ seastar::future<> CyanStore::mount() ceph::decode(collections, p); for (auto& coll : collections) { - string fn = fmt::format("{}/{}", path, coll); - bufferlist cbl; + std::string fn = fmt::format("{}/{}", path, coll); + ceph::bufferlist cbl; if (int r = cbl.read_file(fn.c_str(), &err); r < 0) { throw std::runtime_error("read_file"); } @@ -55,20 +55,20 @@ seastar::future<> CyanStore::mount() seastar::future<> CyanStore::umount() { - set collections; + std::set collections; for (auto& [col, ch] : coll_map) { collections.insert(col); - bufferlist bl; + ceph::bufferlist bl; ceph_assert(ch); ch->encode(bl); - string fn = fmt::format("{}/{}", path, col); + std::string fn = fmt::format("{}/{}", path, col); if (int r = bl.write_file(fn.c_str()); r < 0) { throw std::runtime_error("write_file"); } } - string fn = path + "/collections"; - bufferlist bl; + std::string fn = path + "/collections"; + ceph::bufferlist bl; ceph::encode(collections, bl); if (int r = bl.write_file(fn.c_str()); r < 0) { throw std::runtime_error("write_file"); @@ -78,7 +78,7 @@ seastar::future<> CyanStore::umount() seastar::future<> CyanStore::mkfs() { - string fsid_str; + std::string fsid_str; int r = read_meta("fsid", &fsid_str); if (r == -ENOENT) { osd_fsid.generate_random(); @@ -92,9 +92,9 @@ seastar::future<> CyanStore::mkfs() } } - string fn = path + "/collections"; - bufferlist bl; - set collections; + std::string fn = path + "/collections"; + ceph::bufferlist bl; + std::set collections; ceph::encode(collections, bl); r = bl.write_file(fn.c_str()); if (r < 0) @@ -152,7 +152,7 @@ std::vector CyanStore::list_collections() return collections; } -seastar::future CyanStore::read(CollectionRef c, +seastar::future CyanStore::read(CollectionRef c, const ghobject_t& oid, uint64_t offset, size_t len, @@ -168,17 +168,17 @@ seastar::future CyanStore::read(CollectionRef c, throw std::runtime_error(fmt::format("object does not exist: {}", oid)); } if (offset >= o->get_size()) - return seastar::make_ready_future(); + return seastar::make_ready_future(); size_t l = len; if (l == 0 && offset == 0) // note: len == 0 means read the entire object l = o->get_size(); else if (offset + l > o->get_size()) l = o->get_size() - offset; - bufferlist bl; + ceph::bufferlist bl; if (int r = o->read(offset, l, bl); r < 0) { throw std::runtime_error("read"); } - return seastar::make_ready_future(std::move(bl)); + return seastar::make_ready_future(std::move(bl)); } seastar::future CyanStore::get_attr(CollectionRef c, @@ -232,42 +232,68 @@ CyanStore::omap_get_values(CollectionRef c, return seastar::make_ready_future(std::move(values)); } +seastar::future +CyanStore::omap_get_values( + CollectionRef c, + const ghobject_t &oid, + const std::optional &start + ) { + logger().debug( + "{} {} {}", + __func__, c->cid, oid); + auto o = c->get_object(oid); + if (!o) { + throw std::runtime_error(fmt::format("object does not exist: {}", oid)); + } + omap_values_t values; + for (auto i = start ? o->omap.upper_bound(*start) : o->omap.begin(); + values.size() < MAX_KEYS_PER_OMAP_GET_CALL && i != o->omap.end(); + ++i) { + values.insert(*i); + } + return seastar::make_ready_future( + true, values); +} + seastar::future<> CyanStore::do_transaction(CollectionRef ch, Transaction&& t) { - auto i = t.begin(); - while (i.have_op()) { - Transaction::Op* op = i.decode_op(); - int r = 0; - switch (op->op) { - case Transaction::OP_NOP: - break; - case Transaction::OP_REMOVE: + int r = 0; + try { + auto i = t.begin(); + while (i.have_op()) { + Transaction::Op* op = i.decode_op(); + r = 0; + switch (op->op) { + case Transaction::OP_NOP: + break; + case Transaction::OP_REMOVE: { - coll_t cid = i.get_cid(op->cid); - ghobject_t oid = i.get_oid(op->oid); - r = _remove(cid, oid); + coll_t cid = i.get_cid(op->cid); + ghobject_t oid = i.get_oid(op->oid); + r = _remove(cid, oid); } - case Transaction::OP_TOUCH: + break; + case Transaction::OP_TOUCH: { coll_t cid = i.get_cid(op->cid); ghobject_t oid = i.get_oid(op->oid); r = _touch(cid, oid); } break; - case Transaction::OP_WRITE: + case Transaction::OP_WRITE: { coll_t cid = i.get_cid(op->cid); ghobject_t oid = i.get_oid(op->oid); uint64_t off = op->off; uint64_t len = op->len; uint32_t fadvise_flags = i.get_fadvise_flags(); - bufferlist bl; + ceph::bufferlist bl; i.decode_bl(bl); r = _write(cid, oid, off, len, bl, fadvise_flags); } break; - case Transaction::OP_TRUNCATE: + case Transaction::OP_TRUNCATE: { coll_t cid = i.get_cid(op->cid); ghobject_t oid = i.get_oid(op->oid); @@ -275,31 +301,90 @@ seastar::future<> CyanStore::do_transaction(CollectionRef ch, r = _truncate(cid, oid, off); } break; - case Transaction::OP_SETATTR: + case Transaction::OP_SETATTR: { coll_t cid = i.get_cid(op->cid); ghobject_t oid = i.get_oid(op->oid); - string name = i.decode_string(); - bufferlist bl; + std::string name = i.decode_string(); + ceph::bufferlist bl; i.decode_bl(bl); - map to_set; + std::map to_set; to_set[name] = bufferptr(bl.c_str(), bl.length()); r = _setattrs(cid, oid, to_set); } break; - case Transaction::OP_MKCOLL: + case Transaction::OP_MKCOLL: { coll_t cid = i.get_cid(op->cid); r = _create_collection(cid, op->split_bits); } break; - default: - logger().error("bad op {}", static_cast(op->op)); - abort(); - } - if (r < 0) { - abort(); + case Transaction::OP_OMAP_SETKEYS: + { + coll_t cid = i.get_cid(op->cid); + ghobject_t oid = i.get_oid(op->oid); + std::map aset; + i.decode_attrset(aset); + r = _omap_set_values(cid, oid, std::move(aset)); + } + break; + case Transaction::OP_OMAP_SETHEADER: + { + const coll_t &cid = i.get_cid(op->cid); + const ghobject_t &oid = i.get_oid(op->oid); + ceph::bufferlist bl; + i.decode_bl(bl); + r = _omap_set_header(cid, oid, bl); + } + break; + case Transaction::OP_OMAP_RMKEYS: + { + const coll_t &cid = i.get_cid(op->cid); + const ghobject_t &oid = i.get_oid(op->oid); + std::set keys; + i.decode_keyset(keys); + r = _omap_rmkeys(cid, oid, keys); + } + break; + case Transaction::OP_OMAP_RMKEYRANGE: + { + const coll_t &cid = i.get_cid(op->cid); + const ghobject_t &oid = i.get_oid(op->oid); + string first, last; + first = i.decode_string(); + last = i.decode_string(); + r = _omap_rmkeyrange(cid, oid, first, last); + } + break; + case Transaction::OP_COLL_HINT: + { + ceph::bufferlist hint; + i.decode_bl(hint); + // ignored + break; + } + default: + logger().error("bad op {}", static_cast(op->op)); + abort(); + } + if (r < 0) { + break; + } } + } catch (std::exception &e) { + logger().error("{} got exception {}", __func__, e); + r = -EINVAL; + } + if (r < 0) { + logger().error(" transaction dump:\n"); + JSONFormatter f(true); + f.open_object_section("transaction"); + t.dump(&f); + f.close_section(); + std::stringstream str; + f.flush(str); + logger().error("{}", str.str()); + ceph_assert(r == 0); } return seastar::now(); } @@ -334,7 +419,7 @@ int CyanStore::_touch(const coll_t& cid, const ghobject_t& oid) } int CyanStore::_write(const coll_t& cid, const ghobject_t& oid, - uint64_t offset, size_t len, const bufferlist& bl, + uint64_t offset, size_t len, const ceph::bufferlist& bl, uint32_t fadvise_flags) { logger().debug("{} {} {} {} ~ {}", @@ -355,6 +440,85 @@ int CyanStore::_write(const coll_t& cid, const ghobject_t& oid, return 0; } +int CyanStore::_omap_set_values( + const coll_t& cid, + const ghobject_t& oid, + std::map &&aset) +{ + logger().debug( + "{} {} {} {} keys", + __func__, cid, oid, aset.size()); + + auto c = open_collection(cid); + if (!c) + return -ENOENT; + + ObjectRef o = c->get_or_create_object(oid); + for (auto &&i: aset) { + o->omap.insert(std::move(i)); + } + return 0; +} + +int CyanStore::_omap_set_header( + const coll_t& cid, + const ghobject_t& oid, + const ceph::bufferlist &header) +{ + logger().debug( + "{} {} {} {} bytes", + __func__, cid, oid, header.length()); + + auto c = open_collection(cid); + if (!c) + return -ENOENT; + + ObjectRef o = c->get_or_create_object(oid); + o->omap_header = header; + return 0; +} + +int CyanStore::_omap_rmkeys( + const coll_t& cid, + const ghobject_t& oid, + const std::set &aset) +{ + logger().debug( + "{} {} {} {} keys", + __func__, cid, oid, aset.size()); + + auto c = open_collection(cid); + if (!c) + return -ENOENT; + + ObjectRef o = c->get_or_create_object(oid); + for (auto &i: aset) { + o->omap.erase(i); + } + return 0; +} + +int CyanStore::_omap_rmkeyrange( + const coll_t& cid, + const ghobject_t& oid, + const std::string &first, + const std::string &last) +{ + logger().debug( + "{} {} {} first={} last={}", + __func__, cid, oid, first, last); + + auto c = open_collection(cid); + if (!c) + return -ENOENT; + + ObjectRef o = c->get_or_create_object(oid); + for (auto i = o->omap.lower_bound(first); + i != o->omap.end() && i->first <= last; + o->omap.erase(i++)); + return 0; +} + int CyanStore::_truncate(const coll_t& cid, const ghobject_t& oid, uint64_t size) { logger().debug("{} cid={} oid={} size={}", @@ -373,7 +537,7 @@ int CyanStore::_truncate(const coll_t& cid, const ghobject_t& oid, uint64_t size } int CyanStore::_setattrs(const coll_t& cid, const ghobject_t& oid, - map& aset) + std::map& aset) { logger().debug("{} cid={} oid={}", __func__, cid, oid); @@ -384,7 +548,8 @@ int CyanStore::_setattrs(const coll_t& cid, const ghobject_t& oid, ObjectRef o = c->get_object(oid); if (!o) return -ENOENT; - for (map::const_iterator p = aset.begin(); p != aset.end(); ++p) + for (std::map::const_iterator p = aset.begin(); + p != aset.end(); ++p) o->xattr[p->first] = p->second; return 0; } @@ -427,7 +592,7 @@ int CyanStore::read_meta(const std::string& key, while (r && isspace(buf[r-1])) { --r; } - *value = string{buf, static_cast(r)}; + *value = std::string{buf, static_cast(r)}; return 0; } diff --git a/src/crimson/os/cyan_store.h b/src/crimson/os/cyan_store.h index 411ec7d179bf3..0faed53342db2 100644 --- a/src/crimson/os/cyan_store.h +++ b/src/crimson/os/cyan_store.h @@ -9,6 +9,7 @@ #include #include +#include #include #include "crimson/os/cyan_collection.h" @@ -22,6 +23,8 @@ class Transaction; // a just-enough store for reading/writing the superblock class CyanStore { + constexpr static unsigned MAX_KEYS_PER_OMAP_GET_CALL = 32; + const std::string path; std::unordered_map coll_map; std::map new_coll_map; @@ -63,7 +66,7 @@ public: seastar::future<> umount(); seastar::future<> mkfs(); - seastar::future read(CollectionRef c, + seastar::future read(CollectionRef c, const ghobject_t& oid, uint64_t offset, size_t len, @@ -73,16 +76,26 @@ public: std::string_view name); using attrs_t = std::map>; seastar::future get_attrs(CollectionRef c, const ghobject_t& oid); - using omap_values_t = std::map>; + + using omap_values_t = std::map>; seastar::future omap_get_values( CollectionRef c, const ghobject_t& oid, std::vector&& keys); + seastar::future, ghobject_t> list_objects( CollectionRef c, const ghobject_t& start, const ghobject_t& end, uint64_t limit); + + /// Retrieves paged set of values > start (if present) + seastar::future omap_get_values( + CollectionRef c, ///< [in] collection + const ghobject_t &oid, ///< [in] oid + const std::optional &start ///< [in] start, empty for begin + ); ///< @return values.empty() iff done + CollectionRef create_new_collection(const coll_t& cid); CollectionRef open_collection(const coll_t& cid); std::vector list_collections(); @@ -99,11 +112,28 @@ private: int _remove(const coll_t& cid, const ghobject_t& oid); int _touch(const coll_t& cid, const ghobject_t& oid); int _write(const coll_t& cid, const ghobject_t& oid, - uint64_t offset, size_t len, const bufferlist& bl, + uint64_t offset, size_t len, const ceph::bufferlist& bl, uint32_t fadvise_flags); + int _omap_set_values( + const coll_t& cid, + const ghobject_t& oid, + std::map &&aset); + int _omap_set_header( + const coll_t& cid, + const ghobject_t& oid, + const ceph::bufferlist &header); + int _omap_rmkeys( + const coll_t& cid, + const ghobject_t& oid, + const std::set &aset); + int _omap_rmkeyrange( + const coll_t& cid, + const ghobject_t& oid, + const std::string &first, + const std::string &last); int _truncate(const coll_t& cid, const ghobject_t& oid, uint64_t size); int _setattrs(const coll_t& cid, const ghobject_t& oid, - map& aset); + std::map& aset); int _create_collection(const coll_t& cid, int bits); }; -- 2.39.5