use super::*;
pub struct Ref<'a> {
pub(super) guard: SharedReadGuard<'a, EmbeddedShard>,
pub(super) value: *const [u8],
pub(super) _not_send: PhantomData<*const ()>,
}
impl Ref<'_> {
#[inline(always)]
pub fn value(&self) -> &[u8] {
let _guard = &self.guard;
unsafe { &*self.value }
}
}
impl Deref for Ref<'_> {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.value()
}
}
pub struct RefMut<'a> {
pub(super) guard: SharedWriteGuard<'a, EmbeddedShard>,
pub(super) route_mode: EmbeddedRouteMode,
pub(super) key: SharedBytes,
pub(super) key_hash: u64,
#[cfg_attr(feature = "no-ttl", allow(dead_code))]
pub(super) expire_at_ms: Option<u64>,
pub(super) semantic_generation: &'a AtomicU64,
pub(super) semantic_shadow: Option<&'a SharedShardLock<EmbeddedShard>>,
pub(super) _not_send: PhantomData<*const ()>,
}
impl RefMut<'_> {
#[inline(always)]
fn bump_semantic_generation(&self) {
self.semantic_generation.fetch_add(1, Ordering::AcqRel);
}
#[inline(always)]
fn invalidate_semantic_shadow(&self, now_ms: u64) -> Option<SharedBytes> {
let semantic_shadow = self.semantic_shadow?;
semantic_shadow
.write()
.remove_value_hashed(self.key_hash, self.key.as_ref(), now_ms)
}
#[cfg(feature = "no-ttl")]
#[inline(always)]
fn live_expire_at(&self) -> Option<Option<u64>> {
Some(None)
}
#[cfg(not(feature = "no-ttl"))]
#[inline(always)]
fn live_expire_at(&self) -> Option<Option<u64>> {
match self.expire_at_ms {
Some(expire_at_ms) if expire_at_ms <= ttl_now_millis() => None,
expire_at_ms => Some(expire_at_ms),
}
}
#[inline(always)]
pub fn value(&self) -> Option<&[u8]> {
match self.live_expire_at()? {
None => self
.guard
.get_ref_hashed_shared_no_ttl(self.key_hash, self.key.as_ref()),
Some(_) => {
self.guard
.get_ref_hashed_shared(self.key_hash, self.key.as_ref(), ttl_now_millis())
}
}
}
#[cfg(feature = "mutable-value-slices")]
#[inline(always)]
pub fn value_mut_no_ttl(&mut self) -> Option<&mut [u8]> {
let semantic_generation = self.semantic_generation;
let semantic_shadow = self.semantic_shadow;
let key_hash = self.key_hash;
let key = self.key.clone();
match self.live_expire_at()? {
None => {
let value = self.guard.value_mut_hashed_no_ttl(key_hash, key.as_ref());
if value.is_some() {
if let Some(semantic_shadow) = semantic_shadow {
semantic_shadow
.write()
.remove_value_hashed(key_hash, key.as_ref(), 0);
}
semantic_generation.fetch_add(1, Ordering::AcqRel);
}
value
}
Some(_) => None,
}
}
#[inline(always)]
pub fn set(&mut self, value: SharedBytes) {
match self.live_expire_at() {
Some(None) => {
self.guard.set_value_bytes_hashed_no_ttl(
self.route_mode,
self.key_hash,
self.key.as_ref(),
value,
);
self.invalidate_semantic_shadow(0);
}
Some(expire_at_ms) => {
let now_ms = ttl_now_millis();
self.guard.set_value_bytes_hashed(
self.route_mode,
self.key_hash,
self.key.as_ref(),
value,
expire_at_ms,
now_ms,
);
self.invalidate_semantic_shadow(now_ms);
}
None => {
let now_ms = ttl_now_millis();
let removed =
self.guard
.remove_value_hashed(self.key_hash, self.key.as_ref(), now_ms);
let semantic_removed = self.invalidate_semantic_shadow(now_ms);
if removed.is_some() || semantic_removed.is_some() {
self.bump_semantic_generation();
}
return;
}
}
self.bump_semantic_generation();
}
#[inline(always)]
pub fn set_slice(&mut self, value: &[u8]) {
self.set(SharedBytes::copy_from_slice(value));
}
#[inline(always)]
pub fn remove(mut self) -> Option<SharedBytes> {
let now_ms = ttl_now_millis();
let removed = self
.guard
.remove_value_hashed(self.key_hash, self.key.as_ref(), now_ms);
let semantic_removed = self.invalidate_semantic_shadow(now_ms);
if removed.is_some() || semantic_removed.is_some() {
self.bump_semantic_generation();
}
removed.or(semantic_removed)
}
}
pub enum Entry<'a> {
Occupied(RefMut<'a>),
Vacant(VacantEntry<'a>),
}
impl<'a> Entry<'a> {
#[inline(always)]
pub fn or_insert(self, value: SharedBytes) -> RefMut<'a> {
match self {
Self::Occupied(entry) => entry,
Self::Vacant(entry) => entry.insert(value),
}
}
}
pub struct VacantEntry<'a> {
pub(super) guard: SharedWriteGuard<'a, EmbeddedShard>,
pub(super) route_mode: EmbeddedRouteMode,
pub(super) key: SharedBytes,
pub(super) key_hash: u64,
pub(super) semantic_generation: &'a AtomicU64,
pub(super) semantic_shadow: Option<&'a SharedShardLock<EmbeddedShard>>,
pub(super) _not_send: PhantomData<*const ()>,
}
impl<'a> VacantEntry<'a> {
#[inline(always)]
pub fn insert(mut self, value: SharedBytes) -> RefMut<'a> {
self.guard.set_value_bytes_hashed_no_ttl(
self.route_mode,
self.key_hash,
self.key.as_ref(),
value,
);
if let Some(semantic_shadow) = self.semantic_shadow {
semantic_shadow
.write()
.remove_value_hashed(self.key_hash, self.key.as_ref(), 0);
}
self.semantic_generation.fetch_add(1, Ordering::AcqRel);
RefMut {
guard: self.guard,
route_mode: self.route_mode,
key: self.key,
key_hash: self.key_hash,
expire_at_ms: None,
semantic_generation: self.semantic_generation,
semantic_shadow: self.semantic_shadow,
_not_send: PhantomData,
}
}
}