Skip to main content

lora_store/
snapshot.rs

1//! Snapshot value types — the portable payload + metadata + error
2//! vocabulary every backend speaks.
3//!
4//! The on-disk snapshot container lives in the [`lora-snapshot`] crate
5//! (column-oriented, optionally compressed and authenticated). Backends
6//! produce a [`SnapshotPayload`] through their inherent helpers (e.g.
7//! [`super::InMemoryGraph::snapshot_payload`]); `lora-snapshot` encodes
8//! that payload and reuses the small store-owned binary codec for nested
9//! value/catalog records.
10
11use serde::{Deserialize, Serialize};
12use thiserror::Error;
13
14use crate::memory::{ConstraintDefinition, IndexDefinition, VectorIndexSnapshot};
15use crate::{NodeId, NodeRecord, RelationshipId, RelationshipRecord};
16
17/// Portable representation of an entire store state.
18///
19/// Backends produce and consume this struct through inherent helpers;
20/// the byte-level codec is owned by `lora-snapshot`.
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
22pub struct SnapshotPayload {
23    pub next_node_id: NodeId,
24    pub next_rel_id: RelationshipId,
25    pub nodes: Vec<NodeRecord>,
26    pub relationships: Vec<RelationshipRecord>,
27    /// Catalog of explicitly-declared indexes. Defaulted to empty so
28    /// older snapshots that lack the trailer round-trip cleanly.
29    #[serde(default)]
30    pub indexes: Vec<IndexDefinition>,
31    /// Catalog of explicitly-declared constraints. Defaulted to empty
32    /// so snapshots from versions before constraint support survive
33    /// the round-trip.
34    #[serde(default)]
35    pub constraints: Vec<ConstraintDefinition>,
36    /// Persisted ANN backend state (HNSW today). Defaulted to empty
37    /// so older snapshots that lack the trailer rebuild via the
38    /// existing property-store backfill. Each entry maps to one
39    /// catalog index by name.
40    #[serde(default)]
41    pub vector_indexes: Vec<VectorIndexSnapshot>,
42}
43
44impl SnapshotPayload {
45    pub fn empty() -> Self {
46        Self {
47            next_node_id: 0,
48            next_rel_id: 0,
49            nodes: Vec::new(),
50            relationships: Vec::new(),
51            indexes: Vec::new(),
52            constraints: Vec::new(),
53            vector_indexes: Vec::new(),
54        }
55    }
56}
57
58/// Metadata reported by snapshot encode / decode entry points. Kept
59/// small and stable so callers can log / diff it without reflecting on
60/// the payload.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct SnapshotMeta {
63    /// Format version the payload is written in.
64    pub format_version: u32,
65    /// Number of nodes in the snapshot.
66    pub node_count: usize,
67    /// Number of relationships in the snapshot.
68    pub relationship_count: usize,
69    /// WAL log position captured alongside the snapshot, if any. `None` for
70    /// pure (non-checkpoint) snapshots.
71    pub wal_lsn: Option<u64>,
72}
73
74/// Errors a backend may surface while building or restoring a snapshot
75/// payload. Codec-level errors live in [`lora-snapshot`]; these are the
76/// store-side payload-shaped failures.
77#[derive(Debug, Error)]
78pub enum SnapshotError {
79    #[error("snapshot I/O error: {0}")]
80    Io(#[from] std::io::Error),
81
82    #[error("snapshot payload could not be decoded: {0}")]
83    Decode(String),
84
85    #[error("snapshot payload could not be encoded: {0}")]
86    Encode(String),
87}