diff --git a/src/common/lru_cache.h b/src/common/lru_cache.h index 484e166a6b..7345af89c7 100644 --- a/src/common/lru_cache.h +++ b/src/common/lru_cache.h @@ -204,7 +204,7 @@ class LRUCache : public LRUCacheInterface { void Remove(const K &key) override; /* - * @brief Get the first key that $value = value + * @brief Get the first key that $value = value from lru tail to head * * @param[in] value * @param[out] key @@ -429,10 +429,7 @@ void LRUCache::RemoveLocked(const K &key) { template void LRUCache::MoveToFront( const typename std::list::iterator &elem) { - Item duplica{elem->key, elem->value}; - ll_.erase(elem); - ll_.push_front(duplica); - cache_[*(duplica.key)] = ll_.begin(); + ll_.splice(ll_.begin(), ll_, elem); } template @@ -699,16 +696,8 @@ bool SglLRUCache::MoveBack(const K &key) { if (iter == cache_.end()) { return false; } - // delete the old value - RemoveElement(iter->second); - // put new value at tail - ll_.push_back(key); - cache_[key] = --ll_.end(); - size_++; - if (cacheMetrics_ != nullptr) { - cacheMetrics_->UpdateAddToCacheCount(); - cacheMetrics_->UpdateAddToCacheBytes(KeyTraits::CountBytes(key)); - } + // move key to list tail + ll_.splice(ll_.end(), ll_, iter->second); return true; } @@ -806,10 +795,7 @@ void SglLRUCache::RemoveLocked(const K &key) { template void SglLRUCache::MoveToFront( const typename std::list::iterator &elem) { - K tmp = *elem; - ll_.erase(elem); - ll_.emplace_front(tmp); - cache_[tmp] = ll_.begin(); + ll_.splice(ll_.begin(), ll_, elem); } template diff --git a/test/common/lru_cache_test.cpp b/test/common/lru_cache_test.cpp index a5e9d65e19..518ff3e61a 100644 --- a/test/common/lru_cache_test.cpp +++ b/test/common/lru_cache_test.cpp @@ -212,6 +212,53 @@ TEST(CaCheTest, TestCacheGetLastKVWithFunction) { ASSERT_EQ(false, ok); } +TEST(CaCheTest, TestCachePromotion) { + auto cache = std::make_shared>( + std::make_shared("LruCache")); + + int k, v; + for (int k = 0; k < 5; k++) { + v = k; + cache->Put(k, v); + } + ASSERT_EQ(cache->Size(), 5); + // now cache list: 4 3 2 1 0 + + for (int k = 0; k < 5; k += 2) { + cache->Get(k, &v); + ASSERT_EQ(k, v); + } + // now cache list: 4 2 0 3 1 + + cache->GetLast(&k, &v); + cache->Remove(k); + ASSERT_EQ(1, k); + ASSERT_EQ(1, v); + + cache->GetLast(&k, &v); + cache->Remove(k); + ASSERT_EQ(3, k); + ASSERT_EQ(3, v); + + cache->GetLast(&k, &v); + cache->Remove(k); + ASSERT_EQ(0, k); + ASSERT_EQ(0, v); + + cache->GetLast(&k, &v); + cache->Remove(k); + ASSERT_EQ(2, k); + ASSERT_EQ(2, v); + + cache->GetLast(&k, &v); + cache->Remove(k); + ASSERT_EQ(4, k); + ASSERT_EQ(4, v); + + ASSERT_EQ(0, cache->GetCacheMetrics()->cacheCount.get_value()); + ASSERT_EQ(0, cache->Size()); +} + TEST(SglCaCheTest, TestGetBefore) { auto cache = std::make_shared>( std::make_shared("LruCache")); @@ -302,6 +349,85 @@ TEST(SglCaCheTest, TestCacheHitAndMissMetric) { ASSERT_EQ(10, cache->GetCacheMetrics()->cacheMiss.get_value()); } +TEST(SglCaCheTest, TestCachePromotionAndDemotion) { + auto cache = std::make_shared>( + std::make_shared("LruCache")); + + // test promotion + { + int k; + for (int k = 0; k < 5; k++) { + cache->Put(k); + } + // now cache list: 4 3 2 1 0 + + for (int k = 0; k < 5; k += 2) { + ASSERT_EQ(cache->IsCached(k), true); + } + // now cache list: 4 2 0 3 1 + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(1, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(3, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(0, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(2, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(4, k); + + ASSERT_EQ(0, cache->GetCacheMetrics()->cacheCount.get_value()); + } + + // test demotion + { + int k; + for (int k = 0; k < 5; k++) { + cache->Put(k); + } + // now cache list: 4 3 2 1 0 + + ASSERT_EQ(cache->MoveBack(10), false); + for (int k = 4; k >= 0; k -= 2) { + ASSERT_EQ(cache->MoveBack(k), true); + } + // now cache list: 3 1 4 2 0 + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(0, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(2, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(4, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(1, k); + + cache->GetBack(&k); + cache->Remove(k); + ASSERT_EQ(3, k); + + ASSERT_EQ(0, cache->GetCacheMetrics()->cacheCount.get_value()); + ASSERT_EQ(0, cache->Size()); + } +} + TEST(TimedCaCheTest, test_base) { int maxCount = 5; int timeOutSec = 0; @@ -328,6 +454,12 @@ TEST(TimedCaCheTest, test_base) { ASSERT_TRUE(cache->Get(std::to_string(i), &res)); ASSERT_EQ(std::to_string(i), res); } + + // remove + for (int i = 2; i <= maxCount + 1; i++) { + cache->Remove(std::to_string(i)); + } + ASSERT_EQ(0, cache->Size()); } TEST(TimedCaCheTest, test_timeout) {