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

eldenmoon 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 e24ab70e921 [improve](tablet schema) opt TabletIndex mem (#48273)
e24ab70e921 is described below

commit e24ab70e921d2076559c3d406381efbaf8f41fe0
Author: lihangyu <lihan...@selectdb.com>
AuthorDate: Wed Mar 5 15:11:09 2025 +0800

    [improve](tablet schema) opt TabletIndex mem (#48273)
    
    Reuse TabletIndex like TabletColumn
    
    related PR #42448
---
 be/src/olap/tablet_column_object_pool.cpp       |  73 ++++++++---
 be/src/olap/tablet_column_object_pool.h         |  17 ++-
 be/src/olap/tablet_schema.cpp                   |  80 +++++++-----
 be/src/olap/tablet_schema.h                     |  18 +--
 be/src/olap/tablet_schema_cache.cpp             |   2 +-
 be/test/olap/tablet_column_object_pool_test.cpp | 166 ++++++++++++++++++++++++
 6 files changed, 291 insertions(+), 65 deletions(-)

diff --git a/be/src/olap/tablet_column_object_pool.cpp 
b/be/src/olap/tablet_column_object_pool.cpp
index 6e07fb4e831..db9a20639c9 100644
--- a/be/src/olap/tablet_column_object_pool.cpp
+++ b/be/src/olap/tablet_column_object_pool.cpp
@@ -26,32 +26,67 @@ namespace doris {
 
 bvar::Adder<int64_t> g_tablet_column_cache_count("tablet_column_cache_count");
 bvar::Adder<int64_t> 
g_tablet_column_cache_hit_count("tablet_column_cache_hit_count");
+bvar::Adder<int64_t> g_tablet_index_cache_count("tablet_index_cache_count");
+bvar::Adder<int64_t> 
g_tablet_index_cache_hit_count("tablet_index_cache_hit_count");
+
+template <typename T, typename CacheValueType>
+std::pair<Cache::Handle*, std::shared_ptr<T>> insert_impl(
+        TabletColumnObjectPool* pool, const std::string& key, const char* 
type_name,
+        bvar::Adder<int64_t>& cache_counter, bvar::Adder<int64_t>& hit_counter,
+        std::function<void(std::shared_ptr<T>, const std::string&)> 
init_from_pb) {
+    auto* lru_handle = pool->lookup(key);
+    std::shared_ptr<T> obj_ptr;
 
-std::pair<Cache::Handle*, TabletColumnPtr> 
TabletColumnObjectPool::insert(const std::string& key) {
-    auto* lru_handle = lookup(key);
-    TabletColumnPtr tablet_column_ptr;
     if (lru_handle) {
-        auto* value = (CacheValue*)LRUCachePolicy::value(lru_handle);
-        tablet_column_ptr = value->tablet_column;
-        VLOG_DEBUG << "reuse column ";
-        g_tablet_column_cache_hit_count << 1;
+        auto* value = 
reinterpret_cast<CacheValueType*>(pool->value(lru_handle));
+        obj_ptr = value->value;
+        VLOG_DEBUG << "reuse " << type_name;
+        hit_counter << 1;
     } else {
-        auto* value = new CacheValue;
-        tablet_column_ptr = std::make_shared<TabletColumn>();
-        ColumnPB pb;
-        pb.ParseFromString(key);
-        tablet_column_ptr->init_from_pb(pb);
-        VLOG_DEBUG << "create column ";
-        value->tablet_column = tablet_column_ptr;
-        lru_handle = LRUCachePolicy::insert(key, value, 1, 0, 
CachePriority::NORMAL);
-        g_tablet_column_cache_count << 1;
+        auto* value = new CacheValueType;
+        obj_ptr = std::make_shared<T>();
+        init_from_pb(obj_ptr, key);
+        VLOG_DEBUG << "create " << type_name;
+        value->value = obj_ptr;
+        lru_handle = pool->LRUCachePolicy::insert(key, value, 1, 0, 
CachePriority::NORMAL);
+        cache_counter << 1;
     }
+
     DCHECK(lru_handle != nullptr);
-    return {lru_handle, tablet_column_ptr};
+    return {lru_handle, obj_ptr};
+}
+
+std::pair<Cache::Handle*, TabletColumnPtr> 
TabletColumnObjectPool::insert(const std::string& key) {
+    return insert_impl<TabletColumn, CacheValue>(this, key, "column", 
g_tablet_column_cache_count,
+                                                 
g_tablet_column_cache_hit_count,
+                                                 [](auto&& column, auto&& key) 
{
+                                                     ColumnPB pb;
+                                                     pb.ParseFromString(key);
+                                                     column->init_from_pb(pb);
+                                                 });
 }
 
-TabletColumnObjectPool::CacheValue::~CacheValue() {
-    g_tablet_column_cache_count << -1;
+std::pair<Cache::Handle*, TabletIndexPtr> TabletColumnObjectPool::insert_index(
+        const std::string& key) {
+    return insert_impl<TabletIndex, IndexCacheValue>(this, key, "index", 
g_tablet_index_cache_count,
+                                                     
g_tablet_index_cache_hit_count,
+                                                     [](auto&& index, auto&& 
key) {
+                                                         TabletIndexPB 
index_pb;
+                                                         
index_pb.ParseFromString(key);
+                                                         
index->init_from_pb(index_pb);
+                                                     });
 }
 
+template <typename T>
+TabletColumnObjectPool::BaseCacheValue<T>::BaseCacheValue::~BaseCacheValue() {
+    if constexpr (std::is_same_v<T, TabletColumn>) {
+        g_tablet_column_cache_count << -1;
+    } else {
+        g_tablet_index_cache_count << -1;
+    }
+}
+
+template struct TabletColumnObjectPool::BaseCacheValue<TabletColumn>;
+template struct TabletColumnObjectPool::BaseCacheValue<TabletIndex>;
+
 } // namespace doris
diff --git a/be/src/olap/tablet_column_object_pool.h 
b/be/src/olap/tablet_column_object_pool.h
index 1eead6a25c9..998ba7a9aa4 100644
--- a/be/src/olap/tablet_column_object_pool.h
+++ b/be/src/olap/tablet_column_object_pool.h
@@ -24,8 +24,8 @@
 
 namespace doris {
 
-// TabletColumnObjectPool is a cache for TabletColumn objects. It is used to 
reduce memory consumption
-// when there are a large number of identical TabletColumns in the cluster, 
which usually occurs
+// TabletColumnObjectPool is a cache for TabletColumn/TabletIndex objects. It 
is used to reduce memory consumption
+// when there are a large number of identical TabletColumns/TabletIndex in the 
cluster, which usually occurs
 // when VARIANT type columns are modified and added, each Rowset has an 
individual TabletSchema.
 // Excessive TabletSchemas can lead to significant memory overhead. Reusing 
memory for identical
 // TabletColumns would greatly reduce this memory consumption.
@@ -47,12 +47,17 @@ public:
 
     std::pair<Cache::Handle*, TabletColumnPtr> insert(const std::string& key);
 
+    std::pair<Cache::Handle*, TabletIndexPtr> insert_index(const std::string& 
key);
+
 private:
-    class CacheValue : public LRUCacheValueBase {
-    public:
-        ~CacheValue() override;
-        TabletColumnPtr tablet_column;
+    template <typename T>
+    struct BaseCacheValue : public LRUCacheValueBase {
+        ~BaseCacheValue() override;
+        std::shared_ptr<T> value;
     };
+
+    using CacheValue = BaseCacheValue<TabletColumn>;
+    using IndexCacheValue = BaseCacheValue<TabletIndex>;
 };
 
 } // namespace doris
diff --git a/be/src/olap/tablet_schema.cpp b/be/src/olap/tablet_schema.cpp
index 51e5a8dd179..716711589ea 100644
--- a/be/src/olap/tablet_schema.cpp
+++ b/be/src/olap/tablet_schema.cpp
@@ -573,7 +573,7 @@ void TabletColumn::init_from_pb(const ColumnPB& column) {
         // set path info for variant root column, to prevent from missing
         _column_path = 
std::make_shared<vectorized::PathInData>(_col_name_lower_case);
     }
-    for (auto& column_pb : column.sparse_columns()) {
+    for (const auto& column_pb : column.sparse_columns()) {
         TabletColumn column;
         column.init_from_pb(column_pb);
         
_sparse_cols.emplace_back(std::make_shared<TabletColumn>(std::move(column)));
@@ -816,7 +816,7 @@ void TabletIndex::init_from_pb(const TabletIndexPB& index) {
         _col_unique_ids.push_back(col_unique_id);
     }
     _index_type = index.index_type();
-    for (auto& kv : index.properties()) {
+    for (const auto& kv : index.properties()) {
         _properties[kv.first] = kv.second;
     }
     _escaped_index_suffix_path = index.index_suffix_name();
@@ -905,18 +905,18 @@ void TabletColumn::append_sparse_column(TabletColumn 
column) {
 }
 
 void TabletSchema::append_index(TabletIndex&& index) {
-    _indexes.push_back(std::move(index));
+    _indexes.push_back(std::make_shared<TabletIndex>(index));
 }
 
 void TabletSchema::update_index(const TabletColumn& col, const IndexType& 
index_type,
                                 TabletIndex&& index) {
     int32_t col_unique_id = col.is_extracted_column() ? col.parent_unique_id() 
: col.unique_id();
     const std::string& suffix_path = escape_for_path_name(col.suffix_path());
-    for (size_t i = 0; i < _indexes.size(); i++) {
-        for (int32_t id : _indexes[i].col_unique_ids()) {
-            if (_indexes[i].index_type() == index_type && id == col_unique_id 
&&
-                _indexes[i].get_index_suffix() == suffix_path) {
-                _indexes[i] = std::move(index);
+    for (auto& _indexe : _indexes) {
+        for (int32_t id : _indexe->col_unique_ids()) {
+            if (_indexe->index_type() == index_type && id == col_unique_id &&
+                _indexe->get_index_suffix() == suffix_path) {
+                _indexe = std::make_shared<TabletIndex>(std::move(index));
                 break;
             }
         }
@@ -928,14 +928,22 @@ void TabletSchema::replace_column(size_t pos, 
TabletColumn new_col) {
     _cols[pos] = std::make_shared<TabletColumn>(std::move(new_col));
 }
 
+void TabletSchema::clear_index_cache_handlers() {
+    for (auto* handle : _index_cache_handlers) {
+        TabletColumnObjectPool::instance()->release(handle);
+    }
+    _index_cache_handlers.clear();
+}
+
 void TabletSchema::clear_index() {
+    clear_index_cache_handlers();
     _indexes.clear();
 }
 
 void TabletSchema::remove_index(int64_t index_id) {
-    std::vector<TabletIndex> indexes;
+    std::vector<TabletIndexPtr> indexes;
     for (auto index : _indexes) {
-        if (index.index_id() == index_id) {
+        if (index->index_id() == index_id) {
             continue;
         }
         indexes.emplace_back(std::move(index));
@@ -975,6 +983,7 @@ void TabletSchema::init_from_pb(const TabletSchemaPB& 
schema, bool ignore_extrac
     _field_id_to_index.clear();
     _cluster_key_uids.clear();
     clear_column_cache_handlers();
+    clear_index_cache_handlers();
     for (const auto& i : schema.cluster_key_uids()) {
         _cluster_key_uids.push_back(i);
     }
@@ -1012,9 +1021,17 @@ void TabletSchema::init_from_pb(const TabletSchemaPB& 
schema, bool ignore_extrac
         }
         _num_columns++;
     }
-    for (auto& index_pb : schema.index()) {
-        TabletIndex index;
-        index.init_from_pb(index_pb);
+    for (const auto& index_pb : schema.index()) {
+        TabletIndexPtr index;
+        if (reuse_cache_column) {
+            auto pair = TabletColumnObjectPool::instance()->insert_index(
+                    deterministic_string_serialize(index_pb));
+            index = pair.second;
+            _index_cache_handlers.push_back(pair.first);
+        } else {
+            index = std::make_shared<TabletIndex>();
+            index->init_from_pb(index_pb);
+        }
         _indexes.emplace_back(std::move(index));
     }
     _num_short_key_columns = schema.num_short_key_columns();
@@ -1173,7 +1190,7 @@ void TabletSchema::build_current_tablet_schema(int64_t 
index_id, int32_t version
     }
 
     for (auto& i : index->indexes) {
-        _indexes.emplace_back(*i);
+        _indexes.emplace_back(std::make_shared<TabletIndex>(*i));
     }
 
     if (has_bf_columns) {
@@ -1260,7 +1277,7 @@ void TabletSchema::to_schema_pb(TabletSchemaPB* 
tablet_schema_pb) const {
     }
     for (const auto& index : _indexes) {
         auto* index_pb = tablet_schema_pb->add_index();
-        index.to_schema_pb(index_pb);
+        index->to_schema_pb(index_pb);
     }
     tablet_schema_pb->set_num_short_key_columns(_num_short_key_columns);
     tablet_schema_pb->set_num_rows_per_row_block(_num_rows_per_row_block);
@@ -1347,11 +1364,11 @@ TabletColumn& TabletSchema::mutable_column(size_t 
ordinal) {
 }
 
 void TabletSchema::update_indexes_from_thrift(const 
std::vector<doris::TOlapTableIndex>& tindexes) {
-    std::vector<TabletIndex> indexes;
-    for (auto& tindex : tindexes) {
+    std::vector<TabletIndexPtr> indexes;
+    for (const auto& tindex : tindexes) {
         TabletIndex index;
         index.init_from_thrift(tindex, *this);
-        indexes.emplace_back(std::move(index));
+        indexes.emplace_back(std::make_shared<TabletIndex>(std::move(index)));
     }
     _indexes = std::move(indexes);
 }
@@ -1398,7 +1415,8 @@ void TabletSchema::update_tablet_columns(const 
TabletSchema& tablet_schema,
 
 bool TabletSchema::has_inverted_index_with_index_id(int64_t index_id) const {
     for (size_t i = 0; i < _indexes.size(); i++) {
-        if (_indexes[i].index_type() == IndexType::INVERTED && 
_indexes[i].index_id() == index_id) {
+        if (_indexes[i]->index_type() == IndexType::INVERTED &&
+            _indexes[i]->index_id() == index_id) {
             return true;
         }
     }
@@ -1408,11 +1426,11 @@ bool 
TabletSchema::has_inverted_index_with_index_id(int64_t index_id) const {
 const TabletIndex* TabletSchema::inverted_index(int32_t col_unique_id,
                                                 const std::string& 
suffix_path) const {
     const std::string escaped_suffix = escape_for_path_name(suffix_path);
-    for (size_t i = 0; i < _indexes.size(); i++) {
-        if (_indexes[i].index_type() == IndexType::INVERTED) {
-            for (int32_t id : _indexes[i].col_unique_ids()) {
-                if (id == col_unique_id && _indexes[i].get_index_suffix() == 
escaped_suffix) {
-                    return &(_indexes[i]);
+    for (const auto& _index : _indexes) {
+        if (_index->index_type() == IndexType::INVERTED) {
+            for (int32_t id : _index->col_unique_ids()) {
+                if (id == col_unique_id && _index->get_index_suffix() == 
escaped_suffix) {
+                    return _index.get();
                 }
             }
         }
@@ -1433,9 +1451,9 @@ const TabletIndex* TabletSchema::inverted_index(const 
TabletColumn& col) const {
 
 bool TabletSchema::has_ngram_bf_index(int32_t col_unique_id) const {
     // TODO use more efficient impl
-    for (size_t i = 0; i < _indexes.size(); i++) {
-        if (_indexes[i].index_type() == IndexType::NGRAM_BF) {
-            for (int32_t id : _indexes[i].col_unique_ids()) {
+    for (const auto& _index : _indexes) {
+        if (_index->index_type() == IndexType::NGRAM_BF) {
+            for (int32_t id : _index->col_unique_ids()) {
                 if (id == col_unique_id) {
                     return true;
                 }
@@ -1448,11 +1466,11 @@ bool TabletSchema::has_ngram_bf_index(int32_t 
col_unique_id) const {
 
 const TabletIndex* TabletSchema::get_ngram_bf_index(int32_t col_unique_id) 
const {
     // TODO use more efficient impl
-    for (size_t i = 0; i < _indexes.size(); i++) {
-        if (_indexes[i].index_type() == IndexType::NGRAM_BF) {
-            for (int32_t id : _indexes[i].col_unique_ids()) {
+    for (const auto& _index : _indexes) {
+        if (_index->index_type() == IndexType::NGRAM_BF) {
+            for (int32_t id : _index->col_unique_ids()) {
                 if (id == col_unique_id) {
-                    return &(_indexes[i]);
+                    return _index.get();
                 }
             }
         }
diff --git a/be/src/olap/tablet_schema.h b/be/src/olap/tablet_schema.h
index fbb135188a0..957b9adb2b9 100644
--- a/be/src/olap/tablet_schema.h
+++ b/be/src/olap/tablet_schema.h
@@ -253,8 +253,6 @@ private:
 bool operator==(const TabletColumn& a, const TabletColumn& b);
 bool operator!=(const TabletColumn& a, const TabletColumn& b);
 
-class TabletSchema;
-
 class TabletIndex : public MetadataAdder<TabletIndex> {
 public:
     TabletIndex() = default;
@@ -297,6 +295,8 @@ private:
     std::map<string, string> _properties;
 };
 
+using TabletIndexPtr = std::shared_ptr<TabletIndex>;
+
 class TabletSchema : public MetadataAdder<TabletSchema> {
 public:
     enum ColumnType { NORMAL = 0, DROPPED = 1, VARIANT = 2 };
@@ -402,8 +402,8 @@ public:
     const std::vector<const TabletIndex*> inverted_indexes() const {
         std::vector<const TabletIndex*> inverted_indexes;
         for (const auto& index : _indexes) {
-            if (index.index_type() == IndexType::INVERTED) {
-                inverted_indexes.emplace_back(&index);
+            if (index->index_type() == IndexType::INVERTED) {
+                inverted_indexes.emplace_back(index.get());
             }
         }
         return inverted_indexes;
@@ -411,14 +411,14 @@ public:
     bool has_inverted_index() const {
         for (const auto& index : _indexes) {
             DBUG_EXECUTE_IF("tablet_schema::has_inverted_index", {
-                if (index.col_unique_ids().empty()) {
+                if (index->col_unique_ids().empty()) {
                     throw Exception(Status::InternalError("col unique ids 
cannot be empty"));
                 }
             });
 
-            if (index.index_type() == IndexType::INVERTED) {
+            if (index->index_type() == IndexType::INVERTED) {
                 //if index_id == -1, ignore it.
-                if (!index.col_unique_ids().empty() && 
index.col_unique_ids()[0] >= 0) {
+                if (!index->col_unique_ids().empty() && 
index->col_unique_ids()[0] >= 0) {
                     return true;
                 }
             }
@@ -547,6 +547,7 @@ private:
     TabletSchema(const TabletSchema&) = default;
 
     void clear_column_cache_handlers();
+    void clear_index_cache_handlers();
 
     KeysType _keys_type = DUP_KEYS;
     SortType _sort_type = SortType::LEXICAL;
@@ -554,7 +555,8 @@ private:
     std::vector<TabletColumnPtr> _cols;
     std::vector<Cache::Handle*> _column_cache_handlers;
 
-    std::vector<TabletIndex> _indexes;
+    std::vector<TabletIndexPtr> _indexes;
+    std::vector<Cache::Handle*> _index_cache_handlers;
     std::unordered_map<StringRef, int32_t, StringRefHash> _field_name_to_index;
     std::unordered_map<int32_t, int32_t> _field_id_to_index;
     std::unordered_map<vectorized::PathInDataRef, int32_t, 
vectorized::PathInDataRef::Hash>
diff --git a/be/src/olap/tablet_schema_cache.cpp 
b/be/src/olap/tablet_schema_cache.cpp
index e044ef9c042..b39326551a9 100644
--- a/be/src/olap/tablet_schema_cache.cpp
+++ b/be/src/olap/tablet_schema_cache.cpp
@@ -52,7 +52,7 @@ std::pair<Cache::Handle*, TabletSchemaSPtr> 
TabletSchemaCache::insert(const std:
         tablet_schema_ptr = std::make_shared<TabletSchema>();
         TabletSchemaPB pb;
         pb.ParseFromString(key);
-        // We should reuse the memory of the same TabletColumn object, set 
reuse_cached_column to true
+        // We should reuse the memory of the same TabletColumn/TabletIndex 
object, set reuse_cached_column to true
         tablet_schema_ptr->init_from_pb(pb, false, true);
         value->tablet_schema = tablet_schema_ptr;
         lru_handle = LRUCachePolicy::insert(key_signature, value, 
tablet_schema_ptr->num_columns(),
diff --git a/be/test/olap/tablet_column_object_pool_test.cpp 
b/be/test/olap/tablet_column_object_pool_test.cpp
new file mode 100644
index 00000000000..b28bd843377
--- /dev/null
+++ b/be/test/olap/tablet_column_object_pool_test.cpp
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "olap/tablet_column_object_pool.h"
+
+#include <gen_cpp/olap_file.pb.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+namespace doris {
+
+// Declare external variables
+extern bvar::Adder<int64_t> g_tablet_column_cache_count;
+extern bvar::Adder<int64_t> g_tablet_column_cache_hit_count;
+extern bvar::Adder<int64_t> g_tablet_index_cache_count;
+extern bvar::Adder<int64_t> g_tablet_index_cache_hit_count;
+
+class TabletColumnObjectPoolTest : public testing::Test {
+protected:
+    void SetUp() override {
+        // reset all counters to 0
+        g_tablet_column_cache_count.reset();
+        g_tablet_column_cache_hit_count.reset();
+        g_tablet_index_cache_count.reset();
+        g_tablet_index_cache_hit_count.reset();
+
+        _pool = std::make_unique<TabletColumnObjectPool>(1024);
+    }
+
+    // Helper function to create a column PB
+    std::string create_column_pb() {
+        ColumnPB pb;
+        pb.set_unique_id(123);
+        pb.set_name("test_column");
+        pb.set_type("TINYINT");
+        std::string serialized;
+        pb.SerializeToString(&serialized);
+        return serialized;
+    }
+
+    // Helper function to create an index PB
+    std::string create_index_pb() {
+        TabletIndexPB pb;
+        pb.set_index_id(456);
+        pb.set_index_name("test_index");
+        std::string serialized;
+        pb.SerializeToString(&serialized);
+        return serialized;
+    }
+
+    std::unique_ptr<TabletColumnObjectPool> _pool;
+};
+
+// Test column cache insertion and hit
+TEST_F(TabletColumnObjectPoolTest, TestColumnCacheInsertAndHit) {
+    std::string key = create_column_pb();
+
+    // First insertion
+    int64_t initial_count = g_tablet_column_cache_count.get_value();
+    int64_t initial_hit_count = g_tablet_column_cache_hit_count.get_value();
+
+    auto [handle1, ptr1] = _pool->insert(key);
+    ASSERT_NE(nullptr, handle1);
+    ASSERT_NE(nullptr, ptr1);
+    ASSERT_EQ(initial_count + 1, g_tablet_column_cache_count.get_value());
+
+    // Second insertion with same key should hit cache
+    auto [handle2, ptr2] = _pool->insert(key);
+    ASSERT_NE(nullptr, handle2);
+    ASSERT_NE(nullptr, ptr2);
+    ASSERT_EQ(ptr1, ptr2); // Should return same object
+    ASSERT_EQ(initial_hit_count + 1, 
g_tablet_column_cache_hit_count.get_value());
+
+    _pool->release(handle1);
+    _pool->release(handle2);
+}
+
+// Test index cache insertion and hit
+TEST_F(TabletColumnObjectPoolTest, TestIndexCacheInsertAndHit) {
+    std::string key = create_index_pb();
+
+    // First insertion
+    int64_t initial_count = g_tablet_index_cache_count.get_value();
+    int64_t initial_hit_count = g_tablet_index_cache_hit_count.get_value();
+
+    auto [handle1, ptr1] = _pool->insert_index(key);
+    ASSERT_NE(nullptr, handle1);
+    ASSERT_NE(nullptr, ptr1);
+    ASSERT_EQ(initial_count + 1, g_tablet_index_cache_count.get_value());
+
+    // Second insertion with same key should hit cache
+    auto [handle2, ptr2] = _pool->insert_index(key);
+    ASSERT_NE(nullptr, handle2);
+    ASSERT_NE(nullptr, ptr2);
+    ASSERT_EQ(ptr1, ptr2); // Should return same object
+    ASSERT_EQ(initial_hit_count + 1, 
g_tablet_index_cache_hit_count.get_value());
+
+    _pool->release(handle1);
+    _pool->release(handle2);
+}
+
+// Test cache eviction
+TEST_F(TabletColumnObjectPoolTest, TestCacheEviction) {
+    // Create a small cache
+    TabletColumnObjectPool small_pool(2); // Only 2 entries
+
+    std::string key1 = create_column_pb();
+    std::string key2 = create_column_pb();
+    std::string key3 = create_column_pb();
+
+    // Insert first two entries
+    auto [handle1, ptr1] = small_pool.insert(key1);
+    auto [handle2, ptr2] = small_pool.insert(key2);
+
+    // Release handle1 to allow eviction
+    small_pool.release(handle1);
+
+    // Insert third entry should evict first entry
+    auto [handle3, ptr3] = small_pool.insert(key3);
+
+    // Try to get first entry again - should be a new object
+    auto [handle1_new, ptr1_new] = small_pool.insert(key1);
+    ASSERT_NE(ptr1, ptr1_new); // Should be different objects
+
+    small_pool.release(handle2);
+    small_pool.release(handle3);
+    small_pool.release(handle1_new);
+}
+
+// Test destructor behavior
+TEST_F(TabletColumnObjectPoolTest, TestDestructor) {
+    {
+        TabletColumnObjectPool temp_pool(10);
+        std::string key = create_column_pb();
+
+        int64_t initial_count = g_tablet_column_cache_count.get_value();
+        auto [handle, ptr] = temp_pool.insert(key);
+        ASSERT_EQ(initial_count + 1, g_tablet_column_cache_count.get_value());
+
+        temp_pool.release(handle);
+    } // temp_pool destructor should be called here
+    // Verify counter was decremented
+    ASSERT_EQ(g_tablet_column_cache_count.get_value(), 0);
+}
+
+} // namespace doris
+
+// int main(int argc, char** argv) {
+//     ::testing::InitGoogleTest(&argc, argv);
+//     return RUN_ALL_TESTS();
+// }
\ No newline at end of file


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

Reply via email to