Skip to main content

ic_memory/ledger/
error.rs

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