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

yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.2 by this push:
     new 4a7ef30003c branch-4.2: [fix](cloud) Reclaim orphaned rowset warmup 
states #69325 (#69415)
4a7ef30003c is described below

commit 4a7ef30003c98a30b3f70317b9e0d3ba7f4ca3b7
Author: bobhan1 <[email protected]>
AuthorDate: Fri Oct 23 10:03:24 2026 +0800

    branch-4.2: [fix](cloud) Reclaim orphaned rowset warmup states #69325 
(#69415)
    
    ### What problem does this PR solve?
    
    Issue Number: N/A
    
    Related PR: #69325
    
    Backport #69325 to `branch-4.2`. Event-driven warmup can finish before
    the target synchronizes a rowset's metadata. If the source compacts that
    rowset first, its completed warmup record can bypass the target's rowset
    GC and remain allocated indefinitely.
    
    Reuse tablet vacuum to reclaim aged completed records absent from both
    visible and stale rowsets, including tablets without stale or unused
    rowsets, and release oversized hash buckets. Preserve running attempts
    and local query version paths. Carry attempt generations through
    callbacks and index registration, use consistent metadata locking for
    state removal, and clear unused-rowset caches after releasing tablet
    locks.
    
    Resolve the backport conflicts using 4.2's existing segment download
    helpers, contiguous segment IDs and cache recycling API.
    
    ### Release note
    
    Cloud backends reclaim orphaned completed rowset warmup records to
    reduce memory growth. `warm_up_rowset_state_gc_grace_period_seconds`
    controls the grace period and defaults to 3600 seconds.
    
    ### Check List (For Author)
    
    - Test
        - [ ] Regression test
    - [x] Unit Test: ASAN BE UT build and all 74 selected tests across four
    suites passed with `./run-be-ut.sh --run
    
--filter='CloudTabletWarmUpStateTest.*:CloudTabletMgrTest.*:*PreferCache*:*FreshnessTolerance*'
    -j100`. Includes the six new GC/callback/vacuum tests and existing
    prefer-cache/freshness-tolerance coverage.
    - [x] Manual test: clang-format 16 check on all nine changed files and
    `git diff --check upstream/branch-4.2...HEAD` passed.
    - Behavior changed:
    - [x] Yes. Aged orphaned completed warmup records are reclaimed and may
    subsequently be warmed again. Running and local visible/stale records
    remain tracked.
    - Does this need documentation?
        - [x] No.
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label
---
 be/src/cloud/cloud_internal_service.cpp |  19 +-
 be/src/cloud/cloud_tablet.cpp           | 122 +++++++----
 be/src/cloud/cloud_tablet.h             |  24 ++-
 be/src/cloud/cloud_tablet_mgr.cpp       |  23 ++-
 be/src/cloud/cloud_warm_up_manager.cpp  |  16 +-
 be/src/cloud/config.cpp                 |   2 +
 be/src/cloud/config.h                   |   1 +
 be/test/cloud/cloud_tablet_mgr_test.cpp |  36 ++++
 be/test/cloud/cloud_tablet_test.cpp     | 350 ++++++++++++++++++++++++--------
 9 files changed, 448 insertions(+), 145 deletions(-)

diff --git a/be/src/cloud/cloud_internal_service.cpp 
b/be/src/cloud/cloud_internal_service.cpp
index 120efbfa1b3..74f24ce9907 100644
--- a/be/src/cloud/cloud_internal_service.cpp
+++ b/be/src/cloud/cloud_internal_service.cpp
@@ -1024,7 +1024,8 @@ void handle_segment_download_done(Status st, int64_t 
tablet_id, const RowsetId&
                                   int64_t segment_id, 
std::shared_ptr<CloudTablet> tablet,
                                   std::shared_ptr<bthread::CountdownEvent> 
wait, Version version,
                                   int64_t segment_size, int64_t request_ts, 
int64_t handle_ts,
-                                  std::string job_id_str, int64_t 
upstream_trigger_ts_ms) {
+                                  std::string job_id_str, int64_t 
upstream_trigger_ts_ms,
+                                  uint64_t generation) {
     
DBUG_EXECUTE_IF("CloudInternalServiceImpl::warm_up_rowset.download_segment", {
         auto sleep_time = dp->param<int>("sleep", 3);
         LOG_INFO("[verbose] block download for rowset={}, version={}, 
sleep={}",
@@ -1071,7 +1072,7 @@ void handle_segment_download_done(Status st, int64_t 
tablet_id, const RowsetId&
                      << " rowset_id: " << rowset_id.to_string() << ", error: " 
<< st;
     }
     if 
(tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset_id, st, 1,
-                                               0)
+                                               0, generation)
                 .trigger_source == WarmUpTriggerSource::EVENT_DRIVEN) {
         VLOG_DEBUG << "warmup rowset " << version.to_string() << "(" << 
rowset_id.to_string()
                    << ") completed";
@@ -1088,7 +1089,7 @@ void handle_inverted_index_download_done(Status st, 
int64_t tablet_id, const Row
                                          
std::shared_ptr<bthread::CountdownEvent> wait,
                                          Version version, uint64_t idx_size, 
int64_t request_ts,
                                          int64_t handle_ts, std::string 
job_id_str,
-                                         int64_t upstream_trigger_ts_ms) {
+                                         int64_t upstream_trigger_ts_ms, 
uint64_t generation) {
     
DBUG_EXECUTE_IF("CloudInternalServiceImpl::warm_up_rowset.download_inverted_idx",
 {
         auto sleep_time = dp->param<int>("sleep", 3);
         LOG_INFO(
@@ -1129,7 +1130,7 @@ void handle_inverted_index_download_done(Status st, 
int64_t tablet_id, const Row
                      << " rowset_id: " << rowset_id << ", error: " << st;
     }
     if 
(tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset_id, st, 0,
-                                               1)
+                                               1, generation)
                 .trigger_source == WarmUpTriggerSource::EVENT_DRIVEN) {
         VLOG_DEBUG << "warmup rowset " << version.to_string() << "(" << 
rowset_id.to_string()
                    << ") completed";
@@ -1204,7 +1205,9 @@ void 
CloudInternalServiceImpl::warm_up_rowset(google::protobuf::RpcController* c
         }
         int64_t expiration_time = 
tablet_meta->file_cache_ttl_expiration_time();
 
-        if (!tablet->add_rowset_warmup_state(rs_meta, 
WarmUpTriggerSource::EVENT_DRIVEN)) {
+        const auto generation =
+                tablet->add_rowset_warmup_state(rs_meta, 
WarmUpTriggerSource::EVENT_DRIVEN);
+        if (!generation) {
             LOG(INFO) << "found duplicate warmup task for rowset " << 
rowset_id.to_string()
                       << ", skip it";
             
g_warmup_ed_downstream_progress_tracker.record_task_done(job_id_str,
@@ -1239,7 +1242,7 @@ void 
CloudInternalServiceImpl::warm_up_rowset(google::protobuf::RpcController* c
                                     handle_segment_download_done(
                                             st, tablet_id, rowset_id, 
segment_id, tablet, wait,
                                             version, segment_size, request_ts, 
handle_ts,
-                                            job_id_str, 
upstream_trigger_ts_ms);
+                                            job_id_str, 
upstream_trigger_ts_ms, *generation);
                                 },
                         .tablet_id = tablet_id};
 
@@ -1270,13 +1273,13 @@ void 
CloudInternalServiceImpl::warm_up_rowset(google::protobuf::RpcController* c
                                     handle_inverted_index_download_done(
                                             st, tablet_id, rowset_id, 
segment_id, index_path,
                                             tablet, wait, version, idx_size, 
request_ts, handle_ts,
-                                            job_id_str, 
upstream_trigger_ts_ms);
+                                            job_id_str, 
upstream_trigger_ts_ms, *generation);
                                 },
                         .tablet_id = tablet_id};
                 g_file_cache_event_driven_warm_up_submitted_index_num << 1;
                 g_file_cache_event_driven_warm_up_submitted_index_size << 
idx_size;
                 tablet->update_rowset_warmup_state_inverted_idx_num(
-                        WarmUpTriggerSource::EVENT_DRIVEN, rowset_id, 1);
+                        WarmUpTriggerSource::EVENT_DRIVEN, rowset_id, 1, 
*generation);
                 if (wait) {
                     wait->add_count();
                 }
diff --git a/be/src/cloud/cloud_tablet.cpp b/be/src/cloud/cloud_tablet.cpp
index a2548d5fa5d..c582418a131 100644
--- a/be/src/cloud/cloud_tablet.cpp
+++ b/be/src/cloud/cloud_tablet.cpp
@@ -36,6 +36,7 @@
 #include <ratio>
 #include <shared_mutex>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "cloud/cloud_meta_mgr.h"
@@ -689,8 +690,10 @@ void CloudTablet::remove_unused_rowsets() {
     int64_t removed_delete_bitmap_num = 0;
     OlapStopWatch watch;
     {
+        // Warmup callbacks use _meta_lock; take it before _gc_mutex, as 
add_rowsets does.
+        std::unique_lock meta_lock(_meta_lock);
         std::lock_guard<std::mutex> lock(_gc_mutex);
-        // 1. remove unused rowsets's cache data and delete bitmap
+        // 1. select unused rowsets and remove their warmup states and delete 
bitmap
         for (auto it = _unused_rowsets.begin(); it != _unused_rowsets.end();) {
             auto& rs = it->second;
             if (rs.use_count() > 1) {
@@ -701,7 +704,6 @@ void CloudTablet::remove_unused_rowsets() {
             }
             tablet_meta()->remove_rowset_delete_bitmap(rs->rowset_id(), 
rs->version());
             _rowset_warm_up_states.erase(rs->rowset_id());
-            rs->clear_cache();
             g_unused_rowsets_count << -1;
             g_unused_rowsets_bytes << -rs->total_disk_size();
             removed_rowsets.push_back(std::move(rs));
@@ -712,7 +714,10 @@ void CloudTablet::remove_unused_rowsets() {
     {
         std::vector<RecycledRowsets> recycled_rowsets;
 
+        // Keep selected rowsets alive here, but release tablet locks before 
clearing
+        // caches: a compaction batch can synchronously remove many cached 
blocks.
         for (auto& rs : removed_rowsets) {
+            rs->clear_cache();
             auto index_names = rs->get_index_file_names();
             recycled_rowsets.emplace_back(rs->rowset_id(), rs->num_segments(), 
index_names);
             int64_t segment_size_sum = 0;
@@ -1593,44 +1598,47 @@ Status CloudTablet::check_delete_bitmap_cache(int64_t 
txn_id,
 
 WarmUpState CloudTablet::get_rowset_warmup_state(RowsetId rowset_id) {
     std::shared_lock rlock(_meta_lock);
-    if (!_rowset_warm_up_states.contains(rowset_id)) {
+    auto it = _rowset_warm_up_states.find(rowset_id);
+    if (it == _rowset_warm_up_states.end()) {
         return {.trigger_source = WarmUpTriggerSource::NONE, .progress = 
WarmUpProgress::NONE};
     }
-    auto& warmup_info = _rowset_warm_up_states[rowset_id];
-    warmup_info.update_state();
-    return warmup_info.state;
+    return it->second.state;
 }
 
-bool CloudTablet::add_rowset_warmup_state(const RowsetMeta& rowset, 
WarmUpTriggerSource source,
-                                          
std::chrono::steady_clock::time_point start_tp) {
+std::optional<uint64_t> CloudTablet::add_rowset_warmup_state(
+        const RowsetMeta& rowset, WarmUpTriggerSource source,
+        std::chrono::steady_clock::time_point start_tp) {
     std::lock_guard wlock(_meta_lock);
     return add_rowset_warmup_state_unlocked(rowset, source, start_tp);
 }
 
 bool 
CloudTablet::update_rowset_warmup_state_inverted_idx_num(WarmUpTriggerSource 
source,
-                                                              RowsetId 
rowset_id, int64_t delta) {
+                                                              RowsetId 
rowset_id, int64_t delta,
+                                                              uint64_t 
generation) {
     std::lock_guard wlock(_meta_lock);
-    return update_rowset_warmup_state_inverted_idx_num_unlocked(source, 
rowset_id, delta);
+    return update_rowset_warmup_state_inverted_idx_num_unlocked(source, 
rowset_id, delta,
+                                                                generation);
 }
 
 bool 
CloudTablet::update_rowset_warmup_state_inverted_idx_num_unlocked(WarmUpTriggerSource
 source,
                                                                        
RowsetId rowset_id,
-                                                                       int64_t 
delta) {
+                                                                       int64_t 
delta,
+                                                                       
uint64_t generation) {
     auto it = _rowset_warm_up_states.find(rowset_id);
     if (it == _rowset_warm_up_states.end()) {
         return false;
     }
-    if (it->second.state.trigger_source != source) {
-        // Only the same trigger source can update the state
+    // A JOB may replace the attempt while its previous producer is still 
registering indexes.
+    if (it->second.generation != generation || it->second.state.trigger_source 
!= source) {
         return false;
     }
     it->second.num_inverted_idx += delta;
     return true;
 }
 
-bool CloudTablet::add_rowset_warmup_state_unlocked(const RowsetMeta& rowset,
-                                                   WarmUpTriggerSource source,
-                                                   
std::chrono::steady_clock::time_point start_tp) {
+std::optional<uint64_t> CloudTablet::add_rowset_warmup_state_unlocked(
+        const RowsetMeta& rowset, WarmUpTriggerSource source,
+        std::chrono::steady_clock::time_point start_tp) {
     auto rowset_id = rowset.rowset_id();
 
     // Check if rowset already has warmup state
@@ -1643,11 +1651,11 @@ bool 
CloudTablet::add_rowset_warmup_state_unlocked(const RowsetMeta& rowset,
             if (existing_state.trigger_source == WarmUpTriggerSource::JOB &&
                 existing_state.progress == WarmUpProgress::DOING) {
                 // Same job type already in progress, skip to avoid duplicate 
warmup
-                return false;
+                return std::nullopt;
             }
         } else {
             // For non-job warmup (EVENT_DRIVEN, SYNC_ROWSET), skip if any 
warmup exists
-            return false;
+            return std::nullopt;
         }
     }
 
@@ -1662,9 +1670,49 @@ bool CloudTablet::add_rowset_warmup_state_unlocked(const 
RowsetMeta& rowset,
             .state = {.trigger_source = source,
                       .progress = (rowset.num_segments() == 0 ? 
WarmUpProgress::DONE
                                                               : 
WarmUpProgress::DOING)},
+            .generation = ++_next_warmup_generation,
             .num_segments = rowset.num_segments(),
             .start_tp = start_tp};
-    return true;
+    return _next_warmup_generation;
+}
+
+size_t CloudTablet::gc_rowset_warmup_states(std::chrono::seconds grace_period,
+                                            
std::chrono::steady_clock::time_point now) {
+    std::unique_lock lock(_meta_lock);
+    // Rowset GC can leave an empty map with a large bucket array.
+    if (_rowset_warm_up_states.empty()) {
+        decltype(_rowset_warm_up_states)().swap(_rowset_warm_up_states);
+        return 0;
+    }
+
+    std::unordered_set<RowsetId> live_rowset_ids;
+    live_rowset_ids.reserve(_rs_version_map.size() + 
_stale_rs_version_map.size());
+    traverse_rowsets_unlocked(
+            [&](const RowsetSharedPtr& rs) { 
live_rowset_ids.insert(rs->rowset_id()); }, true);
+
+    size_t removed = 0;
+    for (auto it = _rowset_warm_up_states.begin(); it != 
_rowset_warm_up_states.end();) {
+        const auto& info = it->second;
+        // R1 may be warmed up, compacted into R2, and never synchronized 
locally. Keep
+        // recent attempts for deduplication and DOING attempts for 
cache-aware queries.
+        // Stale rowsets can still be selected by those queries and must also 
be retained.
+        if (info.state.progress == WarmUpProgress::DONE && info.has_finished() 
&&
+            now - info.start_tp >= grace_period && 
!live_rowset_ids.contains(it->first)) {
+            it = _rowset_warm_up_states.erase(it);
+            ++removed;
+        } else {
+            ++it;
+        }
+    }
+
+    // Erasing nodes does not release the bucket array. Shrink only at a low 
watermark
+    // so normal insertion/GC cycles do not repeatedly rebuild the table.
+    if (_rowset_warm_up_states.empty()) {
+        decltype(_rowset_warm_up_states)().swap(_rowset_warm_up_states);
+    } else if (_rowset_warm_up_states.size() < 
_rowset_warm_up_states.bucket_count() / 4) {
+        _rowset_warm_up_states.rehash(0);
+    }
+    return removed;
 }
 
 void CloudTablet::RowsetWarmUpInfo::update_state() {
@@ -1681,10 +1729,13 @@ void CloudTablet::RowsetWarmUpInfo::update_state() {
 WarmUpState CloudTablet::complete_rowset_segment_warmup(WarmUpTriggerSource 
trigger_source,
                                                         RowsetId rowset_id, 
Status status,
                                                         int64_t segment_num,
-                                                        int64_t 
inverted_idx_num) {
+                                                        int64_t 
inverted_idx_num,
+                                                        uint64_t generation) {
     std::lock_guard wlock(_meta_lock);
     auto it = _rowset_warm_up_states.find(rowset_id);
-    if (it == _rowset_warm_up_states.end()) {
+    // GC permits a new attempt for the same RowsetId. Late callbacks from the 
old
+    // attempt must not advance the new attempt, even when their sources match.
+    if (it == _rowset_warm_up_states.end() || it->second.generation != 
generation) {
         return {.trigger_source = WarmUpTriggerSource::NONE, .progress = 
WarmUpProgress::NONE};
     }
     auto& warmup_info = it->second;
@@ -1792,8 +1843,7 @@ bool 
CloudTablet::_check_rowset_should_be_visible_but_not_warmed_up(
 
 void CloudTablet::_submit_segment_download_task(const RowsetSharedPtr& rs,
                                                 const StorageResource* 
storage_resource, int seg_id,
-
-                                                int64_t expiration_time) {
+                                                int64_t expiration_time, 
uint64_t generation) {
     // clang-format off
     const auto& rowset_meta = rs->rowset_meta();
     auto self = std::dynamic_pointer_cast<CloudTablet>(shared_from_this());
@@ -1829,7 +1879,7 @@ void CloudTablet::_submit_segment_download_task(const 
RowsetSharedPtr& rs,
                                         std::chrono::seconds(sleep_time));
                             }
                 });
-                
self->complete_rowset_segment_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset_meta->rowset_id(), st, 1, 0);
+                
self->complete_rowset_segment_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset_meta->rowset_id(), st, 1, 0, generation);
                 if (!st) {
                     LOG_WARNING("add rowset warm up error ").error(st);
                 }
@@ -1842,7 +1892,8 @@ void CloudTablet::_submit_segment_download_task(const 
RowsetSharedPtr& rs,
 void CloudTablet::_submit_inverted_index_download_task(const RowsetSharedPtr& 
rs,
                                                        const StorageResource* 
storage_resource,
                                                        const io::Path& 
idx_path, int64_t idx_size,
-                                                       int64_t 
expiration_time) {
+                                                       int64_t expiration_time,
+                                                       uint64_t generation) {
     // clang-format off
     const auto& rowset_meta = rs->rowset_meta();
     auto self = std::dynamic_pointer_cast<CloudTablet>(shared_from_this());
@@ -1872,14 +1923,14 @@ void 
CloudTablet::_submit_inverted_index_download_task(const RowsetSharedPtr& rs
                             rs->rowset_id().to_string(), idx_path.string(), 
sleep_time);
                     
std::this_thread::sleep_for(std::chrono::seconds(sleep_time));
                 });
-                
self->complete_rowset_segment_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset_meta->rowset_id(), st, 0, 1);
+                
self->complete_rowset_segment_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset_meta->rowset_id(), st, 0, 1, generation);
                 if (!st) {
                     LOG_WARNING("add rowset warm up error ").error(st);
                 }
             }},
             .tablet_id = _tablet_meta->tablet_id(),
     };
-    
self->update_rowset_warmup_state_inverted_idx_num_unlocked(WarmUpTriggerSource::SYNC_ROWSET,
 rowset_meta->rowset_id(), 1);
+    
self->update_rowset_warmup_state_inverted_idx_num_unlocked(WarmUpTriggerSource::SYNC_ROWSET,
 rowset_meta->rowset_id(), 1, generation);
     
_engine.file_cache_block_downloader().submit_download_task(std::move(meta));
     g_file_cache_cloud_tablet_submitted_index_num << 1;
     g_file_cache_cloud_tablet_submitted_index_size << idx_size;
@@ -1897,7 +1948,7 @@ void 
CloudTablet::_add_rowsets_directly(std::vector<RowsetSharedPtr>& rowsets,
             // inside RowsetMeta::fs() which causes SingleFlight deadlock when 
the
             // tablet is not yet cached (during initial load_tablet).
             
rs->rowset_meta()->set_encryption_algorithm(_tablet_meta->encryption_algorithm());
-            bool warm_up_state_updated = false;
+            std::optional<uint64_t> generation;
             // Warmup rowset data in background
             for (int seg_id = 0; seg_id < rs->num_segments(); ++seg_id) {
                 const auto& rowset_meta = rs->rowset_meta();
@@ -1920,21 +1971,21 @@ void 
CloudTablet::_add_rowsets_directly(std::vector<RowsetSharedPtr>& rowsets,
                     g_file_cache_cloud_tablet_submitted_segment_size
                             << rs->rowset_meta()->segment_file_size(seg_id);
                 }
-                if (!warm_up_state_updated) {
+                if (!generation) {
                     VLOG_DEBUG << "warm up rowset " << rs->version() << "(" << 
rs->rowset_id()
                                << ") triggerd by sync rowset";
-                    if (!add_rowset_warmup_state_unlocked(*(rs->rowset_meta()),
-                                                          
WarmUpTriggerSource::SYNC_ROWSET)) {
+                    generation = 
add_rowset_warmup_state_unlocked(*(rs->rowset_meta()),
+                                                                  
WarmUpTriggerSource::SYNC_ROWSET);
+                    if (!generation) {
                         LOG(INFO) << "found duplicate warmup task for rowset " 
<< rs->rowset_id()
                                   << ", skip it";
                         break;
                     }
-                    warm_up_state_updated = true;
                 }
 
                 if (!config::file_cache_enable_only_warm_up_idx) {
                     _submit_segment_download_task(rs, 
storage_resource.value(), seg_id,
-                                                  expiration_time);
+                                                  expiration_time, 
*generation);
                 }
 
                 auto schema_ptr = rowset_meta->tablet_schema();
@@ -1955,7 +2006,7 @@ void 
CloudTablet::_add_rowsets_directly(std::vector<RowsetSharedPtr>& rowsets,
                                 *rowset_meta, seg_id, index->index_id(), 
index->get_index_suffix());
                         _submit_inverted_index_download_task(rs, 
storage_resource.value(), idx_path,
                                                              
index_size_map[index->index_id()],
-                                                             expiration_time);
+                                                             expiration_time, 
*generation);
                     }
                 } else {
                     if (schema_ptr->has_inverted_or_ann_index()) {
@@ -1969,7 +2020,8 @@ void 
CloudTablet::_add_rowsets_directly(std::vector<RowsetSharedPtr>& rowsets,
                         auto idx_path =
                                 
storage_resource.value()->remote_idx_v2_path(*rowset_meta, seg_id);
                         _submit_inverted_index_download_task(rs, 
storage_resource.value(), idx_path,
-                                                             idx_size, 
expiration_time);
+                                                             idx_size, 
expiration_time,
+                                                             *generation);
                     }
                 }
             }
diff --git a/be/src/cloud/cloud_tablet.h b/be/src/cloud/cloud_tablet.h
index 47b92acac06..2957acab483 100644
--- a/be/src/cloud/cloud_tablet.h
+++ b/be/src/cloud/cloud_tablet.h
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <memory>
+#include <optional>
 #include <tuple>
 
 #include "storage/partial_update_info.h"
@@ -388,16 +389,23 @@ public:
 
     // Add warmup state management
     WarmUpState get_rowset_warmup_state(RowsetId rowset_id);
-    bool add_rowset_warmup_state(
+    std::optional<uint64_t> add_rowset_warmup_state(
             const RowsetMeta& rowset, WarmUpTriggerSource source,
             std::chrono::steady_clock::time_point start_tp = 
std::chrono::steady_clock::now());
     bool update_rowset_warmup_state_inverted_idx_num(WarmUpTriggerSource 
source, RowsetId rowset_id,
-                                                     int64_t delta);
+                                                     int64_t delta, uint64_t 
generation);
     bool 
update_rowset_warmup_state_inverted_idx_num_unlocked(WarmUpTriggerSource source,
-                                                              RowsetId 
rowset_id, int64_t delta);
+                                                              RowsetId 
rowset_id, int64_t delta,
+                                                              uint64_t 
generation);
     WarmUpState complete_rowset_segment_warmup(WarmUpTriggerSource 
trigger_source,
                                                RowsetId rowset_id, Status 
status,
-                                               int64_t segment_num, int64_t 
inverted_idx_num);
+                                               int64_t segment_num, int64_t 
inverted_idx_num,
+                                               uint64_t generation);
+
+    // Warmup can arrive before metadata sync and never enter the local Rowset 
GC lifecycle.
+    size_t gc_rowset_warmup_states(
+            std::chrono::seconds grace_period,
+            std::chrono::steady_clock::time_point now = 
std::chrono::steady_clock::now());
 
     bool is_rowset_warmed_up(const RowsetId& rowset_id) const;
 
@@ -443,7 +451,7 @@ private:
 
     Status sync_if_not_running(SyncRowsetStats* stats = nullptr);
 
-    bool add_rowset_warmup_state_unlocked(
+    std::optional<uint64_t> add_rowset_warmup_state_unlocked(
             const RowsetMeta& rowset, WarmUpTriggerSource source,
             std::chrono::steady_clock::time_point start_tp = 
std::chrono::steady_clock::now());
 
@@ -458,13 +466,13 @@ private:
     // Submit a segment download task for warming up
     void _submit_segment_download_task(const RowsetSharedPtr& rs,
                                        const StorageResource* 
storage_resource, int seg_id,
-                                       int64_t expiration_time);
+                                       int64_t expiration_time, uint64_t 
generation);
 
     // Submit an inverted index download task for warming up
     void _submit_inverted_index_download_task(const RowsetSharedPtr& rs,
                                               const StorageResource* 
storage_resource,
                                               const io::Path& idx_path, 
int64_t idx_size,
-                                              int64_t expiration_time);
+                                              int64_t expiration_time, 
uint64_t generation);
 
     // Add rowsets directly with warmup
     void _add_rowsets_directly(std::vector<RowsetSharedPtr>& rowsets, bool 
warmup_delta_data);
@@ -529,6 +537,7 @@ private:
     // for warm up states management
     struct RowsetWarmUpInfo {
         WarmUpState state;
+        uint64_t generation = 0;
         int64_t num_segments = 0;
         int64_t num_inverted_idx = 0;
         int64_t num_segments_warmed_up = 0;
@@ -548,6 +557,7 @@ private:
 
         void update_state();
     };
+    uint64_t _next_warmup_generation = 0;
     std::unordered_map<RowsetId, RowsetWarmUpInfo> _rowset_warm_up_states;
 
     mutable std::shared_mutex _warmed_up_rowsets_mutex;
diff --git a/be/src/cloud/cloud_tablet_mgr.cpp 
b/be/src/cloud/cloud_tablet_mgr.cpp
index b18dfe9401c..9b021c6b7dd 100644
--- a/be/src/cloud/cloud_tablet_mgr.cpp
+++ b/be/src/cloud/cloud_tablet_mgr.cpp
@@ -321,19 +321,28 @@ void CloudTabletMgr::vacuum_stale_rowsets(const 
CountDownLatch& stop_latch) {
             .tag("num_tablets", tablets_to_vacuum.size());
 
     {
-        LOG_INFO("begin to remove unused rowsets");
+        LOG_INFO("begin to remove unused rowsets and orphaned warmup states");
         std::vector<std::shared_ptr<CloudTablet>> 
tablets_to_remove_unused_rowsets;
         tablets_to_remove_unused_rowsets.reserve(_tablet_map->size());
+        // A tablet can have orphaned warmup states without any stale/unused 
Rowset.
         _tablet_map->traverse([&tablets_to_remove_unused_rowsets](auto&& t) {
-            if (t->need_remove_unused_rowsets()) {
-                tablets_to_remove_unused_rowsets.push_back(t);
-            }
+            tablets_to_remove_unused_rowsets.push_back(t);
         });
+        size_t removed_warmup_states = 0;
         for (auto& t : tablets_to_remove_unused_rowsets) {
-            t->remove_unused_rowsets();
+            // Stop can arrive during a long sweep over tablets with large 
state maps.
+            if (stop_latch.count() <= 0) {
+                break;
+            }
+            if (t->need_remove_unused_rowsets()) {
+                t->remove_unused_rowsets();
+            }
+            removed_warmup_states += t->gc_rowset_warmup_states(
+                    
std::chrono::seconds(config::warm_up_rowset_state_gc_grace_period_seconds));
         }
-        LOG_INFO("finish remove unused rowsets")
-                .tag("num_tablets", tablets_to_remove_unused_rowsets.size());
+        LOG_INFO("finish remove unused rowsets and orphaned warmup states")
+                .tag("num_tablets", tablets_to_remove_unused_rowsets.size())
+                .tag("removed_warmup_states", removed_warmup_states);
         if (config::enable_check_agg_and_remove_pre_rowsets_delete_bitmap) {
             int64_t max_useless_rowset_count = 0;
             int64_t tablet_id_with_max_useless_rowset_count = 0;
diff --git a/be/src/cloud/cloud_warm_up_manager.cpp 
b/be/src/cloud/cloud_warm_up_manager.cpp
index 9446fedb9d2..44741b978ca 100644
--- a/be/src/cloud/cloud_warm_up_manager.cpp
+++ b/be/src/cloud/cloud_warm_up_manager.cpp
@@ -303,7 +303,9 @@ void CloudWarmUpManager::handle_jobs() {
                 }
 
                 int64_t expiration_time = 
tablet_meta->file_cache_ttl_expiration_time();
-                if (!tablet->add_rowset_warmup_state(*rs, 
WarmUpTriggerSource::JOB)) {
+                const auto generation =
+                        tablet->add_rowset_warmup_state(*rs, 
WarmUpTriggerSource::JOB);
+                if (!generation) {
                     LOG(INFO) << "found duplicate warmup task for rowset " << 
rs->rowset_id()
                               << ", skip it";
                     continue;
@@ -318,12 +320,12 @@ void CloudWarmUpManager::handle_jobs() {
                                 
storage_resource.value()->remote_segment_path(*rs, seg_id),
                                 rs->segment_file_size(cast_set<int>(seg_id)), 
rs->fs(),
                                 expiration_time, wait, false,
-                                [tablet, rs, seg_id](Status st) {
+                                [tablet, rs, seg_id, generation](Status st) {
                                     VLOG_DEBUG << "warmup rowset " << 
rs->version() << " segment "
                                                << seg_id << " completed";
                                     if (tablet->complete_rowset_segment_warmup(
                                                       
WarmUpTriggerSource::JOB, rs->rowset_id(), st,
-                                                      1, 0)
+                                                      1, 0, *generation)
                                                 .trigger_source == 
WarmUpTriggerSource::JOB) {
                                         VLOG_DEBUG << "warmup rowset " << 
rs->version()
                                                    << " completed";
@@ -362,7 +364,7 @@ void CloudWarmUpManager::handle_jobs() {
                                 }
                             }
                             
tablet->update_rowset_warmup_state_inverted_idx_num(
-                                    WarmUpTriggerSource::JOB, rs->rowset_id(), 
1);
+                                    WarmUpTriggerSource::JOB, rs->rowset_id(), 
1, *generation);
                             submit_download_tasks(
                                     idx_path, file_size, rs->fs(), 
expiration_time, wait, true,
                                     [=](Status st) {
@@ -371,7 +373,7 @@ void CloudWarmUpManager::handle_jobs() {
                                                    << "inverted idx:" << 
idx_path << " completed";
                                         if 
(tablet->complete_rowset_segment_warmup(
                                                           
WarmUpTriggerSource::JOB, rs->rowset_id(),
-                                                          st, 0, 1)
+                                                          st, 0, 1, 
*generation)
                                                     .trigger_source == 
WarmUpTriggerSource::JOB) {
                                             VLOG_DEBUG << "warmup rowset " << 
rs->version()
                                                        << " completed";
@@ -386,7 +388,7 @@ void CloudWarmUpManager::handle_jobs() {
                             file_size = idx_file_info.has_index_size() ? 
idx_file_info.index_size()
                                                                        : -1;
                             
tablet->update_rowset_warmup_state_inverted_idx_num(
-                                    WarmUpTriggerSource::JOB, rs->rowset_id(), 
1);
+                                    WarmUpTriggerSource::JOB, rs->rowset_id(), 
1, *generation);
                             submit_download_tasks(
                                     idx_path, file_size, rs->fs(), 
expiration_time, wait, true,
                                     [=](Status st) {
@@ -395,7 +397,7 @@ void CloudWarmUpManager::handle_jobs() {
                                                    << "inverted idx:" << 
idx_path << " completed";
                                         if 
(tablet->complete_rowset_segment_warmup(
                                                           
WarmUpTriggerSource::JOB, rs->rowset_id(),
-                                                          st, 0, 1)
+                                                          st, 0, 1, 
*generation)
                                                     .trigger_source == 
WarmUpTriggerSource::JOB) {
                                             VLOG_DEBUG << "warmup rowset " << 
rs->version()
                                                        << " completed";
diff --git a/be/src/cloud/config.cpp b/be/src/cloud/config.cpp
index 36375b242ad..4261fe405c2 100644
--- a/be/src/cloud/config.cpp
+++ b/be/src/cloud/config.cpp
@@ -63,6 +63,8 @@ 
DEFINE_mInt32(cloud_single_rowset_compaction_segment_group_size, "64");
 
 DEFINE_mInt32(refresh_s3_info_interval_s, "60");
 DEFINE_mInt32(vacuum_stale_rowsets_interval_s, "300");
+// Retain recent completed attempts when warmup arrives before the target's 
metadata sync.
+DEFINE_mInt64(warm_up_rowset_state_gc_grace_period_seconds, "3600");
 DEFINE_mInt32(schedule_sync_tablets_interval_s, "600");
 
 DEFINE_mInt32(mow_stream_load_commit_retry_times, "5");
diff --git a/be/src/cloud/config.h b/be/src/cloud/config.h
index 270ca667688..033a8ddff95 100644
--- a/be/src/cloud/config.h
+++ b/be/src/cloud/config.h
@@ -104,6 +104,7 @@ 
DECLARE_mInt32(cloud_single_rowset_compaction_segment_group_size);
 // CloudStorageEngine config
 DECLARE_mInt32(refresh_s3_info_interval_s);
 DECLARE_mInt32(vacuum_stale_rowsets_interval_s);
+DECLARE_mInt64(warm_up_rowset_state_gc_grace_period_seconds);
 DECLARE_mInt32(schedule_sync_tablets_interval_s);
 
 // Cloud mow
diff --git a/be/test/cloud/cloud_tablet_mgr_test.cpp 
b/be/test/cloud/cloud_tablet_mgr_test.cpp
index a5e6968afb4..ac956dbc19a 100644
--- a/be/test/cloud/cloud_tablet_mgr_test.cpp
+++ b/be/test/cloud/cloud_tablet_mgr_test.cpp
@@ -35,6 +35,7 @@
 #include "cpp/sync_point.h"
 #include "storage/tablet/tablet_meta.h"
 #include "util/countdown_latch.h"
+#include "util/defer_op.h"
 #include "util/uid_util.h"
 
 namespace doris {
@@ -56,6 +57,41 @@ protected:
     CloudStorageEngine _engine;
 };
 
+TEST_F(CloudTabletMgrTest, 
VacuumReclaimsWarmupStatesWithoutStaleOrUnusedRowsets) {
+    auto sp = SyncPoint::get_instance();
+    sp->clear_all_call_backs();
+    Defer cleanup([sp] {
+        sp->disable_processing();
+        sp->clear_all_call_backs();
+    });
+    sp->set_call_back("CloudMetaMgr::get_tablet_meta", [this](auto&& args) {
+        *try_any_cast<TabletMetaSharedPtr*>(args[1]) = _tablet_meta;
+        try_any_cast_ret<Status>(args)->second = true;
+    });
+    sp->set_call_back("CloudMetaMgr::sync_tablet_rowsets",
+                      [](auto&& args) { try_any_cast_ret<Status>(args)->second 
= true; });
+    sp->enable_processing();
+
+    CloudTabletMgr mgr(_engine);
+    auto result = mgr.get_tablet(_tablet_meta->tablet_id());
+    ASSERT_TRUE(result.has_value()) << result.error();
+    auto tablet = result.value();
+    RowsetMeta rowset;
+    rowset.set_rowset_id(_engine.next_rowset_id());
+    rowset.set_num_segments(0);
+    ASSERT_TRUE(tablet->add_rowset_warmup_state(
+            rowset, WarmUpTriggerSource::EVENT_DRIVEN,
+            std::chrono::steady_clock::now() -
+                    
std::chrono::seconds(config::warm_up_rowset_state_gc_grace_period_seconds +
+                                         1)));
+    ASSERT_FALSE(tablet->has_stale_rowsets());
+    ASSERT_FALSE(tablet->need_remove_unused_rowsets());
+
+    CountDownLatch stop_latch(1);
+    mgr.vacuum_stale_rowsets(stop_latch);
+    EXPECT_EQ(tablet->get_rowset_warmup_state(rowset.rowset_id()).progress, 
WarmUpProgress::NONE);
+}
+
 // Test concurrent get_tablet calls for the same tablet_id.
 // Reproduces bug where tablet ends up in cache but not in _tablet_map.
 //
diff --git a/be/test/cloud/cloud_tablet_test.cpp 
b/be/test/cloud/cloud_tablet_test.cpp
index 7df8ad0607b..913d98e794b 100644
--- a/be/test/cloud/cloud_tablet_test.cpp
+++ b/be/test/cloud/cloud_tablet_test.cpp
@@ -24,7 +24,11 @@
 
 #include <chrono>
 #include <cstdint>
+#include <future>
+#include <mutex>
 #include <ranges>
+#include <shared_mutex>
+#include <tuple>
 
 #include "cloud/cloud_meta_mgr.h"
 #include "cloud/cloud_storage_engine.h"
@@ -69,6 +73,26 @@ public:
     }
 
 protected:
+    // Existing state-transition tests complete the current attempt. Tests for 
late
+    // callbacks pass the saved generation directly to the production 
interface.
+    uint64_t warmup_generation(const RowsetId& id) const {
+        std::shared_lock lock(_tablet->get_header_lock());
+        auto it = _tablet->_rowset_warm_up_states.find(id);
+        // The nonexistent-rowset test intentionally has no generation to 
complete.
+        return it == _tablet->_rowset_warm_up_states.end() ? 0 : 
it->second.generation;
+    }
+
+    WarmUpState complete_warmup(WarmUpTriggerSource source, RowsetId id, 
Status status,
+                                int64_t segments, int64_t indexes) {
+        return _tablet->complete_rowset_segment_warmup(source, id, status, 
segments, indexes,
+                                                       warmup_generation(id));
+    }
+
+    bool update_warmup_index_count(WarmUpTriggerSource source, RowsetId id, 
int64_t delta) {
+        return _tablet->update_rowset_warmup_state_inverted_idx_num(source, 
id, delta,
+                                                                    
warmup_generation(id));
+    }
+
     std::string _json_rowset_meta;
     TabletMetaSharedPtr _tablet_meta;
     std::shared_ptr<CloudTablet> _tablet;
@@ -77,6 +101,171 @@ protected:
 
 class CloudTabletDeleteBitmapTest : public CloudTabletWarmUpStateTest {};
 
+TEST_F(CloudTabletWarmUpStateTest, GcOnlyOldCompletedOrphans) {
+    const auto now = steady_clock::now();
+    const auto old = now - hours(2);
+    auto visible = create_rowset(Version(1, 1), 0);
+    auto stale = create_rowset(Version(2, 2), 0);
+    // A different RowsetId for the same version is not a live rowset.
+    auto orphan = create_rowset(Version(1, 1), 1);
+    auto recent = create_rowset(Version(3, 3), 0);
+    auto doing = create_rowset(Version(4, 4), 1);
+    auto pending_index = create_rowset(Version(5, 5), 1);
+    auto empty = create_rowset(Version(6, 6), 0);
+    ASSERT_TRUE(visible && stale && orphan && recent && doing && pending_index 
&& empty);
+
+    _tablet->_rs_version_map.emplace(visible->version(), visible);
+    _tablet->_stale_rs_version_map.emplace(stale->version(), stale);
+    for (const auto& rs : {visible, stale, orphan, doing, pending_index, 
empty}) {
+        ASSERT_TRUE(_tablet->add_rowset_warmup_state(*rs->rowset_meta(),
+                                                     
WarmUpTriggerSource::EVENT_DRIVEN, old));
+    }
+    ASSERT_TRUE(_tablet->add_rowset_warmup_state(
+            *recent->rowset_meta(), WarmUpTriggerSource::EVENT_DRIVEN, now - 
minutes(30)));
+    complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, orphan->rowset_id(), 
Status::OK(), 1, 0);
+    complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
pending_index->rowset_id(), Status::OK(), 1,
+                    0);
+    // The segment can complete before its index is registered. DONE alone is 
insufficient.
+    ASSERT_TRUE(update_warmup_index_count(WarmUpTriggerSource::EVENT_DRIVEN,
+                                          pending_index->rowset_id(), 1));
+    
ASSERT_EQ(_tablet->get_rowset_warmup_state(pending_index->rowset_id()).progress,
+              WarmUpProgress::DONE);
+
+    EXPECT_EQ(_tablet->gc_rowset_warmup_states(hours(1), now), 2);
+    EXPECT_EQ(_tablet->_rowset_warm_up_states.size(), 5);
+    
EXPECT_FALSE(_tablet->_rowset_warm_up_states.contains(orphan->rowset_id()));
+    EXPECT_FALSE(_tablet->_rowset_warm_up_states.contains(empty->rowset_id()));
+    for (const auto& rs : {visible, stale, recent, doing, pending_index}) {
+        EXPECT_TRUE(_tablet->_rowset_warm_up_states.contains(rs->rowset_id()));
+    }
+    EXPECT_FALSE(_tablet->is_rowset_warmed_up(doing->rowset_id()));
+    EXPECT_TRUE(_tablet->is_rowset_warmed_up(orphan->rowset_id()));
+}
+
+TEST_F(CloudTabletWarmUpStateTest, GcHonorsGracePeriodBoundary) {
+    const auto now = steady_clock::now();
+    auto expired = create_rowset(Version(1, 1), 0);
+    auto retained = create_rowset(Version(2, 2), 0);
+    ASSERT_TRUE(expired && retained);
+    ASSERT_TRUE(_tablet->add_rowset_warmup_state(
+            *expired->rowset_meta(), WarmUpTriggerSource::EVENT_DRIVEN, now - 
hours(1)));
+    ASSERT_TRUE(_tablet->add_rowset_warmup_state(*retained->rowset_meta(),
+                                                 
WarmUpTriggerSource::EVENT_DRIVEN,
+                                                 now - hours(1) + seconds(1)));
+    EXPECT_EQ(_tablet->gc_rowset_warmup_states(hours(1), now), 1);
+    
EXPECT_TRUE(_tablet->_rowset_warm_up_states.contains(retained->rowset_id()));
+    EXPECT_EQ(_tablet->gc_rowset_warmup_states(hours(1), now + seconds(1)), 1);
+}
+
+TEST_F(CloudTabletWarmUpStateTest, IgnoreSupersededCallbacksAfterOrphanGc) {
+    const auto now = steady_clock::now();
+    auto rowset = create_rowset(Version(1, 1), 2);
+    ASSERT_NE(rowset, nullptr);
+    const auto id = rowset->rowset_id();
+    const auto event_generation = _tablet->add_rowset_warmup_state(
+            *rowset->rowset_meta(), WarmUpTriggerSource::EVENT_DRIVEN, now - 
hours(2));
+    ASSERT_TRUE(event_generation);
+    // JOB can replace an EVENT_DRIVEN attempt whose callbacks are still 
outstanding.
+    const auto job_generation = _tablet->add_rowset_warmup_state(
+            *rowset->rowset_meta(), WarmUpTriggerSource::JOB, now - hours(2));
+    ASSERT_TRUE(job_generation);
+    _tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::JOB, id, 
Status::OK(), 2, 0,
+                                            *job_generation);
+    ASSERT_EQ(_tablet->gc_rowset_warmup_states(hours(1), now), 1);
+    const auto new_generation = _tablet->add_rowset_warmup_state(
+            *rowset->rowset_meta(), WarmUpTriggerSource::EVENT_DRIVEN, now);
+    ASSERT_TRUE(new_generation);
+    ASSERT_NE(*event_generation, *new_generation);
+
+    
EXPECT_EQ(_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN,
 id,
+                                                      Status::OK(), 1, 0, 
*event_generation)
+                      .progress,
+              WarmUpProgress::NONE);
+    EXPECT_FALSE(_tablet->update_rowset_warmup_state_inverted_idx_num(
+            WarmUpTriggerSource::EVENT_DRIVEN, id, 1, *event_generation));
+    EXPECT_EQ(_tablet->_rowset_warm_up_states.at(id).num_segments_warmed_up, 
0);
+    EXPECT_EQ(_tablet->_rowset_warm_up_states.at(id).num_inverted_idx, 0);
+    
EXPECT_EQ(_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN,
 id,
+                                                      Status::OK(), 1, 0, 
*new_generation)
+                      .progress,
+              WarmUpProgress::DOING);
+    
EXPECT_EQ(_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN,
 id,
+                                                      Status::OK(), 1, 0, 
*new_generation)
+                      .progress,
+              WarmUpProgress::DONE);
+}
+
+TEST_F(CloudTabletWarmUpStateTest, GcReleasesBucketsWithAndWithoutLiveStates) {
+    const auto now = steady_clock::now();
+    const auto empty_bucket_count = 
_tablet->_rowset_warm_up_states.bucket_count();
+    auto visible = create_rowset(Version(1, 1), 0);
+    ASSERT_NE(visible, nullptr);
+    _tablet->_rs_version_map.emplace(visible->version(), visible);
+    ASSERT_TRUE(_tablet->add_rowset_warmup_state(
+            *visible->rowset_meta(), WarmUpTriggerSource::EVENT_DRIVEN, now - 
hours(2)));
+    _tablet->_rowset_warm_up_states.reserve(4096);
+    const auto large_bucket_count = 
_tablet->_rowset_warm_up_states.bucket_count();
+    for (int i = 0; i < 128; ++i) {
+        auto rs = create_rowset(Version(i + 2, i + 2), 0);
+        ASSERT_NE(rs, nullptr);
+        ASSERT_TRUE(_tablet->add_rowset_warmup_state(
+                *rs->rowset_meta(), WarmUpTriggerSource::EVENT_DRIVEN, now - 
hours(2)));
+    }
+    EXPECT_EQ(_tablet->gc_rowset_warmup_states(hours(1), now), 128);
+    EXPECT_LT(_tablet->_rowset_warm_up_states.bucket_count(), 
large_bucket_count);
+    
EXPECT_TRUE(_tablet->_rowset_warm_up_states.contains(visible->rowset_id()));
+
+    _tablet->_rs_version_map.clear();
+    EXPECT_EQ(_tablet->gc_rowset_warmup_states(hours(1), now), 1);
+    EXPECT_EQ(_tablet->_rowset_warm_up_states.bucket_count(), 
empty_bucket_count);
+    // The old unused-Rowset GC can erase all nodes before this maintenance 
step runs.
+    _tablet->_rowset_warm_up_states.reserve(4096);
+    EXPECT_EQ(_tablet->gc_rowset_warmup_states(hours(1), now), 0);
+    EXPECT_EQ(_tablet->_rowset_warm_up_states.bucket_count(), 
empty_bucket_count);
+}
+
+TEST_F(CloudTabletWarmUpStateTest, ConcurrentCallbacksReadsAndOrphanGc) {
+    const auto now = steady_clock::now();
+    std::promise<void> ready;
+    auto start = ready.get_future().share();
+    auto rowset = create_rowset(Version(1, 1), 2);
+    ASSERT_NE(rowset, nullptr);
+    const auto id = rowset->rowset_id();
+    auto writer = std::async(std::launch::async, [&] {
+        start.wait();
+        for (int i = 0; i < 200; ++i) {
+            auto generation = _tablet->add_rowset_warmup_state(
+                    *rowset->rowset_meta(), WarmUpTriggerSource::JOB, now - 
hours(2));
+            ASSERT_TRUE(generation);
+            _tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::JOB, 
id, Status::OK(), 1,
+                                                    0, *generation);
+            _tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::JOB, 
id, Status::OK(), 1,
+                                                    0, *generation);
+        }
+    });
+    auto reader = std::async(std::launch::async, [&] {
+        start.wait();
+        for (int i = 0; i < 400; ++i) {
+            auto state = _tablet->get_rowset_warmup_state(id);
+            EXPECT_TRUE(state.progress == WarmUpProgress::NONE ||
+                        state.progress == WarmUpProgress::DOING ||
+                        state.progress == WarmUpProgress::DONE);
+        }
+    });
+    auto gc = std::async(std::launch::async, [&] {
+        start.wait();
+        for (int i = 0; i < 400; ++i) {
+            _tablet->gc_rowset_warmup_states(hours(1), now);
+        }
+    });
+    ready.set_value();
+    writer.get();
+    reader.get();
+    gc.get();
+    _tablet->gc_rowset_warmup_states(hours(1), now);
+    EXPECT_TRUE(_tablet->_rowset_warm_up_states.empty());
+}
+
 TEST_F(CloudTabletDeleteBitmapTest, 
AggDeleteBitmapForCompactionReturnsPreRowsetStats) {
     auto rowset1 = create_rowset(Version(1, 1), 2);
     auto rowset2 = create_rowset(Version(2, 2));
@@ -165,7 +354,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestAddRowsetWarmupStateTriggeredByJob) {
     auto rowset = create_rowset(Version(1, 1), 5);
     ASSERT_NE(rowset, nullptr);
 
-    bool result = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                    
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(result);
 
@@ -181,7 +370,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestAddRowsetWarmupStateTriggeredBySyncRowset
     auto rowset = create_rowset(Version(2, 2), 3);
     ASSERT_NE(rowset, nullptr);
 
-    bool result = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                    
WarmUpTriggerSource::SYNC_ROWSET);
     EXPECT_TRUE(result);
 
@@ -198,12 +387,12 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestAddDuplicateRowsetWarmupState) {
     ASSERT_NE(rowset, nullptr);
 
     // First addition should succeed
-    bool result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(result1);
 
     // Second addition should fail
-    bool result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::SYNC_ROWSET);
     EXPECT_FALSE(result2);
 
@@ -218,8 +407,8 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestAddDuplicateRowsetWarmupState) {
 TEST_F(CloudTabletWarmUpStateTest, TestCompleteRowsetSegmentWarmupNonExistent) 
{
     auto non_existent_id = _engine.next_rowset_id();
 
-    WarmUpState result = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::SYNC_ROWSET, non_existent_id, Status::OK(), 
1, 0);
+    WarmUpState result =
+            complete_warmup(WarmUpTriggerSource::SYNC_ROWSET, non_existent_id, 
Status::OK(), 1, 0);
     WarmUpState expected_state = WarmUpState {WarmUpTriggerSource::NONE, 
WarmUpProgress::NONE};
     EXPECT_EQ(result, expected_state);
 }
@@ -230,20 +419,20 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestCompleteRowsetSegmentWarmupPartial) {
     ASSERT_NE(rowset, nullptr);
 
     // Add rowset warmup state
-    bool add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                        
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(add_result);
 
     // Complete one segment, should still be in TRIGGERED_BY_EVENT_DRIVEN state
-    WarmUpState result1 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result1 = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                          Status::OK(), 1, 0);
     WarmUpState expected_state =
             WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result1, expected_state);
 
     // Complete second segment, should still be in TRIGGERED_BY_EVENT_DRIVEN 
state
-    WarmUpState result2 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result2 = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                          Status::OK(), 1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result2, expected_state);
 
@@ -259,20 +448,20 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestCompleteRowsetSegmentWarmupFull) {
     ASSERT_NE(rowset, nullptr);
 
     // Add rowset warmup state
-    bool add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                        
WarmUpTriggerSource::SYNC_ROWSET);
     EXPECT_TRUE(add_result);
 
     // Complete first segment
-    WarmUpState result1 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::SYNC_ROWSET, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result1 = complete_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset->rowset_id(),
+                                          Status::OK(), 1, 0);
     WarmUpState expected_state =
             WarmUpState {WarmUpTriggerSource::SYNC_ROWSET, 
WarmUpProgress::DOING};
     EXPECT_EQ(result1, expected_state);
 
     // Complete second segment, should transition to DONE state
-    WarmUpState result2 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::SYNC_ROWSET, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result2 = complete_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset->rowset_id(),
+                                          Status::OK(), 1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::SYNC_ROWSET, 
WarmUpProgress::DONE};
     EXPECT_EQ(result2, expected_state);
 
@@ -288,25 +477,25 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestCompleteRowsetSegmentWarmupWithInvertedIn
     ASSERT_NE(rowset, nullptr);
 
     // Add rowset warmup state
-    bool add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                        
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(add_result);
 
-    EXPECT_TRUE(_tablet->update_rowset_warmup_state_inverted_idx_num(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 1));
-    EXPECT_TRUE(_tablet->update_rowset_warmup_state_inverted_idx_num(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 1));
+    EXPECT_TRUE(
+            update_warmup_index_count(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(), 1));
+    EXPECT_TRUE(
+            update_warmup_index_count(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(), 1));
 
     // Complete one segment file
-    WarmUpState result1 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result1 = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                          Status::OK(), 1, 0);
     WarmUpState expected_state =
             WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result1, expected_state);
 
     // Complete inverted index file, should still be in 
TRIGGERED_BY_EVENT_DRIVEN state
-    WarmUpState result2 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
Status::OK(), 0, 1);
+    WarmUpState result2 = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                          Status::OK(), 0, 1);
     expected_state = WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result2, expected_state);
 
