use std::ops::Bound;
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
use std::sync::Arc;
use bytes::Bytes;
use crossbeam_skiplist::map::Entry;
use crossbeam_skiplist::SkipMap;
use parking_lot::RwLock;
use crate::error::Result;
use crate::iter::InternalIterator;
use crate::key::{self, KeyRef, Kind, MemKey};
const ENTRY_OVERHEAD: usize = 32;
const ARENA_CHUNK: usize = 1 << 20;
thread_local! {
static ARENA: std::cell::RefCell<bytes::BytesMut> = std::cell::RefCell::new(bytes::BytesMut::new());
}
pub(crate) fn detach(value: Bytes, backing: usize) -> Bytes {
if value.len().saturating_mul(2) < backing {
Bytes::copy_from_slice(&value)
} else {
value
}
}
pub fn arena_copy(len: usize, fill: impl FnOnce(&mut bytes::BytesMut)) -> Bytes {
ARENA.with(|arena| {
let mut arena = arena.borrow_mut();
if arena.capacity() - arena.len() < len {
*arena = bytes::BytesMut::with_capacity(len.max(ARENA_CHUNK));
}
fill(&mut arena);
arena.split().freeze()
})
}
#[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: SkipMap<MemKey, Bytes>,
tombstones: RwLock<Vec<RangeTombstone>>,
has_tombstones: AtomicBool,
size: AtomicUsize,
max_seq: AtomicU64,
first_wal: u64,
}
impl Memtable {
pub fn new(first_wal: u64) -> Self {
Memtable {
map: SkipMap::new(),
tombstones: RwLock::new(Vec::new()),
has_tombstones: AtomicBool::new(false),
size: 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]) {
let bytes = self.insert_entry(cf, key, seq, kind, value);
self.account(bytes, seq);
}
#[cfg(test)]
pub fn insert_entry(&self, cf: u32, key: &[u8], seq: u64, kind: Kind, value: &[u8]) -> usize {
let encoded = MemKey(Bytes::from(key::encode(cf, key, seq, kind)));
self.map.insert(encoded, Bytes::copy_from_slice(value));
key.len() + value.len() + ENTRY_OVERHEAD
}
pub fn insert_shared(&self, encoded_key: Bytes, value: Bytes) -> usize {
let bytes = encoded_key.len() + value.len() + ENTRY_OVERHEAD;
self.map.insert(MemKey(encoded_key), value);
bytes
}
pub fn account(&self, bytes: usize, max_seq: u64) {
self.size.fetch_add(bytes, Ordering::Relaxed);
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.size
.fetch_add(start.len() + end.len() + ENTRY_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.size.load(Ordering::Relaxed)
}
pub fn is_empty(&self) -> bool {
self.map.is_empty() && !self.has_tombstones.load(Ordering::Acquire)
}
pub fn get(&self, cf: u32, key: &[u8], snapshot: u64) -> Option<Version> {
let probe = key::at_snapshot(cf, key, snapshot);
let entry = self.map.lower_bound(Bound::Included(KeyRef::new(&probe)))?;
let found = key::parse(&entry.key().0)?;
(found.cf == cf && found.user_key == key).then(|| Version {
seq: found.seq,
kind: found.kind,
value: detach(entry.value().clone(), ARENA_CHUNK),
})
}
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 = (Bytes, Bytes)> + '_ {
self.map
.iter()
.map(|e| (e.key().0.clone(), e.value().clone()))
}
}
pub struct MemIter {
mem: Arc<Memtable>,
current: Option<(Bytes, Bytes)>,
}
impl MemIter {
pub fn new(mem: Arc<Memtable>) -> Self {
MemIter { mem, current: None }
}
}
fn owned(entry: Option<Entry<'_, MemKey, Bytes>>) -> Option<(Bytes, Bytes)> {
entry.map(|e| (e.key().0.clone(), e.value().clone()))
}
impl InternalIterator for MemIter {
fn seek_ge(&mut self, target: &[u8]) {
self.current = owned(
self.mem
.map
.lower_bound(Bound::Included(KeyRef::new(target))),
);
}
fn seek_le(&mut self, target: &[u8]) {
self.current = owned(
self.mem
.map
.upper_bound(Bound::Included(KeyRef::new(target))),
);
}
fn seek_to_last(&mut self) {
self.current = owned(self.mem.map.back());
}
fn next(&mut self) {
if let Some((key, _)) = self.current.take() {
self.current = owned(self.mem.map.lower_bound(Bound::Excluded(KeyRef::new(&key))));
}
}
fn prev(&mut self) {
if let Some((key, _)) = self.current.take() {
self.current = owned(self.mem.map.upper_bound(Bound::Excluded(KeyRef::new(&key))));
}
}
fn valid(&self) -> bool {
self.current.is_some()
}
fn key(&self) -> &[u8] {
&self.current.as_ref().expect("valid").0
}
fn value(&self) -> Bytes {
self.current.as_ref().expect("valid").1.clone()
}
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());
}
}