use crate::message::StreamMessage;
use async_trait::async_trait;
use futures_core::Stream;
use serde::{Deserialize, Serialize};
use std::pin::Pin;
use thiserror::Error;
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum StartPosition {
Latest,
Offset(u64),
}
#[derive(Debug, Error)]
pub enum PersistentStorageError {
#[error("I/O error: {0}")]
Io(String),
#[error("WAL error: {0}")]
Wal(String),
#[error("Cloud storage error: {0}")]
Cloud(String),
#[error("Metadata store error: {0}")]
Metadata(String),
#[error("Unsupported: {0}")]
Unsupported(String),
#[error("Other: {0}")]
Other(String),
}
pub type TopicStream =
Pin<Box<dyn Stream<Item = Result<StreamMessage, PersistentStorageError>> + Send>>;
#[async_trait]
pub trait PersistentStorage: Send + Sync + std::fmt::Debug + 'static {
async fn append_message(
&self,
topic_name: &str,
msg: StreamMessage,
) -> Result<u64, PersistentStorageError>;
async fn append_batch(
&self,
topic_name: &str,
messages: &[StreamMessage],
) -> Result<(u64, u64), PersistentStorageError> {
if messages.is_empty() {
return Err(PersistentStorageError::Other("empty batch".to_string()));
}
let mut first = 0u64;
let mut last = 0u64;
for (i, msg) in messages.iter().enumerate() {
let offset = self.append_message(topic_name, msg.clone()).await?;
if i == 0 {
first = offset;
}
last = offset;
}
Ok((first, last))
}
async fn create_reader(
&self,
topic_name: &str,
start: StartPosition,
) -> Result<TopicStream, PersistentStorageError>;
async fn ack_checkpoint(
&self,
topic_name: &str,
up_to_offset: u64,
) -> Result<(), PersistentStorageError>;
async fn flush(&self, topic_name: &str) -> Result<(), PersistentStorageError>;
fn current_offset(&self) -> u64;
}