Skip to content

Commit b19f5cf

Browse files
committed
TQ: Support persisting state to ledger
Builds on #9296 This commit persists state to a ledger, following the pattern used in the bootstore. It's done this way because the `PersistentState` itself is contained in the sans-io layer, but we must save it in the async task layer. The sans-io layer shouldn't know how the state is persisted, just that it is, and so we recreate the ledger for every time we write it. A follow up will PR will deal with the early networking information saved by the bootstore, and will be very similar.
1 parent a505cda commit b19f5cf

File tree

5 files changed

+281
-7
lines changed

5 files changed

+281
-7
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

trust-quorum/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ gfss.workspace = true
2222
hex.workspace = true
2323
hkdf.workspace = true
2424
iddqd.workspace = true
25+
omicron-common.workspace = true
2526
omicron-uuid-kinds.workspace = true
2627
rand = { workspace = true, features = ["os_rng"] }
2728
secrecy.workspace = true

trust-quorum/src/ledgers.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! Persistent storage for the trust quorum task
6+
//!
7+
//! We write two pieces of data to M.2 devices in production via
8+
//! [`omicron_common::ledger::Ledger`]:
9+
//!
10+
//! 1. [`trust_quorum_protocol::PersistentState`] for trust quorum state
11+
//! 2. A network config blob required for pre-rack-unlock configuration
12+
13+
use camino::Utf8PathBuf;
14+
use omicron_common::ledger::{Ledger, Ledgerable};
15+
use serde::{Deserialize, Serialize};
16+
use slog::{Logger, info};
17+
use trust_quorum_protocol::PersistentState;
18+
19+
/// A wrapper type around [`PersistentState`] for use as a [`Ledger`]
20+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21+
pub struct PersistentStateLedger {
22+
pub generation: u64,
23+
pub state: PersistentState,
24+
}
25+
26+
impl Ledgerable for PersistentStateLedger {
27+
fn is_newer_than(&self, other: &Self) -> bool {
28+
self.generation > other.generation
29+
}
30+
31+
fn generation_bump(&mut self) {
32+
self.generation += 1;
33+
}
34+
}
35+
36+
impl PersistentStateLedger {
37+
/// Save the persistent state to a ledger and return the new generation
38+
/// number.
39+
///
40+
/// Panics if the ledger cannot be saved.
41+
pub async fn save(
42+
log: &Logger,
43+
paths: Vec<Utf8PathBuf>,
44+
generation: u64,
45+
state: PersistentState,
46+
) -> u64 {
47+
let persistent_state = PersistentStateLedger { generation, state };
48+
let mut ledger = Ledger::new_with(log, paths, persistent_state);
49+
ledger
50+
.commit()
51+
.await
52+
.expect("Critical: Failed to save bootstore ledger for Fsm::State");
53+
ledger.data().generation
54+
}
55+
56+
/// Return Some(`PersistentStateLedger`) if it exists on disk, otherwise
57+
/// return `None`.
58+
pub async fn load(
59+
log: &Logger,
60+
paths: Vec<Utf8PathBuf>,
61+
) -> Option<PersistentStateLedger> {
62+
let Some(ledger) =
63+
Ledger::<PersistentStateLedger>::new(&log, paths).await
64+
else {
65+
return None;
66+
};
67+
let persistent_state = ledger.into_inner();
68+
info!(
69+
log,
70+
"Loaded persistent state from ledger with generation {}",
71+
persistent_state.generation
72+
);
73+
Some(persistent_state)
74+
}
75+
}

trust-quorum/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
mod connection_manager;
88
pub(crate) mod established_conn;
9+
mod ledgers;
910
mod task;
1011

1112
pub(crate) use connection_manager::{

0 commit comments

Comments
 (0)