@@ -322,23 +511,23 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestCompleteRowsetSegmentWarmupWithInvertedIn
     ASSERT_NE(rowset, nullptr);
 
     // Add rowset warmup state
-    bool add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                        
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(add_result);
 
-    EXPECT_TRUE(_tablet->update_rowset_warmup_state_inverted_idx_num(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 1));
+    EXPECT_TRUE(
+            update_warmup_index_count(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(), 1));
 
     // Complete segment file
-    WarmUpState result1 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result1 = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                          Status::OK(), 1, 0);
     WarmUpState expected_state =
             WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result1, expected_state);
 
     // Complete inverted index file
-    WarmUpState result2 = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
Status::OK(), 0, 1);
+    WarmUpState result2 = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                          Status::OK(), 0, 1);
     expected_state = WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DONE};
     EXPECT_EQ(result2, expected_state);
 
@@ -354,14 +543,14 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestCompleteRowsetSegmentWarmupWithError) {
     ASSERT_NE(rowset, nullptr);
 
     // Add rowset warmup state
-    bool add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                        
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(add_result);
 
     // Complete with error status, should still transition to DONE when all 
segments complete
     Status error_status = Status::InternalError("Test error");
-    WarmUpState result = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
error_status, 1, 0);
+    WarmUpState result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                         error_status, 1, 0);
     WarmUpState expected_state =
             WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DONE};
     EXPECT_EQ(result, expected_state);
