use bytes::{Bytes, BytesMut};
use velo_ext::InFlightGuard;
use super::descriptor::{DescriptorBackend, RdmaDescriptor};
use super::rdma::{PinnedBuf, RegionWatch};
use super::store::{DEFAULT_CHUNK_SIZE, StageMode};
const GATE_CHUNK: usize = DEFAULT_CHUNK_SIZE as usize;
#[derive(Clone, Debug)]
pub(crate) struct PinnedRemote {
pub backend: DescriptorBackend,
pub addr: u64,
pub len: u64,
pub generation: u64,
pub packed_key: Bytes,
}
pub(crate) struct ExternalSlice {
_in_flight: InFlightGuard,
watch: RegionWatch,
ptr: usize,
len: usize,
}
pub(crate) enum PinnedStaging {
Pool(PinnedBuf),
External(ExternalSlice),
}
pub(crate) struct PinnedSlot {
staging: PinnedStaging,
remote: PinnedRemote,
}
impl PinnedSlot {
pub(crate) fn from_pool(buf: PinnedBuf, backend: DescriptorBackend) -> Self {
let r = buf.remote();
Self {
remote: PinnedRemote {
backend,
addr: r.addr,
len: r.len,
generation: r.generation,
packed_key: r.packed_key,
},
staging: PinnedStaging::Pool(buf),
}
}
pub(crate) fn from_region(
in_flight: InFlightGuard,
watch: RegionWatch,
backend: DescriptorBackend,
addr: u64,
len: u64,
generation: u64,
packed_key: Bytes,
) -> Self {
Self {
remote: PinnedRemote {
backend,
addr,
len,
generation,
packed_key,
},
staging: PinnedStaging::External(ExternalSlice {
_in_flight: in_flight,
watch,
ptr: addr as usize,
len: len as usize,
}),
}
}
pub(crate) fn len(&self) -> u64 {
self.remote.len
}
pub(crate) fn is_live(&self) -> bool {
match &self.staging {
PinnedStaging::Pool(_) => true,
PinnedStaging::External(slice) => !slice.watch.is_deregistered(),
}
}
pub(crate) fn descriptor(&self) -> Option<RdmaDescriptor> {
if !self.is_live() {
return None;
}
Some(RdmaDescriptor {
backend: self.remote.backend,
generation: self.remote.generation,
addr: self.remote.addr,
len: self.remote.len,
packed_key: self.remote.packed_key.clone(),
})
}
pub(crate) fn backend(&self) -> DescriptorBackend {
self.remote.backend
}
pub(crate) fn read_at(&self, offset: u64, len: usize) -> Option<Bytes> {
if len == 0 {
return Some(Bytes::new());
}
let end = offset.checked_add(len as u64)?;
if end > self.remote.len {
return None;
}
let start = usize::try_from(offset).ok()?;
let stop = start.checked_add(len)?;
match &self.staging {
PinnedStaging::Pool(buf) => buf.get(start..stop).map(Bytes::copy_from_slice),
PinnedStaging::External(slice) => {
if stop > slice.len {
return None;
}
let mut out = BytesMut::zeroed(len);
let mut done = 0usize;
while done < len {
let take = (len - done).min(GATE_CHUNK);
let from = start + done;
let copied = slice.watch.with_live(|| {
unsafe {
std::ptr::copy_nonoverlapping(
(slice.ptr as *const u8).add(from),
out[done..done + take].as_mut_ptr(),
take,
);
}
});
copied?;
done += take;
}
Some(out.freeze())
}
}
}
pub(crate) fn to_bytes(&self) -> Option<Bytes> {
self.read_at(0, usize::try_from(self.remote.len).ok()?)
}
pub(crate) fn stage_mode(&self) -> StageMode {
StageMode::Pinned
}
}
impl std::fmt::Debug for PinnedSlot {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let staging = match &self.staging {
PinnedStaging::Pool(_) => "pool",
PinnedStaging::External(_) => "external",
};
f.debug_struct("PinnedSlot")
.field("staging", &staging)
.field("addr", &self.remote.addr)
.field("len", &self.remote.len)
.field("generation", &self.remote.generation)
.field("live", &self.is_live())
.finish()
}
}