krabka_verified/retention/
delete_target.rs1#[cfg(creusot)]
2use super::{remote_prefix_charge, remote_retention_model};
3use {super::RemoteRetentionSegment, creusot_std::prelude::*};
4
5#[ensures(result@ == if deletes_allowed {
21 remote_retention_model(segments@, 0, size_debt@)
22} else {
23 0
24})]
25#[ensures(result@ <= [email protected]())]
26#[ensures(!deletes_allowed ==> result@ == 0)]
27#[ensures(retention_prefix_funded(segments@, size_debt@, result@))]
28#[ensures(deletes_allowed && result@ < [email protected]()
29 ==> segments@[result@].blocked || (!segments@[result@].log_start_breached && !segments@[result@].time_expired
30 && (size_debt@ == 0 || remote_prefix_charge(segments@, result@) >= size_debt@
31 || remote_prefix_charge(segments@, result@ + 1) > size_debt@)))]
32#[must_use]
33pub fn remote_retention_prefix(
34 deletes_allowed: bool,
35 segments: &[RemoteRetentionSegment],
36 size_debt: u64,
37) -> usize {
38 if !deletes_allowed {
39 return 0;
40 }
41 let mut debt = size_debt;
42 let mut len = 0usize;
43 #[invariant(len@ <= [email protected]())]
44 #[invariant(remote_prefix_charge(segments@, len@) >= 0)]
45 #[invariant(debt@ == if remote_prefix_charge(segments@, len@) <= size_debt@ {
46 size_debt@ - remote_prefix_charge(segments@, len@)
47 } else { 0 })]
48 #[invariant(retention_prefix_funded(segments@, size_debt@, len@))]
49 #[invariant(remote_retention_model(segments@, len@, debt@)
50 == remote_retention_model(segments@, 0, size_debt@))]
51 #[variant([email protected]() - len@)]
52 while len < segments.len() {
53 let Some(&segment) = segments.get(len) else {
54 break;
55 };
56 if segment.blocked {
57 break;
58 }
59 if segment.log_start_breached {
60 } else if segment.time_expired {
62 debt = debt.saturating_sub(segment.size);
63 } else if debt > 0 && segment.size <= debt {
64 debt -= segment.size;
65 } else {
66 break;
67 }
68 len += 1;
69 }
70 len
71}
72
73#[ensures(match (last_offset, result) {
79 (None, result) => result == None,
80 (Some(last), None) => last@ == i64::MAX@,
81 (Some(last), Some(target)) => last@ < i64::MAX@ && target@ == last@ + 1,
82})]
83#[must_use]
84pub fn retention_delete_target(last_offset: Option<i64>) -> Option<i64> {
85 match last_offset {
86 Some(last) if last < i64::MAX => Some(last + 1),
87 Some(_) | None => None,
88 }
89}
90
91#[cfg(creusot)]
93#[cfg_attr(test, mutants::skip)]
94#[logic(open)]
95fn retention_prefix_funded(segments: Seq<RemoteRetentionSegment>, debt: Int, count: Int) -> bool {
97 pearlite! { forall<i: Int> 0 <= i && i < count ==> !segments[i].blocked && (segments[i].log_start_breached
98 || segments[i].time_expired || (super::remote_charge_funded(debt, remote_prefix_charge(segments, i), remote_prefix_charge(segments, i + 1)))) }
99}