This is an automated email from the ASF dual-hosted git repository.

zhangchen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new e5f884a6fc [enhancement](cache) make segment cache prune more 
effectively (#17011)
e5f884a6fc is described below

commit e5f884a6fc2d08996dfc04d27898889d772a091b
Author: zhannngchen <48427519+zhannngc...@users.noreply.github.com>
AuthorDate: Thu Feb 23 18:24:18 2023 +0800

    [enhancement](cache) make segment cache prune more effectively (#17011)
    
    BloomFilter in MoW table may consume lots of memory, and it's life cycle is 
same as segment. This patch try to improve the efficiency of recycling segment 
cache, to release the memory in time.
---
 be/src/common/config.h          |  2 +-
 be/src/olap/lru_cache.cpp       | 10 ++++++---
 be/src/olap/lru_cache.h         |  6 ++---
 be/src/olap/segment_loader.cpp  |  3 ++-
 be/test/olap/lru_cache_test.cpp | 50 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/be/src/common/config.h b/be/src/common/config.h
index d3e5ecd2d2..2058dbbc14 100644
--- a/be/src/common/config.h
+++ b/be/src/common/config.h
@@ -220,7 +220,7 @@ 
CONF_mInt64(memory_limitation_per_thread_for_schema_change_bytes, "2147483648");
 CONF_mInt64(memory_limitation_per_thread_for_storage_migration_bytes, 
"100000000");
 
 // the clean interval of file descriptor cache and segment cache
-CONF_mInt32(cache_clean_interval, "1800");
+CONF_mInt32(cache_clean_interval, "60");
 // the clean interval of tablet lookup cache
 CONF_mInt32(tablet_lookup_cache_clean_interval, "30");
 CONF_mInt32(disk_stat_monitor_interval, "5");
diff --git a/be/src/olap/lru_cache.cpp b/be/src/olap/lru_cache.cpp
index 00dff82d1f..cbce38da1b 100644
--- a/be/src/olap/lru_cache.cpp
+++ b/be/src/olap/lru_cache.cpp
@@ -464,7 +464,7 @@ int64_t LRUCache::prune() {
     return pruned_count;
 }
 
-int64_t LRUCache::prune_if(CacheValuePredicate pred) {
+int64_t LRUCache::prune_if(CacheValuePredicate pred, bool lazy_mode) {
     LRUHandle* to_remove_head = nullptr;
     {
         std::lock_guard l(_mutex);
@@ -475,6 +475,8 @@ int64_t LRUCache::prune_if(CacheValuePredicate pred) {
                 _evict_one_entry(p);
                 p->next = to_remove_head;
                 to_remove_head = p;
+            } else if (lazy_mode) {
+                break;
             }
             p = next;
         }
@@ -486,6 +488,8 @@ int64_t LRUCache::prune_if(CacheValuePredicate pred) {
                 _evict_one_entry(p);
                 p->next = to_remove_head;
                 to_remove_head = p;
+            } else if (lazy_mode) {
+                break;
             }
             p = next;
         }
@@ -613,10 +617,10 @@ int64_t ShardedLRUCache::prune() {
     return num_prune;
 }
 
-int64_t ShardedLRUCache::prune_if(CacheValuePredicate pred) {
+int64_t ShardedLRUCache::prune_if(CacheValuePredicate pred, bool lazy_mode) {
     int64_t num_prune = 0;
     for (int s = 0; s < _num_shards; s++) {
-        num_prune += _shards[s]->prune_if(pred);
+        num_prune += _shards[s]->prune_if(pred, lazy_mode);
     }
     return num_prune;
 }
diff --git a/be/src/olap/lru_cache.h b/be/src/olap/lru_cache.h
index 50749db662..1913321df3 100644
--- a/be/src/olap/lru_cache.h
+++ b/be/src/olap/lru_cache.h
@@ -221,7 +221,7 @@ public:
     // Same as prune(), but the entry will only be pruned if the predicate 
matched.
     // NOTICE: the predicate should be simple enough, or the prune_if() 
function
     // may hold lock for a long time to execute predicate.
-    virtual int64_t prune_if(CacheValuePredicate pred) { return 0; }
+    virtual int64_t prune_if(CacheValuePredicate pred, bool lazy_mode = false) 
{ return 0; }
 
     virtual int64_t mem_consumption() = 0;
 
@@ -339,7 +339,7 @@ public:
     void release(Cache::Handle* handle);
     void erase(const CacheKey& key, uint32_t hash);
     int64_t prune();
-    int64_t prune_if(CacheValuePredicate pred);
+    int64_t prune_if(CacheValuePredicate pred, bool lazy_mode = false);
 
     void set_cache_value_time_extractor(CacheValueTimeExtractor 
cache_value_time_extractor);
     void set_cache_value_check_timestamp(bool cache_value_check_timestamp);
@@ -409,7 +409,7 @@ public:
     Slice value_slice(Handle* handle) override;
     virtual uint64_t new_id() override;
     virtual int64_t prune() override;
-    virtual int64_t prune_if(CacheValuePredicate pred) override;
+    int64_t prune_if(CacheValuePredicate pred, bool lazy_mode = false) 
override;
     int64_t mem_consumption() override;
 
 private:
diff --git a/be/src/olap/segment_loader.cpp b/be/src/olap/segment_loader.cpp
index 3e604adf17..fa1e6c8751 100644
--- a/be/src/olap/segment_loader.cpp
+++ b/be/src/olap/segment_loader.cpp
@@ -97,7 +97,8 @@ Status SegmentLoader::prune() {
 
     MonotonicStopWatch watch;
     watch.start();
-    int64_t prune_num = _cache->prune_if(pred);
+    // Prune cache in lazy mode to save cpu and minimize the time holding 
write lock
+    int64_t prune_num = _cache->prune_if(pred, true);
     LOG(INFO) << "prune " << prune_num
               << " entries in segment cache. cost(ms): " << 
watch.elapsed_time() / 1000 / 1000;
     return Status::OK();
diff --git a/be/test/olap/lru_cache_test.cpp b/be/test/olap/lru_cache_test.cpp
index c779996c54..83604a26bb 100644
--- a/be/test/olap/lru_cache_test.cpp
+++ b/be/test/olap/lru_cache_test.cpp
@@ -314,6 +314,56 @@ TEST_F(CacheTest, Prune) {
     EXPECT_EQ(0, cache.get_usage());
 }
 
+TEST_F(CacheTest, PruneIfLazyMode) {
+    LRUCache cache(LRUCacheType::NUMBER);
+    cache.set_capacity(10);
+
+    // The lru usage is 1, add one entry
+    CacheKey key1("100");
+    insert_LRUCache(cache, key1, 100, CachePriority::NORMAL);
+    EXPECT_EQ(1, cache.get_usage());
+
+    CacheKey key2("200");
+    insert_LRUCache(cache, key2, 200, CachePriority::DURABLE);
+    EXPECT_EQ(2, cache.get_usage());
+
+    CacheKey key3("300");
+    insert_LRUCache(cache, key3, 300, CachePriority::NORMAL);
+    EXPECT_EQ(3, cache.get_usage());
+
+    CacheKey key4("666");
+    insert_LRUCache(cache, key4, 666, CachePriority::NORMAL);
+    EXPECT_EQ(4, cache.get_usage());
+
+    CacheKey key5("500");
+    insert_LRUCache(cache, key5, 500, CachePriority::NORMAL);
+    EXPECT_EQ(5, cache.get_usage());
+
+    CacheKey key6("600");
+    insert_LRUCache(cache, key6, 600, CachePriority::NORMAL);
+    EXPECT_EQ(6, cache.get_usage());
+
+    CacheKey key7("700");
+    insert_LRUCache(cache, key7, 700, CachePriority::DURABLE);
+    EXPECT_EQ(7, cache.get_usage());
+
+    auto pred = [](const void* value) -> bool { return false; };
+    cache.prune_if(pred, true);
+    EXPECT_EQ(7, cache.get_usage());
+
+    // in lazy mode, the first item not satisfied the pred2, `prune_if` then 
stopped
+    // and no item's removed.
+    auto pred2 = [](const void* value) -> bool { return 
DecodeValue((void*)value) > 400; };
+    cache.prune_if(pred2, true);
+    EXPECT_EQ(7, cache.get_usage());
+
+    // in normal priority, 100, 300 are removed
+    // in durable priority, 200 is removed
+    auto pred3 = [](const void* value) -> bool { return 
DecodeValue((void*)value) <= 600; };
+    EXPECT_EQ(3, cache.prune_if(pred3, true));
+    EXPECT_EQ(4, cache.get_usage());
+}
+
 TEST_F(CacheTest, HeavyEntries) {
     // Add a bunch of light and heavy entries and then count the combined
     // size of items still in the cache, which must be approximately the


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to