@@ -399,18 +588,18 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestMultipleRowsetsWarmupState) {
     EXPECT_EQ(_tablet->get_rowset_warmup_state(rowset3->rowset_id()), 
expected_state);
 
     // Complete rowset1 (2 segments)
-    WarmUpState result = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset1->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset1->rowset_id(),
+                                         Status::OK(), 1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result, expected_state);
-    result = 
_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN,
-                                                     rowset1->rowset_id(), 
Status::OK(), 1, 0);
+    result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset1->rowset_id(), Status::OK(),
+                             1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DONE};
     EXPECT_EQ(result, expected_state);
 
     // Complete rowset3 (1 segment)
-    result = 
_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN,
-                                                     rowset3->rowset_id(), 
Status::OK(), 1, 0);
+    result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset3->rowset_id(), Status::OK(),
+                             1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DONE};
     EXPECT_EQ(result, expected_state);
 
@@ -429,7 +618,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestWarmupStateWithZeroSegments) {
     ASSERT_NE(rowset, nullptr);
 
     // Add rowset with zero segments
-    bool add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto add_result = 
_tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                        
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(add_result);
 
@@ -454,17 +643,17 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestConcurrentWarmupStateAccess) {
                                                  
WarmUpTriggerSource::SYNC_ROWSET));
 
     // Interleaved completion operations
