diff options
Diffstat (limited to 'src/rgw/rgw_cache.h')
-rw-r--r-- | src/rgw/rgw_cache.h | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/rgw/rgw_cache.h b/src/rgw/rgw_cache.h new file mode 100644 index 00000000..b0696237 --- /dev/null +++ b/src/rgw/rgw_cache.h @@ -0,0 +1,219 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_RGWCACHE_H +#define CEPH_RGWCACHE_H + +#include "rgw_rados.h" +#include <string> +#include <map> +#include <unordered_map> +#include "include/types.h" +#include "include/utime.h" +#include "include/ceph_assert.h" +#include "common/RWLock.h" + +enum { + UPDATE_OBJ, + REMOVE_OBJ, +}; + +#define CACHE_FLAG_DATA 0x01 +#define CACHE_FLAG_XATTRS 0x02 +#define CACHE_FLAG_META 0x04 +#define CACHE_FLAG_MODIFY_XATTRS 0x08 +#define CACHE_FLAG_OBJV 0x10 + +#define mydout(v) lsubdout(T::cct, rgw, v) + +struct ObjectMetaInfo { + uint64_t size; + real_time mtime; + + ObjectMetaInfo() : size(0) {} + + void encode(bufferlist& bl) const { + ENCODE_START(2, 2, bl); + encode(size, bl); + encode(mtime, bl); + ENCODE_FINISH(bl); + } + void decode(bufferlist::const_iterator& bl) { + DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl); + decode(size, bl); + decode(mtime, bl); + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + static void generate_test_instances(list<ObjectMetaInfo*>& o); +}; +WRITE_CLASS_ENCODER(ObjectMetaInfo) + +struct ObjectCacheInfo { + int status = 0; + uint32_t flags = 0; + uint64_t epoch = 0; + bufferlist data; + map<string, bufferlist> xattrs; + map<string, bufferlist> rm_xattrs; + ObjectMetaInfo meta; + obj_version version = {}; + ceph::coarse_mono_time time_added; + + ObjectCacheInfo() = default; + + void encode(bufferlist& bl) const { + ENCODE_START(5, 3, bl); + encode(status, bl); + encode(flags, bl); + encode(data, bl); + encode(xattrs, bl); + encode(meta, bl); + encode(rm_xattrs, bl); + encode(epoch, bl); + encode(version, bl); + ENCODE_FINISH(bl); + } + void decode(bufferlist::const_iterator& bl) { + DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl); + decode(status, bl); + decode(flags, bl); + decode(data, bl); + decode(xattrs, bl); + decode(meta, bl); + if (struct_v >= 2) + decode(rm_xattrs, bl); + if (struct_v >= 4) + decode(epoch, bl); + if (struct_v >= 5) + decode(version, bl); + DECODE_FINISH(bl); + } + void dump(Formatter *f) const; + static void generate_test_instances(list<ObjectCacheInfo*>& o); +}; +WRITE_CLASS_ENCODER(ObjectCacheInfo) + +struct RGWCacheNotifyInfo { + uint32_t op; + rgw_raw_obj obj; + ObjectCacheInfo obj_info; + off_t ofs; + string ns; + + RGWCacheNotifyInfo() : op(0), ofs(0) {} + + void encode(bufferlist& obl) const { + ENCODE_START(2, 2, obl); + encode(op, obl); + encode(obj, obl); + encode(obj_info, obl); + encode(ofs, obl); + encode(ns, obl); + ENCODE_FINISH(obl); + } + void decode(bufferlist::const_iterator& ibl) { + DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, ibl); + decode(op, ibl); + decode(obj, ibl); + decode(obj_info, ibl); + decode(ofs, ibl); + decode(ns, ibl); + DECODE_FINISH(ibl); + } + void dump(Formatter *f) const; + static void generate_test_instances(list<RGWCacheNotifyInfo*>& o); +}; +WRITE_CLASS_ENCODER(RGWCacheNotifyInfo) + +class RGWChainedCache { +public: + virtual ~RGWChainedCache() {} + virtual void chain_cb(const string& key, void *data) = 0; + virtual void invalidate(const string& key) = 0; + virtual void invalidate_all() = 0; + virtual void unregistered() {} + + struct Entry { + RGWChainedCache *cache; + const string& key; + void *data; + + Entry(RGWChainedCache *_c, const string& _k, void *_d) : cache(_c), key(_k), data(_d) {} + }; +}; + + +struct ObjectCacheEntry { + ObjectCacheInfo info; + std::list<string>::iterator lru_iter; + uint64_t lru_promotion_ts; + uint64_t gen; + std::vector<pair<RGWChainedCache *, string> > chained_entries; + + ObjectCacheEntry() : lru_promotion_ts(0), gen(0) {} +}; + +class ObjectCache { + std::unordered_map<string, ObjectCacheEntry> cache_map; + std::list<string> lru; + unsigned long lru_size; + unsigned long lru_counter; + unsigned long lru_window; + RWLock lock; + CephContext *cct; + + vector<RGWChainedCache *> chained_cache; + + bool enabled; + ceph::timespan expiry; + + void touch_lru(const string& name, ObjectCacheEntry& entry, + std::list<string>::iterator& lru_iter); + void remove_lru(const string& name, std::list<string>::iterator& lru_iter); + void invalidate_lru(ObjectCacheEntry& entry); + + void do_invalidate_all(); + +public: + ObjectCache() : lru_size(0), lru_counter(0), lru_window(0), lock("ObjectCache"), cct(NULL), enabled(false) { } + ~ObjectCache(); + int get(const std::string& name, ObjectCacheInfo& bl, uint32_t mask, rgw_cache_entry_info *cache_info); + std::optional<ObjectCacheInfo> get(const std::string& name) { + std::optional<ObjectCacheInfo> info{std::in_place}; + auto r = get(name, *info, 0, nullptr); + return r < 0 ? std::nullopt : info; + } + + template<typename F> + void for_each(const F& f) { + RWLock::RLocker l(lock); + if (enabled) { + auto now = ceph::coarse_mono_clock::now(); + for (const auto& [name, entry] : cache_map) { + if (expiry.count() && (now - entry.info.time_added) < expiry) { + f(name, entry); + } + } + } + } + + void put(const std::string& name, ObjectCacheInfo& bl, rgw_cache_entry_info *cache_info); + bool remove(const std::string& name); + void set_ctx(CephContext *_cct) { + cct = _cct; + lru_window = cct->_conf->rgw_cache_lru_size / 2; + expiry = std::chrono::seconds(cct->_conf.get_val<uint64_t>( + "rgw_cache_expiry_interval")); + } + bool chain_cache_entry(std::initializer_list<rgw_cache_entry_info*> cache_info_entries, + RGWChainedCache::Entry *chained_entry); + + void set_enabled(bool status); + + void chain_cache(RGWChainedCache *cache); + void unchain_cache(RGWChainedCache *cache); + void invalidate_all(); +}; + +#endif |