#![cfg_attr(not(any(test, feature = "proptest-impl")), allow(dead_code))]
use std::{
any::type_name,
collections::{BTreeMap, HashMap},
fmt::Debug,
hash::Hash,
marker::PhantomData,
ops::RangeBounds,
};
use crate::service::finalized_state::{DiskWriteBatch, FromDisk, IntoDisk, ReadDisk, WriteDisk};
use super::DiskDb;
#[derive(Clone)]
pub struct TypedColumnFamily<'cf, Key, Value>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
{
db: DiskDb,
cf: rocksdb::ColumnFamilyRef<'cf>,
_cf_name: String,
_marker: PhantomData<(Key, Value)>,
}
#[must_use = "batches must be written to the database"]
#[derive(Debug, Eq, PartialEq)]
pub struct WriteTypedBatch<'cf, Key, Value, Batch>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
Batch: WriteDisk,
{
inner: TypedColumnFamily<'cf, Key, Value>,
batch: Batch,
}
impl<Key, Value> Debug for TypedColumnFamily<'_, Key, Value>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(&format!(
"TypedColumnFamily<{}, {}>",
type_name::<Key>(),
type_name::<Value>()
))
.field("db", &self.db)
.field("cf", &self._cf_name)
.finish()
}
}
impl<Key, Value> PartialEq for TypedColumnFamily<'_, Key, Value>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
{
fn eq(&self, other: &Self) -> bool {
self.db == other.db && self._cf_name == other._cf_name
}
}
impl<Key, Value> Eq for TypedColumnFamily<'_, Key, Value>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
{
}
impl<'cf, Key, Value> TypedColumnFamily<'cf, Key, Value>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
{
pub fn new(db: &'cf DiskDb, cf_name: &str) -> Option<Self> {
let cf = db.cf_handle(cf_name)?;
Some(Self {
db: db.clone(),
cf,
_cf_name: cf_name.to_string(),
_marker: PhantomData,
})
}
pub fn new_batch_for_writing(self) -> WriteTypedBatch<'cf, Key, Value, DiskWriteBatch> {
WriteTypedBatch {
inner: self,
batch: DiskWriteBatch::new(),
}
}
pub fn take_batch_for_writing(
self,
batch: DiskWriteBatch,
) -> WriteTypedBatch<'cf, Key, Value, DiskWriteBatch> {
WriteTypedBatch { inner: self, batch }
}
pub fn with_batch_for_writing(
self,
batch: &mut DiskWriteBatch,
) -> WriteTypedBatch<'cf, Key, Value, &mut DiskWriteBatch> {
WriteTypedBatch { inner: self, batch }
}
pub fn zs_is_empty(&self) -> bool {
self.db.zs_is_empty(&self.cf)
}
pub fn zs_get(&self, key: &Key) -> Option<Value> {
self.db.zs_get(&self.cf, key)
}
pub fn zs_contains(&self, key: &Key) -> bool {
self.db.zs_contains(&self.cf, key)
}
pub fn zs_first_key_value(&self) -> Option<(Key, Value)> {
self.db.zs_first_key_value(&self.cf)
}
pub fn zs_last_key_value(&self) -> Option<(Key, Value)> {
self.db.zs_last_key_value(&self.cf)
}
pub fn zs_next_key_value_from(&self, lower_bound: &Key) -> Option<(Key, Value)> {
self.db.zs_next_key_value_from(&self.cf, lower_bound)
}
pub fn zs_next_key_value_strictly_after(&self, lower_bound: &Key) -> Option<(Key, Value)> {
self.db
.zs_next_key_value_strictly_after(&self.cf, lower_bound)
}
pub fn zs_prev_key_value_back_from(&self, upper_bound: &Key) -> Option<(Key, Value)> {
self.db.zs_prev_key_value_back_from(&self.cf, upper_bound)
}
pub fn zs_prev_key_value_strictly_before(&self, upper_bound: &Key) -> Option<(Key, Value)> {
self.db
.zs_prev_key_value_strictly_before(&self.cf, upper_bound)
}
pub fn zs_forward_range_iter<Range>(
&self,
range: Range,
) -> impl Iterator<Item = (Key, Value)> + '_
where
Range: RangeBounds<Key>,
{
self.db.zs_forward_range_iter(&self.cf, range)
}
pub fn zs_reverse_range_iter<Range>(
&self,
range: Range,
) -> impl Iterator<Item = (Key, Value)> + '_
where
Range: RangeBounds<Key>,
{
self.db.zs_reverse_range_iter(&self.cf, range)
}
}
impl<Key, Value> TypedColumnFamily<'_, Key, Value>
where
Key: IntoDisk + FromDisk + Debug + Ord,
Value: IntoDisk + FromDisk,
{
pub fn zs_items_in_range_ordered<Range>(&self, range: Range) -> BTreeMap<Key, Value>
where
Range: RangeBounds<Key>,
{
self.db.zs_items_in_range_ordered(&self.cf, range)
}
}
impl<Key, Value> TypedColumnFamily<'_, Key, Value>
where
Key: IntoDisk + FromDisk + Debug + Hash + Eq,
Value: IntoDisk + FromDisk,
{
pub fn zs_items_in_range_unordered<Range>(&self, range: Range) -> HashMap<Key, Value>
where
Range: RangeBounds<Key>,
{
self.db.zs_items_in_range_unordered(&self.cf, range)
}
}
impl<Key, Value, Batch> WriteTypedBatch<'_, Key, Value, Batch>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
Batch: WriteDisk,
{
pub fn zs_insert(mut self, key: &Key, value: &Value) -> Self {
self.batch.zs_insert(&self.inner.cf, key, value);
self
}
pub fn zs_delete(mut self, key: &Key) -> Self {
self.batch.zs_delete(&self.inner.cf, key);
self
}
pub fn zs_delete_range(mut self, from: &Key, until_strictly_before: &Key) -> Self {
self.batch
.zs_delete_range(&self.inner.cf, from, until_strictly_before);
self
}
}
impl<Key, Value> WriteTypedBatch<'_, Key, Value, DiskWriteBatch>
where
Key: IntoDisk + FromDisk + Debug,
Value: IntoDisk + FromDisk,
{
pub fn write_batch(self) -> Result<(), rocksdb::Error> {
self.inner.db.write(self.batch)
}
}