class TestSimplePolicy :public ::testing::Test {
public:
SimplePolicy* m_simple_policy;
- const uint64_t m_entry_num;
+ const uint64_t m_cache_size;
uint64_t m_entry_index;
std::vector<std::string> m_promoted_lru;
std::vector<std::string> m_promoting_lru;
- TestSimplePolicy() : m_entry_num(100), m_entry_index(0) {}
+ TestSimplePolicy() : m_cache_size(100), m_entry_index(0) {}
~TestSimplePolicy() {}
static void SetUpTestCase() {}
static void TearDownTestCase() {}
void SetUp() override {
- m_simple_policy = new SimplePolicy(g_ceph_context, m_entry_num, 0.1);
- for (uint64_t i = 0; i < m_entry_num / 2; i++, m_entry_index++) {
+ m_simple_policy = new SimplePolicy(g_ceph_context, m_cache_size, 0.1);
+ // populate 50 entries
+ for (uint64_t i = 0; i < m_cache_size / 2; i++, m_entry_index++) {
insert_entry_into_promoted_lru(generate_file_name(m_entry_index));
}
}
}
void insert_entry_into_promoted_lru(std::string cache_file_name) {
- ASSERT_EQ(m_entry_num - m_promoted_lru.size() - m_promoting_lru.size(), m_simple_policy->get_free_entry_num());
+ ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size());
ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num());
ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num());
ASSERT_EQ(OBJ_CACHE_NONE, m_simple_policy->get_status(cache_file_name));
m_simple_policy->lookup_object(cache_file_name);
ASSERT_EQ(OBJ_CACHE_SKIP, m_simple_policy->get_status(cache_file_name));
- ASSERT_EQ(m_entry_num - m_promoted_lru.size() - m_promoting_lru.size() - 1, m_simple_policy->get_free_entry_num());
+ ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size());
ASSERT_EQ(m_promoting_lru.size() + 1, m_simple_policy->get_promoting_entry_num());
ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num());
- m_simple_policy->update_status(cache_file_name, OBJ_CACHE_PROMOTED);
+ m_simple_policy->update_status(cache_file_name, OBJ_CACHE_PROMOTED, 1);
m_promoted_lru.push_back(cache_file_name);
ASSERT_EQ(OBJ_CACHE_PROMOTED, m_simple_policy->get_status(cache_file_name));
- ASSERT_EQ(m_entry_num - m_promoted_lru.size() - m_promoting_lru.size(), m_simple_policy->get_free_entry_num());
+ ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size());
ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num());
ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num());
}
void insert_entry_into_promoting_lru(std::string cache_file_name) {
- ASSERT_EQ(m_entry_num - m_promoted_lru.size() - m_promoting_lru.size(), m_simple_policy->get_free_entry_num());
+ ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size());
ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num());
ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num());
ASSERT_EQ(OBJ_CACHE_NONE, m_simple_policy->get_status(cache_file_name));
m_simple_policy->lookup_object(cache_file_name);
m_promoting_lru.push_back(cache_file_name);
ASSERT_EQ(OBJ_CACHE_SKIP, m_simple_policy->get_status(cache_file_name));
- ASSERT_EQ(m_entry_num - m_promoted_lru.size() - m_promoting_lru.size(), m_simple_policy->get_free_entry_num());
+ ASSERT_EQ(m_cache_size - m_promoted_lru.size(), m_simple_policy->get_free_size());
ASSERT_EQ(m_promoting_lru.size(), m_simple_policy->get_promoting_entry_num());
ASSERT_EQ(m_promoted_lru.size(), m_simple_policy->get_promoted_entry_num());
}
TEST_F(TestSimplePolicy, test_lookup_miss_and_no_free) {
// exhaust cache space
- uint64_t left_entry_num = m_entry_num - m_promoted_lru.size() - m_promoting_lru.size();
- for(uint64_t i = 0; i < left_entry_num; i++, ++m_entry_index) {
+ uint64_t left_entry_num = m_cache_size - m_promoted_lru.size();
+ for (uint64_t i = 0; i < left_entry_num; i++, ++m_entry_index) {
insert_entry_into_promoted_lru(generate_file_name(m_entry_index));
}
- ASSERT_TRUE(0 == m_simple_policy->get_free_entry_num());
+ ASSERT_TRUE(0 == m_simple_policy->get_free_size());
ASSERT_TRUE(m_simple_policy->lookup_object("no_this_cache_file_name") == OBJ_CACHE_SKIP);
}
-TEST_F(TestSimplePolicy, test_lookup_miss_and_free_space) {
- ASSERT_TRUE(m_entry_num - m_promoting_lru.size() - m_promoted_lru.size() == m_simple_policy->get_free_entry_num());
+TEST_F(TestSimplePolicy, test_lookup_miss_and_have_free) {
+ ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size());
ASSERT_TRUE(m_simple_policy->lookup_object("miss_but_have_free_space_file_name") == OBJ_CACHE_NONE);
ASSERT_TRUE(m_simple_policy->get_status("miss_but_have_free_space_file_name") == OBJ_CACHE_SKIP);
}
TEST_F(TestSimplePolicy, test_lookup_hit_and_promoting) {
- ASSERT_TRUE(m_entry_num - m_promoting_lru.size() - m_promoted_lru.size() == m_simple_policy->get_free_entry_num());
+ ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size());
insert_entry_into_promoting_lru("promoting_file_1");
insert_entry_into_promoting_lru("promoting_file_2");
insert_entry_into_promoted_lru(generate_file_name(++m_entry_index));
TEST_F(TestSimplePolicy, test_lookup_hit_and_promoted) {
ASSERT_TRUE(m_promoted_lru.size() == m_simple_policy->get_promoted_entry_num());
- for(uint64_t index = 0; index < m_entry_index; index++) {
+ for (uint64_t index = 0; index < m_entry_index; index++) {
ASSERT_TRUE(m_simple_policy->get_status(generate_file_name(index)) == OBJ_CACHE_PROMOTED);
}
}
TEST_F(TestSimplePolicy, test_update_state_from_promoting_to_none) {
- ASSERT_TRUE(m_entry_num - m_promoting_lru.size() - m_promoted_lru.size() == m_simple_policy->get_free_entry_num());
+ ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size());
insert_entry_into_promoting_lru("promoting_to_none_file_1");
insert_entry_into_promoting_lru("promoting_to_none_file_2");
insert_entry_into_promoted_lru(generate_file_name(++m_entry_index));
TEST_F(TestSimplePolicy, test_update_state_from_promoted_to_none) {
ASSERT_TRUE(m_promoted_lru.size() == m_simple_policy->get_promoted_entry_num());
- for(uint64_t index = 0; index < m_entry_index; index++) {
+ for (uint64_t index = 0; index < m_entry_index; index++) {
ASSERT_TRUE(m_simple_policy->get_status(generate_file_name(index)) == OBJ_CACHE_PROMOTED);
m_simple_policy->update_status(generate_file_name(index), OBJ_CACHE_NONE);
ASSERT_TRUE(m_simple_policy->get_status(generate_file_name(index)) == OBJ_CACHE_NONE);
}
TEST_F(TestSimplePolicy, test_update_state_from_promoting_to_promoted) {
- ASSERT_TRUE(m_entry_num - m_promoting_lru.size() - m_promoted_lru.size() == m_simple_policy->get_free_entry_num());
+ ASSERT_TRUE(m_cache_size - m_promoted_lru.size() == m_simple_policy->get_free_size());
insert_entry_into_promoting_lru("promoting_to_promoted_file_1");
insert_entry_into_promoting_lru("promoting_to_promoted_file_2");
insert_entry_into_promoting_lru("promoting_to_promoted_file_3");
TEST_F(TestSimplePolicy, test_evict_list_0) {
std::list<std::string> evict_entry_list;
// 0.1 is watermark
- ASSERT_TRUE((float)m_simple_policy->get_free_entry_num() > m_entry_num*0.1);
+ ASSERT_TRUE((float)m_simple_policy->get_free_size() > m_cache_size*0.1);
m_simple_policy->get_evict_list(&evict_entry_list);
ASSERT_TRUE(evict_entry_list.size() == 0);
}
TEST_F(TestSimplePolicy, test_evict_list_10) {
- uint64_t left_entry_num = m_entry_num - m_promoted_lru.size() - m_promoting_lru.size();
- for(uint64_t i = 0; i < left_entry_num; i++, ++m_entry_index) {
+ uint64_t left_entry_num = m_cache_size - m_promoted_lru.size();
+ for (uint64_t i = 0; i < left_entry_num; i++, ++m_entry_index) {
insert_entry_into_promoted_lru(generate_file_name(m_entry_index));
}
- ASSERT_TRUE(0 == m_simple_policy->get_free_entry_num());
+ ASSERT_TRUE(0 == m_simple_policy->get_free_size());
std::list<std::string> evict_entry_list;
m_simple_policy->get_evict_list(&evict_entry_list);
- ASSERT_TRUE(10 == evict_entry_list.size());
- ASSERT_TRUE(m_entry_num - 10 == m_simple_policy->get_promoted_entry_num());
+ // evict 10% of old entries
+ ASSERT_TRUE(m_cache_size*0.1 == evict_entry_list.size());
+ ASSERT_TRUE(m_cache_size - m_cache_size*0.1 == m_simple_policy->get_promoted_entry_num());
- for(auto it = evict_entry_list.begin(); it != evict_entry_list.end(); it++) {
+ for (auto it = evict_entry_list.begin(); it != evict_entry_list.end(); it++) {
ASSERT_TRUE(*it == m_promoted_lru.front());
m_promoted_lru.erase(m_promoted_lru.begin());
}
namespace ceph {
namespace immutable_obj_cache {
-SimplePolicy::SimplePolicy(CephContext *cct, uint64_t block_num,
+SimplePolicy::SimplePolicy(CephContext *cct, uint64_t cache_size,
float watermark)
- : cct(cct), m_watermark(watermark), m_entry_count(block_num),
- m_cache_map_lock("rbd::cache::SimplePolicy::m_cache_map_lock"),
- m_free_list_lock("rbd::cache::SimplePolicy::m_free_list_lock") {
+ : cct(cct), m_watermark(watermark), m_max_cache_size(cache_size),
+ m_cache_map_lock("rbd::cache::SimplePolicy::m_cache_map_lock") {
ldout(cct, 20) << dendl;
m_max_inflight_ops = cct->_conf.get_val<uint64_t>("immutable_object_cache_max_inflight_ops");
- for(uint64_t i = 0; i < m_entry_count; i++) {
- m_free_list.push_back(new Entry());
- }
+ m_cache_size = 0;
}
SimplePolicy::~SimplePolicy() {
ldout(cct, 20) << dendl;
for (auto it: m_cache_map) {
- Entry* entry = reinterpret_cast<Entry*>(it.second);
+ Entry* entry = (it.second);
delete entry;
}
- for(auto it : m_free_list) {
- Entry* entry = it;
- delete entry;
- }
+
}
cache_status_t SimplePolicy::alloc_entry(std::string file_name) {
ldout(cct, 20) << "object is under promoting: " << file_name << dendl;
return OBJ_CACHE_SKIP;
}
- m_free_list_lock.lock();
- if (m_free_list.size() && (inflight_ops < m_max_inflight_ops)) {
- Entry* entry = m_free_list.front();
+ if ((m_cache_size < m_max_cache_size) && (inflight_ops < m_max_inflight_ops)) {
+ Entry* entry = new Entry();
ceph_assert(entry != nullptr);
- m_free_list.pop_front();
- m_free_list_lock.unlock();
m_cache_map[file_name] = entry;
wlocker.unlock();
update_status(file_name, OBJ_CACHE_SKIP);
return OBJ_CACHE_NONE; // start promotion request
}
- m_free_list_lock.unlock();
// if there's no free entry, return skip to read from rados
return OBJ_CACHE_SKIP;
}
}
void SimplePolicy::update_status(std::string file_name,
- cache_status_t new_status) {
+ cache_status_t new_status, uint64_t size) {
ldout(cct, 20) << "update status for: " << file_name
<< " new status = " << new_status << dendl;
if (entry->status == OBJ_CACHE_SKIP && new_status== OBJ_CACHE_PROMOTED) {
m_promoted_lru.lru_insert_top(entry);
entry->status = new_status;
+ entry->size = size;
+ m_cache_size += entry->size;
inflight_ops--;
return;
}
// mark this entry as free
entry->file_name = "";
entry->status = new_status;
- {
- Mutex::Locker free_list_locker(m_free_list_lock);
- m_free_list.push_back(entry);
- }
+
m_cache_map.erase(entry_it);
inflight_ops--;
return;
// to evict
if (entry->status == OBJ_CACHE_PROMOTED && 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;
- {
- Mutex::Locker free_list_locker(m_free_list_lock);
- m_free_list.push_back(entry);
- }
+
m_promoted_lru.lru_remove(entry);
m_cache_map.erase(entry_it);
+ m_cache_size -= size;
return;
}
RWLock::WLocker locker(m_cache_map_lock);
// check free ratio, pop entries from LRU
- if ((float)m_free_list.size() / m_entry_count < m_watermark) {
- int evict_num = m_entry_count * 0.1; //TODO(): make this configurable
+ if ((double)m_cache_size / m_max_cache_size > (1 - m_watermark)) {
+ int evict_num = m_cache_map.size() * 0.1; //TODO(): make this configurable
for (int i = 0; i < evict_num; i++) {
Entry* entry = reinterpret_cast<Entry*>(m_promoted_lru.lru_expire());
if (entry == nullptr) {
}
// for unit test
-uint64_t SimplePolicy::get_free_entry_num() {
- Mutex::Locker free_list_locker(m_free_list_lock);
- return m_free_list.size();
+uint64_t SimplePolicy::get_free_size() {
+ return m_max_cache_size - m_cache_size;
}
uint64_t SimplePolicy::get_promoting_entry_num() {