-    WarmUpState result = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset1->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset1->rowset_id(),
+                                         Status::OK(), 1, 0);
     WarmUpState expected_state =
             WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result, expected_state);
-    result = 
_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::SYNC_ROWSET,
-                                                     rowset2->rowset_id(), 
Status::OK(), 1, 0);
+    result = complete_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset2->rowset_id(), Status::OK(),
+                             1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::SYNC_ROWSET, 
WarmUpProgress::DOING};
     EXPECT_EQ(result, expected_state);
-    result = 
_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN,
-                                                     rowset1->rowset_id(), 
Status::OK(), 1, 0);
+    result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset1->rowset_id(), Status::OK(),
+                             1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DOING};
     EXPECT_EQ(result, expected_state);
 
@@ -480,31 +669,30 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestCompleteRowsetSegmentWarmupTriggerSource)
     auto rowset = create_rowset(Version(13, 13), 1);
     ASSERT_NE(rowset, nullptr);
     // Add rowset warmup state
-    bool add_result =
+    auto add_result =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(add_result);
 
     // Attempt to update inverted index num with a different trigger source, 
should fail
-    bool update_result = _tablet->update_rowset_warmup_state_inverted_idx_num(
-            WarmUpTriggerSource::SYNC_ROWSET, rowset->rowset_id(), 1);
+    bool update_result =
+            update_warmup_index_count(WarmUpTriggerSource::SYNC_ROWSET, 
rowset->rowset_id(), 1);
     EXPECT_FALSE(update_result);
