Select segments for compaction based on the configuration. Returns segments to compact, sorted by min_lsn (oldest first). Selects segments that: 1. Are too small (below target size) 2. Have high tombstone ratios 3. Are adjacent in LSN space (can be merged cleanly)
(
segments: &[SegmentMeta],
config: &CompactionConfig,
)
| 100 | /// 2. Have high tombstone ratios |
| 101 | /// 3. Are adjacent in LSN space (can be merged cleanly) |
| 102 | pub fn select_segments_for_compaction( |
| 103 | segments: &[SegmentMeta], |
| 104 | config: &CompactionConfig, |
| 105 | ) -> Vec<usize> { |
| 106 | if segments.len() < config.min_segments_to_compact { |
| 107 | return Vec::new(); |
| 108 | } |
| 109 | |
| 110 | let mut candidates: Vec<(usize, &SegmentMeta)> = segments |
| 111 | .iter() |
| 112 | .enumerate() |
| 113 | .filter(|(_, s)| { |
| 114 | s.size_bytes < config.target_segment_bytes as u64 |
| 115 | || s.needs_compaction(config.tombstone_ratio_threshold) |
| 116 | }) |
| 117 | .collect(); |
| 118 | |
| 119 | // Sort by min_lsn (oldest first) for monotonic ordering. |
| 120 | candidates.sort_by_key(|(_, s)| s.min_lsn); |
| 121 | |
| 122 | // Take up to max_segments_per_pass. |
| 123 | candidates |
| 124 | .iter() |
| 125 | .take(config.max_segments_per_pass) |
| 126 | .map(|(i, _)| *i) |
| 127 | .collect() |
| 128 | } |
| 129 | |
| 130 | /// Plan a compaction: compute the expected output segment metadata. |
| 131 | /// |