use std::cell::UnsafeCell;
use crate::size_class::{NUM_CLASSES, SizeClass};
pub(crate) struct TlsState {
pub pool_id: u64,
pub caches: [Vec<Vec<u8>>; NUM_CLASSES],
pub limit: usize,
}
thread_local! {
static TLS: UnsafeCell<TlsState> = const { UnsafeCell::new(TlsState::new()) };
}
impl TlsState {
pub const fn new() -> Self {
Self {
pool_id: 0,
caches: [
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
],
limit: 0,
}
}
#[inline(always)]
pub fn with<R>(f: impl FnOnce(&mut Self) -> R) -> R {
TLS.with(|cell| {
let state = unsafe { &mut *cell.get() };
f(state)
})
}
#[inline(always)]
pub fn owns(&self, pool_id: u64) -> bool {
self.pool_id == pool_id
}
#[inline]
pub fn bind(&mut self, pool_id: u64, limit: usize) {
if self.pool_id != pool_id {
for cache in &mut self.caches {
cache.clear();
}
}
self.pool_id = pool_id;
self.limit = limit;
}
#[inline]
pub fn refill(&mut self, class_idx: usize, class: &SizeClass, batch: usize) -> Option<Vec<u8>> {
let first = class.pop()?;
let remaining = batch.saturating_sub(1);
for _ in 0..remaining {
if let Some(buf) = class.pop() {
self.caches[class_idx].push(buf);
} else {
break;
}
}
Some(first)
}
#[inline]
pub fn spill(&mut self, class_idx: usize, class: &SizeClass, batch: usize) {
for _ in 0..batch {
if let Some(buf) = self.caches[class_idx].pop() {
if class.push(buf).is_err() {
break;
}
} else {
break;
}
}
}
}