Skip to content

Commit 9564992

Browse files
committed
rework call-once-ness of spawn_reconciliation_task
1 parent a41323a commit 9564992

File tree

1 file changed

+47
-46
lines changed

1 file changed

+47
-46
lines changed

sled-agent/config-reconciler/src/handle.rs

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ use sled_storage::manager::NestedDatasetConfig;
1717
use sled_storage::manager::NestedDatasetListOptions;
1818
use sled_storage::manager::NestedDatasetLocation;
1919
use slog::Logger;
20-
use slog::warn;
2120
use std::sync::Arc;
22-
use std::sync::Mutex;
2321
use std::sync::OnceLock;
2422
use tokio::sync::watch;
2523

@@ -59,6 +57,16 @@ pub enum TimeSyncConfig {
5957
Skip,
6058
}
6159

60+
#[derive(Debug)]
61+
pub struct ConfigReconcilerHandleSpawnToken {
62+
key_requester: StorageKeyRequester,
63+
time_sync_config: TimeSyncConfig,
64+
reconciler_result_tx: watch::Sender<ReconcilerResult>,
65+
currently_managed_zpools_tx: watch::Sender<Arc<CurrentlyManagedZpools>>,
66+
ledger_task_log: Logger,
67+
reconciler_task_log: Logger,
68+
}
69+
6270
#[derive(Debug)]
6371
pub struct ConfigReconcilerHandle {
6472
raw_disks_tx: RawDisksSender,
@@ -67,15 +75,8 @@ pub struct ConfigReconcilerHandle {
6775
reconciler_result_rx: watch::Receiver<ReconcilerResult>,
6876
currently_managed_zpools_rx: CurrentlyManagedZpoolsReceiver,
6977

70-
// `None` until `spawn_reconciliation_task()` is called.
78+
// Empty until `spawn_reconciliation_task()` is called.
7179
ledger_task: OnceLock<LedgerTaskHandle>,
72-
73-
// We have a two-phase initialization: we get some of our dependencies when
74-
// `Self::new()` is called and the rest when
75-
// `Self::spawn_reconciliation_task()` is called. We hold the dependencies
76-
// that are available in `new` but not needed until
77-
// `spawn_reconciliation_task` in this field.
78-
reconciler_task_dependencies: Mutex<Option<ReconcilerTaskDependencies>>,
7980
}
8081

8182
impl ConfigReconcilerHandle {
@@ -93,7 +94,7 @@ impl ConfigReconcilerHandle {
9394
key_requester: StorageKeyRequester,
9495
time_sync_config: TimeSyncConfig,
9596
base_log: &Logger,
96-
) -> Self {
97+
) -> (Self, ConfigReconcilerHandleSpawnToken) {
9798
let mount_config = Arc::new(mount_config);
9899

99100
// Spawn the task that monitors our internal disks (M.2s).
@@ -111,14 +112,27 @@ impl ConfigReconcilerHandle {
111112
base_log,
112113
);
113114

114-
// Stash the dependencies the reconciler task will need in
115-
// `spawn_reconciliation_task()`.
116115
let (reconciler_result_tx, reconciler_result_rx) =
117116
watch::channel(ReconcilerResult::default());
118117
let (currently_managed_zpools_tx, currently_managed_zpools_rx) =
119118
watch::channel(Arc::default());
120-
let reconciler_task_dependencies =
121-
Mutex::new(Some(ReconcilerTaskDependencies {
119+
120+
(
121+
Self {
122+
raw_disks_tx,
123+
internal_disks_rx,
124+
dataset_task,
125+
ledger_task: OnceLock::new(),
126+
reconciler_result_rx,
127+
currently_managed_zpools_rx:
128+
CurrentlyManagedZpoolsReceiver::new(
129+
currently_managed_zpools_rx,
130+
),
131+
},
132+
// Stash the dependencies the reconciler task will need in
133+
// `spawn_reconciliation_task()` inside this token that the caller
134+
// has to hold until it has the other outside dependencies ready.
135+
ConfigReconcilerHandleSpawnToken {
122136
key_requester,
123137
time_sync_config,
124138
reconciler_result_tx,
@@ -127,25 +141,19 @@ impl ConfigReconcilerHandle {
127141
.new(slog::o!("component" => "SledConfigLedgerTask")),
128142
reconciler_task_log: base_log
129143
.new(slog::o!("component" => "ConfigReconcilerTask")),
130-
}));
131-
132-
Self {
133-
raw_disks_tx,
134-
internal_disks_rx,
135-
dataset_task,
136-
ledger_task: OnceLock::new(),
137-
reconciler_result_rx,
138-
currently_managed_zpools_rx: CurrentlyManagedZpoolsReceiver::new(
139-
currently_managed_zpools_rx,
140-
),
141-
reconciler_task_dependencies,
142-
}
144+
},
145+
)
143146
}
144147

145148
/// Spawn the primary config reconciliation task.
146149
///
147-
/// This method can effectively only be called once; any subsequent calls
148-
/// will log a warning and do nothing.
150+
/// This method can effectively only be called once, because the caller must
151+
/// supply the `token` returned by `new()` when this handle was created.
152+
///
153+
/// # Panics
154+
///
155+
/// Panics if called multiple times, which is statically impossible outside
156+
/// shenanigans to get a second `ConfigReconcilerHandleSpawnToken`.
149157
pub fn spawn_reconciliation_task<
150158
T: SledAgentFacilities,
151159
U: SledAgentArtifactStore,
@@ -154,26 +162,16 @@ impl ConfigReconcilerHandle {
154162
underlay_vnic: EtherstubVnic,
155163
sled_agent_facilities: T,
156164
sled_agent_artifact_store: U,
157-
log: &Logger,
165+
token: ConfigReconcilerHandleSpawnToken,
158166
) {
159-
let ReconcilerTaskDependencies {
167+
let ConfigReconcilerHandleSpawnToken {
160168
key_requester,
161169
time_sync_config,
162170
reconciler_result_tx,
163171
currently_managed_zpools_tx,
164172
ledger_task_log,
165173
reconciler_task_log,
166-
} = match self.reconciler_task_dependencies.lock().unwrap().take() {
167-
Some(dependencies) => dependencies,
168-
None => {
169-
warn!(
170-
log,
171-
"spawn_reconciliation_task() called multiple times \
172-
(ignored after first call)"
173-
);
174-
return;
175-
}
176-
};
174+
} = token;
177175

178176
// Spawn the task that manages our config ledger.
179177
let (ledger_task, current_config_rx) =
@@ -184,10 +182,13 @@ impl ConfigReconcilerHandle {
184182
);
185183
match self.ledger_task.set(ledger_task) {
186184
Ok(()) => (),
187-
// We know via the `lock().take()` above that this only executes
188-
// once, so `ledger_task` is always set here.
185+
// We can only be called with the `token` we returned in `new()` and
186+
// we document that we panic if called multiple times via some
187+
// multi-token shenanigans.
189188
Err(_) => {
190-
unreachable!("spawn_reconciliation_task() only executes once")
189+
panic!(
190+
"spawn_reconciliation_task() called with multiple tokens"
191+
)
191192
}
192193
}
193194

0 commit comments

Comments
 (0)