Repository: tikv/tikv
File: components/raftstore/src/store/entry_storage.rs (Rust)

Code before:
/// recent entries. Each cache entry contains:
/// - term: The term number of a sequence of entries
/// - latest_index: The highest log index that shares this term
///
/// The cache maintains entries in descending order by index, allowing quick
/// lookups of terms for any given log index. The small fixed capacity helps
/// keep memory overhead minimal while caching the most relevant term
/// information.
struct TermCache {
    cache: VecDeque<(u64, u64)>, // (term, latest_index)
    capacity: usize,
}

impl Default for TermCache {
    fn default() -> Self {
        TermCache {
            cache: Default::default(),
            capacity: 8, /* 8 is enough for the recent updated terms.
                          * Small capacity will make the extra memory
                          * cost negligible. */
        }
    }
}

impl TermCache {
    fn append(&mut self, index: u64, term: u64) {
        // Update the previous entry if it's in the same term.
        if let Some(first_term) = self.cache.front().map(|(first_term, _)| *first_term) {
            if first_term > term {
                return;
            }
            let pos = (term - first_term) as usize;
            if pos < self.cache.len() {
                let (t, idx) = self.cache[pos];
                assert_eq!(t, term);
                if idx < index {
                    self.cache[pos].1 = index;
                }
                return;
            }
        }
        // New term.
        self.cache.push_back((term, index));
        if self.cache.len() > self.capacity {
            self.cache.pop_front();
        }
    }

    /// Push entries to the left of the cache.
    fn prepend(&mut self, entries: &[Entry]) {
        for e in entries.iter().rev() {

Review comment (suggestion):
It needs to support raft log gc to reflect truncated logs, because raft-rs determines whether to send a snapshot based on the results of the `term()` method.

Code after:
/// This cache optimizes term lookups by storing term-to-index mappings for
/// recent entries. Each cache entry contains:
/// - term: The term number of a sequence of entries
/// - start_index: The start raft log index that shares this term
///
/// The cache maintains entries in monotonically increasing order by term,
/// allowing quick lookups of terms for any given log index. The small fixed
/// capacity helps keep memory overhead minimal while caching the most relevant
/// term information.
struct TermCache {
    cache: VecDeque<(u64, u64)>, // (term, start_index)
    capacity: usize,
}

impl Default for TermCache {
    fn default() -> Self {
        TermCache {
            cache: Default::default(),
            capacity: 8, /* 8 is enough for the recent updated terms.
                          * Small capacity will make the extra memory
                          * cost negligible. */
        }
    }
}

impl TermCache {
    fn append(&mut self, index: u64, term: u64) {
        // Check if we can update an existing entry or insert into the cache
        if let Some(first_term) = self.cache.front().map(|(first_term, _)| *first_term) {
            match first_term.cmp(&(term + 1)) {
                Greater => {
                    // Skip terms with gaps, as they represent stale/unfresh information.
                    return;
                }
                Equal => {
                    // Insert older term at the front if there's available space.
                    if self.cache.len() < self.capacity {
                        self.cache.push_front((term, index));
                    }
                    return;
                }
                Less => {
                    // Calculate position of the term in the cache (terms are stored sequentially)
                    let pos = (term - first_term) as usize;
                    if pos < self.cache.len() {
                        let (cached_term, cached_start_idx) = self.cache[pos];
                        assert_eq!(cached_term, term);

                        // Update start index only if the new index is smaller (extends the term
                        // range)
                        if cached_start_idx > index {