heddle_pack/store/pack/repack/
policy.rs1#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
5pub struct RepackInventory {
6 pub loose_objects: u64,
8 pub loose_bytes: u64,
10 pub pack_count: u64,
12 pub pack_bytes: u64,
14 pub duplicate_objects: u64,
16 pub packed_objects: u64,
18}
19
20impl RepackInventory {
21 pub fn fragmentation_bps(self) -> u16 {
23 if self.packed_objects == 0 {
24 return 0;
25 }
26 let bps = self
27 .duplicate_objects
28 .saturating_mul(10_000)
29 .checked_div(self.packed_objects)
30 .unwrap_or(0);
31 bps.min(10_000) as u16
32 }
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub enum RepackReason {
38 Manual,
40 LooseObjects { count: u64 },
42 PackCount { count: u64 },
44 PackBytes { bytes: u64 },
46 Fragmentation { basis_points: u16 },
48}
49
50#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub struct RepackPolicy {
56 pub loose_object_threshold: Option<u64>,
58 pub pack_count_threshold: Option<u64>,
60 pub pack_bytes_threshold: Option<u64>,
62 pub fragmentation_threshold_bps: Option<u16>,
64}
65
66impl Default for RepackPolicy {
67 fn default() -> Self {
68 Self {
69 loose_object_threshold: Some(10_000),
70 pack_count_threshold: Some(8),
71 pack_bytes_threshold: Some(1024 * 1024 * 1024),
72 fragmentation_threshold_bps: Some(1_500),
73 }
74 }
75}
76
77impl RepackPolicy {
78 pub fn evaluate(self, inventory: RepackInventory) -> Option<RepackReason> {
80 if self
81 .loose_object_threshold
82 .is_some_and(|threshold| inventory.loose_objects >= threshold)
83 {
84 return Some(RepackReason::LooseObjects {
85 count: inventory.loose_objects,
86 });
87 }
88 if self
89 .pack_count_threshold
90 .is_some_and(|threshold| inventory.pack_count >= threshold)
91 {
92 return Some(RepackReason::PackCount {
93 count: inventory.pack_count,
94 });
95 }
96 if inventory.pack_count > 1
97 && self
98 .pack_bytes_threshold
99 .is_some_and(|threshold| inventory.pack_bytes >= threshold)
100 {
101 return Some(RepackReason::PackBytes {
102 bytes: inventory.pack_bytes,
103 });
104 }
105 let fragmentation = inventory.fragmentation_bps();
106 if self
107 .fragmentation_threshold_bps
108 .is_some_and(|threshold| fragmentation >= threshold)
109 {
110 return Some(RepackReason::Fragmentation {
111 basis_points: fragmentation,
112 });
113 }
114 None
115 }
116}