// -*- 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 #include #include #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& o); }; WRITE_CLASS_ENCODER(ObjectMetaInfo) struct ObjectCacheInfo { int status = 0; uint32_t flags = 0; uint64_t epoch = 0; bufferlist data; map xattrs; map 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& 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& 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::iterator lru_iter; uint64_t lru_promotion_ts; uint64_t gen; std::vector > chained_entries; ObjectCacheEntry() : lru_promotion_ts(0), gen(0) {} }; class ObjectCache { std::unordered_map cache_map; std::list lru; unsigned long lru_size; unsigned long lru_counter; unsigned long lru_window; RWLock lock; CephContext *cct; vector chained_cache; bool enabled; ceph::timespan expiry; void touch_lru(const string& name, ObjectCacheEntry& entry, std::list::iterator& lru_iter); void remove_lru(const string& name, std::list::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 get(const std::string& name) { std::optional info{std::in_place}; auto r = get(name, *info, 0, nullptr); return r < 0 ? std::nullopt : info; } template 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( "rgw_cache_expiry_interval")); } bool chain_cache_entry(std::initializer_list 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