cfxcore/block_data_manager/
db_gc_manager.rs

1use malloc_size_of_derive::MallocSizeOf as DeriveMallocSizeOf;
2use std::cmp::min;
3
4/// Each time we make a new checkpoint, we will mark more data as garbage
5/// depending on the parameters. To avoid the GC process affecting normal
6/// transaction execution or RPC-handling, we GC data gradually, and expect to
7/// finish removing the data in a previous era with less time than the period
8/// that the consensus graph makes a new era (the default configuration is to
9/// finish GC with half an era).
10#[derive(Default, DeriveMallocSizeOf, Debug)]
11pub struct GCProgress {
12    // The earliest not-garbage-collected epoch.
13    // This is the only field that we persist to disk as the GC progress.
14    pub next_to_process: u64,
15
16    // The last epoch that we are allowed to garbage collect.
17    pub gc_end: u64,
18
19    // The best epoch number of the last time we garbage collect data.
20    // This is compared with the latest epoch number to decide how many epochs
21    // to GC this time.
22    pub last_consensus_best_epoch: u64,
23
24    // The epoch number that we want to finish garbage collection of
25    // `self.gc_end`.
26    pub expected_end_consensus_best_epoch: u64,
27}
28
29impl GCProgress {
30    pub fn new(next_to_process: u64) -> Self {
31        Self {
32            next_to_process,
33            ..Default::default()
34        }
35    }
36
37    /// Compute the GC base range to make sure the GC progress is proportional
38    /// to the consensus progress.
39    /// The actual GC range for each kind of data is the returned base range
40    /// minus the corresponding `additional_maintained*` offset.
41    ///
42    /// Return `Some((start_epoch, end_epoch))` and the range `[start_epoch,
43    /// end_epoch)` will be GCed. Return `None` if there is no work to be
44    /// done.
45    pub fn get_gc_base_range(&self, best_epoch: u64) -> Option<(u64, u64)> {
46        if self.gc_end <= self.next_to_process
47            || best_epoch <= self.last_consensus_best_epoch
48        {
49            return None;
50        }
51        let best_epoch =
52            min(best_epoch, self.expected_end_consensus_best_epoch);
53        let batch_size = (self.gc_end - self.next_to_process)
54            * (best_epoch - self.last_consensus_best_epoch)
55            / (self.expected_end_consensus_best_epoch
56                - self.last_consensus_best_epoch);
57        Some((self.next_to_process, self.next_to_process + batch_size))
58    }
59}