Skip to main content

ic_memory/ledger/
error.rs

1use crate::{
2    key::{StableKey, StableKeyError},
3    ledger::LedgerPayloadEnvelopeError,
4    physical::CommitRecoveryError,
5    slot::MemoryManagerSlot,
6};
7
8///
9/// LedgerIntegrityError
10///
11/// Decoded ledger violates structural allocation-history invariants.
12///
13
14#[non_exhaustive]
15#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
16pub enum LedgerIntegrityError {
17    /// Current structural recovery ceiling exceeded.
18    #[error("ledger exceeds {resource} limit {limit}")]
19    LimitExceeded {
20        resource: &'static str,
21        limit: usize,
22    },
23    /// Stable key appears in more than one allocation record.
24    #[error("stable key '{stable_key}' appears in more than one allocation record")]
25    DuplicateStableKey {
26        /// Duplicate stable key.
27        stable_key: StableKey,
28    },
29    /// Allocation slot appears in more than one allocation record.
30    #[error("allocation slot '{slot:?}' appears in more than one allocation record")]
31    DuplicateSlot {
32        /// Duplicate allocation slot.
33        slot: MemoryManagerSlot,
34    },
35    /// Allocation record generation ordering is invalid.
36    #[error("stable key '{stable_key}' has first_generation after last_seen_generation")]
37    InvalidRecordGenerationOrder {
38        /// Stable key whose record is invalid.
39        stable_key: StableKey,
40        /// First generation in the record.
41        first_generation: u64,
42        /// Last seen generation in the record.
43        last_seen_generation: u64,
44    },
45    /// Allocation record points past the current generation.
46    #[error(
47        "stable key '{stable_key}' references generation {generation} after current generation {current_generation}"
48    )]
49    FutureRecordGeneration {
50        /// Stable key whose record is invalid.
51        stable_key: StableKey,
52        /// Generation referenced by the record.
53        generation: u64,
54        /// Current ledger generation.
55        current_generation: u64,
56    },
57    /// Retired generation predates the allocation record.
58    #[error("stable key '{stable_key}' was retired before first_generation")]
59    RetiredBeforeFirstGeneration {
60        /// Stable key whose record is invalid.
61        stable_key: StableKey,
62        /// First generation in the record.
63        first_generation: u64,
64        /// Retired generation in the record.
65        retired_generation: u64,
66    },
67    /// Retirement does not occur after the record's final observation.
68    #[error("stable key '{stable_key}' was retired at or before last_seen_generation")]
69    RetirementNotAfterLastSeen {
70        /// Stable key whose record is invalid.
71        stable_key: StableKey,
72        /// Latest generation that observed the allocation.
73        last_seen_generation: u64,
74        /// Generation that retired the allocation.
75        retired_generation: u64,
76    },
77    /// Allocation record has no schema metadata history.
78    #[error("stable key '{stable_key}' has empty schema metadata history")]
79    EmptySchemaHistory {
80        /// Stable key whose record is invalid.
81        stable_key: StableKey,
82    },
83    /// First schema metadata record does not begin with the allocation record.
84    #[error(
85        "stable key '{stable_key}' has schema metadata that does not begin at first_generation"
86    )]
87    SchemaHistoryStartMismatch {
88        /// Stable key whose record is invalid.
89        stable_key: StableKey,
90        /// Allocation's first committed generation.
91        first_generation: u64,
92        /// First schema metadata generation.
93        schema_generation: u64,
94    },
95    /// Schema metadata generation history is not strictly increasing.
96    #[error("stable key '{stable_key}' has non-increasing schema metadata generation history")]
97    NonIncreasingSchemaHistory {
98        /// Stable key whose record is invalid.
99        stable_key: StableKey,
100    },
101    /// Schema metadata generation is outside the allocation record lifetime.
102    #[error("stable key '{stable_key}' has schema metadata generation outside the ledger bounds")]
103    SchemaHistoryOutOfBounds {
104        /// Stable key whose record is invalid.
105        stable_key: StableKey,
106        /// Schema metadata generation.
107        generation: u64,
108    },
109    /// Schema metadata was recorded after the allocation was last observed.
110    #[error("stable key '{stable_key}' has schema metadata after last_seen_generation")]
111    SchemaHistoryAfterLastSeen {
112        /// Stable key whose record is invalid.
113        stable_key: StableKey,
114        /// Schema metadata generation.
115        generation: u64,
116        /// Latest generation that observed the allocation.
117        last_seen_generation: u64,
118    },
119    /// Generation record appears more than once.
120    #[error("generation {generation} appears more than once")]
121    DuplicateGeneration {
122        /// Duplicate generation.
123        generation: u64,
124    },
125    /// Generation record points past the current generation.
126    #[error("generation {generation} is after current generation {current_generation}")]
127    FutureGeneration {
128        /// Generation record value.
129        generation: u64,
130        /// Current ledger generation.
131        current_generation: u64,
132    },
133    /// Generation parent does not precede the child generation.
134    #[error("generation {generation} has invalid parent generation {parent_generation}")]
135    InvalidParentGeneration {
136        /// Generation record value.
137        generation: u64,
138        /// Invalid parent generation.
139        parent_generation: u64,
140    },
141    /// Current ledger generation has no committed generation record.
142    #[error("current generation {current_generation} has no committed generation record")]
143    MissingCurrentGenerationRecord {
144        /// Current ledger generation.
145        current_generation: u64,
146    },
147    /// Generation records are not strictly increasing in durable order.
148    #[error("generation records are not strictly increasing at generation {generation}")]
149    NonIncreasingGenerationRecords {
150        /// Non-increasing generation.
151        generation: u64,
152    },
153    /// Generation record parent does not match the previous committed generation.
154    #[error(
155        "generation {generation} does not link to previous committed generation {expected_parent}"
156    )]
157    BrokenGenerationChain {
158        /// Generation whose parent link is invalid.
159        generation: u64,
160        /// Expected parent generation.
161        expected_parent: u64,
162        /// Actual parent generation.
163        actual_parent: u64,
164    },
165    /// Allocation record refers to a generation absent from committed history.
166    #[error("stable key '{stable_key}' references unknown generation {generation}")]
167    UnknownRecordGeneration {
168        /// Stable key whose record is invalid.
169        stable_key: StableKey,
170        /// Unknown generation.
171        generation: u64,
172    },
173}
174
175///
176/// LedgerCommitError
177///
178/// Failure to recover or commit a logical allocation ledger.
179#[non_exhaustive]
180#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
181pub enum LedgerCommitError {
182    /// Protected physical commit recovery failed.
183    #[error(transparent)]
184    Recovery(CommitRecoveryError),
185    /// Logical ledger payload envelope could not be decoded.
186    #[error(transparent)]
187    PayloadEnvelope(LedgerPayloadEnvelopeError),
188    /// Physical slot generation and decoded logical ledger generation disagree.
189    #[error(
190        "physical generation {physical_generation} does not match logical ledger generation {logical_generation}"
191    )]
192    PhysicalLogicalGenerationMismatch {
193        /// Generation encoded in the physical commit slot.
194        physical_generation: u64,
195        /// Generation decoded from the logical allocation ledger.
196        logical_generation: u64,
197    },
198    /// Built-in ledger decoding failed.
199    #[error("allocation ledger codec failed: {0}")]
200    Codec(String),
201    /// Decoded ledger violates structural allocation-history invariants.
202    #[error(transparent)]
203    Integrity(LedgerIntegrityError),
204}
205
206///
207/// AllocationStageError
208///
209/// Failure to stage a validated allocation generation.
210///
211
212#[non_exhaustive]
213#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
214pub enum AllocationStageError {
215    #[error(transparent)]
216    Integrity(#[from] LedgerIntegrityError),
217    /// Validated declarations were produced against a different ledger generation.
218    #[error(
219        "validated allocations were produced at generation {validated_generation}, but ledger is at generation {ledger_generation}"
220    )]
221    StaleValidatedAllocations {
222        /// Generation carried by the validated allocation capability.
223        validated_generation: u64,
224        /// Current ledger generation.
225        ledger_generation: u64,
226    },
227    /// Stable key was historically bound to a different slot.
228    #[error("stable key '{stable_key}' was historically bound to a different allocation slot")]
229    StableKeySlotConflict {
230        /// Stable key being declared.
231        stable_key: StableKey,
232        /// Historical slot for the stable key.
233        historical_slot: MemoryManagerSlot,
234        /// Slot claimed by the declaration.
235        declared_slot: MemoryManagerSlot,
236    },
237    /// Slot was historically bound to a different stable key.
238    #[error("allocation slot '{slot:?}' was historically bound to stable key '{historical_key}'")]
239    SlotStableKeyConflict {
240        /// Slot being declared.
241        slot: MemoryManagerSlot,
242        /// Historical stable key for the slot.
243        historical_key: StableKey,
244        /// Stable key claimed by the declaration.
245        declared_key: StableKey,
246    },
247    /// Current declaration attempted to revive a retired allocation.
248    #[error("stable key '{stable_key}' was explicitly retired and cannot be redeclared")]
249    RetiredAllocation {
250        /// Retired stable key.
251        stable_key: StableKey,
252        /// Retired allocation slot.
253        slot: MemoryManagerSlot,
254    },
255}
256
257///
258/// AllocationReservationError
259///
260/// Failure to stage a reservation generation.
261#[non_exhaustive]
262#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
263pub enum AllocationReservationError {
264    #[error(transparent)]
265    Integrity(#[from] LedgerIntegrityError),
266    /// Ledger generation cannot be advanced without overflow.
267    #[error("ledger generation {generation} cannot be advanced without overflow")]
268    GenerationOverflow {
269        /// Current ledger generation.
270        generation: u64,
271    },
272    /// Reservation count exceeds the usable allocation-slot domain.
273    #[error("generation contains {count} reservations, exceeding the 255-allocation limit")]
274    TooManyReservations {
275        /// Number of reservations in the staged generation.
276        count: usize,
277    },
278    /// Stable key was historically bound to a different slot.
279    #[error("stable key '{stable_key}' was historically bound to a different allocation slot")]
280    StableKeySlotConflict {
281        /// Stable key being reserved.
282        stable_key: StableKey,
283        /// Historical slot for the stable key.
284        historical_slot: MemoryManagerSlot,
285        /// Slot claimed by the reservation.
286        reserved_slot: MemoryManagerSlot,
287    },
288    /// Slot was historically bound to a different stable key.
289    #[error("allocation slot '{slot:?}' was historically bound to stable key '{historical_key}'")]
290    SlotStableKeyConflict {
291        /// Slot being reserved.
292        slot: MemoryManagerSlot,
293        /// Historical stable key for the slot.
294        historical_key: StableKey,
295        /// Stable key claimed by the reservation.
296        reserved_key: StableKey,
297    },
298    /// Allocation already exists as an active record.
299    #[error("stable key '{stable_key}' is already active and cannot be reserved")]
300    ActiveAllocation {
301        /// Active stable key.
302        stable_key: StableKey,
303        /// Active allocation slot.
304        slot: MemoryManagerSlot,
305    },
306    /// Allocation was already retired and cannot be reserved.
307    #[error("stable key '{stable_key}' was explicitly retired and cannot be reserved")]
308    RetiredAllocation {
309        /// Retired stable key.
310        stable_key: StableKey,
311        /// Retired allocation slot.
312        slot: MemoryManagerSlot,
313    },
314}
315
316///
317/// AllocationRetirementError
318///
319/// Failure to stage an explicit retirement generation.
320#[non_exhaustive]
321#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
322pub enum AllocationRetirementError {
323    #[error(transparent)]
324    Integrity(#[from] LedgerIntegrityError),
325    /// Stable-key grammar failure.
326    #[error(transparent)]
327    Key(StableKeyError),
328    /// Ledger generation cannot be advanced without overflow.
329    #[error("ledger generation {generation} cannot be advanced without overflow")]
330    GenerationOverflow {
331        /// Current ledger generation.
332        generation: u64,
333    },
334    /// Stable key has no historical allocation record.
335    #[error("stable key '{0}' has no allocation record to retire")]
336    UnknownStableKey(StableKey),
337    /// Stable key was historically bound to a different slot.
338    #[error("stable key '{stable_key}' cannot be retired for a different allocation slot")]
339    SlotMismatch {
340        /// Stable key being retired.
341        stable_key: StableKey,
342        /// Historical slot for the stable key.
343        historical_slot: MemoryManagerSlot,
344        /// Slot named by the retirement request.
345        retired_slot: MemoryManagerSlot,
346    },
347    /// Allocation was already retired.
348    #[error("stable key '{stable_key}' was already retired")]
349    AlreadyRetired {
350        /// Retired stable key.
351        stable_key: StableKey,
352        /// Retired allocation slot.
353        slot: MemoryManagerSlot,
354    },
355}