use crate::bench::{bench_async, bench_regular, Benchmark};
use crate::server::{server_async, server_regular};
use crate::*;
use hashbrown::HashMap;
use log::debug;
use std::sync::mpsc::{Receiver, Sender};
use std::sync::Arc;
use toml::Table;
pub enum BenchKVMap {
Regular(Arc<Box<dyn KVMap>>),
Async(Arc<Box<dyn AsyncKVMap>>),
}
impl BenchKVMap {
pub(crate) fn bench(&self, phases: &Vec<Arc<Benchmark>>) {
match self {
BenchKVMap::Regular(map) => {
bench_regular(map.clone(), phases);
}
BenchKVMap::Async(map) => {
bench_async(map.clone(), phases);
}
};
}
pub(crate) fn server(
&self,
host: &str,
port: &str,
nr_workers: usize,
stop_rx: Receiver<()>,
grace_tx: Sender<()>,
) {
match self {
BenchKVMap::Regular(map) => {
server_regular(map.clone(), host, port, nr_workers, stop_rx, grace_tx);
}
BenchKVMap::Async(map) => {
server_async(map.clone(), host, port, nr_workers, stop_rx, grace_tx);
}
}
}
}
pub struct Registry<'a> {
pub(crate) name: &'a str,
constructor: fn(&Table) -> BenchKVMap,
}
impl<'a> Registry<'a> {
pub const fn new(name: &'a str, constructor: fn(&Table) -> BenchKVMap) -> Self {
Self { name, constructor }
}
}
inventory::collect!(Registry<'static>);
#[derive(Deserialize, Clone, Debug)]
pub(crate) struct BenchKVMapOpt {
name: String,
#[serde(flatten)]
opt: Table,
}
impl BenchKVMap {
pub(crate) fn new(opt: &BenchKVMapOpt) -> BenchKVMap {
let mut registered: HashMap<&'static str, fn(&Table) -> BenchKVMap> = HashMap::new();
for r in inventory::iter::<Registry> {
debug!("Adding supported kvmap: {}", r.name);
assert!(registered.insert(r.name, r.constructor).is_none()); }
let f = registered.get(opt.name.as_str()).unwrap_or_else(|| {
panic!("map {} not found in registry", opt.name);
});
f(&opt.opt)
}
}
pub mod btreemap;
#[cfg(feature = "chashmap")]
pub mod chashmap;
#[cfg(feature = "contrie")]
pub mod contrie;
#[cfg(feature = "dashmap")]
pub mod dashmap;
#[cfg(feature = "flurry")]
pub mod flurry;
pub mod hashmap;
pub mod null;
#[cfg(feature = "papaya")]
pub mod papaya;
pub mod remote;
pub mod remotereplicated;
pub mod remotesharded;
#[cfg(feature = "rocksdb")]
pub mod rocksdb;
#[cfg(feature = "scc")]
pub mod scc;
#[cfg(test)]
mod tests {
use super::*;
fn _map_test(map: &impl KVMap) {
let mut handle = map.handle();
handle.set(b"foo", b"bar");
assert_eq!(handle.get(b"foo"), Some((*b"bar").into()));
assert_eq!(handle.get(b"f00"), None);
handle.set(b"foo", b"0ar");
assert_eq!(handle.get(b"foo"), Some((*b"0ar").into()));
handle.delete(b"foo");
assert_eq!(handle.get(b"foo"), None);
}
fn _map_test_scan(map: &impl KVMap) {
let mut handle = map.handle();
for i in 10000..20000usize {
let bytes = i.clone().to_be_bytes();
handle.set(&bytes, &bytes);
}
let v = handle.scan(&10000_usize.to_be_bytes(), 10000);
assert_eq!(v.len(), 10000);
for i in 10000..20000usize {
let bytes = i.clone().to_be_bytes();
assert_eq!(*v[i - 10000].0, bytes);
assert_eq!(*v[i - 10000].1, bytes);
}
let v = handle.scan(&10000_usize.to_be_bytes(), 20000);
assert_eq!(v.len(), 10000);
for i in 10000..20000usize {
let bytes = i.clone().to_be_bytes();
assert_eq!(*v[i - 10000].0, bytes);
assert_eq!(*v[i - 10000].1, bytes);
}
let v = handle.scan(&10000_usize.to_be_bytes(), 5);
assert_eq!(v.len(), 5);
for i in 10000..10005usize {
let bytes = i.clone().to_be_bytes();
assert_eq!(*v[i - 10000].0, bytes);
assert_eq!(*v[i - 10000].1, bytes);
}
let v = handle.scan(&13333_usize.to_be_bytes(), 444);
assert_eq!(v.len(), 444);
for i in 13333..13777usize {
let bytes = i.clone().to_be_bytes();
assert_eq!(*v[i - 13333].0, bytes);
assert_eq!(*v[i - 13333].1, bytes);
}
let v = handle.scan(&13333_usize.to_be_bytes(), 0);
assert_eq!(v.len(), 0);
let v = handle.scan(&20000_usize.to_be_bytes(), 10000);
assert_eq!(v.len(), 0);
let v = handle.scan(&0_usize.to_be_bytes(), 5000);
assert_eq!(v.len(), 5000);
for i in 10000..15000usize {
let bytes = i.clone().to_be_bytes();
assert_eq!(*v[i - 10000].0, bytes);
assert_eq!(*v[i - 10000].1, bytes);
}
let v = handle.scan(&8000_usize.to_be_bytes(), 5000);
assert_eq!(v.len(), 5000);
for i in 10000..15000usize {
let bytes = i.clone().to_be_bytes();
assert_eq!(*v[i - 10000].0, bytes);
assert_eq!(*v[i - 10000].1, bytes);
}
}
#[test]
fn mutex_btreemap() {
let mut map = btreemap::MutexBTreeMap::new();
_map_test(&mut map);
}
#[test]
fn rwlock_btreemap() {
let mut map = btreemap::RwLockBTreeMap::new();
_map_test(&mut map);
}
#[test]
#[cfg(feature = "chashmap")]
fn chashmap() {
let mut map = chashmap::CHashMap::new();
_map_test(&mut map);
}
#[test]
#[cfg(feature = "contrie")]
fn contrie() {
let mut map = contrie::Contrie::new();
_map_test(&mut map);
}
#[test]
#[cfg(feature = "dashmap")]
fn dashmap() {
let mut map = dashmap::DashMap::new();
_map_test(&mut map);
}
#[test]
#[cfg(feature = "flurry")]
fn flurry() {
let mut map = flurry::Flurry::new();
_map_test(&mut map);
}
#[test]
fn mutex_hashmap() {
let opt = hashmap::MutexHashMapOpt { shards: 512 };
let mut map = hashmap::MutexHashMap::new(&opt);
_map_test(&mut map);
}
#[test]
fn rwlock_hashmap() {
let opt = hashmap::RwLockHashMapOpt { shards: 512 };
let mut map = hashmap::RwLockHashMap::new(&opt);
_map_test(&mut map);
}
#[test]
#[cfg(feature = "papaya")]
fn papaya() {
let mut map = papaya::Papaya::new();
_map_test(&mut map);
}
#[test]
fn nullmap() {
let mut map = null::NullMap::new();
assert!(map.get("foo".as_bytes().into()).is_none());
}
#[test]
#[cfg(feature = "scc")]
fn scchashmap() {
let mut map = scc::SccHashMap::new();
_map_test(&mut map);
}
#[test]
#[cfg(feature = "rocksdb")]
fn rocksdb() {
let tmp_dir = tempfile::tempdir().unwrap();
let opt = rocksdb::RocksDBOpt {
path: tmp_dir.path().to_str().unwrap().to_string(),
};
let mut map = rocksdb::RocksDB::new(&opt);
_map_test(&mut map);
}
#[test]
#[cfg(feature = "rocksdb")]
fn rocksdb_scan() {
let tmp_dir = tempfile::tempdir().unwrap();
let opt = rocksdb::RocksDBOpt {
path: tmp_dir.path().to_str().unwrap().to_string(),
};
let mut map = rocksdb::RocksDB::new(&opt);
_map_test_scan(&mut map);
}
}