use crate::OwnedPinnableSlice;
use rocksdb::ColumnFamilyTtl;
use std::marker::PhantomData;
use std::sync::Arc;
pub trait ColumnFamily {
const NAME: &'static str;
fn write_options(opts: &mut rocksdb::WriteOptions) {
let _unused = opts;
}
fn read_options(opts: &mut rocksdb::ReadOptions) {
let _unused = opts;
}
}
pub trait ColumnFamilyOptions<C>: ColumnFamily {
fn options(opts: &mut rocksdb::Options, ctx: &mut C) {
let _unused = opts;
let _unused = ctx;
}
fn ttl() -> ColumnFamilyTtl {
ColumnFamilyTtl::Disabled
}
}
pub struct Table<T> {
cf: CfHandle,
db: Arc<rocksdb::DB>,
write_config: rocksdb::WriteOptions,
read_config: rocksdb::ReadOptions,
_ty: PhantomData<T>,
}
impl<T> Table<T>
where
T: ColumnFamily,
{
pub fn new(db: Arc<rocksdb::DB>) -> Self {
use rocksdb::AsColumnFamilyRef;
let cf = CfHandle(db.cf_handle(T::NAME).unwrap().inner());
let mut write_config = Default::default();
T::write_options(&mut write_config);
let mut read_config = Default::default();
T::read_options(&mut read_config);
Self {
cf,
db,
write_config,
read_config,
_ty: Default::default(),
}
}
pub fn cf(&'_ self) -> BoundedCfHandle<'_> {
BoundedCfHandle {
inner: self.cf.0,
_lifetime: PhantomData,
}
}
pub fn get_unbounded_cf(&self) -> UnboundedCfHandle {
UnboundedCfHandle {
inner: self.cf.0,
db: self.db.clone(),
}
}
#[inline]
pub fn db(&self) -> &Arc<rocksdb::DB> {
&self.db
}
#[inline]
pub fn read_config(&self) -> &rocksdb::ReadOptions {
&self.read_config
}
pub fn new_read_config(&self) -> rocksdb::ReadOptions {
let mut read_config = Default::default();
T::read_options(&mut read_config);
read_config
}
#[inline]
pub fn write_config(&self) -> &rocksdb::WriteOptions {
&self.write_config
}
pub fn new_write_config(&self) -> rocksdb::WriteOptions {
let mut write_config = Default::default();
T::write_options(&mut write_config);
write_config
}
#[inline]
pub fn get<K: AsRef<[u8]>>(
&self,
key: K,
) -> Result<Option<rocksdb::DBPinnableSlice<'_>>, rocksdb::Error> {
fn db_get<'a>(
db: &'a rocksdb::DB,
cf: CfHandle,
key: &[u8],
readopts: &rocksdb::ReadOptions,
) -> Result<Option<rocksdb::DBPinnableSlice<'a>>, rocksdb::Error> {
db.get_pinned_cf_opt(&cf, key, readopts)
}
db_get(self.db.as_ref(), self.cf, key.as_ref(), &self.read_config)
}
#[inline]
pub fn get_owned<K: AsRef<[u8]>>(
&self,
key: K,
) -> Result<Option<OwnedPinnableSlice>, rocksdb::Error> {
let data = self.get(key)?;
Ok(data.map(|data| {
unsafe { OwnedPinnableSlice::new(self.db.clone(), data) }
}))
}
pub fn multi_get<K: AsRef<[u8]>>(
&self,
keys: &[K],
) -> Vec<Result<Option<Vec<u8>>, rocksdb::Error>> {
self.db.multi_get_cf_opt(
keys.iter().map(|k| (&self.cf, k.as_ref())),
&self.read_config,
)
}
pub fn batched_multi_get<K: AsRef<[u8]>>(
&self,
keys: &[K],
sorted_input: bool,
) -> Vec<Result<Option<rocksdb::DBPinnableSlice<'_>>, rocksdb::Error>> {
self.db
.batched_multi_get_cf_opt(&self.cf, keys, sorted_input, &self.read_config)
}
#[inline]
pub fn insert<K, V>(&self, key: K, value: V) -> Result<(), rocksdb::Error>
where
K: AsRef<[u8]>,
V: AsRef<[u8]>,
{
fn db_insert(
db: &rocksdb::DB,
cf: CfHandle,
key: &[u8],
value: &[u8],
writeopts: &rocksdb::WriteOptions,
) -> Result<(), rocksdb::Error> {
db.put_cf_opt(&cf, key, value, writeopts)
}
db_insert(
self.db.as_ref(),
self.cf,
key.as_ref(),
value.as_ref(),
&self.write_config,
)
}
#[allow(unused)]
#[inline]
pub fn remove<K: AsRef<[u8]>>(&self, key: K) -> Result<(), rocksdb::Error> {
fn db_remove(
db: &rocksdb::DB,
cf: CfHandle,
key: &[u8],
writeopts: &rocksdb::WriteOptions,
) -> Result<(), rocksdb::Error> {
db.delete_cf_opt(&cf, key, writeopts)
}
db_remove(self.db.as_ref(), self.cf, key.as_ref(), &self.write_config)
}
#[inline]
pub fn contains_key<K: AsRef<[u8]>>(&self, key: K) -> Result<bool, rocksdb::Error> {
fn db_contains_key(
db: &rocksdb::DB,
cf: CfHandle,
key: &[u8],
readopts: &rocksdb::ReadOptions,
) -> Result<bool, rocksdb::Error> {
match db.get_pinned_cf_opt(&cf, key, readopts) {
Ok(value) => Ok(value.is_some()),
Err(e) => Err(e),
}
}
db_contains_key(self.db.as_ref(), self.cf, key.as_ref(), &self.read_config)
}
pub fn iterator(&'_ self, mode: rocksdb::IteratorMode) -> rocksdb::DBIterator<'_> {
let mut read_config = Default::default();
T::read_options(&mut read_config);
self.db.iterator_cf_opt(&self.cf, read_config, mode)
}
#[allow(unused)]
pub fn prefix_iterator<P>(&'_ self, prefix: P) -> rocksdb::DBRawIterator<'_>
where
P: AsRef<[u8]>,
{
let mut read_config = Default::default();
T::read_options(&mut read_config);
read_config.set_prefix_same_as_start(true);
let mut iter = self.db.raw_iterator_cf_opt(&self.cf, read_config);
iter.seek(prefix.as_ref());
iter
}
pub fn raw_iterator(&'_ self) -> rocksdb::DBRawIterator<'_> {
let mut read_config = Default::default();
T::read_options(&mut read_config);
self.db.raw_iterator_cf_opt(&self.cf, read_config)
}
}
#[derive(Copy, Clone)]
pub struct BoundedCfHandle<'a> {
inner: *mut librocksdb_sys::rocksdb_column_family_handle_t,
_lifetime: PhantomData<&'a ()>,
}
impl rocksdb::AsColumnFamilyRef for BoundedCfHandle<'_> {
#[inline]
fn inner(&self) -> *mut librocksdb_sys::rocksdb_column_family_handle_t {
self.inner
}
}
unsafe impl Send for BoundedCfHandle<'_> {}
#[derive(Clone)]
pub struct UnboundedCfHandle {
inner: *mut librocksdb_sys::rocksdb_column_family_handle_t,
db: Arc<rocksdb::DB>,
}
impl UnboundedCfHandle {
#[inline]
pub fn db(&self) -> &Arc<rocksdb::DB> {
&self.db
}
#[inline]
pub fn bound(&self) -> BoundedCfHandle<'_> {
BoundedCfHandle {
inner: self.inner,
_lifetime: PhantomData,
}
}
}
unsafe impl Send for UnboundedCfHandle {}
unsafe impl Sync for UnboundedCfHandle {}
#[derive(Copy, Clone)]
#[repr(transparent)]
struct CfHandle(*mut librocksdb_sys::rocksdb_column_family_handle_t);
impl rocksdb::AsColumnFamilyRef for CfHandle {
#[inline]
fn inner(&self) -> *mut librocksdb_sys::rocksdb_column_family_handle_t {
self.0
}
}
unsafe impl Send for CfHandle {}
unsafe impl Sync for CfHandle {}