krabka_verified/
producer_snapshot.rs1#[cfg(creusot)]
15use crate::producer::ProducerDecision;
16use creusot_std::prelude::*;
17
18#[cfg(creusot)]
20#[cfg_attr(test, mutants::skip)]
21#[logic(open)]
22pub(crate) fn retained_producer_row(end: Int, row: ProducerSnapshotEntryFacts, pid: i64) -> bool {
24 pearlite! {
25 snapshot_entry_valid_model(end, row) && row.last_offset@ >= 0
26 && row.producer_id == pid
27 }
28}
29
30#[cfg(creusot)]
32#[cfg_attr(test, mutants::skip)]
33#[logic(open)]
34pub fn snapshot_sequence_matches(row: ProducerSnapshotEntryFacts, base: Int, delta: Int) -> bool {
36 pearlite! {
37 base == crate::producer::sequence_modulo_2_31(row.last_sequence@ - row.offset_delta@)
38 && row.last_sequence@ == crate::producer::sequence_modulo_2_31(base + delta)
39 }
40}
41
42#[cfg(creusot)]
44#[cfg_attr(test, mutants::skip)]
45#[logic(open)]
46pub(crate) fn recovered_batch_coordinates(
48 row: ProducerSnapshotEntryFacts,
49 base: Int,
50 frontier: Int,
51 end: Int,
52) -> bool {
53 pearlite! { base == row.last_offset@ - row.offset_delta@
54 && frontier == row.last_offset@ + 1
55 && 0 <= base && base < frontier && frontier <= end }
56}
57
58#[cfg(creusot)]
60#[cfg_attr(test, mutants::skip)]
61#[logic(open)]
62pub(crate) fn nonduplicate_snapshot_decision(
64 incoming_epoch: Int,
65 epoch: Int,
66 sequence: Int,
67 last_sequence: Int,
68) -> ProducerDecision {
69 pearlite! { if incoming_epoch < epoch { ProducerDecision::Fenced }
70 else if incoming_epoch > epoch {
71 if sequence == 0 { ProducerDecision::Append } else { ProducerDecision::OutOfOrder }
72 } else if sequence == crate::producer::sequence_modulo_2_31(last_sequence + 1) { ProducerDecision::Append }
73 else { ProducerDecision::OutOfOrder } }
74}
75
76#[krabka_macros::model_type]
81pub struct ProducerReloadRange {
82 pub log_start: i64,
85 pub local_start: i64,
88 pub log_end: i64,
90}
91
92#[krabka_macros::model_type(proof(std::clone::Clone, Copy))]
99pub struct ProducerSnapshotEntryFacts {
100 pub producer_id: i64,
102 pub producer_epoch: i16,
104 pub last_sequence: i32,
106 pub last_offset: i64,
108 pub offset_delta: i32,
110 pub coordinator_epoch: i32,
112 pub current_txn_first_offset: i64,
114}
115
116mod snapshot_transaction_valid;
117#[cfg(test)]
118pub(crate) use snapshot_transaction_valid::take_classifier_visits;
119#[cfg(creusot)]
120pub use snapshot_transaction_valid::{
121 is_segment_base, kafka_reload_keeps, kafka_replay_start, kafka_stray_removed,
122 snapshot_last_record_valid, snapshot_transaction_valid,
123};
124pub use snapshot_transaction_valid::{
125 producer_snapshot_latest_index, producer_snapshot_reload_keeps,
126 producer_snapshot_reload_log_start, producer_snapshot_stray, producer_snapshot_strays,
127};
128
129mod replay_start;
130#[cfg(creusot)]
131pub use replay_start::snapshot_entry_valid_model;
132pub use replay_start::{producer_snapshot_entry_valid, producer_snapshot_replay_start};
133
134#[cfg(creusot)]
136#[cfg_attr(test, mutants::skip)]
137#[logic(open)]
138pub(crate) fn producer_offsets_ordered(rows: Seq<ProducerSnapshotEntryFacts>) -> bool {
140 pearlite! { forall<i: Int, j: Int> 0 <= i && i < j && j < rows.len() ==> rows[i].last_offset@ < rows[j].last_offset@ }
141}
142
143#[cfg(test)]
144mod tests;