spark_storage/cache_peer/
server_impl.rs1use std::net::{TcpListener, TcpStream, ToSocketAddrs};
11
12use anyhow::{Context, Result, bail};
13
14#[derive(Clone, Debug)]
18pub struct RdmaConfig {
19 pub rails: Vec<(String, u32)>,
21 pub max_blade_bytes: u64,
24 pub swap_dir: Option<std::path::PathBuf>,
29 pub swap_cap_bytes: u64,
35 pub per_kind_swap_cap_bytes: std::collections::HashMap<u8, u64>,
41}
42
43impl Default for RdmaConfig {
44 fn default() -> Self {
45 Self {
46 rails: vec![("roceP2p1s0f1".into(), 3), ("rocep1s0f1".into(), 3)],
47 max_blade_bytes: 0,
48 swap_dir: None,
49 swap_cap_bytes: 50 * 1024 * 1024 * 1024,
50 per_kind_swap_cap_bytes: std::collections::HashMap::new(),
51 }
52 }
53}
54
55pub fn serve<A: ToSocketAddrs>(addr: A, rdma: RdmaConfig) -> Result<()> {
58 let listener = TcpListener::bind(addr).context("bind cache-peer listener")?;
59 let local = listener.local_addr().ok();
60 let ledger = std::sync::Arc::new(crate::blade_cap::CommitLedger::new(rdma.max_blade_bytes));
63 tracing::info!(
64 "cache-peer (RW RDMA overflow blade) listening on {:?} (rails {:?}, cap {})",
65 local,
66 rdma.rails,
67 if rdma.max_blade_bytes == 0 {
68 "unlimited".to_string()
69 } else {
70 format!(
71 "{:.1} GiB",
72 rdma.max_blade_bytes as f64 / (1024.0 * 1024.0 * 1024.0)
73 )
74 },
75 );
76 if rdma.max_blade_bytes == 0 && rdma.swap_dir.is_some() {
82 tracing::warn!(
83 "cache-peer paging registry active with NO blade ceiling (--max-blade-gb 0 = \
84 unlimited): each new (kind, shape) arena pins RDMA-registered RAM without bound. \
85 Set --max-blade-gb <G> to cap total memlocked blade RAM."
86 );
87 }
88 for conn in listener.incoming() {
89 let stream = match conn {
90 Ok(s) => s,
91 Err(e) => {
92 tracing::warn!("cache-peer accept error: {e}");
93 continue;
94 }
95 };
96 let rdma = rdma.clone();
97 let ledger = ledger.clone();
98 std::thread::spawn(move || {
99 if let Err(e) = handle_conn(stream, &rdma, &ledger) {
100 tracing::warn!("cache-peer connection ended: {e}");
101 }
102 });
103 }
104 Ok(())
105}
106
107#[cfg(not(atlas_rdma_verbs))]
108fn handle_conn(
109 _stream: TcpStream,
110 _rdma: &RdmaConfig,
111 _ledger: &std::sync::Arc<crate::blade_cap::CommitLedger>,
112) -> Result<()> {
113 bail!("cache-peer needs a build with rdma-core (atlas_rdma_verbs)");
114}
115
116#[cfg(atlas_rdma_verbs)]
117fn handle_conn(
118 mut stream: TcpStream,
119 rdma: &RdmaConfig,
120 ledger: &std::sync::Arc<crate::blade_cap::CommitLedger>,
121) -> Result<()> {
122 use super::registry::{self, Mmap, SharedPaging};
123 use atlas_rdma::verbs::Verbs;
124 use atlas_rdma::wire::{CacheServerParams, STATUS_OK, VerbsClientParams};
125 use std::io::{Read, Write};
126 stream.set_nodelay(true).ok();
127
128 let mut b8 = [0u8; 8];
137 stream.read_exact(&mut b8).context("read paging magic")?;
138 let first = u64::from_le_bytes(b8);
139 let (kind, arena_bytes, blob) = crate::snapshot_swap::parse_paging_header(first, &mut stream)?;
140 let total = arena_bytes as usize;
141 let blob = blob as usize;
142 if total == 0 || total > (1usize << 42) {
147 bail!("implausible blade arena size: {total}");
148 }
149 let paging: Option<(u8, usize)> = if blob == 0 {
150 None } else {
152 if !total.is_multiple_of(blob) {
153 bail!("paging: arena_bytes {total} not a multiple of blob_bytes {blob}");
154 }
155 if rdma.swap_dir.is_none() {
159 bail!("paging client but peer started without --swap-dir; refusing");
160 }
161 Some((kind.0, blob))
162 };
163 let mut b1 = [0u8; 1];
164 stream.read_exact(&mut b1).context("read n_rails")?;
165 let n_rails = b1[0] as usize;
166 if n_rails == 0 || n_rails > rdma.rails.len() {
167 bail!(
168 "client asked for {n_rails} rails; peer has {}",
169 rdma.rails.len()
170 );
171 }
172
173 let pid = std::process::id();
178 let shared: Option<std::sync::Arc<SharedPaging>> = match paging {
179 Some((kind, blob)) => Some(registry::get_or_init_shared_paging(
180 rdma, kind, total, blob, ledger,
181 )?),
182 None => None,
183 };
184 let local: Option<(crate::blade_cap::Reservation, Mmap)> = if shared.is_none() {
187 let reservation = ledger.try_reserve(total as u64).context("kv blade cap")?;
188 let arena = Mmap::anon(total).context("mmap kv blade arena")?;
189 Some((reservation, arena))
190 } else {
191 None
192 };
193 let (arena_base, arena_len): (*mut libc::c_void, usize) = match (&shared, &local) {
194 (Some(sh), _) => (sh.arena.addr, sh.arena.len),
195 (None, Some((_, arena))) => (arena.addr, arena.len),
196 _ => unreachable!("exactly one of shared/local is set"),
197 };
198 let mut rails: Vec<Verbs> = Vec::with_capacity(n_rails);
201 let mut rkeys: Vec<u32> = Vec::with_capacity(n_rails);
202 for (i, (dev, gid)) in rdma.rails.iter().take(n_rails).enumerate() {
203 let psn = (0x5a5a5a ^ pid ^ ((i as u32) << 20)) & 0xff_ffff;
204 let mut v = Verbs::create(dev, *gid, psn)?;
205 let keys = unsafe { v.reg_mr_rw(arena_base as *mut _, arena_len)? };
207 rkeys.push(keys.rkey);
208 rails.push(v);
209 }
210
211 stream.write_all(&[n_rails as u8]).context("send n_rails")?;
213 for (v, rkey) in rails.iter().zip(&rkeys) {
214 CacheServerParams {
215 qpn: v.qpn(),
216 psn: v.psn(),
217 gid: v.gid(),
218 base_addr: arena_base as u64,
219 rkey: *rkey,
220 }
221 .write_to(&mut stream)
222 .context("send kv server params")?;
223 }
224
225 stream.read_exact(&mut b1).context("read client n_rails")?;
227 if b1[0] as usize != n_rails {
228 bail!("client rail count mismatch");
229 }
230 for v in rails.iter_mut() {
231 let cp = VerbsClientParams::read_from(&mut stream).context("read kv client params")?;
232 v.connect(cp.qpn, cp.psn, &cp.gid)?;
233 }
234 stream
235 .write_all(&[STATUS_OK])
236 .context("send kv ready ack")?;
237 let mode = if paging.is_some() {
238 "paging"
239 } else {
240 "raw one-sided"
241 };
242 tracing::info!(
243 "cache-peer client connected: kind {}, {n_rails} rail(s), {:.1} GiB RW blade ({mode})",
244 kind.0,
245 total as f64 / (1024.0 * 1024.0 * 1024.0),
246 );
247
248 if let Some(sh) = shared {
250 tracing::info!("cache-peer PAGING client joined shared arena ({n_rails} rail(s))");
256 let r = crate::snapshot_swap::run_paging_loop_shared(&mut stream, &sh.residency);
257 drop(rails); return r;
259 }
260
261 let mut sink = [0u8; 8];
264 loop {
265 match stream.read(&mut sink) {
266 Ok(0) => break,
267 Ok(_) => {}
268 Err(_) => break,
269 }
270 }
271 drop(rails);
273 drop(local);
274 Ok(())
275}