pub const NO_EXPIRY: u64 = 0;
#[derive(Debug, Clone)]
pub struct KvEntry {
pub hash: u64,
pub key: Vec<u8>,
pub value: KvValue,
pub expire_at_ms: u64,
}
impl KvEntry {
pub fn inline(hash: u64, key: Vec<u8>, data: Vec<u8>, expire_at_ms: u64) -> Self {
Self {
hash,
key,
value: KvValue::Inline(data),
expire_at_ms,
}
}
pub fn overflow(hash: u64, key: Vec<u8>, index: u32, len: u32, expire_at_ms: u64) -> Self {
Self {
hash,
key,
value: KvValue::Overflow { index, len },
expire_at_ms,
}
}
pub fn has_ttl(&self) -> bool {
self.expire_at_ms != NO_EXPIRY
}
pub fn is_expired(&self, now_ms: u64) -> bool {
self.expire_at_ms != NO_EXPIRY && now_ms >= self.expire_at_ms
}
pub fn inline_value(&self) -> Option<&[u8]> {
match &self.value {
KvValue::Inline(data) => Some(data),
KvValue::Overflow { .. } => None,
}
}
pub fn mem_size(&self) -> usize {
let fixed = 48;
let key_size = self.key.len();
let value_size = match &self.value {
KvValue::Inline(data) => data.len(),
KvValue::Overflow { .. } => 8,
};
fixed + key_size + value_size
}
}
#[derive(Debug, Clone)]
pub enum KvValue {
Inline(Vec<u8>),
Overflow {
index: u32,
len: u32,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn entry_inline_creation() {
let entry = KvEntry::inline(12345, b"mykey".to_vec(), b"myvalue".to_vec(), NO_EXPIRY);
assert_eq!(entry.hash, 12345);
assert_eq!(entry.key, b"mykey");
assert_eq!(entry.inline_value(), Some(b"myvalue".as_slice()));
assert!(!entry.has_ttl());
assert!(!entry.is_expired(1_000_000));
}
#[test]
fn entry_with_ttl() {
let entry = KvEntry::inline(1, b"k".to_vec(), b"v".to_vec(), 5000);
assert!(entry.has_ttl());
assert!(!entry.is_expired(4999));
assert!(entry.is_expired(5000));
assert!(entry.is_expired(5001));
}
#[test]
fn entry_overflow() {
let entry = KvEntry::overflow(1, b"k".to_vec(), 0, 1024, NO_EXPIRY);
assert!(entry.inline_value().is_none());
assert!(!entry.has_ttl());
match &entry.value {
KvValue::Overflow { index, len } => {
assert_eq!(*index, 0);
assert_eq!(*len, 1024);
}
_ => panic!("expected overflow"),
}
}
#[test]
fn mem_size_is_reasonable() {
let entry = KvEntry::inline(1, b"key".to_vec(), b"val".to_vec(), NO_EXPIRY);
let size = entry.mem_size();
assert_eq!(size, 54);
}
}