#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Record {
pub value: Vec<u8>,
pub version: RecordVersion,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct RecordVersion(u64);
impl RecordVersion {
#[must_use]
pub const fn from_raw(raw: u64) -> Self {
Self(raw)
}
pub(crate) const fn new(raw: u64) -> Self {
Self(raw)
}
#[must_use]
pub const fn as_u64(self) -> u64 {
self.0
}
}
#[derive(Debug, Default)]
pub struct AtomicBatch {
pub(crate) pending: Vec<BatchOp>,
}
#[derive(Debug)]
pub(crate) enum BatchOp {
Put {
key: Vec<u8>,
value: Vec<u8>,
},
PutIfAbsent {
key: Vec<u8>,
value: Vec<u8>,
},
CompareAndPut {
key: Vec<u8>,
expected: RecordVersion,
value: Vec<u8>,
},
Delete {
key: Vec<u8>,
},
DeleteIfVersion {
key: Vec<u8>,
expected: RecordVersion,
},
AssertVersion {
key: Vec<u8>,
expected: RecordVersion,
},
AssertPrefixEmpty {
prefix: Vec<u8>,
},
Rename {
src: Vec<u8>,
dst: Vec<u8>,
force: bool,
},
}
impl BatchOp {
pub(crate) const fn emits_wal(&self) -> bool {
!matches!(
self,
Self::AssertVersion { .. } | Self::AssertPrefixEmpty { .. }
)
}
}
impl AtomicBatch {
pub fn put(&mut self, key: &[u8], value: &[u8]) {
self.pending.push(BatchOp::Put {
key: key.to_vec(),
value: value.to_vec(),
});
}
pub fn put_if_absent(&mut self, key: &[u8], value: &[u8]) {
self.pending.push(BatchOp::PutIfAbsent {
key: key.to_vec(),
value: value.to_vec(),
});
}
pub fn compare_and_put(&mut self, key: &[u8], expected: RecordVersion, value: &[u8]) {
self.pending.push(BatchOp::CompareAndPut {
key: key.to_vec(),
expected,
value: value.to_vec(),
});
}
pub fn delete(&mut self, key: &[u8]) {
self.pending.push(BatchOp::Delete { key: key.to_vec() });
}
pub fn delete_if_version(&mut self, key: &[u8], expected: RecordVersion) {
self.pending.push(BatchOp::DeleteIfVersion {
key: key.to_vec(),
expected,
});
}
pub fn assert_version(&mut self, key: &[u8], expected: RecordVersion) {
self.pending.push(BatchOp::AssertVersion {
key: key.to_vec(),
expected,
});
}
pub fn assert_prefix_empty(&mut self, prefix: &[u8]) {
self.pending.push(BatchOp::AssertPrefixEmpty {
prefix: prefix.to_vec(),
});
}
pub fn rename(&mut self, src: &[u8], dst: &[u8], force: bool) {
self.pending.push(BatchOp::Rename {
src: src.to_vec(),
dst: dst.to_vec(),
force,
});
}
pub fn len(&self) -> usize {
self.pending.len()
}
pub fn is_empty(&self) -> bool {
self.pending.is_empty()
}
}