Skip to main content

kvbm_engine/leader/
onboarding.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use anyhow::Result;
5use tokio::sync::mpsc;
6
7use super::session::SessionId;
8use super::types::StagingMode;
9
10/// Status of an onboarding operation.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum OnboardingStatus {
13    /// Searching for blocks (local or remote).
14    Searching,
15
16    /// Holding blocks without staging (StagingMode::Hold).
17    /// Provides location breakdown for cost analysis.
18    /// - `local_g2`: number of blocks in local G2 (ready to use)
19    /// - `local_g3`: number of blocks in local G3 (needs local staging)
20    /// - `remote_g2`: number of blocks in remote G2 (needs RDMA pull)
21    /// - `remote_g3`: number of blocks in remote G3 (needs remote staging + RDMA)
22    /// - `pending_g4`: number of blocks with G4 load in progress
23    /// - `loaded_g4`: number of blocks successfully loaded from G4 (included in local_g2)
24    /// - `failed_g4`: number of blocks that failed to load from G4
25    Holding {
26        local_g2: usize,
27        local_g3: usize,
28        remote_g2: usize,
29        remote_g3: usize,
30        pending_g4: usize,
31        loaded_g4: usize,
32        failed_g4: usize,
33    },
34
35    /// Preparing: staging G3→G2 (StagingMode::Prepare or Full).
36    /// - `matched`: total number of blocks matched during search
37    /// - `staging_local`: number of local G3→G2 transfers in progress
38    /// - `staging_remote`: number of remote G3→G2 transfers in progress
39    Preparing {
40        matched: usize,
41        staging_local: usize,
42        staging_remote: usize,
43    },
44
45    /// Prepared: all blocks in G2, session still alive (StagingMode::Prepare).
46    /// - `local_g2`: number of blocks in local G2
47    /// - `remote_g2`: number of blocks in remote G2 instances
48    Prepared { local_g2: usize, remote_g2: usize },
49
50    /// Staging: full mode with RDMA pulls (StagingMode::Full).
51    /// - `matched`: total number of blocks matched
52    /// - `staging_local`: local G3→G2 in progress
53    /// - `staging_remote`: remote G3→G2 in progress
54    /// - `pulling`: remote G2→local G2 (RDMA) in progress
55    Staging {
56        matched: usize,
57        staging_local: usize,
58        staging_remote: usize,
59        pulling: usize,
60    },
61
62    /// Operation complete - all blocks are in initiator's G2 (StagingMode::Full).
63    /// Or terminal state for Hold/Prepare modes.
64    /// - `matched`: total number of blocks in local G2
65    Complete { matched_blocks: usize },
66}
67
68/// Control commands for managing live sessions.
69#[derive(Debug)]
70pub(crate) enum SessionControl {
71    /// Trigger prepare operation (Hold → Prepare): stage all G3→G2
72    Prepare,
73
74    /// Trigger pull operation (Prepare → Full): RDMA pull remote G2→local G2
75    Pull,
76
77    /// Cancel session and release all blocks
78    Cancel,
79
80    /// Shutdown session (normal completion)
81    Shutdown,
82}
83
84/// Handle to a live onboarding session for deferred operations.
85///
86/// Only available for StagingMode::Hold and StagingMode::Prepare.
87#[derive(Debug)]
88pub struct SessionHandle {
89    session_id: SessionId,
90    mode: StagingMode,
91    control_tx: mpsc::Sender<SessionControl>,
92}
93
94impl SessionHandle {
95    pub(crate) fn new(
96        session_id: SessionId,
97        mode: StagingMode,
98        control_tx: mpsc::Sender<SessionControl>,
99    ) -> Self {
100        Self {
101            session_id,
102            mode,
103            control_tx,
104        }
105    }
106
107    /// Get the session ID.
108    pub fn session_id(&self) -> SessionId {
109        self.session_id
110    }
111
112    /// Get the current staging mode.
113    pub fn mode(&self) -> StagingMode {
114        self.mode
115    }
116
117    /// Trigger G3→G2 staging on all instances (Hold → Prepare).
118    ///
119    /// The server validates that the session is in Hold mode before processing.
120    /// After this completes, the session transitions to Prepare mode internally.
121    pub async fn prepare(&self) -> Result<()> {
122        self.control_tx
123            .send(SessionControl::Prepare)
124            .await
125            .map_err(|_| anyhow::anyhow!("session task has exited"))
126    }
127
128    /// Trigger RDMA pull from remote G2→local G2 (Prepare → Complete).
129    ///
130    /// The server validates that the session is in Prepare mode before processing.
131    /// After this completes, the session transitions to Complete status.
132    pub async fn pull(&self) -> Result<()> {
133        self.control_tx
134            .send(SessionControl::Pull)
135            .await
136            .map_err(|_| anyhow::anyhow!("session task has exited"))
137    }
138
139    /// Cancel session and release all held blocks.
140    pub async fn cancel(&self) -> Result<()> {
141        self.control_tx
142            .send(SessionControl::Cancel)
143            .await
144            .map_err(|_| anyhow::anyhow!("session task has exited"))
145    }
146
147    /// Shutdown session (used internally).
148    #[expect(dead_code)]
149    pub(crate) async fn shutdown(&self) -> Result<()> {
150        self.control_tx
151            .send(SessionControl::Shutdown)
152            .await
153            .map_err(|_| anyhow::anyhow!("session task has exited"))
154    }
155}