use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
use std::sync::Arc;
use bytes::Bytes;
use parking_lot::RwLock;
use crate::error::Result;
use crate::iter::InternalIterator;
use crate::key::{self, Kind};
use crate::skiplist::{Cursor, SkipList};
const TOMBSTONE_OVERHEAD: usize = std::mem::size_of::<RangeTombstone>();
pub(crate) fn detach(value: Bytes, backing: usize) -> Bytes {
if copies(value.len(), backing) {
Bytes::copy_from_slice(&value)
} else {
value
}
}
pub(crate) fn detach_from(value: &[u8], backing: usize, handle: impl FnOnce() -> Bytes) -> Bytes {
if copies(value.len(), backing) {
Bytes::copy_from_slice(value)
} else {
handle()
}
}
fn copies(len: usize, backing: usize) -> bool {
len.saturating_mul(2) < backing
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RangeTombstone {
pub cf: u32,
pub start: Bytes,
pub end: Bytes,
pub seq: u64,
}
impl RangeTombstone {
pub fn covers(&self, cf: u32, key: &[u8]) -> bool {
self.cf == cf && &self.start[..] <= key && key < &self.end[..]
}
}
pub fn covering_seq<'a>(
tombstones: impl IntoIterator<Item = &'a RangeTombstone>,
cf: u32,
key: &[u8],
snapshot: u64,
) -> u64 {
tombstones
.into_iter()
.filter(|t| t.seq <= snapshot && t.covers(cf, key))
.map(|t| t.seq)
.max()
.unwrap_or(0)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Version {
pub seq: u64,
pub kind: Kind,
pub value: Bytes,
}
pub struct Memtable {
map: SkipList,
tombstones: RwLock<Vec<RangeTombstone>>,
has_tombstones: AtomicBool,
tombstone_bytes: AtomicUsize,
max_seq: AtomicU64,
first_wal: u64,
}
impl Memtable {
pub fn new(first_wal: u64) -> Self {
Memtable {
map: SkipList::new(),
tombstones: RwLock::new(Vec::new()),
has_tombstones: AtomicBool::new(false),
tombstone_bytes: AtomicUsize::new(0),
max_seq: AtomicU64::new(0),
first_wal,
}
}
pub fn first_wal(&self) -> u64 {
self.first_wal
}
pub fn max_seq(&self) -> u64 {
self.max_seq.load(Ordering::Relaxed)
}
#[cfg(test)]
pub fn insert(&self, cf: u32, key: &[u8], seq: u64, kind: Kind, value: &[u8]) {
self.insert_entry(cf, key, seq, kind, value);
self.account(seq);
}
pub fn insert_entry(&self, cf: u32, key: &[u8], seq: u64, kind: Kind, value: &[u8]) {
self.map.insert(
&[&cf.to_be_bytes(), key, &key::trailer_bytes(seq, kind)],
value,
);
}
pub fn account(&self, max_seq: u64) {
self.max_seq.fetch_max(max_seq, Ordering::Relaxed);
}
pub fn insert_range_tombstone(&self, cf: u32, start: &[u8], end: &[u8], seq: u64) {
self.max_seq.fetch_max(seq, Ordering::Relaxed);
self.tombstone_bytes.fetch_add(
start.len() + end.len() + TOMBSTONE_OVERHEAD,
Ordering::Relaxed,
);
self.has_tombstones.store(true, Ordering::Release);
self.tombstones.write().push(RangeTombstone {
cf,
start: Bytes::copy_from_slice(start),
end: Bytes::copy_from_slice(end),
seq,
});
}
pub fn approximate_size(&self) -> usize {
self.map.memory_usage() + self.tombstone_bytes.load(Ordering::Relaxed)
}
pub fn is_empty(&self) -> bool {
self.map.is_empty() && !self.has_tombstones.load(Ordering::Acquire)
}
#[cfg(any(test, feature = "fuzzing"))]
pub fn get(&self, cf: u32, key: &[u8], snapshot: u64) -> Option<Version> {
self.get_at(&key::LookupKey::new(cf, key, snapshot))
}
pub fn get_at(&self, lookup: &key::LookupKey<'_>) -> Option<Version> {
let at = self.map.seek_ge(lookup.internal())?;
let found = key::parse(unsafe { self.map.key(at) })?;
(found.cf == lookup.cf && found.user_key == lookup.user_key).then(|| Version {
seq: found.seq,
kind: found.kind,
value: Bytes::copy_from_slice(unsafe { self.map.value(at) }),
})
}
pub fn tombstones(&self) -> Vec<RangeTombstone> {
if !self.has_tombstones.load(Ordering::Acquire) {
return Vec::new();
}
self.tombstones.read().clone()
}
pub fn range_tombstone_seq(&self, cf: u32, key: &[u8], snapshot: u64) -> u64 {
if !self.has_tombstones.load(Ordering::Acquire) {
return 0;
}
covering_seq(self.tombstones.read().iter(), cf, key, snapshot)
}
pub fn entries(&self) -> impl Iterator<Item = (&[u8], &[u8])> + '_ {
self.map.iter()
}
}
pub struct MemIter {
mem: Arc<Memtable>,
at: Option<Cursor>,
}
impl MemIter {
pub fn new(mem: Arc<Memtable>) -> Self {
MemIter { mem, at: None }
}
fn current(&self) -> Cursor {
self.at.expect("valid")
}
}
impl InternalIterator for MemIter {
fn seek_ge(&mut self, target: &[u8]) {
self.at = self.mem.map.seek_ge(target);
}
fn seek_le(&mut self, target: &[u8]) {
self.at = self.mem.map.seek_le(target);
}
fn seek_to_last(&mut self) {
self.at = self.mem.map.last();
}
fn next(&mut self) {
if let Some(at) = self.at {
self.at = unsafe { self.mem.map.next(at) };
}
}
fn prev(&mut self) {
if let Some(at) = self.at {
self.at = self.mem.map.seek_lt(unsafe { self.mem.map.key(at) });
}
}
fn valid(&self) -> bool {
self.at.is_some()
}
fn key(&self) -> &[u8] {
unsafe { self.mem.map.key(self.current()) }
}
fn value(&self) -> Bytes {
Bytes::copy_from_slice(unsafe { self.mem.map.value(self.current()) })
}
fn status(&self) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_reader_sees_the_newest_version_at_its_snapshot() {
let mem = Memtable::new(1);
mem.insert(0, b"k", 1, Kind::Put, b"v1");
mem.insert(0, b"k", 5, Kind::Put, b"v5");
mem.insert(0, b"k", 9, Kind::Delete, b"");
assert_eq!(mem.get(0, b"k", 0), None);
assert_eq!(
mem.get(0, b"k", 4).unwrap().value,
Bytes::from_static(b"v1")
);
assert_eq!(
mem.get(0, b"k", 8).unwrap().value,
Bytes::from_static(b"v5")
);
assert_eq!(mem.get(0, b"k", 9).unwrap().kind, Kind::Delete);
}
#[test]
fn column_families_and_prefixes_do_not_leak_into_each_other() {
let mem = Memtable::new(1);
mem.insert(1, b"k", 1, Kind::Put, b"cf1");
mem.insert(0, b"kk", 2, Kind::Put, b"longer");
assert_eq!(mem.get(0, b"k", 10), None);
assert_eq!(mem.get(1, b"kk", 10), None);
}
#[test]
fn range_tombstones_apply_at_and_after_their_sequence() {
let mem = Memtable::new(1);
mem.insert_range_tombstone(0, b"b", b"d", 7);
assert_eq!(mem.range_tombstone_seq(0, b"c", 6), 0);
assert_eq!(mem.range_tombstone_seq(0, b"c", 7), 7);
assert_eq!(mem.range_tombstone_seq(0, b"d", 7), 0, "end is exclusive");
assert_eq!(
mem.range_tombstone_seq(1, b"c", 7),
0,
"other column family"
);
}
#[test]
fn the_cursor_walks_both_ways() {
let mem = Arc::new(Memtable::new(1));
for (i, k) in [b"a", b"b", b"c"].iter().enumerate() {
mem.insert(0, *k, i as u64 + 1, Kind::Put, b"");
}
let mut it = MemIter::new(mem);
it.seek_ge(&key::first_of(0, b"b"));
assert_eq!(key::parse(it.key()).unwrap().user_key, b"b");
it.next();
assert_eq!(key::parse(it.key()).unwrap().user_key, b"c");
it.next();
assert!(!it.valid());
it.seek_le(&key::last_of(0, b"b"));
assert_eq!(key::parse(it.key()).unwrap().user_key, b"b");
it.prev();
assert_eq!(key::parse(it.key()).unwrap().user_key, b"a");
it.prev();
assert!(!it.valid());
}
}