use std::sync::Arc;
use bytes::Bytes;
use slatedb::{ByteRangeBounds, DbIterator, DbReader, DbTransaction, config::ScanOptions};
const SCAN_READ_AHEAD_BYTES: usize = 4 * 1024 * 1024;
const SCAN_FETCH_TASKS: usize = 8;
fn bulk_scan_options() -> ScanOptions {
ScanOptions {
read_ahead_bytes: SCAN_READ_AHEAD_BYTES,
max_fetch_tasks: SCAN_FETCH_TASKS,
..ScanOptions::default()
}
}
#[derive(Clone, Copy)]
pub(crate) enum ReadHandle<'a> {
Tx(&'a DbTransaction),
Reader(&'a DbReader),
}
impl ReadHandle<'_> {
pub(crate) async fn get<K: AsRef<[u8]> + Send>(
&self,
key: K,
) -> Result<Option<Bytes>, slatedb::Error> {
match self {
Self::Tx(tx) => tx.get(key).await,
Self::Reader(reader) => reader.get(key).await,
}
}
pub(crate) fn is_isolated(&self) -> bool {
matches!(self, Self::Tx(_))
}
pub(crate) async fn scan_prefix<P, T>(
&self,
prefix: P,
subrange: T,
) -> Result<DbIterator, slatedb::Error>
where
P: AsRef<[u8]> + Send,
T: ByteRangeBounds + Send,
{
let options = bulk_scan_options();
match self {
Self::Tx(tx) => {
tx.scan_prefix_with_options(prefix, subrange, &options)
.await
}
Self::Reader(reader) => {
reader
.scan_prefix_with_options(prefix, subrange, &options)
.await
}
}
}
}
pub(crate) enum ReadSession {
Tx(DbTransaction),
Reader(Arc<DbReader>),
}
impl ReadSession {
pub(crate) fn handle(&self) -> ReadHandle<'_> {
match self {
Self::Tx(tx) => ReadHandle::Tx(tx),
Self::Reader(reader) => ReadHandle::Reader(reader),
}
}
pub(crate) fn finish(self) {
if let Self::Tx(tx) = self {
tx.rollback();
}
}
}