use crate::{
BoxFut, DhtArc, K2Result, OpId, SpaceId, Timestamp, builder, config,
};
use bytes::Bytes;
use futures::future::BoxFuture;
use std::cmp::Ordering;
use std::sync::Arc;
pub(crate) mod proto {
include!("../proto/gen/kitsune2.op_store.rs");
}
pub use proto::Op;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MetaOp {
pub op_id: OpId,
pub op_data: Bytes,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct IncomingOp {
pub op_id: OpId,
pub op_data: Bytes,
pub metadata: Option<Bytes>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct StoredOp {
pub op_id: OpId,
pub created_at: Timestamp,
}
impl Ord for StoredOp {
fn cmp(&self, other: &Self) -> Ordering {
(&self.created_at, &self.op_id).cmp(&(&other.created_at, &other.op_id))
}
}
impl PartialOrd for StoredOp {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg_attr(any(test, feature = "mockall"), mockall::automock)]
pub trait OpStore: 'static + Send + Sync + std::fmt::Debug {
fn process_incoming_ops(
&self,
op_list: Vec<IncomingOp>,
) -> BoxFuture<'_, K2Result<Vec<OpId>>>;
fn retrieve_op_hashes_in_time_slice(
&self,
arc: DhtArc,
start: Timestamp,
end: Timestamp,
) -> BoxFuture<'_, K2Result<(Vec<OpId>, u32)>>;
fn retrieve_ops(
&self,
op_ids: Vec<OpId>,
) -> BoxFuture<'_, K2Result<Vec<MetaOp>>>;
fn filter_out_existing_ops(
&self,
op_ids: Vec<OpId>,
) -> BoxFuture<'_, K2Result<Vec<OpId>>>;
fn retrieve_op_ids_bounded(
&self,
arc: DhtArc,
start: Timestamp,
limit_bytes: u32,
) -> BoxFuture<'_, K2Result<(Vec<OpId>, u32, Timestamp)>>;
fn earliest_timestamp_in_arc(
&self,
arc: DhtArc,
) -> BoxFuture<'_, K2Result<Option<Timestamp>>>;
fn store_slice_hash(
&self,
arc: DhtArc,
slice_index: u64,
slice_hash: Bytes,
) -> BoxFuture<'_, K2Result<()>>;
fn slice_hash_count(&self, arc: DhtArc) -> BoxFuture<'_, K2Result<u64>>;
fn retrieve_slice_hash(
&self,
arc: DhtArc,
slice_index: u64,
) -> BoxFuture<'_, K2Result<Option<Bytes>>>;
fn retrieve_slice_hashes(
&self,
arc: DhtArc,
) -> BoxFuture<'_, K2Result<Vec<(u64, Bytes)>>>;
fn query_total_op_count(&self) -> BoxFuture<'_, K2Result<u64>>;
}
pub type DynOpStore = Arc<dyn OpStore>;
pub trait OpStoreFactory: 'static + Send + Sync + std::fmt::Debug {
fn default_config(&self, config: &mut config::Config) -> K2Result<()>;
fn validate_config(&self, config: &config::Config) -> K2Result<()>;
fn create(
&self,
builder: Arc<builder::Builder>,
space_id: SpaceId,
) -> BoxFut<'static, K2Result<DynOpStore>>;
}
pub type DynOpStoreFactory = Arc<dyn OpStoreFactory>;
#[cfg(test)]
mod test {
use super::*;
use prost::Message;
#[test]
fn happy_op_encode_decode() {
let op = Op {
op_id: Bytes::from_static(b"test_op_id"),
data: Bytes::from(vec![1; 128]),
};
let op_enc = op.encode_to_vec();
let op_dec = Op::decode(op_enc.as_slice()).unwrap();
assert_eq!(op_dec, op);
}
}