-    update_result = _tablet->update_rowset_warmup_state_inverted_idx_num(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 1);
+    update_result =
+            update_warmup_index_count(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(), 1);
     EXPECT_FALSE(update_result);
 
     // Attempt to complete with a different trigger source, should not update 
state
-    WarmUpState result = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::SYNC_ROWSET, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result = complete_warmup(WarmUpTriggerSource::SYNC_ROWSET, 
rowset->rowset_id(),
+                                         Status::OK(), 1, 0);
     WarmUpState expected_state = WarmUpState {WarmUpTriggerSource::JOB, 
WarmUpProgress::DOING};
     EXPECT_EQ(result, expected_state);
-    result = 
_tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::EVENT_DRIVEN,
-                                                     rowset->rowset_id(), 
Status::OK(), 1, 0);
+    result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(), Status::OK(),
+                             1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::JOB, 
WarmUpProgress::DOING};
     EXPECT_EQ(result, expected_state);
 
     // Now complete with the correct trigger source
-    result = _tablet->complete_rowset_segment_warmup(WarmUpTriggerSource::JOB, 
rowset->rowset_id(),
-                                                     Status::OK(), 1, 0);
+    result = complete_warmup(WarmUpTriggerSource::JOB, rowset->rowset_id(), 
Status::OK(), 1, 0);
     expected_state = WarmUpState {WarmUpTriggerSource::JOB, 
WarmUpProgress::DONE};
     EXPECT_EQ(result, expected_state);
 }
