pub trait SliceTransform {
fn transform<'a>(&self, key: &'a [u8]) -> &'a [u8];
fn in_domain(&self, _key: &[u8]) -> bool {
true }
fn name(&self) -> &str {
"RustSliceTransform\0"
}
}
#[doc(hidden)]
pub mod c {
use std::os::raw::c_char;
use super::SliceTransform;
#[no_mangle]
pub unsafe extern "C" fn rust_slice_transform_call(
t: *mut (),
key: &&[u8], ret_value: *mut *const c_char,
ret_len: *mut usize,
) {
let trans = t as *mut Box<dyn SliceTransform>;
let ret = (*trans).transform(key);
*ret_value = ret.as_ptr() as *const _;
*ret_len = ret.len();
}
#[no_mangle]
pub unsafe extern "C" fn rust_slice_transform_name(t: *mut ()) -> *const c_char {
let trans = t as *mut Box<dyn SliceTransform>;
(*trans).name().as_ptr() as *const _
}
#[no_mangle]
pub unsafe extern "C" fn rust_slice_transform_in_domain(t: *mut (), key: &&[u8]) -> c_char {
let trans = t as *mut Box<dyn SliceTransform>;
(*trans).in_domain(key) as c_char
}
#[no_mangle]
pub unsafe extern "C" fn rust_slice_transform_drop(t: *mut ()) {
let trans = t as *mut Box<dyn SliceTransform>;
Box::from_raw(trans);
}
}
#[cfg(test)]
mod tests {
use super::super::rocksdb::*;
use super::*;
pub struct MySliceTransform;
impl SliceTransform for MySliceTransform {
fn transform<'a>(&self, key: &'a [u8]) -> &'a [u8] {
assert!(key.len() > 10);
&key[3..9]
}
}
#[test]
fn customized_prefix_extractor() {
let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();
let db = DB::open(
Options::default()
.map_db_options(|db| db.create_if_missing(true))
.map_cf_options(|cf| {
cf.prefix_extractor(Box::new(MySliceTransform))
.memtable_prefix_bloom_size_ratio(0.1) }),
&tmp_dir,
)
.unwrap();
assert!(db.put(&WriteOptions::default(), b"AA-abcdef-003", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"AA-abcdef-001", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"AA-abcdef-002", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"BB-abcdef-005", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"AA-abcdef-002", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"CC-abcdef-001", b"23333").is_ok());
let mut it = db.new_iterator(&ReadOptions::default().pin_data(true).prefix_same_as_start(true));
it.seek(b"---abcdef--");
assert!(it.is_valid());
let mut keys = vec![];
while it.is_valid() {
keys.push(String::from_utf8_lossy(it.key()).to_owned().to_string());
it.next();
}
assert!(keys.contains(&"CC-abcdef-001".to_string()));
assert!(keys.contains(&"BB-abcdef-005".to_string()));
assert!(keys.contains(&"AA-abcdef-002".to_string()));
}
#[test]
fn prefix_extractor_capped() {
let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();
let db = DB::open(
Options::default()
.map_db_options(|db| db.create_if_missing(true))
.map_cf_options(|cf| {
cf.prefix_extractor_capped(3) .memtable_prefix_bloom_size_ratio(0.1) }),
&tmp_dir,
)
.unwrap();
assert!(db.put(&WriteOptions::default(), b"abc-003", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"abc-001", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"abc-002", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"abc-005", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"abc-002", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"abc-006", b"23333").is_ok());
assert!(db.put(&WriteOptions::default(), b"def-000", b"23333").is_ok());
let mut it = db.new_iterator(&ReadOptions::default().pin_data(true).prefix_same_as_start(true));
it.seek(b"abc-");
assert!(it.is_valid());
let mut keys = vec![];
while it.is_valid() {
keys.push(String::from_utf8_lossy(it.key()).to_owned().to_string());
it.next();
}
assert!(keys.contains(&"abc-001".to_string()));
assert!(keys.contains(&"abc-005".to_string()));
assert!(keys.contains(&"abc-002".to_string()));
assert!(!keys.contains(&"def-000".to_string()));
}
}