summaryrefslogtreecommitdiffstats
path: root/src/tools/immutable_object_cache/SimplePolicy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/immutable_object_cache/SimplePolicy.cc')
-rw-r--r--src/tools/immutable_object_cache/SimplePolicy.cc216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/tools/immutable_object_cache/SimplePolicy.cc b/src/tools/immutable_object_cache/SimplePolicy.cc
new file mode 100644
index 000000000..3a7375ba9
--- /dev/null
+++ b/src/tools/immutable_object_cache/SimplePolicy.cc
@@ -0,0 +1,216 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "common/debug.h"
+#include "SimplePolicy.h"
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_immutable_obj_cache
+#undef dout_prefix
+#define dout_prefix *_dout << "ceph::cache::SimplePolicy: " << this << " " \
+ << __func__ << ": "
+
+namespace ceph {
+namespace immutable_obj_cache {
+
+SimplePolicy::SimplePolicy(CephContext *cct, uint64_t cache_size,
+ uint64_t max_inflight, double watermark)
+ : cct(cct), m_watermark(watermark), m_max_inflight_ops(max_inflight),
+ m_max_cache_size(cache_size) {
+
+ ldout(cct, 20) << "max cache size= " << m_max_cache_size
+ << " ,watermark= " << m_watermark
+ << " ,max inflight ops= " << m_max_inflight_ops << dendl;
+
+ m_cache_size = 0;
+
+}
+
+SimplePolicy::~SimplePolicy() {
+ ldout(cct, 20) << dendl;
+
+ for (auto it : m_cache_map) {
+ Entry* entry = (it.second);
+ delete entry;
+ }
+}
+
+cache_status_t SimplePolicy::alloc_entry(std::string file_name) {
+ ldout(cct, 20) << "alloc entry for: " << file_name << dendl;
+
+ std::unique_lock wlocker{m_cache_map_lock};
+
+ // cache hit when promoting
+ if (m_cache_map.find(file_name) != m_cache_map.end()) {
+ ldout(cct, 20) << "object is under promoting: " << file_name << dendl;
+ return OBJ_CACHE_SKIP;
+ }
+
+ if ((m_cache_size < m_max_cache_size) &&
+ (inflight_ops < m_max_inflight_ops)) {
+ Entry* entry = new Entry();
+ ceph_assert(entry != nullptr);
+ m_cache_map[file_name] = entry;
+ wlocker.unlock();
+ update_status(file_name, OBJ_CACHE_SKIP);
+ return OBJ_CACHE_NONE; // start promotion request
+ }
+
+ // if there's no free entry, return skip to read from rados
+ return OBJ_CACHE_SKIP;
+}
+
+cache_status_t SimplePolicy::lookup_object(std::string file_name) {
+ ldout(cct, 20) << "lookup: " << file_name << dendl;
+
+ std::shared_lock rlocker{m_cache_map_lock};
+
+ auto entry_it = m_cache_map.find(file_name);
+ // simply promote on first lookup
+ if (entry_it == m_cache_map.end()) {
+ rlocker.unlock();
+ return alloc_entry(file_name);
+ }
+
+ Entry* entry = entry_it->second;
+
+ if (entry->status == OBJ_CACHE_PROMOTED || entry->status == OBJ_CACHE_DNE) {
+ // bump pos in lru on hit
+ m_promoted_lru.lru_touch(entry);
+ }
+
+ return entry->status;
+}
+
+void SimplePolicy::update_status(std::string file_name,
+ cache_status_t new_status, uint64_t size) {
+ ldout(cct, 20) << "update status for: " << file_name
+ << " new status = " << new_status << dendl;
+
+ std::unique_lock locker{m_cache_map_lock};
+
+ auto entry_it = m_cache_map.find(file_name);
+ if (entry_it == m_cache_map.end()) {
+ return;
+ }
+
+ ceph_assert(entry_it != m_cache_map.end());
+ Entry* entry = entry_it->second;
+
+ // to promote
+ if (entry->status == OBJ_CACHE_NONE && new_status== OBJ_CACHE_SKIP) {
+ entry->status = new_status;
+ entry->file_name = file_name;
+ inflight_ops++;
+ return;
+ }
+
+ // promoting done
+ if (entry->status == OBJ_CACHE_SKIP && (new_status== OBJ_CACHE_PROMOTED ||
+ new_status== OBJ_CACHE_DNE)) {
+ m_promoted_lru.lru_insert_top(entry);
+ entry->status = new_status;
+ entry->size = size;
+ m_cache_size += entry->size;
+ inflight_ops--;
+ return;
+ }
+
+ // promoting failed
+ if (entry->status == OBJ_CACHE_SKIP && new_status== OBJ_CACHE_NONE) {
+ // mark this entry as free
+ entry->file_name = "";
+ entry->status = new_status;
+
+ m_cache_map.erase(entry_it);
+ inflight_ops--;
+ delete entry;
+ return;
+ }
+
+ // to evict
+ if ((entry->status == OBJ_CACHE_PROMOTED || entry->status == OBJ_CACHE_DNE) &&
+ new_status== OBJ_CACHE_NONE) {
+ // mark this entry as free
+ uint64_t size = entry->size;
+ entry->file_name = "";
+ entry->size = 0;
+ entry->status = new_status;
+
+ m_promoted_lru.lru_remove(entry);
+ m_cache_map.erase(entry_it);
+ m_cache_size -= size;
+ delete entry;
+ return;
+ }
+}
+
+int SimplePolicy::evict_entry(std::string file_name) {
+ ldout(cct, 20) << "to evict: " << file_name << dendl;
+
+ update_status(file_name, OBJ_CACHE_NONE);
+
+ return 0;
+}
+
+cache_status_t SimplePolicy::get_status(std::string file_name) {
+ ldout(cct, 20) << file_name << dendl;
+
+ std::shared_lock locker{m_cache_map_lock};
+ auto entry_it = m_cache_map.find(file_name);
+ if (entry_it == m_cache_map.end()) {
+ return OBJ_CACHE_NONE;
+ }
+
+ return entry_it->second->status;
+}
+
+void SimplePolicy::get_evict_list(std::list<std::string>* obj_list) {
+ ldout(cct, 20) << dendl;
+
+ std::unique_lock locker{m_cache_map_lock};
+ // check free ratio, pop entries from LRU
+ if ((double)m_cache_size > m_max_cache_size * m_watermark) {
+ // TODO(dehao): make this configurable
+ int evict_num = m_cache_map.size() * 0.1;
+ for (int i = 0; i < evict_num; i++) {
+ Entry* entry = reinterpret_cast<Entry*>(m_promoted_lru.lru_expire());
+ if (entry == nullptr) {
+ continue;
+ }
+ std::string file_name = entry->file_name;
+ obj_list->push_back(file_name);
+ }
+ }
+}
+
+// for unit test
+uint64_t SimplePolicy::get_free_size() {
+ return m_max_cache_size - m_cache_size;
+}
+
+uint64_t SimplePolicy::get_promoting_entry_num() {
+ uint64_t index = 0;
+ std::shared_lock rlocker{m_cache_map_lock};
+ for (auto it : m_cache_map) {
+ if (it.second->status == OBJ_CACHE_SKIP) {
+ index++;
+ }
+ }
+ return index;
+}
+
+uint64_t SimplePolicy::get_promoted_entry_num() {
+ return m_promoted_lru.lru_get_size();
+}
+
+std::string SimplePolicy::get_evict_entry() {
+ Entry* entry = reinterpret_cast<Entry*>(m_promoted_lru.lru_get_next_expire());
+ if (entry == nullptr) {
+ return "";
+ }
+ return entry->file_name;
+}
+
+} // namespace immutable_obj_cache
+} // namespace ceph