mod collection;
mod keys;
mod raw;
use std::{
ops::Deref,
result::Result as StdResult,
sync::{
Arc,
atomic::{AtomicBool, AtomicU64, Ordering::Relaxed},
},
};
pub use collection::RawCollectionRead;
use parking_lot::Mutex;
use wdev::Device;
use wepoch::{EpochGuard, Participant};
use wval::SessionPrefixBuf;
use crate::{error::Result, store::WedbStore};
pub const HASH_MAX_COMPACT_ENTRIES: usize = 512;
pub const HASH_MAX_COMPACT_VALUE: usize = 64;
pub const SET_MAX_COMPACT_ENTRIES: usize = 128;
pub const SET_MAX_COMPACT_VALUE: usize = 64;
pub const ZSET_MAX_COMPACT_ENTRIES: usize = 128;
pub const ZSET_MAX_COMPACT_MEMBER: usize = 64;
pub const MAX_COMPACT_TOTAL_BYTES: usize = 4096;
pub struct StoreSession<D: Device> {
pub store: Arc<WedbStore<D>>,
pub participant: Participant,
pub copy_reads_to_tail: AtomicBool,
pub record_elision: AtomicBool,
pub namespace: AtomicU64,
pub active_db: AtomicU64,
}
impl<D: Device> StoreSession<D> {
pub fn new(store: Arc<WedbStore<D>>, participant: Participant) -> Self {
Self {
store,
participant,
copy_reads_to_tail: AtomicBool::new(false),
record_elision: AtomicBool::new(false),
namespace: AtomicU64::new(0),
active_db: AtomicU64::new(0),
}
}
#[inline(always)]
pub fn namespace(&self) -> u64 {
self.namespace.load(Relaxed)
}
#[inline(always)]
pub fn active_db(&self) -> u64 {
self.active_db.load(Relaxed)
}
#[inline(always)]
pub fn session_prefix(&self) -> SessionPrefixBuf {
SessionPrefixBuf::new(self.namespace.load(Relaxed), self.active_db.load(Relaxed))
}
pub fn set_context(&self, ns: u64, db: u64) {
self.namespace.store(ns, Relaxed);
self.active_db.store(db, Relaxed);
}
#[inline]
pub fn set_active_db(&self, db: u64) {
self.set_context(self.namespace(), db);
}
#[inline]
pub fn set_copy_reads_to_tail(&self, enable: bool) {
self.copy_reads_to_tail.store(enable, Relaxed);
}
#[inline]
pub fn copy_reads_to_tail(&self) -> bool {
self.copy_reads_to_tail.load(Relaxed)
}
#[inline]
pub fn set_record_elision(&self, enable: bool) {
self.record_elision.store(enable, Relaxed);
}
#[inline]
pub fn record_elision(&self) -> bool {
self.record_elision.load(Relaxed)
}
#[inline]
pub fn enter_batch(&self) -> BatchStoreSession<'_, D> {
let guard = self.participant.enter();
BatchStoreSession {
session: self,
_guard: guard,
}
}
#[inline]
pub fn store(&self) -> &Arc<WedbStore<D>> {
&self.store
}
#[inline]
pub fn participant(&self) -> &Participant {
&self.participant
}
}
pub(crate) struct SessionSlot<D: Device> {
slot: Mutex<Option<StoreSession<D>>>,
}
impl<D: Device> SessionSlot<D> {
pub(crate) const fn new() -> Self {
Self {
slot: Mutex::new(None),
}
}
pub(crate) fn take(&self, store: &Arc<WedbStore<D>>) -> Result<StoreSession<D>> {
match self.slot.lock().take() {
Some(s) => Ok(s),
None => store.new_session(),
}
}
pub(crate) fn restore(&self, session: StoreSession<D>) {
*self.slot.lock() = Some(session);
}
}
pub struct BatchStoreSession<'a, D: Device> {
pub session: &'a StoreSession<D>,
_guard: EpochGuard<'a>,
}
impl<'a, D: Device> Deref for BatchStoreSession<'a, D> {
type Target = StoreSession<D>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.session
}
}
impl<'a, D: Device> BatchStoreSession<'a, D> {
#[inline(always)]
pub fn try_read_in_memory<R>(
&self,
key: &[u8],
f: impl FnOnce(&[u8]) -> R,
) -> Result<Option<Option<R>>> {
self.session.try_read_in_memory_unprotected(key, f)
}
#[inline(always)]
pub fn try_modify_in_place<R>(
&self,
key: &[u8],
f: impl FnOnce(&mut [u8]) -> Option<R>,
) -> Result<Option<R>> {
self.session.try_modify_in_place_unprotected(key, f)
}
#[inline(always)]
pub fn try_modify_with_slack(&self, key: &[u8], new_val: &[u8]) -> Result<bool> {
self.session.try_modify_with_slack_unprotected(key, new_val)
}
#[inline(always)]
pub fn try_upsert_sync(&self, key: &[u8], val: &[u8]) -> Result<StdResult<u64, u64>> {
self.session.try_upsert_sync_unprotected(key, val)
}
#[inline(always)]
pub fn try_read_sync<R>(
&self,
key: &[u8],
f: impl FnOnce(&[u8]) -> R,
) -> Result<Option<Option<R>>> {
if self.session.has_ttl_tag_unprotected(key)? {
return Ok(None);
}
self.session.try_read_in_memory_unprotected(key, f)
}
#[inline(always)]
pub async fn upsert(&self, key: &[u8], val: &[u8]) -> Result<u64> {
self.session.upsert(key, val).await
}
#[inline(always)]
pub async fn read(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
self.session.read(key).await
}
}