metrale_storage/backend/
mod.rs1use anyhow::Result;
13
14use crate::group::{GroupKey, GroupLayout, KvKind};
15
16#[cfg(target_os = "linux")]
18pub mod io_uring;
19pub mod posix;
20
21#[cfg(target_os = "linux")]
22pub use self::io_uring::IoUringBackend;
23pub use posix::PosixBackend;
24
25#[derive(Clone, Copy, Debug)]
27pub struct ReadRequest {
28 pub group: GroupKey,
29 pub dst_dev_ptr: u64,
30}
31
32#[derive(Clone, Copy, Debug)]
36pub struct BlockReadRequest {
37 pub base_key: GroupKey,
38 pub dst_dev_ptr: u64,
39}
40
41pub fn expand_blocks_to_groups(spec: &GroupLayout, reqs: &[BlockReadRequest]) -> Vec<ReadRequest> {
46 let nkv = spec.num_kv_heads;
47 let gs = spec.group_stride;
48 let mut out = Vec::with_capacity(reqs.len() * 2 * nkv as usize);
49 for r in reqs {
50 let layer = r.base_key.layer;
51 let block = r.base_key.block;
52 for kh in 0..nkv {
53 out.push(ReadRequest {
54 group: GroupKey::new(layer, block, kh, KvKind::K),
55 dst_dev_ptr: r.dst_dev_ptr + (kh as u64) * gs,
56 });
57 out.push(ReadRequest {
58 group: GroupKey::new(layer, block, kh, KvKind::V),
59 dst_dev_ptr: r.dst_dev_ptr + (nkv as u64 + kh as u64) * gs,
60 });
61 }
62 }
63 out
64}
65
66pub trait StorageBackend: Send + Sync {
67 fn read(&mut self, requests: &[ReadRequest], stream: u64) -> Result<()>;
70
71 fn read_async(&mut self, requests: &[ReadRequest], stream: u64) -> Result<()> {
74 self.read(requests, stream)
75 }
76
77 fn write_from_host(&mut self, key: GroupKey, src: &[u8]) -> Result<()>;
80
81 fn group_layout(&self) -> GroupLayout;
83
84 fn read_blocks(&mut self, requests: &[BlockReadRequest], stream: u64) -> Result<()> {
87 let groups = expand_blocks_to_groups(&self.group_layout(), requests);
88 self.read(&groups, stream)
89 }
90
91 fn read_blocks_async(&mut self, requests: &[BlockReadRequest], stream: u64) -> Result<()> {
94 let groups = expand_blocks_to_groups(&self.group_layout(), requests);
95 self.read_async(&groups, stream)
96 }
97
98 fn write_block_from_host(&mut self, base_key: GroupKey, src: &[u8]) -> Result<()> {
103 let spec = self.group_layout();
104 let nkv = spec.num_kv_heads as usize;
105 let gs = spec.group_stride as usize;
106 let expect = 2 * nkv * gs;
107 if src.len() != expect {
108 anyhow::bail!(
109 "write_block_from_host: src len {} != block bytes {expect}",
110 src.len()
111 );
112 }
113 let layer = base_key.layer;
114 let block = base_key.block;
115 for kh in 0..nkv {
116 let k_off = kh * gs;
117 let v_off = (nkv + kh) * gs;
118 self.write_from_host(
119 GroupKey::new(layer, block, kh as u16, KvKind::K),
120 &src[k_off..k_off + gs],
121 )?;
122 self.write_from_host(
123 GroupKey::new(layer, block, kh as u16, KvKind::V),
124 &src[v_off..v_off + gs],
125 )?;
126 }
127 Ok(())
128 }
129
130 fn write_blocks_run(&mut self, base_key: GroupKey, run_len: usize, src: &[u8]) -> Result<()> {
135 let spec = self.group_layout();
136 let block_bytes = spec.block_bytes() as usize;
137 let expect = run_len * block_bytes;
138 if src.len() != expect {
139 anyhow::bail!(
140 "write_blocks_run: src len {} != run bytes {expect} ({run_len} × {block_bytes})",
141 src.len()
142 );
143 }
144 for i in 0..run_len {
145 let off = i * block_bytes;
146 self.write_block_from_host(
147 GroupKey::new(base_key.layer, base_key.block + i as u32, 0, KvKind::K),
148 &src[off..off + block_bytes],
149 )?;
150 }
151 Ok(())
152 }
153
154 fn supports_write_run_coalescing(&self) -> bool {
157 false
158 }
159
160 fn register_landing_region(&mut self, base: u64, len: usize) -> Result<()> {
164 let _ = (base, len);
165 Ok(())
166 }
167}
168
169#[cfg(test)]
170#[path = "mod_tests.rs"]
171mod coalesce_tests;