use std::collections::HashMap;
use std::path::Path;
use std::sync::{Arc, Mutex};
use async_trait::async_trait;
use crate::error::{StreamResult, task_failed};
#[async_trait]
pub trait StateStore: Send + Sync {
async fn put(&self, namespace: &str, key: &[u8], value: &[u8]) -> StreamResult<()>;
async fn get(&self, namespace: &str, key: &[u8]) -> StreamResult<Option<Vec<u8>>>;
async fn delete(&self, namespace: &str, key: &[u8]) -> StreamResult<()>;
async fn delete_prefix(&self, namespace: &str, key_prefix: &[u8]) -> StreamResult<()>;
async fn list_prefix(
&self,
namespace: &str,
key_prefix: &[u8],
) -> StreamResult<Vec<(Vec<u8>, Vec<u8>)>>;
fn persistent_db_path(&self) -> Option<&Path> {
None
}
}
pub fn state_db_err(reason: impl Into<String>) -> crate::error::StreamError {
task_failed(0, reason)
}
pub fn in_memory_job_state() -> Arc<dyn StateStore> {
Arc::new(InMemoryStateStore::default())
}
type InMemoryStoreMap = HashMap<(String, Vec<u8>), Vec<u8>>;
#[derive(Default)]
pub struct InMemoryStateStore {
inner: Mutex<InMemoryStoreMap>,
}
#[async_trait]
impl StateStore for InMemoryStateStore {
async fn put(&self, namespace: &str, key: &[u8], value: &[u8]) -> StreamResult<()> {
self.inner
.lock()
.unwrap()
.insert((namespace.to_string(), key.to_vec()), value.to_vec());
Ok(())
}
async fn get(&self, namespace: &str, key: &[u8]) -> StreamResult<Option<Vec<u8>>> {
Ok(self
.inner
.lock()
.unwrap()
.get(&(namespace.to_string(), key.to_vec()))
.cloned())
}
async fn delete(&self, namespace: &str, key: &[u8]) -> StreamResult<()> {
self.inner
.lock()
.unwrap()
.remove(&(namespace.to_string(), key.to_vec()));
Ok(())
}
async fn delete_prefix(&self, namespace: &str, key_prefix: &[u8]) -> StreamResult<()> {
let ns = namespace.to_string();
let mut guard = self.inner.lock().unwrap();
guard.retain(|(n, k), _| !(n == &ns && k.starts_with(key_prefix)));
Ok(())
}
async fn list_prefix(
&self,
namespace: &str,
key_prefix: &[u8],
) -> StreamResult<Vec<(Vec<u8>, Vec<u8>)>> {
let ns = namespace.to_string();
let guard = self.inner.lock().unwrap();
let mut out: Vec<(Vec<u8>, Vec<u8>)> = guard
.iter()
.filter(|((n, k), _)| n == &ns && k.starts_with(key_prefix))
.map(|((_, k), v)| (k.clone(), v.clone()))
.collect();
out.sort_by(|a, b| a.0.cmp(&b.0));
Ok(out)
}
}