diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/common/hobject.h | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/common/hobject.h | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/src/common/hobject.h b/src/common/hobject.h new file mode 100644 index 000000000..34191ccf5 --- /dev/null +++ b/src/common/hobject.h @@ -0,0 +1,515 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef __CEPH_OS_HOBJECT_H +#define __CEPH_OS_HOBJECT_H + +#if FMT_VERSION >= 90000 +#include <fmt/ostream.h> +#endif + +#include "include/types.h" + +#include "json_spirit/json_spirit_value.h" +#include "include/ceph_assert.h" // spirit clobbers it! + +#include "reverse.h" + +namespace ceph { + class Formatter; +} + +#ifndef UINT64_MAX +#define UINT64_MAX (18446744073709551615ULL) +#endif +#ifndef INT64_MIN +#define INT64_MIN ((int64_t)0x8000000000000000ll) +#endif + +struct hobject_t { +public: + static const int64_t POOL_META = -1; + static const int64_t POOL_TEMP_START = -2; // and then negative + + static bool is_temp_pool(int64_t pool) { + return pool <= POOL_TEMP_START; + } + static int64_t get_temp_pool(int64_t pool) { + return POOL_TEMP_START - pool; + } + static bool is_meta_pool(int64_t pool) { + return pool == POOL_META; + } + +public: + object_t oid; + snapid_t snap; +private: + uint32_t hash; + bool max; + uint32_t nibblewise_key_cache; + uint32_t hash_reverse_bits; +public: + int64_t pool; + std::string nspace; + +private: + std::string key; + + class hobject_t_max {}; + +public: + const std::string& get_key() const { + return key; + } + + void set_key(const std::string& key_) { + if (key_ == oid.name) + key.clear(); + else + key = key_; + } + + std::string to_str() const; + + uint32_t get_hash() const { + return hash; + } + void set_hash(uint32_t value) { + hash = value; + build_hash_cache(); + } + + static bool match_hash(uint32_t to_check, uint32_t bits, uint32_t match) { + return (match & ~((~0)<<bits)) == (to_check & ~((~0)<<bits)); + } + bool match(uint32_t bits, uint32_t match) const { + return match_hash(hash, bits, match); + } + + bool is_temp() const { + return is_temp_pool(pool) && pool != INT64_MIN; + } + bool is_meta() const { + return is_meta_pool(pool); + } + int64_t get_logical_pool() const { + if (is_temp_pool(pool)) + return get_temp_pool(pool); // it's reversible + else + return pool; + } + + hobject_t() : snap(0), hash(0), max(false), pool(INT64_MIN) { + build_hash_cache(); + } + + hobject_t(const hobject_t &rhs) = default; + hobject_t(hobject_t &&rhs) = default; + hobject_t(hobject_t_max &&singleton) : hobject_t() { + max = true; + } + hobject_t &operator=(const hobject_t &rhs) = default; + hobject_t &operator=(hobject_t &&rhs) = default; + hobject_t &operator=(hobject_t_max &&singleton) { + *this = hobject_t(); + max = true; + return *this; + } + + // maximum sorted value. + static hobject_t_max get_max() { + return hobject_t_max(); + } + + hobject_t(const object_t& oid, const std::string& key, snapid_t snap, + uint32_t hash, int64_t pool, const std::string& nspace) + : oid(oid), snap(snap), hash(hash), max(false), + pool(pool), nspace(nspace), + key(oid.name == key ? std::string() : key) { + build_hash_cache(); + } + + hobject_t(const sobject_t &soid, const std::string &key, uint32_t hash, + int64_t pool, const std::string& nspace) + : oid(soid.oid), snap(soid.snap), hash(hash), max(false), + pool(pool), nspace(nspace), + key(soid.oid.name == key ? std::string() : key) { + build_hash_cache(); + } + + // used by Crimson + hobject_t(const std::string &key, snapid_t snap, uint32_t reversed_hash, + int64_t pool, const std::string& nspace) + : oid(key), snap(snap), max(false), pool(pool), nspace(nspace) { + set_bitwise_key_u32(reversed_hash); + } + + /// @return min hobject_t ret s.t. ret.hash == this->hash + hobject_t get_boundary() const { + if (is_max()) + return *this; + hobject_t ret; + ret.set_hash(hash); + ret.pool = pool; + return ret; + } + + hobject_t get_object_boundary() const { + if (is_max()) + return *this; + hobject_t ret = *this; + ret.snap = 0; + return ret; + } + + /// @return head version of this hobject_t + hobject_t get_head() const { + hobject_t ret(*this); + ret.snap = CEPH_NOSNAP; + return ret; + } + + /// @return snapdir version of this hobject_t + hobject_t get_snapdir() const { + hobject_t ret(*this); + ret.snap = CEPH_SNAPDIR; + return ret; + } + + /// @return true if object is snapdir + bool is_snapdir() const { + return snap == CEPH_SNAPDIR; + } + + /// @return true if object is head + bool is_head() const { + return snap == CEPH_NOSNAP; + } + + /// @return true if object is neither head nor snapdir nor max + bool is_snap() const { + return !is_max() && !is_head() && !is_snapdir(); + } + + /// @return true iff the object should have a snapset in it's attrs + bool has_snapset() const { + return is_head() || is_snapdir(); + } + + /* Do not use when a particular hash function is needed */ + explicit hobject_t(const sobject_t &o) : + oid(o.oid), snap(o.snap), max(false), pool(POOL_META) { + set_hash(std::hash<sobject_t>()(o)); + } + + bool is_max() const { + ceph_assert(!max || (*this == hobject_t(hobject_t::get_max()))); + return max; + } + bool is_min() const { + // this needs to match how it's constructed + return snap == 0 && + hash == 0 && + !max && + pool == INT64_MIN; + } + + static uint32_t _reverse_bits(uint32_t v) { + return reverse_bits(v); + } + static uint32_t _reverse_nibbles(uint32_t retval) { + return reverse_nibbles(retval); + } + + /** + * Returns set S of strings such that for any object + * h where h.match(bits, mask), there is some string + * s \f$\in\f$ S such that s is a prefix of h.to_str(). + * Furthermore, for any s \f$\in\f$ S, s is a prefix of + * h.str() implies that h.match(bits, mask). + */ + static std::set<std::string> get_prefixes( + uint32_t bits, + uint32_t mask, + int64_t pool); + + // filestore nibble-based key + uint32_t get_nibblewise_key_u32() const { + ceph_assert(!max); + return nibblewise_key_cache; + } + uint64_t get_nibblewise_key() const { + return max ? 0x100000000ull : nibblewise_key_cache; + } + + // newer bit-reversed key + uint32_t get_bitwise_key_u32() const { + ceph_assert(!max); + return hash_reverse_bits; + } + uint64_t get_bitwise_key() const { + return max ? 0x100000000ull : hash_reverse_bits; + } + + // please remember to update set_bitwise_key_u32() also + // once you change build_hash_cache() + void build_hash_cache() { + nibblewise_key_cache = _reverse_nibbles(hash); + hash_reverse_bits = _reverse_bits(hash); + } + void set_bitwise_key_u32(uint32_t value) { + hash = _reverse_bits(value); + // below is identical to build_hash_cache() and shall be + // updated correspondingly if you change build_hash_cache() + nibblewise_key_cache = _reverse_nibbles(hash); + hash_reverse_bits = value; + } + + const std::string& get_effective_key() const { + if (key.length()) + return key; + return oid.name; + } + + hobject_t make_temp_hobject(const std::string& name) const { + return hobject_t(object_t(name), "", CEPH_NOSNAP, + hash, + get_temp_pool(pool), + ""); + } + + void swap(hobject_t &o) { + hobject_t temp(o); + o = (*this); + (*this) = temp; + } + + const std::string &get_namespace() const { + return nspace; + } + + bool parse(const std::string& s); + + void encode(ceph::buffer::list& bl) const; + void decode(ceph::bufferlist::const_iterator& bl); + void decode(json_spirit::Value& v); + void dump(ceph::Formatter *f) const; + static void generate_test_instances(std::list<hobject_t*>& o); + friend int cmp(const hobject_t& l, const hobject_t& r); + auto operator<=>(const hobject_t &rhs) const noexcept { + auto cmp = max <=> rhs.max; + if (cmp != 0) return cmp; + cmp = pool <=> rhs.pool; + if (cmp != 0) return cmp; + cmp = get_bitwise_key() <=> rhs.get_bitwise_key(); + if (cmp != 0) return cmp; + cmp = nspace <=> rhs.nspace; + if (cmp != 0) return cmp; + if (!(get_key().empty() && rhs.get_key().empty())) { + cmp = get_effective_key() <=> rhs.get_effective_key(); + if (cmp != 0) return cmp; + } + cmp = oid <=> rhs.oid; + if (cmp != 0) return cmp; + return snap <=> rhs.snap; + } + bool operator==(const hobject_t& rhs) const noexcept { + return operator<=>(rhs) == 0; + } + friend struct ghobject_t; +}; +WRITE_CLASS_ENCODER(hobject_t) + +namespace std { +template<> struct hash<hobject_t> { + size_t operator()(const hobject_t &r) const { + static rjhash<uint64_t> RJ; + return RJ(r.get_hash() ^ r.snap); + } +}; +} // namespace std + +std::ostream& operator<<(std::ostream& out, const hobject_t& o); + +template <typename T> +struct always_false { + using value = std::false_type; +}; + +template <typename T> +inline bool operator==(const hobject_t &lhs, const T&) { + static_assert(always_false<T>::value::value, "Do not compare to get_max()"); + return lhs.is_max(); +} +template <typename T> +inline bool operator==(const T&, const hobject_t &rhs) { + static_assert(always_false<T>::value::value, "Do not compare to get_max()"); + return rhs.is_max(); +} +template <typename T> +inline bool operator!=(const hobject_t &lhs, const T&) { + static_assert(always_false<T>::value::value, "Do not compare to get_max()"); + return !lhs.is_max(); +} +template <typename T> +inline bool operator!=(const T&, const hobject_t &rhs) { + static_assert(always_false<T>::value::value, "Do not compare to get_max()"); + return !rhs.is_max(); +} + +extern int cmp(const hobject_t& l, const hobject_t& r); +template <typename T> +static inline int cmp(const hobject_t &l, const T&) { + static_assert(always_false<T>::value::value, "Do not compare to get_max()"); + return l.is_max() ? 0 : -1; +} +template <typename T> +static inline int cmp(const T&, const hobject_t&r) { + static_assert(always_false<T>::value::value, "Do not compare to get_max()"); + return r.is_max() ? 0 : 1; +} + + + +typedef version_t gen_t; + +struct ghobject_t { + static const gen_t NO_GEN = UINT64_MAX; + + bool max = false; + shard_id_t shard_id = shard_id_t::NO_SHARD; + hobject_t hobj; + gen_t generation = NO_GEN; + + ghobject_t() = default; + + explicit ghobject_t(const hobject_t &obj) + : hobj(obj) {} + + ghobject_t(const hobject_t &obj, gen_t gen, shard_id_t shard) + : shard_id(shard), + hobj(obj), + generation(gen) {} + + // used by Crimson + ghobject_t(shard_id_t shard, int64_t pool, uint32_t reversed_hash, + const std::string& nspace, const std::string& oid, + snapid_t snap, gen_t gen) + : shard_id(shard), + hobj(oid, snap, reversed_hash, pool, nspace), + generation(gen) {} + + static ghobject_t make_pgmeta(int64_t pool, uint32_t hash, shard_id_t shard) { + hobject_t h(object_t(), std::string(), CEPH_NOSNAP, hash, pool, std::string()); + return ghobject_t(h, NO_GEN, shard); + } + bool is_pgmeta() const { + // make sure we are distinct from hobject_t(), which has pool INT64_MIN + return hobj.pool >= 0 && hobj.oid.name.empty(); + } + + bool match(uint32_t bits, uint32_t match) const { + return hobj.match_hash(hobj.hash, bits, match); + } + /// @return min ghobject_t ret s.t. ret.hash == this->hash + ghobject_t get_boundary() const { + if (hobj.is_max()) + return *this; + ghobject_t ret; + ret.hobj.set_hash(hobj.hash); + ret.shard_id = shard_id; + ret.hobj.pool = hobj.pool; + return ret; + } + uint32_t get_nibblewise_key_u32() const { + return hobj.get_nibblewise_key_u32(); + } + uint32_t get_nibblewise_key() const { + return hobj.get_nibblewise_key(); + } + + bool is_degenerate() const { + return generation == NO_GEN && shard_id == shard_id_t::NO_SHARD; + } + + bool is_no_gen() const { + return generation == NO_GEN; + } + + bool is_no_shard() const { + return shard_id == shard_id_t::NO_SHARD; + } + + void set_shard(shard_id_t s) { + shard_id = s; + } + + bool parse(const std::string& s); + + // maximum sorted value. + static ghobject_t get_max() { + ghobject_t h; + h.max = true; + h.hobj = hobject_t::get_max(); // so that is_max() => hobj.is_max() + return h; + } + bool is_max() const { + return max; + } + bool is_min() const { + return *this == ghobject_t(); + } + + void swap(ghobject_t &o) { + ghobject_t temp(o); + o = (*this); + (*this) = temp; + } + + void encode(ceph::buffer::list& bl) const; + void decode(ceph::buffer::list::const_iterator& bl); + void decode(json_spirit::Value& v); + size_t encoded_size() const; + void dump(ceph::Formatter *f) const; + static void generate_test_instances(std::list<ghobject_t*>& o); + friend int cmp(const ghobject_t& l, const ghobject_t& r); + auto operator<=>(const ghobject_t&) const = default; + bool operator==(const ghobject_t&) const = default; +}; +WRITE_CLASS_ENCODER(ghobject_t) + +namespace std { + template<> struct hash<ghobject_t> { + size_t operator()(const ghobject_t &r) const { + static rjhash<uint64_t> RJ; + static hash<hobject_t> HO; + size_t hash = HO(r.hobj); + hash = RJ(hash ^ r.generation); + hash = hash ^ r.shard_id.id; + return hash; + } + }; +} // namespace std + +std::ostream& operator<<(std::ostream& out, const ghobject_t& o); + +#if FMT_VERSION >= 90000 +template <> struct fmt::formatter<ghobject_t> : fmt::ostream_formatter {}; +#endif + +extern int cmp(const ghobject_t& l, const ghobject_t& r); + + +#endif |