use super::{AssocTable, Rendezvous, RouteTable, Sidecar, Transport};
use crate::session::cluster::error::ResourceScope;
mod endpoint_lease;
#[cfg(all(test, hibana_repo_tests))]
mod tests;
impl<'rv, 'cfg, T: Transport> Rendezvous<'rv, 'cfg, T>
where
'cfg: 'rv,
{
#[inline]
unsafe fn allocate_persistent_sidecar_bytes(
&mut self,
bytes: usize,
align: usize,
) -> Option<*mut u8> {
let (slab_ptr, _) = self.slab_ptr_and_len();
let base = slab_ptr as usize;
let start = Self::align_up(base + self.image_frontier as usize, align).checked_sub(base)?;
let end = start.checked_add(bytes)?;
if end > self.endpoint_storage_floor() {
return None;
}
if end > u32::MAX as usize {
return None;
}
let end_u32 = crate::invariant_ok(u32::try_from(end));
self.set_image_frontier(end_u32);
Some(
unsafe { slab_ptr.add(start) },
)
}
#[inline]
pub(crate) fn allocate_external_persistent_sidecar_bytes(
&mut self,
bytes: usize,
align: usize,
) -> Option<Sidecar<u8>> {
let ptr = unsafe { self.allocate_persistent_sidecar_bytes(bytes, align) }?;
Some(Sidecar::from_raw_parts(ptr, bytes))
}
#[inline]
pub(crate) fn release_external_persistent_sidecar(&mut self, sidecar: Sidecar<u8>) {
if sidecar.is_empty() {
return;
}
let (slab_ptr, _) = self.slab_ptr_and_len();
let base = slab_ptr.addr();
let payload_start = crate::invariant_some(sidecar.ptr().addr().checked_sub(base));
let payload_end = crate::invariant_some(payload_start.checked_add(sidecar.bytes()));
if payload_end > self.image_frontier as usize {
crate::invariant();
}
if payload_end == self.image_frontier as usize {
let payload_start = crate::invariant_ok(u32::try_from(payload_start));
self.set_image_frontier(payload_start);
}
}
#[inline]
fn lane_base(&self) -> u32 {
self.lane_range.start
}
#[inline]
fn lane_slot_count(&self) -> usize {
if self.lane_range.end < self.lane_range.start {
crate::invariant();
}
(self.lane_range.end - self.lane_range.start) as usize
}
#[inline]
fn target_lane_slots(required_lane_slots: usize) -> Option<usize> {
if required_lane_slots > usize::from(crate::runtime_core::consts::LANE_DOMAIN_SIZE) {
return None;
}
Some(required_lane_slots.max(1))
}
#[inline]
fn target_assoc_slots(required_assoc_slots: usize) -> Option<usize> {
if required_assoc_slots > usize::from(u16::MAX) {
return None;
}
Some(required_assoc_slots.max(1))
}
#[inline]
fn lease_sidecar<S>(&mut self, bytes: usize, align: usize) -> Option<Sidecar<S>> {
Some(
self.allocate_external_persistent_sidecar_bytes(bytes, align)?
.cast::<S>(),
)
}
#[inline]
fn release_sidecar<S>(&mut self, sidecar: Sidecar<S>) {
self.release_external_persistent_sidecar(sidecar.cast::<u8>());
}
fn ensure_lane_storage(
&mut self,
required_lane_slots: usize,
required_assoc_slots: usize,
) -> Result<(), ResourceScope> {
let target_lane_slots = self
.lane_slot_count()
.max(Self::target_lane_slots(required_lane_slots).ok_or(ResourceScope::LaneStorage)?);
let target_assoc_slots = self
.assoc
.assoc_slots()
.max(Self::target_assoc_slots(required_assoc_slots).ok_or(ResourceScope::LaneStorage)?);
let lane_base = self.lane_base();
let target_slots_u32 =
u32::try_from(target_lane_slots).map_err(|_| ResourceScope::LaneStorage)?;
let lane_end = lane_base
.checked_add(target_slots_u32)
.ok_or(ResourceScope::LaneStorage)?;
let core_growth = self.lane_slot_count() < target_lane_slots
|| self.assoc.assoc_slots() < target_assoc_slots;
let assoc_was_bound = self.assoc.is_bound();
let need_assoc = !assoc_was_bound || core_growth;
if !need_assoc {
return Ok(());
}
let source_assoc = self.assoc_storage;
let lease = self
.lease_sidecar::<u8>(
AssocTable::storage_bytes(target_assoc_slots),
AssocTable::storage_align(),
)
.ok_or(ResourceScope::LaneStorage)?;
unsafe {
if assoc_was_bound {
self.assoc.init_replacement_storage(
lease.ptr(),
lane_base,
target_lane_slots,
target_assoc_slots,
);
} else {
self.assoc.bind_from_storage(
lease.ptr(),
lane_base,
target_lane_slots,
target_assoc_slots,
);
}
}
if assoc_was_bound {
self.release_sidecar(source_assoc);
self.assoc.clear_current_overflow_waiters();
unsafe {
self.assoc.commit_storage(
lease.ptr(),
lane_base,
target_lane_slots,
target_assoc_slots,
);
}
}
self.assoc_storage = lease;
self.lane_range = lane_base..lane_end;
Ok(())
}
pub(crate) fn ensure_core_lane_tables_for_assoc_entries(
&mut self,
required_lane_slots: usize,
required_assoc_slots: usize,
) -> Result<(), ResourceScope> {
self.ensure_lane_storage(required_lane_slots, required_assoc_slots)
}
pub(crate) fn ensure_route_table_capacity(
&mut self,
required_frame_slots: usize,
required_lane_slots: usize,
) -> Result<(), ResourceScope> {
if required_frame_slots == 0
|| (self.routes.route_slots() >= required_frame_slots
&& self.routes.lane_slots() >= required_lane_slots)
{
return Ok(());
}
let lease = self
.lease_sidecar::<u8>(
RouteTable::storage_bytes(required_frame_slots, required_lane_slots),
RouteTable::storage_align(),
)
.ok_or(ResourceScope::RouteTable)?;
let source_route = self.route_storage;
if self.routes.route_slots() == 0 {
unsafe {
self.routes.bind_from_storage_with_layout(
lease.ptr(),
required_frame_slots,
self.lane_base(),
required_lane_slots,
);
}
self.route_storage = lease;
return Ok(());
}
unsafe {
self.routes.migrate_from_storage(
lease.ptr(),
required_frame_slots,
self.lane_base(),
required_lane_slots,
);
}
self.release_sidecar(source_route);
self.routes.clear_current_waiters();
unsafe {
self.routes.rebind_from_storage(
lease.ptr(),
required_frame_slots,
self.lane_base(),
required_lane_slots,
);
}
self.route_storage = lease;
Ok(())
}
}