@@ -515,7 +703,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobTriggerOverridesNonJobStates) {
     ASSERT_NE(rowset, nullptr);
 
     // First, add EVENT_DRIVEN warmup state
-    bool result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(result1);
 
@@ -526,7 +714,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobTriggerOverridesNonJobStates) {
     EXPECT_EQ(state, expected_state);
 
     // Now add JOB warmup state, should override EVENT_DRIVEN
-    bool result2 =
+    auto result2 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result2);
 
@@ -542,7 +730,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobTriggerOverridesSyncRowsetState) {
     ASSERT_NE(rowset, nullptr);
 
     // First, add SYNC_ROWSET warmup state
-    bool result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::SYNC_ROWSET);
     EXPECT_TRUE(result1);
 
@@ -553,7 +741,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobTriggerOverridesSyncRowsetState) {
     EXPECT_EQ(state, expected_state);
 
     // Now add JOB warmup state, should override SYNC_ROWSET
-    bool result2 =
+    auto result2 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result2);
 
@@ -569,7 +757,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobTriggerCannotOverrideAnotherJob) {
     ASSERT_NE(rowset, nullptr);
 
     // First, add JOB warmup state
-    bool result1 =
+    auto result1 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result1);
 
@@ -579,7 +767,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobTriggerCannotOverrideAnotherJob) {
     EXPECT_EQ(state, expected_state);
 
     // Try to add another JOB warmup state, should fail
-    bool result2 =
+    auto result2 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_FALSE(result2);
 
@@ -595,7 +783,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestEventDrivenCannotOverrideJobState) {
     ASSERT_NE(rowset, nullptr);
 
     // First, add JOB warmup state
-    bool result1 =
+    auto result1 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result1);
 
