use std::collections::BTreeMap;
use moire::sync::SyncMutex;
use vox_types::{MaybeSend, MaybeSync, MethodId, OperationId, PostcardPayload};
pub struct SealedResponse {
pub response: PostcardPayload,
pub method_id: MethodId,
}
pub enum OperationState {
Unknown,
Admitted,
Sealed,
}
pub trait OperationStore: MaybeSend + MaybeSync + 'static {
fn admit(&self, operation_id: OperationId);
fn lookup(&self, operation_id: OperationId) -> OperationState;
fn get_sealed(&self, operation_id: OperationId) -> Option<SealedResponse>;
fn seal(&self, operation_id: OperationId, method_id: MethodId, response: &PostcardPayload);
fn remove(&self, operation_id: OperationId);
}
enum InMemoryState {
Admitted,
Sealed {
response: PostcardPayload,
method_id: MethodId,
},
}
pub struct InMemoryOperationStore {
inner: SyncMutex<InMemoryRegistry>,
}
#[derive(Default)]
struct InMemoryRegistry {
operations: BTreeMap<OperationId, InMemoryState>,
}
impl InMemoryOperationStore {
pub fn new() -> Self {
Self::default()
}
}
impl Default for InMemoryOperationStore {
fn default() -> Self {
Self {
inner: SyncMutex::new("driver.operations", InMemoryRegistry::default()),
}
}
}
impl OperationStore for InMemoryOperationStore {
fn admit(&self, operation_id: OperationId) {
let mut inner = self.inner.lock();
inner
.operations
.entry(operation_id)
.or_insert(InMemoryState::Admitted);
tracing::trace!(
%operation_id,
operations = inner.operations.len(),
"operation store admit"
);
}
fn lookup(&self, operation_id: OperationId) -> OperationState {
let inner = self.inner.lock();
match inner.operations.get(&operation_id) {
None => OperationState::Unknown,
Some(InMemoryState::Admitted) => OperationState::Admitted,
Some(InMemoryState::Sealed { .. }) => OperationState::Sealed,
}
}
fn get_sealed(&self, operation_id: OperationId) -> Option<SealedResponse> {
let inner = self.inner.lock();
match inner.operations.get(&operation_id) {
Some(InMemoryState::Sealed {
response,
method_id,
}) => Some(SealedResponse {
response: response.clone(),
method_id: *method_id,
}),
_ => None,
}
}
fn seal(&self, operation_id: OperationId, method_id: MethodId, response: &PostcardPayload) {
let mut inner = self.inner.lock();
inner.operations.insert(
operation_id,
InMemoryState::Sealed {
response: response.clone(),
method_id,
},
);
tracing::trace!(
%operation_id,
response_bytes = response.as_bytes().len(),
operations = inner.operations.len(),
"operation store seal"
);
}
fn remove(&self, operation_id: OperationId) {
let mut inner = self.inner.lock();
if matches!(
inner.operations.get(&operation_id),
Some(InMemoryState::Admitted)
) {
inner.operations.remove(&operation_id);
tracing::trace!(
%operation_id,
operations = inner.operations.len(),
"operation store remove admitted"
);
}
}
}