use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicU64, Ordering};
use crate::concurrency::{Guard as LatchGuard, HybridLatch};
use crate::store::BlobFrame;
use super::AlignedBlobBuf;
const CLEAN_DIRTY_SEQ: u64 = 0;
pub struct CachedBlob {
latch: HybridLatch,
buf: UnsafeCell<AlignedBlobBuf>,
dirty_seq_hint: AtomicU64,
pub(super) last_touched: AtomicU64,
}
unsafe impl Sync for CachedBlob {}
impl CachedBlob {
pub(super) fn new(buf: AlignedBlobBuf) -> Self {
Self {
latch: HybridLatch::new(),
buf: UnsafeCell::new(buf),
dirty_seq_hint: AtomicU64::new(CLEAN_DIRTY_SEQ),
last_touched: AtomicU64::new(0),
}
}
pub(super) fn dirty_hint_needs_map_publish(&self, seq: u64) -> bool {
let mut cur = self.dirty_seq_hint.load(Ordering::Acquire);
loop {
if cur != CLEAN_DIRTY_SEQ && cur <= seq {
return false;
}
let next = if cur == CLEAN_DIRTY_SEQ {
seq
} else {
cur.min(seq)
};
match self.dirty_seq_hint.compare_exchange_weak(
cur,
next,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return true,
Err(actual) => cur = actual,
}
}
}
pub(super) fn take_dirty_hint(&self) -> Option<u64> {
match self.dirty_seq_hint.swap(CLEAN_DIRTY_SEQ, Ordering::AcqRel) {
CLEAN_DIRTY_SEQ => None,
seq => Some(seq),
}
}
pub(super) fn clear_dirty_hint(&self) {
self.dirty_seq_hint
.store(CLEAN_DIRTY_SEQ, Ordering::Release);
}
#[must_use]
pub(crate) fn last_touched(&self) -> u64 {
self.last_touched.load(Ordering::Relaxed)
}
pub fn read_optimistic(&self) -> OptimisticGuard<'_> {
OptimisticGuard {
latch: LatchGuard::optimistic(&self.latch),
buf: &self.buf,
}
}
pub fn read(&self) -> BlobReadGuard<'_> {
BlobReadGuard {
_latch: LatchGuard::shared(&self.latch),
buf: &self.buf,
}
}
#[must_use]
pub(crate) fn content_version(&self) -> u64 {
self.latch.current_version()
}
#[must_use]
pub(crate) fn validate_content_version(&self, version: u64) -> bool {
self.latch.validate(version)
}
pub fn write(&self) -> BlobWriteGuard<'_> {
BlobWriteGuard {
_latch: LatchGuard::exclusive(&self.latch),
buf: &self.buf,
}
}
}
pub struct OptimisticGuard<'a> {
latch: LatchGuard<'a>,
buf: &'a UnsafeCell<AlignedBlobBuf>,
}
impl<'a> OptimisticGuard<'a> {
#[must_use]
pub fn as_slice(&self) -> &'a [u8] {
unsafe { (&*self.buf.get()).as_slice() }
}
#[must_use]
pub fn validate(&self) -> bool {
self.latch.validate()
}
}
pub struct BlobReadGuard<'a> {
_latch: LatchGuard<'a>,
buf: &'a UnsafeCell<AlignedBlobBuf>,
}
impl Deref for BlobReadGuard<'_> {
type Target = AlignedBlobBuf;
fn deref(&self) -> &AlignedBlobBuf {
unsafe { &*self.buf.get() }
}
}
pub struct BlobWriteGuard<'a> {
_latch: LatchGuard<'a>,
buf: &'a UnsafeCell<AlignedBlobBuf>,
}
impl BlobWriteGuard<'_> {
pub fn frame(&mut self) -> BlobFrame<'_> {
BlobFrame::wrap(self.as_mut_slice())
}
}
impl Deref for BlobWriteGuard<'_> {
type Target = AlignedBlobBuf;
fn deref(&self) -> &AlignedBlobBuf {
unsafe { &*self.buf.get() }
}
}
impl DerefMut for BlobWriteGuard<'_> {
fn deref_mut(&mut self) -> &mut AlignedBlobBuf {
unsafe { &mut *self.buf.get() }
}
}