@@ -605,7 +793,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestEventDrivenCannotOverrideJobState) {
     EXPECT_EQ(state, expected_state);
 
     // Try to add EVENT_DRIVEN warmup state, should fail
-    bool result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_FALSE(result2);
 
@@ -621,7 +809,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestSyncRowsetCannotOverrideJobState) {
     ASSERT_NE(rowset, nullptr);
 
     // First, add JOB warmup state
-    bool result1 =
+    auto result1 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result1);
 
@@ -631,7 +819,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestSyncRowsetCannotOverrideJobState) {
     EXPECT_EQ(state, expected_state);
 
     // Try to add SYNC_ROWSET warmup state, should fail
-    bool result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::SYNC_ROWSET);
     EXPECT_FALSE(result2);
 
@@ -647,7 +835,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestEventDrivenCannotOverrideSyncRowsetState)
     ASSERT_NE(rowset, nullptr);
 
     // First, add SYNC_ROWSET warmup state
-    bool result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::SYNC_ROWSET);
     EXPECT_TRUE(result1);
 
@@ -658,7 +846,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestEventDrivenCannotOverrideSyncRowsetState)
     EXPECT_EQ(state, expected_state);
 
     // Try to add EVENT_DRIVEN warmup state, should fail
-    bool result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_FALSE(result2);
 
