meta_srv/gc/
tracker.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::{HashMap, HashSet};
16use std::time::Instant;
17
18use common_telemetry::info;
19use store_api::storage::RegionId;
20
21use crate::error::Result;
22use crate::gc::scheduler::GcScheduler;
23
24/// Tracks GC timing information for a region.
25#[derive(Debug, Clone)]
26pub(crate) struct RegionGcInfo {
27    /// Last time a regular GC was performed on this region.
28    pub(crate) last_gc_time: Instant,
29    /// Last time a full file listing GC was performed on this region.
30    pub(crate) last_full_listing_time: Option<Instant>,
31}
32
33/// Tracks the last GC time for regions to implement cooldown.
34pub(crate) type RegionGcTracker = HashMap<RegionId, RegionGcInfo>;
35
36impl GcScheduler {
37    /// Clean up stale entries from the region GC tracker if enough time has passed.
38    /// This removes entries for regions that no longer exist in the current table routes.
39    pub(crate) async fn cleanup_tracker_if_needed(&self) -> Result<()> {
40        let last_cleanup = *self.last_tracker_cleanup.lock().await;
41        let now = Instant::now();
42
43        // Check if enough time has passed since last cleanup
44        if now.saturating_duration_since(last_cleanup) < self.config.tracker_cleanup_interval {
45            return Ok(());
46        }
47
48        info!("Starting region GC tracker cleanup");
49        let cleanup_start = Instant::now();
50
51        // Get all current region IDs from table routes
52        let table_to_region_stats = self.ctx.get_table_to_region_stats().await?;
53        let mut current_regions = HashSet::new();
54        for region_stats in table_to_region_stats.values() {
55            for region_stat in region_stats {
56                current_regions.insert(region_stat.id);
57            }
58        }
59
60        let table_reparts = self.ctx.get_table_reparts().await?;
61        for (_, repart) in table_reparts {
62            for src_region in repart.src_to_dst.keys() {
63                current_regions.insert(*src_region);
64            }
65        }
66
67        // Remove stale entries from tracker
68        let mut tracker = self.region_gc_tracker.lock().await;
69        let initial_count = tracker.len();
70        tracker.retain(|region_id, _| current_regions.contains(region_id));
71        let removed_count = initial_count - tracker.len();
72
73        *self.last_tracker_cleanup.lock().await = now;
74
75        info!(
76            "Completed region GC tracker cleanup: removed {} stale entries out of {} total (retained {}). Duration: {:?}",
77            removed_count,
78            initial_count,
79            tracker.len(),
80            cleanup_start.elapsed()
81        );
82
83        Ok(())
84    }
85
86    pub(crate) async fn update_full_listing_time(
87        &self,
88        region_id: RegionId,
89        did_full_listing: bool,
90    ) {
91        let mut gc_tracker = self.region_gc_tracker.lock().await;
92        let now = Instant::now();
93
94        gc_tracker
95            .entry(region_id)
96            .and_modify(|info| {
97                if did_full_listing {
98                    info.last_full_listing_time = Some(now);
99                }
100                info.last_gc_time = now;
101            })
102            .or_insert_with(|| RegionGcInfo {
103                last_gc_time: now,
104                // prevent need to full listing on the first GC
105                last_full_listing_time: Some(now),
106            });
107    }
108}