11b1a2175SSamuel Ortiz // Copyright © 2019 Intel Corporation
21b1a2175SSamuel Ortiz //
31b1a2175SSamuel Ortiz // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
41b1a2175SSamuel Ortiz //
51b1a2175SSamuel Ortiz
66f5d4702SRob Bradford use anyhow::anyhow;
76f5d4702SRob Bradford use serde::{Deserialize, Serialize};
81b1a2175SSamuel Ortiz use thiserror::Error;
91b1a2175SSamuel Ortiz
1088a9f799SRob Bradford use crate::protocol::MemoryRangeTable;
1188a9f799SRob Bradford
12aa98589bSRob Bradford pub mod protocol;
13aa98589bSRob Bradford
141b1a2175SSamuel Ortiz #[derive(Error, Debug)]
151b1a2175SSamuel Ortiz pub enum MigratableError {
16*30ee2c12SPhilipp Schuster #[error("Failed to pause migratable component")]
171b1a2175SSamuel Ortiz Pause(#[source] anyhow::Error),
181b1a2175SSamuel Ortiz
19*30ee2c12SPhilipp Schuster #[error("Failed to resume migratable component")]
201b1a2175SSamuel Ortiz Resume(#[source] anyhow::Error),
211b1a2175SSamuel Ortiz
22*30ee2c12SPhilipp Schuster #[error("Failed to snapshot migratable component")]
231b1a2175SSamuel Ortiz Snapshot(#[source] anyhow::Error),
241b1a2175SSamuel Ortiz
25*30ee2c12SPhilipp Schuster #[error("Failed to restore migratable component")]
261b1a2175SSamuel Ortiz Restore(#[source] anyhow::Error),
271b1a2175SSamuel Ortiz
28*30ee2c12SPhilipp Schuster #[error("Failed to send migratable component snapshot")]
291b1a2175SSamuel Ortiz MigrateSend(#[source] anyhow::Error),
301b1a2175SSamuel Ortiz
31*30ee2c12SPhilipp Schuster #[error("Failed to receive migratable component snapshot")]
321b1a2175SSamuel Ortiz MigrateReceive(#[source] anyhow::Error),
33aa98589bSRob Bradford
34*30ee2c12SPhilipp Schuster #[error("Socket error")]
35aa98589bSRob Bradford MigrateSocket(#[source] std::io::Error),
36c1b96204SSebastien Boeuf
37*30ee2c12SPhilipp Schuster #[error("Failed to start migration for migratable component")]
381c3f8236SSebastien Boeuf StartDirtyLog(#[source] anyhow::Error),
39c1b96204SSebastien Boeuf
40*30ee2c12SPhilipp Schuster #[error("Failed to stop migration for migratable component")]
411c3f8236SSebastien Boeuf StopDirtyLog(#[source] anyhow::Error),
42c1b96204SSebastien Boeuf
43*30ee2c12SPhilipp Schuster #[error("Failed to retrieve dirty ranges for migratable component")]
441c3f8236SSebastien Boeuf DirtyLog(#[source] anyhow::Error),
45f65538b0SSebastien Boeuf
46*30ee2c12SPhilipp Schuster #[error("Failed to start migration for migratable component")]
47a9ccb20eSSebastien Boeuf StartMigration(#[source] anyhow::Error),
48a9ccb20eSSebastien Boeuf
49*30ee2c12SPhilipp Schuster #[error("Failed to complete migration for migratable component")]
50f65538b0SSebastien Boeuf CompleteMigration(#[source] anyhow::Error),
5105968f5cSPhilipp Schuster
52*30ee2c12SPhilipp Schuster #[error("Failed to release a disk lock before the migration")]
5305968f5cSPhilipp Schuster UnlockError(#[source] anyhow::Error),
541b1a2175SSamuel Ortiz }
551b1a2175SSamuel Ortiz
561b1a2175SSamuel Ortiz /// A Pausable component can be paused and resumed.
571b1a2175SSamuel Ortiz pub trait Pausable {
581b1a2175SSamuel Ortiz /// Pause the component.
pause(&mut self) -> std::result::Result<(), MigratableError>591b1a2175SSamuel Ortiz fn pause(&mut self) -> std::result::Result<(), MigratableError> {
601b1a2175SSamuel Ortiz Ok(())
611b1a2175SSamuel Ortiz }
621b1a2175SSamuel Ortiz
631b1a2175SSamuel Ortiz /// Resume the component.
resume(&mut self) -> std::result::Result<(), MigratableError>641b1a2175SSamuel Ortiz fn resume(&mut self) -> std::result::Result<(), MigratableError> {
651b1a2175SSamuel Ortiz Ok(())
661b1a2175SSamuel Ortiz }
671b1a2175SSamuel Ortiz }
681b1a2175SSamuel Ortiz
691b1a2175SSamuel Ortiz /// A Snapshottable component snapshot section.
7060c8a72eSBo Chen ///
711b1a2175SSamuel Ortiz /// Migratable component can split their migration snapshot into
721b1a2175SSamuel Ortiz /// separate sections.
731b1a2175SSamuel Ortiz /// Splitting a component migration data into different sections
741b1a2175SSamuel Ortiz /// allows for easier and forward compatible extensions.
751b1a2175SSamuel Ortiz #[derive(Clone, Default, Deserialize, Serialize)]
7610ab87d6SRob Bradford pub struct SnapshotData {
7710ab87d6SRob Bradford state: String,
7810ab87d6SRob Bradford }
791b1a2175SSamuel Ortiz
804517b76aSSebastien Boeuf impl SnapshotData {
8108c4e503SRob Bradford /// Generate the state data from the snapshot data
to_state<'a, T>(&'a self) -> Result<T, MigratableError> where T: Deserialize<'a>,8208c4e503SRob Bradford pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError>
8308c4e503SRob Bradford where
8408c4e503SRob Bradford T: Deserialize<'a>,
8508c4e503SRob Bradford {
8610ab87d6SRob Bradford serde_json::from_str(&self.state)
875b3bcfa2SSebastien Boeuf .map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {}", e)))
88bbda0871SRob Bradford }
89bbda0871SRob Bradford
9008c4e503SRob Bradford /// Create from state that can be serialized
new_from_state<T>(state: &T) -> Result<Self, MigratableError> where T: Serialize,915b3bcfa2SSebastien Boeuf pub fn new_from_state<T>(state: &T) -> Result<Self, MigratableError>
9208c4e503SRob Bradford where
9308c4e503SRob Bradford T: Serialize,
9408c4e503SRob Bradford {
9510ab87d6SRob Bradford let state = serde_json::to_string(state)
965b3bcfa2SSebastien Boeuf .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {}", e)))?;
9708c4e503SRob Bradford
9810ab87d6SRob Bradford Ok(SnapshotData { state })
99bbda0871SRob Bradford }
10008c4e503SRob Bradford }
10108c4e503SRob Bradford
10260c8a72eSBo Chen /// Data structure to describe snapshot data
10360c8a72eSBo Chen ///
10412b72ba3SPhilipp Schuster /// A Snapshottable component's snapshot is a tree of snapshots, where leaves
1051b1a2175SSamuel Ortiz /// contain the snapshot data. Nodes of this tree track all their children
1061b1a2175SSamuel Ortiz /// through the snapshots field, which is basically their sub-components.
1071b1a2175SSamuel Ortiz /// Leaves will typically have an empty snapshots map, while nodes usually
1081b1a2175SSamuel Ortiz /// carry an empty snapshot_data.
1091b1a2175SSamuel Ortiz ///
1101b1a2175SSamuel Ortiz /// For example, a device manager snapshot is the composition of all its
1111b1a2175SSamuel Ortiz /// devices snapshots. The device manager Snapshot would have no snapshot_data
1121b1a2175SSamuel Ortiz /// but one Snapshot child per tracked device. Then each device's Snapshot
1134517b76aSSebastien Boeuf /// would carry an empty snapshots map but a map of SnapshotData, i.e.
1141b1a2175SSamuel Ortiz /// the actual device snapshot data.
1151b1a2175SSamuel Ortiz #[derive(Clone, Default, Deserialize, Serialize)]
1161b1a2175SSamuel Ortiz pub struct Snapshot {
1171b1a2175SSamuel Ortiz /// The Snapshottable component snapshots.
1181d104331SSebastien Boeuf pub snapshots: std::collections::BTreeMap<String, Snapshot>,
1191b1a2175SSamuel Ortiz
1201b1a2175SSamuel Ortiz /// The Snapshottable component's snapshot data.
1211b1a2175SSamuel Ortiz /// A map of snapshot sections, indexed by the section ids.
1224517b76aSSebastien Boeuf pub snapshot_data: Option<SnapshotData>,
1231b1a2175SSamuel Ortiz }
1241b1a2175SSamuel Ortiz
1251b1a2175SSamuel Ortiz impl Snapshot {
from_data(data: SnapshotData) -> Self1263931b99dSSebastien Boeuf pub fn from_data(data: SnapshotData) -> Self {
1273931b99dSSebastien Boeuf Snapshot {
1283931b99dSSebastien Boeuf snapshot_data: Some(data),
1293931b99dSSebastien Boeuf ..Default::default()
1303931b99dSSebastien Boeuf }
1313931b99dSSebastien Boeuf }
1323931b99dSSebastien Boeuf
1336f5d4702SRob Bradford /// Create from state that can be serialized
new_from_state<T>(state: &T) -> Result<Self, MigratableError> where T: Serialize,134748018acSSebastien Boeuf pub fn new_from_state<T>(state: &T) -> Result<Self, MigratableError>
1356f5d4702SRob Bradford where
1366f5d4702SRob Bradford T: Serialize,
1376f5d4702SRob Bradford {
1383931b99dSSebastien Boeuf Ok(Snapshot::from_data(SnapshotData::new_from_state(state)?))
1396f5d4702SRob Bradford }
1406f5d4702SRob Bradford
1411b1a2175SSamuel Ortiz /// Add a sub-component's Snapshot to the Snapshot.
add_snapshot(&mut self, id: String, snapshot: Snapshot)142748018acSSebastien Boeuf pub fn add_snapshot(&mut self, id: String, snapshot: Snapshot) {
143748018acSSebastien Boeuf self.snapshots.insert(id, snapshot);
1441b1a2175SSamuel Ortiz }
1451b1a2175SSamuel Ortiz
1466f5d4702SRob Bradford /// Generate the state data from the snapshot
to_state<'a, T>(&'a self) -> Result<T, MigratableError> where T: Deserialize<'a>,1475b3bcfa2SSebastien Boeuf pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError>
1486f5d4702SRob Bradford where
1496f5d4702SRob Bradford T: Deserialize<'a>,
1506f5d4702SRob Bradford {
15108c4e503SRob Bradford self.snapshot_data
1525b3bcfa2SSebastien Boeuf .as_ref()
1535b3bcfa2SSebastien Boeuf .ok_or_else(|| MigratableError::Restore(anyhow!("Missing snapshot data")))?
15408c4e503SRob Bradford .to_state()
1556f5d4702SRob Bradford }
1561b1a2175SSamuel Ortiz }
1571b1a2175SSamuel Ortiz
snapshot_from_id(snapshot: Option<&Snapshot>, id: &str) -> Option<Snapshot>1581f0e5eb6SSebastien Boeuf pub fn snapshot_from_id(snapshot: Option<&Snapshot>, id: &str) -> Option<Snapshot> {
1591d104331SSebastien Boeuf snapshot.and_then(|s| s.snapshots.get(id).cloned())
1601f0e5eb6SSebastien Boeuf }
1611f0e5eb6SSebastien Boeuf
state_from_id<'a, T>(s: Option<&'a Snapshot>, id: &str) -> Result<Option<T>, MigratableError> where T: Deserialize<'a>,16210ab87d6SRob Bradford pub fn state_from_id<'a, T>(s: Option<&'a Snapshot>, id: &str) -> Result<Option<T>, MigratableError>
1631f0e5eb6SSebastien Boeuf where
16410ab87d6SRob Bradford T: Deserialize<'a>,
1651f0e5eb6SSebastien Boeuf {
16610ab87d6SRob Bradford if let Some(s) = s.as_ref() {
16710ab87d6SRob Bradford s.snapshots.get(id).map(|s| s.to_state()).transpose()
16810ab87d6SRob Bradford } else {
16910ab87d6SRob Bradford Ok(None)
17010ab87d6SRob Bradford }
1711f0e5eb6SSebastien Boeuf }
1721f0e5eb6SSebastien Boeuf
1731b1a2175SSamuel Ortiz /// A snapshottable component can be snapshotted.
1741b1a2175SSamuel Ortiz pub trait Snapshottable: Pausable {
1751b1a2175SSamuel Ortiz /// The snapshottable component id.
id(&self) -> String1761b1a2175SSamuel Ortiz fn id(&self) -> String {
1771b1a2175SSamuel Ortiz String::new()
1781b1a2175SSamuel Ortiz }
1791b1a2175SSamuel Ortiz
1801b1a2175SSamuel Ortiz /// Take a component snapshot.
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>181871138d5SSebastien Boeuf fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
182748018acSSebastien Boeuf Ok(Snapshot::default())
1831b1a2175SSamuel Ortiz }
1841b1a2175SSamuel Ortiz }
1851b1a2175SSamuel Ortiz
1861b1a2175SSamuel Ortiz /// A transportable component can be sent or receive to a specific URL.
1871b1a2175SSamuel Ortiz ///
1881b1a2175SSamuel Ortiz /// This trait is meant to be used for component that have custom
1891b1a2175SSamuel Ortiz /// transport handlers.
1901b1a2175SSamuel Ortiz pub trait Transportable: Pausable + Snapshottable {
1911b1a2175SSamuel Ortiz /// Send a component snapshot.
1921b1a2175SSamuel Ortiz ///
1931b1a2175SSamuel Ortiz /// # Arguments
1941b1a2175SSamuel Ortiz ///
1951b1a2175SSamuel Ortiz /// * `snapshot` - The migratable component snapshot to send.
1961b1a2175SSamuel Ortiz /// * `destination_url` - The destination URL to send the snapshot to. This
1971b1a2175SSamuel Ortiz /// could be an HTTP endpoint, a TCP address or a local file.
send( &self, _snapshot: &Snapshot, _destination_url: &str, ) -> std::result::Result<(), MigratableError>1981b1a2175SSamuel Ortiz fn send(
1991b1a2175SSamuel Ortiz &self,
2001b1a2175SSamuel Ortiz _snapshot: &Snapshot,
2011b1a2175SSamuel Ortiz _destination_url: &str,
2021b1a2175SSamuel Ortiz ) -> std::result::Result<(), MigratableError> {
2031b1a2175SSamuel Ortiz Ok(())
2041b1a2175SSamuel Ortiz }
2051b1a2175SSamuel Ortiz
2061b1a2175SSamuel Ortiz /// Receive a component snapshot.
2071b1a2175SSamuel Ortiz ///
2081b1a2175SSamuel Ortiz /// # Arguments
2091b1a2175SSamuel Ortiz ///
2101b1a2175SSamuel Ortiz /// * `source_url` - The source URL to fetch the snapshot from. This could be an HTTP
2111b1a2175SSamuel Ortiz /// endpoint, a TCP address or a local file.
recv(&self, _source_url: &str) -> std::result::Result<Snapshot, MigratableError>2121b1a2175SSamuel Ortiz fn recv(&self, _source_url: &str) -> std::result::Result<Snapshot, MigratableError> {
213748018acSSebastien Boeuf Ok(Snapshot::default())
2141b1a2175SSamuel Ortiz }
2151b1a2175SSamuel Ortiz }
2161b1a2175SSamuel Ortiz
21760c8a72eSBo Chen /// Trait to define shared behaviors of components that can be migrated
21860c8a72eSBo Chen ///
21960c8a72eSBo Chen /// Examples are device, CPU, RAM, etc.
2201b1a2175SSamuel Ortiz /// All migratable components are paused before being snapshotted, and then
2211b1a2175SSamuel Ortiz /// eventually resumed. Thus any Migratable component must be both Pausable
2221b1a2175SSamuel Ortiz /// and Snapshottable.
2231b1a2175SSamuel Ortiz /// Moreover a migratable component can be transported to a remote or local
2241b1a2175SSamuel Ortiz /// destination and thus must be Transportable.
225c1b96204SSebastien Boeuf pub trait Migratable: Send + Pausable + Snapshottable + Transportable {
start_dirty_log(&mut self) -> std::result::Result<(), MigratableError>226c1b96204SSebastien Boeuf fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
227c1b96204SSebastien Boeuf Ok(())
228c1b96204SSebastien Boeuf }
229c1b96204SSebastien Boeuf
stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError>230c1b96204SSebastien Boeuf fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
231c1b96204SSebastien Boeuf Ok(())
232c1b96204SSebastien Boeuf }
233c1b96204SSebastien Boeuf
dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError>234c1b96204SSebastien Boeuf fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> {
235c1b96204SSebastien Boeuf Ok(MemoryRangeTable::default())
236c1b96204SSebastien Boeuf }
237f65538b0SSebastien Boeuf
start_migration(&mut self) -> std::result::Result<(), MigratableError>238a45e458cSlizhaoxin1 fn start_migration(&mut self) -> std::result::Result<(), MigratableError> {
239a45e458cSlizhaoxin1 Ok(())
240a45e458cSlizhaoxin1 }
241a45e458cSlizhaoxin1
complete_migration(&mut self) -> std::result::Result<(), MigratableError>242f65538b0SSebastien Boeuf fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
243f65538b0SSebastien Boeuf Ok(())
244f65538b0SSebastien Boeuf }
245c1b96204SSebastien Boeuf }
246