@@ -674,7 +862,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestSyncRowsetCannotOverrideEventDrivenState)
     ASSERT_NE(rowset, nullptr);
 
     // First, add EVENT_DRIVEN warmup state
-    bool result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(result1);
 
@@ -685,7 +873,7 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestSyncRowsetCannotOverrideEventDrivenState)
     EXPECT_EQ(state, expected_state);
 
     // Try to add SYNC_ROWSET warmup state, should fail
-    bool result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result2 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::SYNC_ROWSET);
     EXPECT_FALSE(result2);
 
@@ -701,19 +889,19 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobCanOverrideDoneStateFromNonJob) {
     ASSERT_NE(rowset, nullptr);
 
     // First, add EVENT_DRIVEN warmup state
-    bool result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
+    auto result1 = _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()),
                                                     
WarmUpTriggerSource::EVENT_DRIVEN);
     EXPECT_TRUE(result1);
 
     // Complete the warmup to DONE state
-    WarmUpState result = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::EVENT_DRIVEN, rowset->rowset_id(), 
Status::OK(), 1, 0);
+    WarmUpState result = complete_warmup(WarmUpTriggerSource::EVENT_DRIVEN, 
rowset->rowset_id(),
+                                         Status::OK(), 1, 0);
     WarmUpState expected_state =
             WarmUpState {WarmUpTriggerSource::EVENT_DRIVEN, 
WarmUpProgress::DONE};
     EXPECT_EQ(result, expected_state);
 
     // Now add JOB warmup state, should override the DONE state
-    bool result2 =
+    auto result2 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result2);
 
@@ -729,18 +917,18 @@ TEST_F(CloudTabletWarmUpStateTest, 
TestJobCanOverrideDoneStateFromJob) {
     ASSERT_NE(rowset, nullptr);
 
     // First, add EVENT_DRIVEN warmup state
-    bool result1 =
+    auto result1 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result1);
 
     // Complete the warmup to DONE state
-    WarmUpState result = _tablet->complete_rowset_segment_warmup(
-            WarmUpTriggerSource::JOB, rowset->rowset_id(), Status::OK(), 1, 0);
+    WarmUpState result =
+            complete_warmup(WarmUpTriggerSource::JOB, rowset->rowset_id(), 
Status::OK(), 1, 0);
     WarmUpState expected_state = WarmUpState {WarmUpTriggerSource::JOB, 
WarmUpProgress::DONE};
     EXPECT_EQ(result, expected_state);
 
     // Now add JOB warmup state, should override the DONE state
-    bool result2 =
+    auto result2 =
             _tablet->add_rowset_warmup_state(*(rowset->rowset_meta()), 
WarmUpTriggerSource::JOB);
     EXPECT_TRUE(result2);
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to