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

Code before:
        }
    }

    #[inline]
    pub fn flush_entry_cache_metrics(&mut self) {
        // NOTE: memory usage of entry cache is flushed realtime.
        self.cache.flush_stats();
        self.raftlog_fetch_stats.flush_stats();
    }

    pub fn raft_engine(&self) -> &ER {
        &self.raft_engine
    }

    pub fn update_cache_persisted(&mut self, persisted: u64) {
        self.cache.update_persisted(persisted);
    }

    pub fn trace_cached_entries(&mut self, entries: CachedEntries) {
        self.cache.trace_cached_entries(entries);
    }

    #[inline]
    pub fn compact_term_cache(&mut self, idx: u64) {
        // Get the term of the given index.
        let _ = self.term(idx).map(|term| self.term_cache.compact_to(term));
    }

    #[inline]
    pub fn update_term_cache(&mut self, index: u64, term: u64) {
        self.term_cache.append(index, term);
    }

    pub fn clear(&mut self) {
        self.cache = EntryCache::default();
        self.term_cache = TermCache::default();
    }

    pub fn read_scheduler(&self) -> Scheduler<ReadTask<EK>> {
        self.read_scheduler.clone()
    }
}

#[cfg(test)]
pub mod tests {
    use std::{assert_matches::assert_matches, sync::mpsc};

    use engine_test::{kv::KvTestEngine, raft::RaftTestEngine};
    use engine_traits::RaftEngineReadOnly;
    use protobuf::Message;
    use raft::{GetEntriesContext, StorageError};

Review comment (performance):
The `compact_term_cache` method calls `self.term(idx)` which may trigger I/O if the term is not in cache, defeating the purpose of the optimization. Consider checking the term cache first or using a different approach to get the term for compaction.

Code after:

        if !self.is_entry_cache_empty() {
            let cache = &mut self.cache;
            let cache_len = cache.cache.len();
            let drain_to = if half { cache_len / 2 } else { cache_len - 1 };
            let idx = cache.cache[drain_to].index;
            let mem_size_change = cache.compact_to(idx + 1);
            RAFT_ENTRIES_EVICT_BYTES.inc_by(mem_size_change);
        } else if !half {
            let cache = &mut self.cache;
            let mem_size_change = cache.compact_to(u64::MAX);
            RAFT_ENTRIES_EVICT_BYTES.inc_by(mem_size_change);
        }
    }

    #[inline]
    pub fn flush_entry_cache_metrics(&mut self) {
        // NOTE: memory usage of entry cache is flushed realtime.
        self.cache.flush_stats();
        self.raftlog_fetch_stats.flush_stats();
    }

    pub fn raft_engine(&self) -> &ER {
        &self.raft_engine
    }

    pub fn update_cache_persisted(&mut self, persisted: u64) {
        self.cache.update_persisted(persisted);
    }

    pub fn trace_cached_entries(&mut self, entries: CachedEntries) {
        self.cache.trace_cached_entries(entries);
    }

    #[inline]
    pub fn compact_term_cache(&mut self, index: u64) {
        self.term_cache.compact_to(index);
    }

    #[inline]
    pub fn update_term_cache(&mut self, index: u64, term: u64) {
        self.term_cache.append(index, term);
    }

    pub fn clear(&mut self) {
        self.cache = EntryCache::default();
        self.term_cache = TermCache::default();
    }

    pub fn read_scheduler(&self) -> Scheduler<ReadTask<EK>> {
        self.read_scheduler.clone()