Skip to main content

ic_memory/ledger/
error.rs

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