Option("debug_deliberately_leak_memory", Option::TYPE_BOOL, Option::LEVEL_DEV)
.set_default(false)
.set_description(""),
-
+
Option("debug_asserts_on_shutdown", Option::TYPE_BOOL,Option::LEVEL_DEV)
.set_default(false)
.set_description("Enable certain asserts to check for refcounting bugs on shutdown; see http://tracker.ceph.com/issues/21738"),
Option("rgw_reshard_thread_interval", Option::TYPE_UINT, Option::LEVEL_ADVANCED)
.set_default(10_min)
.set_description(""),
+
+ Option("rgw_bucket_info_cache_expiry_interval", Option::TYPE_UINT,
+ Option::LEVEL_ADVANCED)
+ .set_default(15_min)
+ .set_description("Number of seconds before entries in the bucket info "
+ "cache are assumed stale and re-fetched. Zero is never.")
+ .add_tag("performance")
+ .add_service("rgw")
+ .set_long_description("The Rados Gateway stores metadata about buckets in "
+ "an internal cache. This should be kept consistent "
+ "by the OSD's relaying notify events between "
+ "multiple watching RGW processes. In the event "
+ "that this notification protocol fails, bounding "
+ "the length of time that any data in the cache will "
+ "be assumed valid will ensure that any RGW instance "
+ "that falls out of sync will eventually recover. "
+ "This seems to be an issue mostly for large numbers "
+ "of RGW instances under heavy use. If you would like "
+ "to turn off cache expiry, set this value to zero."),
+
});
}
template <class T>
class RGWChainedCacheImpl : public RGWChainedCache {
+ ceph::timespan expiry;
RWLock lock;
- map<string, T> entries;
+ map<string, std::pair<T, ceph::coarse_mono_time>> entries;
public:
RGWChainedCacheImpl() : lock("RGWChainedCacheImpl::lock") {}
void init(RGWRados *store) {
store->register_chained_cache(this);
+ expiry = std::chrono::seconds(store->ctx()->_conf->get_val<uint64_t>(
+ "rgw_bucket_info_cache_expiry_interval"));
}
bool find(const string& key, T *entry) {
RWLock::RLocker rl(lock);
- typename map<string, T>::iterator iter = entries.find(key);
+ auto iter = entries.find(key);
if (iter == entries.end()) {
return false;
}
+ if (expiry.count() &&
+ (ceph::coarse_mono_clock::now() - iter->second.second) > expiry) {
+ return false;
+ }
- *entry = iter->second;
+ *entry = iter->second.first;
return true;
}
void chain_cb(const string& key, void *data) override {
T *entry = static_cast<T *>(data);
RWLock::WLocker wl(lock);
- entries[key] = *entry;
+ entries[key].first = *entry;
+ if (expiry.count() > 0) {
+ entries[key].second = ceph::coarse_mono_clock::now();
+ }
}
void invalidate(const string& key) override {