use std::sync::Arc;
use dynamo_tokens::TokenBlock;
use crate::KvbmSequenceHashProvider;
use crate::blocks::{BlockError, BlockId, BlockMetadata, CompleteBlock, SequenceHash};
use crate::pools::BlockStore;
pub struct MutableBlock<T: BlockMetadata> {
store: Arc<BlockStore<T>>,
block_id: BlockId,
block_size: usize,
armed: bool,
}
impl<T: BlockMetadata + Sync> MutableBlock<T> {
pub(crate) fn from_store(
store: Arc<BlockStore<T>>,
block_id: BlockId,
block_size: usize,
) -> Self {
Self {
store,
block_id,
block_size,
armed: true,
}
}
pub fn block_id(&self) -> BlockId {
self.block_id
}
pub fn block_size(&self) -> usize {
self.block_size
}
pub fn stage(
mut self,
seq_hash: SequenceHash,
block_size: usize,
) -> Result<CompleteBlock<T>, BlockError<MutableBlock<T>>> {
if block_size != self.block_size {
return Err(BlockError::BlockSizeMismatch {
expected: self.block_size,
actual: block_size,
block: self,
});
}
self.store.transition_to_staged(self.block_id, seq_hash);
let id = self.block_id;
let bsize = self.block_size;
let store = self.store.clone();
self.armed = false;
drop(self);
Ok(CompleteBlock::from_store(store, id, bsize, seq_hash))
}
pub fn complete(
self,
token_block: &TokenBlock,
) -> Result<CompleteBlock<T>, BlockError<MutableBlock<T>>> {
let actual = token_block.block_size();
if actual != self.block_size {
return Err(BlockError::BlockSizeMismatch {
expected: self.block_size,
actual,
block: self,
});
}
let seq_hash = token_block.kvbm_sequence_hash();
self.stage(seq_hash, actual)
}
}
impl<T: BlockMetadata> Drop for MutableBlock<T> {
#[inline]
fn drop(&mut self) {
if self.armed {
self.store.release_mutable(self.block_id);
}
}
}
impl<T: BlockMetadata> std::fmt::Debug for MutableBlock<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MutableBlock")
.field("block_id", &self.block_id)
.finish()
}
}