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