fork of https://github.com/rust-rocksdb/rust-rocksdb for nextgraph
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
951 lines
40 KiB
951 lines
40 KiB
8 years ago
|
// This code is based on <https://github.com/facebook/rocksdb/blob/master/db/c_test.c>, revision a10e8a056d569acf6a52045124e6414ad33bdfcd.
|
||
|
|
||
|
#![allow(non_snake_case, non_upper_case_globals, unused_mut, unused_unsafe, unused_variables)]
|
||
|
|
||
|
#[macro_use]
|
||
|
extern crate const_cstr;
|
||
|
extern crate libc;
|
||
|
extern crate rocksdb_sys as ffi;
|
||
|
|
||
|
use ::ffi::*;
|
||
|
use ::libc::*;
|
||
|
use ::std::borrow::Cow;
|
||
|
use ::std::env;
|
||
|
use ::std::ffi::{CStr, CString};
|
||
|
use ::std::io::Write;
|
||
|
use ::std::mem;
|
||
|
use ::std::path::PathBuf;
|
||
|
use ::std::ptr;
|
||
|
use ::std::slice;
|
||
|
use ::std::str;
|
||
|
|
||
|
macro_rules! err_println {
|
||
|
($($arg:tt)*) => (writeln!(&mut ::std::io::stderr(), $($arg)*).expect("failed printing to stderr"));
|
||
|
}
|
||
|
|
||
|
macro_rules! cstr {
|
||
|
($($arg:tt)*) => (const_cstr!($($arg)*));
|
||
|
}
|
||
|
|
||
|
macro_rules! cstrp {
|
||
|
($($arg:tt)*) => (const_cstr!($($arg)*).as_ptr());
|
||
|
}
|
||
|
|
||
|
static mut phase: &'static str = "";
|
||
|
// static mut dbname: *mut c_uchar = ptr::null_mut();
|
||
|
// static mut dbbackupname: *mut c_uchar = ptr::null_mut();
|
||
|
|
||
|
unsafe fn strndup(s: *const c_char, n: size_t) -> *mut c_char {
|
||
|
let r: *mut c_char = malloc(n + 1) as *mut c_char;
|
||
|
if r.is_null() {
|
||
|
return r;
|
||
|
}
|
||
|
strncpy(r, s, n)
|
||
|
}
|
||
|
|
||
|
unsafe fn rstr<'a>(s: *const c_char) -> Cow<'a, str> {
|
||
|
CStr::from_ptr(s).to_string_lossy()
|
||
|
}
|
||
|
|
||
|
fn GetTempDir() -> PathBuf {
|
||
|
return match option_env!("TEST_TMPDIR") {
|
||
|
Some("") | None => env::temp_dir(),
|
||
|
Some(s) => s.into(),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
unsafe fn StartPhase(name: &'static str) {
|
||
|
err_println!("=== Test {}\n", name);
|
||
|
phase = name;
|
||
|
}
|
||
|
|
||
|
macro_rules! CheckNoError {
|
||
|
($err:ident) => { unsafe {
|
||
|
assert!($err.is_null(), "{}: {}", phase, rstr($err));
|
||
|
} };
|
||
|
}
|
||
|
|
||
|
macro_rules! CheckCondition {
|
||
|
($cond:expr) => { unsafe {
|
||
|
assert!($cond, "{}: {}", phase, stringify!($cond));
|
||
|
} };
|
||
|
}
|
||
|
|
||
|
unsafe fn CheckEqual(expected: *const c_char, v: *const c_char, n: size_t) {
|
||
|
if expected.is_null() && v.is_null() {
|
||
|
// ok
|
||
|
} else if !expected.is_null() && !v.is_null() && n == strlen(expected) && memcmp(expected as *const c_void, v as *const c_void, n) == 0 {
|
||
|
// ok
|
||
|
} else {
|
||
|
panic!("{}: expected '{}', got '{}'", phase, rstr(strndup(expected, n)), rstr(strndup(v, 5)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsafe fn Free<T>(ptr: *mut *mut T) {
|
||
|
if !(*ptr).is_null() {
|
||
|
free(*ptr as *mut c_void);
|
||
|
*ptr = ptr::null_mut();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unsafe fn CheckGet(mut db: *mut rocksdb_t, options: *mut rocksdb_readoptions_t, key: *const c_char, expected: *const c_char) {
|
||
|
let mut err: *mut c_char = ptr::null_mut();
|
||
|
let mut val_len: size_t = 0;
|
||
|
let mut val: *mut c_char = rocksdb_get(db, options, key, strlen(key), &mut val_len, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckEqual(expected, val, val_len);
|
||
|
Free(&mut val);
|
||
|
}
|
||
|
|
||
|
unsafe fn CheckGetCF(db: *mut rocksdb_t, options: *const rocksdb_readoptions_t, handle: *mut rocksdb_column_family_handle_t, key: *const c_char, expected: *const c_char) {
|
||
|
let mut err: *mut c_char = ptr::null_mut();
|
||
|
let mut val_len: size_t = 0;
|
||
|
let mut val: *mut c_char = rocksdb_get_cf(db, options, handle, key, strlen(key), &mut val_len, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckEqual(expected, val, val_len);
|
||
|
Free(&mut val);
|
||
|
}
|
||
|
|
||
|
unsafe fn CheckIter(iter: *mut rocksdb_iterator_t, key: *const c_char, val: *const c_char) {
|
||
|
let mut len: size_t = 0;
|
||
|
let mut str: *const c_char;
|
||
|
str = rocksdb_iter_key(iter, &mut len);
|
||
|
CheckEqual(key, str, len);
|
||
|
str = rocksdb_iter_value(iter, &mut len);
|
||
|
CheckEqual(val, str, len);
|
||
|
}
|
||
|
|
||
|
// Callback from rocksdb_writebatch_iterate()
|
||
|
unsafe extern "C" fn CheckPut(ptr: *mut c_void, k: *const c_char, klen: size_t, v: *const c_char, vlen: size_t) {
|
||
|
let mut state: *mut c_int = ptr as *mut c_int;
|
||
|
CheckCondition!(*state < 2);
|
||
|
match *state {
|
||
|
0 => {
|
||
|
CheckEqual(cstrp!("bar"), k, klen);
|
||
|
CheckEqual(cstrp!("b"), v, vlen);
|
||
|
},
|
||
|
1 => {
|
||
|
CheckEqual(cstrp!("box"), k, klen);
|
||
|
CheckEqual(cstrp!("c"), v, vlen);
|
||
|
},
|
||
|
_ => { },
|
||
|
}
|
||
|
*state += 1;
|
||
|
}
|
||
|
|
||
|
// Callback from rocksdb_writebatch_iterate()
|
||
|
unsafe extern "C" fn CheckDel(ptr: *mut c_void, k: *const c_char, klen: size_t) {
|
||
|
let mut state: *mut c_int = ptr as *mut c_int;
|
||
|
CheckCondition!(*state == 2);
|
||
|
CheckEqual(cstrp!("bar"), k, klen);
|
||
|
*state += 1;
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn CmpDestroy(arg: *mut c_void) { }
|
||
|
|
||
|
unsafe extern "C" fn CmpCompare(arg: *mut c_void, a: *const c_char, alen: size_t, b: *const c_char, blen: size_t) -> c_int {
|
||
|
let n = if alen < blen { alen } else { blen };
|
||
|
let mut r = memcmp(a as *const c_void, b as *const c_void, n);
|
||
|
if r == 0 {
|
||
|
if alen < blen {
|
||
|
r = -1;
|
||
|
} else if alen > blen {
|
||
|
r = 1;
|
||
|
}
|
||
|
}
|
||
|
r
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn CmpName(arg: *mut c_void) -> *const c_char {
|
||
|
cstrp!("foo")
|
||
|
}
|
||
|
|
||
|
// Custom filter policy
|
||
|
|
||
|
static mut fake_filter_result: c_uchar = 1;
|
||
|
|
||
|
unsafe extern "C" fn FilterDestroy(arg: *mut c_void) { }
|
||
|
|
||
|
unsafe extern "C" fn FilterName(arg: *mut c_void) -> *const c_char {
|
||
|
cstrp!("TestFilter")
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn FilterCreate(arg: *mut c_void, key_array: *const *const c_char, key_length_array: *const size_t, num_keys: c_int, filter_length: *mut size_t) -> *mut c_char {
|
||
|
*filter_length = 4;
|
||
|
let result = malloc(4);
|
||
|
memcpy(result, cstrp!("fake") as *const c_void, 4);
|
||
|
result as *mut c_char
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn FilterKeyMatch(arg: *mut c_void, key: *const c_char, length: size_t, filter: *const c_char, filter_length: size_t) -> c_uchar {
|
||
|
CheckCondition!(filter_length == 4);
|
||
|
CheckCondition!(memcmp(filter as *const c_void, cstrp!("fake") as *const c_void, filter_length) == 0);
|
||
|
fake_filter_result
|
||
|
}
|
||
|
|
||
|
// Custom compaction filter
|
||
|
|
||
|
unsafe extern "C" fn CFilterDestroy(arg: *mut c_void) { }
|
||
|
|
||
|
unsafe extern "C" fn CFilterName(arg: *mut c_void) -> *const c_char {
|
||
|
cstrp!("foo")
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn CFilterFilter(arg: *mut c_void, level: c_int, key: *const c_char, key_length: size_t, existing_value: *const c_char, value_length: size_t, new_value: *mut *mut c_char, new_value_length: *mut size_t, value_changed: *mut u8) -> c_uchar {
|
||
|
if key_length == 3 {
|
||
|
if memcmp(mem::transmute(key), mem::transmute(cstrp!("bar")), key_length) == 0 {
|
||
|
return 1;
|
||
|
} else if memcmp(mem::transmute(key), mem::transmute(cstrp!("baz")), key_length) == 0 {
|
||
|
*value_changed = 1;
|
||
|
*new_value = cstrp!("newbazvalue") as *mut c_char;
|
||
|
*new_value_length = 11;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
0
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn CFilterFactoryDestroy(arg: *mut c_void) { }
|
||
|
|
||
|
unsafe extern "C" fn CFilterFactoryName(arg: *mut c_void) -> *const c_char {
|
||
|
cstrp!("foo")
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn CFilterCreate(arg: *mut c_void, context: *mut rocksdb_compactionfiltercontext_t) -> *mut rocksdb_compactionfilter_t {
|
||
|
rocksdb_compactionfilter_create(ptr::null_mut(), Some(CFilterDestroy), Some(CFilterFilter), Some(CFilterName))
|
||
|
}
|
||
|
|
||
|
unsafe fn CheckCompaction(dbname: *const c_char, db: *mut rocksdb_t, options: *const rocksdb_options_t, roptions: *mut rocksdb_readoptions_t, woptions: *mut rocksdb_writeoptions_t) -> *mut rocksdb_t {
|
||
|
let mut err: *mut c_char = ptr::null_mut();
|
||
|
let db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("foo"), 3, cstrp!("foovalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
|
||
|
rocksdb_put(db, woptions, cstrp!("bar"), 3, cstrp!("barvalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("bar"), cstrp!("barvalue"));
|
||
|
rocksdb_put(db, woptions, cstrp!("baz"), 3, cstrp!("bazvalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("baz"), cstrp!("bazvalue"));
|
||
|
|
||
|
// Force compaction
|
||
|
rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
|
||
|
// should have filtered bar, but not foo
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
|
||
|
CheckGet(db, roptions, cstrp!("bar"), ptr::null());
|
||
|
CheckGet(db, roptions, cstrp!("baz"), cstrp!("newbazvalue"));
|
||
|
db
|
||
|
}
|
||
|
|
||
|
// Custom merge operator
|
||
|
|
||
|
unsafe extern "C" fn MergeOperatorDestroy(arg: *mut c_void) { }
|
||
|
|
||
|
unsafe extern "C" fn MergeOperatorName(arg: *mut c_void) -> *const c_char {
|
||
|
cstrp!("foo")
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn MergeOperatorFullMerge(arg: *mut c_void, key: *const c_char, key_length: size_t, existing_value: *const c_char, existing_value_length: size_t, operands_list: *const *const c_char, operands_list_length: *const size_t, num_operands: c_int, success: *mut u8, new_value_length: *mut size_t) -> *mut c_char {
|
||
|
*new_value_length = 4;
|
||
|
*success = 1;
|
||
|
let result: *mut c_char = malloc(4) as *mut _;
|
||
|
memcpy(result as *mut _, cstrp!("fake") as *mut _, 4);
|
||
|
result
|
||
|
}
|
||
|
|
||
|
unsafe extern "C" fn MergeOperatorPartialMerge(arg: *mut c_void, key: *const c_char, key_length: size_t, operands_list: *const *const c_char, operands_list_length: *const size_t, num_operands: c_int, success: *mut u8, new_value_length: *mut size_t) -> *mut c_char {
|
||
|
*new_value_length = 4;
|
||
|
*success = 1;
|
||
|
let result: *mut c_char = malloc(4) as *mut _;
|
||
|
memcpy(result as *mut _, cstrp!("fake") as *const _, 4);
|
||
|
result
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn ffi() {
|
||
|
unsafe {
|
||
|
let mut db: *mut rocksdb_t;
|
||
|
let mut cmp: *mut rocksdb_comparator_t;
|
||
|
let mut cache: *mut rocksdb_cache_t;
|
||
|
let mut env: *mut rocksdb_env_t;
|
||
|
let mut options: *mut rocksdb_options_t;
|
||
|
let mut table_options: *mut rocksdb_block_based_table_options_t;
|
||
|
let mut roptions: *mut rocksdb_readoptions_t;
|
||
|
let mut woptions: *mut rocksdb_writeoptions_t;
|
||
|
let mut err: *mut c_char = ptr::null_mut();
|
||
|
let run: c_int = -1;
|
||
|
|
||
|
let dbname = {
|
||
|
let mut dir = GetTempDir();
|
||
|
dir.push(format!("rocksdb_c_test-{}", geteuid()));
|
||
|
let path = dir.to_str().unwrap();
|
||
|
CString::new(path).unwrap()
|
||
|
};
|
||
|
let dbbackupname = {
|
||
|
let mut dir = GetTempDir();
|
||
|
dir.push(format!("rocksdb_c_test-{}-backup", geteuid()));
|
||
|
let path = dir.to_str().unwrap();
|
||
|
CString::new(path).unwrap()
|
||
|
};
|
||
|
|
||
|
let dbname = dbname.as_ptr();
|
||
|
let dbbackupname = dbbackupname.as_ptr();
|
||
|
|
||
|
StartPhase("create_objects");
|
||
|
cmp = rocksdb_comparator_create(ptr::null_mut(), Some(CmpDestroy), Some(CmpCompare), Some(CmpName));
|
||
|
env = rocksdb_create_default_env();
|
||
|
cache = rocksdb_cache_create_lru(100000);
|
||
|
|
||
|
options = rocksdb_options_create();
|
||
|
rocksdb_options_set_comparator(options, cmp);
|
||
|
rocksdb_options_set_error_if_exists(options, 1);
|
||
|
rocksdb_options_set_env(options, env);
|
||
|
rocksdb_options_set_info_log(options, ptr::null_mut());
|
||
|
rocksdb_options_set_write_buffer_size(options, 100000);
|
||
|
rocksdb_options_set_paranoid_checks(options, 1);
|
||
|
rocksdb_options_set_max_open_files(options, 10);
|
||
|
table_options = rocksdb_block_based_options_create();
|
||
|
rocksdb_block_based_options_set_block_cache(table_options, cache);
|
||
|
rocksdb_options_set_block_based_table_factory(options, table_options);
|
||
|
|
||
|
let no_compression = rocksdb_no_compression;
|
||
|
rocksdb_options_set_compression(options, no_compression);
|
||
|
rocksdb_options_set_compression_options(options, -14, -1, 0, 0);
|
||
|
let compression_levels = vec![
|
||
|
no_compression,
|
||
|
no_compression,
|
||
|
no_compression,
|
||
|
no_compression,
|
||
|
];
|
||
|
rocksdb_options_set_compression_per_level(options,
|
||
|
mem::transmute(compression_levels.as_ptr()),
|
||
|
compression_levels.len() as size_t);
|
||
|
|
||
|
roptions = rocksdb_readoptions_create();
|
||
|
rocksdb_readoptions_set_verify_checksums(roptions, 1);
|
||
|
rocksdb_readoptions_set_fill_cache(roptions, 0);
|
||
|
|
||
|
woptions = rocksdb_writeoptions_create();
|
||
|
rocksdb_writeoptions_set_sync(woptions, 1);
|
||
|
|
||
|
StartPhase("destroy");
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
Free(&mut err);
|
||
|
|
||
|
StartPhase("open_error");
|
||
|
rocksdb_open(options, dbname, &mut err);
|
||
|
CheckCondition!(!err.is_null());
|
||
|
Free(&mut err);
|
||
|
|
||
|
StartPhase("open");
|
||
|
rocksdb_options_set_create_if_missing(options, 1);
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("foo") as *const _, ptr::null());
|
||
|
|
||
|
StartPhase("put");
|
||
|
rocksdb_put(db, woptions, cstrp!("foo"), 3, cstrp!("hello"), 5, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
|
||
|
|
||
|
StartPhase("backup_and_restore");
|
||
|
{
|
||
|
rocksdb_destroy_db(options, dbbackupname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
let be = rocksdb_backup_engine_open(options, dbbackupname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_backup_engine_create_new_backup(be, db, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
// need a change to trigger a new backup
|
||
|
rocksdb_delete(db, woptions, cstrp!("does-not-exist"), 14, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_backup_engine_create_new_backup(be, db, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
let bei: *const rocksdb_backup_engine_info_t = rocksdb_backup_engine_get_backup_info(be);
|
||
|
CheckCondition!(rocksdb_backup_engine_info_count(bei) > 1);
|
||
|
rocksdb_backup_engine_info_destroy(bei);
|
||
|
|
||
|
rocksdb_backup_engine_purge_old_backups(be, 1, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
let bei: *const rocksdb_backup_engine_info_t = rocksdb_backup_engine_get_backup_info(be);
|
||
|
CheckCondition!(rocksdb_backup_engine_info_count(bei) == 1);
|
||
|
rocksdb_backup_engine_info_destroy(bei);
|
||
|
|
||
|
rocksdb_delete(db, woptions, cstrp!("foo"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_close(db);
|
||
|
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
let restore_options = rocksdb_restore_options_create();
|
||
|
rocksdb_restore_options_set_keep_log_files(restore_options, 0);
|
||
|
rocksdb_backup_engine_restore_db_from_latest_backup(be, dbname, dbname, restore_options, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_restore_options_destroy(restore_options);
|
||
|
|
||
|
rocksdb_options_set_error_if_exists(options, 0);
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_options_set_error_if_exists(options, 1);
|
||
|
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
|
||
|
|
||
|
rocksdb_backup_engine_close(be);
|
||
|
}
|
||
|
|
||
|
StartPhase("compactall");
|
||
|
rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
|
||
|
|
||
|
StartPhase("compactrange");
|
||
|
rocksdb_compact_range(db, cstrp!("a"), 1, cstrp!("z"), 1);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
|
||
|
|
||
|
StartPhase("writebatch");
|
||
|
{
|
||
|
let mut wb = rocksdb_writebatch_create();
|
||
|
rocksdb_writebatch_put(wb, cstrp!("foo"), 3, cstrp!("a"), 1);
|
||
|
rocksdb_writebatch_clear(wb);
|
||
|
rocksdb_writebatch_put(wb, cstrp!("bar"), 3, cstrp!("b"), 1);
|
||
|
rocksdb_writebatch_put(wb, cstrp!("box"), 3, cstrp!("c"), 1);
|
||
|
rocksdb_writebatch_delete(wb, cstrp!("bar"), 3);
|
||
|
rocksdb_write(db, woptions, wb, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
|
||
|
CheckGet(db, roptions, cstrp!("bar"), ptr::null());
|
||
|
CheckGet(db, roptions, cstrp!("box"), cstrp!("c"));
|
||
|
let mut pos: c_int = 0;
|
||
|
rocksdb_writebatch_iterate(wb, mem::transmute(&mut pos), Some(CheckPut), Some(CheckDel));
|
||
|
CheckCondition!(pos == 3);
|
||
|
rocksdb_writebatch_destroy(wb);
|
||
|
}
|
||
|
|
||
|
StartPhase("writebatch_vectors");
|
||
|
{
|
||
|
let wb = rocksdb_writebatch_create();
|
||
|
let k_list: [*const c_char; 2] = [cstrp!("z"), cstrp!("ap")];
|
||
|
let k_sizes: [size_t; 2] = [1, 2];
|
||
|
let v_list: [*const c_char; 3] = [cstrp!("x"), cstrp!("y"), cstrp!("z")];
|
||
|
let v_sizes: [size_t; 3] = [1, 1, 1];
|
||
|
rocksdb_writebatch_putv(wb, k_list.len() as c_int, k_list.as_ptr(), k_sizes.as_ptr(), v_list.len() as c_int, v_list.as_ptr(), v_sizes.as_ptr());
|
||
|
rocksdb_write(db, woptions, wb, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("zap"), cstrp!("xyz"));
|
||
|
rocksdb_writebatch_delete(wb, cstrp!("zap"), 3);
|
||
|
rocksdb_write(db, woptions, wb, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("zap"), ptr::null());
|
||
|
rocksdb_writebatch_destroy(wb);
|
||
|
}
|
||
|
|
||
|
StartPhase("writebatch_rep");
|
||
|
{
|
||
|
let wb1: *mut rocksdb_writebatch_t = rocksdb_writebatch_create();
|
||
|
rocksdb_writebatch_put(wb1, cstrp!("baz"), 3, cstrp!("d"), 1);
|
||
|
rocksdb_writebatch_put(wb1, cstrp!("quux"), 4, cstrp!("e"), 1);
|
||
|
rocksdb_writebatch_delete(wb1, cstrp!("quux"), 4);
|
||
|
let mut repsize1: size_t = 0;
|
||
|
let mut rep = rocksdb_writebatch_data(wb1, &mut repsize1) as *const c_void;
|
||
|
let mut wb2 = rocksdb_writebatch_create_from(rep as *const c_char, repsize1);
|
||
|
CheckCondition!(rocksdb_writebatch_count(wb1) == rocksdb_writebatch_count(wb2));
|
||
|
let mut repsize2: size_t = 0;
|
||
|
CheckCondition!(memcmp(rep, rocksdb_writebatch_data(wb2, &mut repsize2) as *const c_void, repsize1) == 0);
|
||
|
rocksdb_writebatch_destroy(wb1);
|
||
|
rocksdb_writebatch_destroy(wb2);
|
||
|
}
|
||
|
|
||
|
StartPhase("iter");
|
||
|
{
|
||
|
let mut iter = rocksdb_create_iterator(db, roptions);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
rocksdb_iter_seek_to_first(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
CheckIter(iter, cstrp!("box"), cstrp!("c"));
|
||
|
rocksdb_iter_next(iter);
|
||
|
CheckIter(iter, cstrp!("foo"), cstrp!("hello"));
|
||
|
rocksdb_iter_prev(iter);
|
||
|
CheckIter(iter, cstrp!("box"), cstrp!("c"));
|
||
|
rocksdb_iter_prev(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
rocksdb_iter_seek_to_last(iter);
|
||
|
CheckIter(iter, cstrp!("foo"), cstrp!("hello"));
|
||
|
rocksdb_iter_seek(iter, cstrp!("b"), 1);
|
||
|
CheckIter(iter, cstrp!("box"), cstrp!("c"));
|
||
|
rocksdb_iter_get_error(iter, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_iter_destroy(iter);
|
||
|
}
|
||
|
|
||
|
StartPhase("multiget");
|
||
|
{
|
||
|
let keys: [*const c_char; 3] = [cstrp!("box"), cstrp!("foo"), cstrp!("notfound")];
|
||
|
let keys_sizes: [size_t; 3] = [3, 3, 8];
|
||
|
let mut vals: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
|
||
|
let mut vals_sizes: [size_t; 3] = [0, 0, 0];
|
||
|
let mut errs: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
|
||
|
rocksdb_multi_get(db, roptions, 3, keys.as_ptr(), keys_sizes.as_ptr(), vals.as_mut_ptr(), vals_sizes.as_mut_ptr(), errs.as_mut_ptr());
|
||
|
|
||
|
for i in 0..3 {
|
||
|
CheckEqual(ptr::null(), errs[i], 0);
|
||
|
match i {
|
||
|
0 => CheckEqual(cstrp!("c"), vals[i], vals_sizes[i]),
|
||
|
1 => CheckEqual(cstrp!("hello"), vals[i], vals_sizes[i]),
|
||
|
2 => CheckEqual(ptr::null(), vals[i], vals_sizes[i]),
|
||
|
_ => { },
|
||
|
}
|
||
|
Free(&mut vals[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StartPhase("approximate_sizes");
|
||
|
{
|
||
|
let mut sizes: [uint64_t; 2] = [0, 0];
|
||
|
let start: [*const c_char; 2] = [cstrp!("a"), cstrp!("k00000000000000010000")];
|
||
|
let start_len: [size_t; 2] = [1, 21];
|
||
|
let limit: [*const c_char; 2] = [cstrp!("k00000000000000010000"), cstrp!("z")];
|
||
|
let limit_len: [size_t; 2] = [21, 1];
|
||
|
rocksdb_writeoptions_set_sync(woptions, 0);
|
||
|
for i in 0 .. 20000 {
|
||
|
let keybuf = CString::new(format!("k{:020}", i)).unwrap();
|
||
|
let key = keybuf.to_bytes_with_nul();
|
||
|
let valbuf = CString::new(format!("v{:020}", i)).unwrap();
|
||
|
let val = valbuf.to_bytes_with_nul();
|
||
|
rocksdb_put(db, woptions, key.as_ptr() as *const c_char, key.len() as size_t, val.as_ptr() as *const c_char, val.len() as size_t, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
}
|
||
|
rocksdb_approximate_sizes(db, 2, start.as_ptr(), start_len.as_ptr(), limit.as_ptr(), limit_len.as_ptr(), sizes.as_mut_ptr());
|
||
|
CheckCondition!(sizes[0] > 0);
|
||
|
CheckCondition!(sizes[1] > 0);
|
||
|
}
|
||
|
|
||
|
StartPhase("property");
|
||
|
{
|
||
|
let mut prop: *mut c_char;
|
||
|
prop = rocksdb_property_value(db, cstrp!("nosuchprop"));
|
||
|
CheckCondition!(prop.is_null());
|
||
|
prop = rocksdb_property_value(db, cstrp!("rocksdb.stats"));
|
||
|
CheckCondition!(!prop.is_null());
|
||
|
Free(&mut prop);
|
||
|
}
|
||
|
|
||
|
StartPhase("snapshot");
|
||
|
{
|
||
|
let snap: *const rocksdb_snapshot_t = rocksdb_create_snapshot(db);
|
||
|
rocksdb_delete(db, woptions, cstrp!("foo"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_readoptions_set_snapshot(roptions, snap);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("hello"));
|
||
|
rocksdb_readoptions_set_snapshot(roptions, ptr::null());
|
||
|
CheckGet(db, roptions, cstrp!("foo"), ptr::null());
|
||
|
rocksdb_release_snapshot(db, snap);
|
||
|
}
|
||
|
|
||
|
StartPhase("repair");
|
||
|
{
|
||
|
// If we do not compact here, then the lazy deletion of files (https://reviews.facebook.net/D6123) would leave around deleted files and the repair process will find those files and put them back into the database.
|
||
|
rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_options_set_create_if_missing(options, 0);
|
||
|
rocksdb_options_set_error_if_exists(options, 0);
|
||
|
// rocksdb_options_set_wal_recovery_mode(options, 2);
|
||
|
rocksdb_repair_db(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), ptr::null());
|
||
|
CheckGet(db, roptions, cstrp!("bar"), ptr::null());
|
||
|
CheckGet(db, roptions, cstrp!("box"), cstrp!("c"));
|
||
|
rocksdb_options_set_create_if_missing(options, 1);
|
||
|
rocksdb_options_set_error_if_exists(options, 1);
|
||
|
}
|
||
|
|
||
|
StartPhase("filter");
|
||
|
for run in 0 .. 2 {
|
||
|
// First run uses custom filter, second run uses bloom filter
|
||
|
CheckNoError!(err);
|
||
|
let mut policy: *mut rocksdb_filterpolicy_t = if run == 0 {
|
||
|
rocksdb_filterpolicy_create(ptr::null_mut(), Some(FilterDestroy), Some(FilterCreate), Some(FilterKeyMatch), None, Some(FilterName))
|
||
|
} else {
|
||
|
rocksdb_filterpolicy_create_bloom(10)
|
||
|
};
|
||
|
|
||
|
rocksdb_block_based_options_set_filter_policy(table_options, policy);
|
||
|
|
||
|
// Create new database
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
rocksdb_options_set_block_based_table_factory(options, table_options);
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("foo"), 3, cstrp!("foovalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("bar"), 3, cstrp!("barvalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_compact_range(db, ptr::null(), 0, ptr::null(), 0);
|
||
|
|
||
|
fake_filter_result = 1;
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
|
||
|
CheckGet(db, roptions, cstrp!("bar"), cstrp!("barvalue"));
|
||
|
if phase == "" {
|
||
|
// Must not find value when custom filter returns false
|
||
|
fake_filter_result = 0;
|
||
|
CheckGet(db, roptions, cstrp!("foo"), ptr::null());
|
||
|
CheckGet(db, roptions, cstrp!("bar"), ptr::null());
|
||
|
fake_filter_result = 1;
|
||
|
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
|
||
|
CheckGet(db, roptions, cstrp!("bar"), cstrp!("barvalue"));
|
||
|
}
|
||
|
// Reset the policy
|
||
|
rocksdb_block_based_options_set_filter_policy(table_options, ptr::null_mut());
|
||
|
rocksdb_options_set_block_based_table_factory(options, table_options);
|
||
|
}
|
||
|
|
||
|
StartPhase("compaction_filter");
|
||
|
{
|
||
|
let options_with_filter = rocksdb_options_create();
|
||
|
rocksdb_options_set_create_if_missing(options_with_filter, 1);
|
||
|
let cfilter = rocksdb_compactionfilter_create(ptr::null_mut(), Some(CFilterDestroy), Some(CFilterFilter), Some(CFilterName));
|
||
|
// Create new database
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options_with_filter, dbname, &mut err);
|
||
|
rocksdb_options_set_compaction_filter(options_with_filter, cfilter);
|
||
|
db = CheckCompaction(dbname, db, options_with_filter, roptions, woptions);
|
||
|
|
||
|
rocksdb_options_set_compaction_filter(options_with_filter, ptr::null_mut());
|
||
|
rocksdb_compactionfilter_destroy(cfilter);
|
||
|
rocksdb_options_destroy(options_with_filter);
|
||
|
}
|
||
|
|
||
|
StartPhase("compaction_filter_factory");
|
||
|
{
|
||
|
let mut options_with_filter_factory = rocksdb_options_create();
|
||
|
rocksdb_options_set_create_if_missing(options_with_filter_factory, 1);
|
||
|
let mut factory = rocksdb_compactionfilterfactory_create(ptr::null_mut(), Some(CFilterFactoryDestroy), Some(CFilterCreate), Some(CFilterFactoryName));
|
||
|
// Create new database
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options_with_filter_factory, dbname, &mut err);
|
||
|
rocksdb_options_set_compaction_filter_factory(options_with_filter_factory, factory);
|
||
|
db = CheckCompaction(dbname, db, options_with_filter_factory, roptions, woptions);
|
||
|
|
||
|
rocksdb_options_set_compaction_filter_factory(options_with_filter_factory, ptr::null_mut());
|
||
|
rocksdb_options_destroy(options_with_filter_factory);
|
||
|
}
|
||
|
|
||
|
StartPhase("merge_operator");
|
||
|
{
|
||
|
let mut merge_operator = rocksdb_mergeoperator_create(ptr::null_mut(), Some(MergeOperatorDestroy), Some(MergeOperatorFullMerge), Some(MergeOperatorPartialMerge), None, Some(MergeOperatorName));
|
||
|
// Create new database
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
rocksdb_options_set_merge_operator(options, merge_operator);
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("foo"), 3, cstrp!("foovalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("foovalue"));
|
||
|
rocksdb_merge(db, woptions, cstrp!("foo"), 3, cstrp!("barvalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("foo"), cstrp!("fake"));
|
||
|
|
||
|
// Merge of a non-existing value
|
||
|
rocksdb_merge(db, woptions, cstrp!("bar"), 3, cstrp!("barvalue"), 8, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGet(db, roptions, cstrp!("bar"), cstrp!("fake"));
|
||
|
}
|
||
|
|
||
|
StartPhase("columnfamilies");
|
||
|
{
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
let mut db_options = rocksdb_options_create();
|
||
|
rocksdb_options_set_create_if_missing(db_options, 1);
|
||
|
db = rocksdb_open(db_options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
let mut cfh = rocksdb_create_column_family(db, db_options, cstrp!("cf1"), & mut err);
|
||
|
rocksdb_column_family_handle_destroy(cfh);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_close(db);
|
||
|
|
||
|
let mut cflen: size_t = 0;
|
||
|
let column_fams_raw = rocksdb_list_column_families(db_options, dbname, &mut cflen, &mut err);
|
||
|
let column_fams = slice::from_raw_parts(column_fams_raw, cflen as usize);
|
||
|
CheckEqual(cstrp!("default"), column_fams[0], 7);
|
||
|
CheckEqual(cstrp!("cf1"), column_fams[1], 3);
|
||
|
CheckCondition!(cflen == 2);
|
||
|
rocksdb_list_column_families_destroy(column_fams_raw, cflen);
|
||
|
|
||
|
let mut cf_options = rocksdb_options_create();
|
||
|
|
||
|
let cf_names: [*const c_char; 2] = [cstrp!("default"), cstrp!("cf1")];
|
||
|
let cf_opts: [*const rocksdb_options_t; 2] = [cf_options, cf_options];
|
||
|
let mut handles: [*mut rocksdb_column_family_handle_t; 2] = [ptr::null_mut(), ptr::null_mut()];
|
||
|
db = rocksdb_open_column_families(db_options, dbname, 2, cf_names.as_ptr(), cf_opts.as_ptr(), handles.as_mut_ptr(), &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_put_cf(db, woptions, handles[1], cstrp!("foo"), 3, cstrp!("hello"), 5, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
CheckGetCF(db, roptions, handles[1], cstrp!("foo"), cstrp!("hello"));
|
||
|
|
||
|
rocksdb_delete_cf(db, woptions, handles[1], cstrp!("foo"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
CheckGetCF(db, roptions, handles[1], cstrp!("foo"), ptr::null());
|
||
|
|
||
|
let mut wb = rocksdb_writebatch_create();
|
||
|
rocksdb_writebatch_put_cf(wb, handles[1], cstrp!("baz"), 3, cstrp!("a"), 1);
|
||
|
rocksdb_writebatch_clear(wb);
|
||
|
rocksdb_writebatch_put_cf(wb, handles[1], cstrp!("bar"), 3, cstrp!("b"), 1);
|
||
|
rocksdb_writebatch_put_cf(wb, handles[1], cstrp!("box"), 3, cstrp!("c"), 1);
|
||
|
rocksdb_writebatch_delete_cf(wb, handles[1], cstrp!("bar"), 3);
|
||
|
rocksdb_write(db, woptions, wb, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckGetCF(db, roptions, handles[1], cstrp!("baz"), ptr::null());
|
||
|
CheckGetCF(db, roptions, handles[1], cstrp!("bar"), ptr::null());
|
||
|
CheckGetCF(db, roptions, handles[1], cstrp!("box"), cstrp!("c"));
|
||
|
rocksdb_writebatch_destroy(wb);
|
||
|
|
||
|
let keys: [*const c_char; 3] = [cstrp!("box"), cstrp!("box"), cstrp!("barfooxx")];
|
||
|
let get_handles: [*const rocksdb_column_family_handle_t; 3] = [handles[0], handles[1], handles[1]];
|
||
|
let keys_sizes: [size_t; 3] = [3, 3, 8];
|
||
|
let mut vals: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
|
||
|
let mut vals_sizes: [size_t; 3] = [0, 0, 0];
|
||
|
let mut errs: [*mut c_char; 3] = [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()];
|
||
|
rocksdb_multi_get_cf(db, roptions, get_handles.as_ptr(), 3, keys.as_ptr(), keys_sizes.as_ptr(), vals.as_mut_ptr(), vals_sizes.as_mut_ptr(), errs.as_mut_ptr());
|
||
|
|
||
|
for i in 0 .. 3 {
|
||
|
CheckEqual(ptr::null(), errs[i], 0);
|
||
|
match i {
|
||
|
0 => CheckEqual(ptr::null(), vals[i], vals_sizes[i]), // wrong cf
|
||
|
1 => CheckEqual(cstrp!("c"), vals[i], vals_sizes[i]), // bingo
|
||
|
2 => CheckEqual(ptr::null(), vals[i], vals_sizes[i]), // normal not found
|
||
|
_ => { },
|
||
|
}
|
||
|
Free(&mut vals[i]);
|
||
|
}
|
||
|
|
||
|
let mut iter = rocksdb_create_iterator_cf(db, roptions, handles[1]);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
rocksdb_iter_seek_to_first(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
|
||
|
let mut i: u32 = 0;
|
||
|
while rocksdb_iter_valid(iter) != 0 {
|
||
|
rocksdb_iter_next(iter);
|
||
|
i += 1;
|
||
|
}
|
||
|
CheckCondition!(i == 1);
|
||
|
rocksdb_iter_get_error(iter, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_iter_destroy(iter);
|
||
|
|
||
|
let mut iters_cf_handles: [*mut rocksdb_column_family_handle_t; 2] = [handles[0], handles[1]];
|
||
|
let mut iters_handles: [*mut rocksdb_iterator_t; 2] = [ptr::null_mut(), ptr::null_mut()];
|
||
|
rocksdb_create_iterators(db, roptions, iters_cf_handles.as_mut_ptr(), iters_handles.as_mut_ptr(), 2, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
iter = iters_handles[0];
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
rocksdb_iter_seek_to_first(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
rocksdb_iter_destroy(iter);
|
||
|
|
||
|
iter = iters_handles[1];
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
rocksdb_iter_seek_to_first(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
|
||
|
let mut i: u32 = 0;
|
||
|
while rocksdb_iter_valid(iter) != 0 {
|
||
|
rocksdb_iter_next(iter);
|
||
|
i += 1;
|
||
|
}
|
||
|
CheckCondition!(i == 1);
|
||
|
rocksdb_iter_get_error(iter, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_iter_destroy(iter);
|
||
|
|
||
|
rocksdb_drop_column_family(db, handles[1], &mut err);
|
||
|
CheckNoError!(err);
|
||
|
for i in 0..2 {
|
||
|
rocksdb_column_family_handle_destroy(handles[i]);
|
||
|
}
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
rocksdb_options_destroy(db_options);
|
||
|
rocksdb_options_destroy(cf_options);
|
||
|
}
|
||
|
|
||
|
StartPhase("prefix");
|
||
|
{
|
||
|
// Create new database
|
||
|
rocksdb_options_set_allow_mmap_reads(options, 1);
|
||
|
rocksdb_options_set_prefix_extractor(options, rocksdb_slicetransform_create_fixed_prefix(3));
|
||
|
rocksdb_options_set_hash_skip_list_rep(options, 5000, 4, 4);
|
||
|
rocksdb_options_set_plain_table_factory(options, 4, 10, 0.75, 16);
|
||
|
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_put(db, woptions, cstrp!("foo1"), 4, cstrp!("foo"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("foo2"), 4, cstrp!("foo"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("foo3"), 4, cstrp!("foo"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("bar1"), 4, cstrp!("bar"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("bar2"), 4, cstrp!("bar"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("bar3"), 4, cstrp!("bar"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
let mut iter = rocksdb_create_iterator(db, roptions);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
|
||
|
rocksdb_iter_seek(iter, cstrp!("bar"), 3);
|
||
|
rocksdb_iter_get_error(iter, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
|
||
|
CheckIter(iter, cstrp!("bar1"), cstrp!("bar"));
|
||
|
rocksdb_iter_next(iter);
|
||
|
CheckIter(iter, cstrp!("bar2"), cstrp!("bar"));
|
||
|
rocksdb_iter_next(iter);
|
||
|
CheckIter(iter, cstrp!("bar3"), cstrp!("bar"));
|
||
|
rocksdb_iter_get_error(iter, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_iter_destroy(iter);
|
||
|
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
}
|
||
|
|
||
|
StartPhase("cuckoo_options");
|
||
|
{
|
||
|
let mut cuckoo_options = rocksdb_cuckoo_options_create();
|
||
|
rocksdb_cuckoo_options_set_hash_ratio(cuckoo_options, 0.5);
|
||
|
rocksdb_cuckoo_options_set_max_search_depth(cuckoo_options, 200);
|
||
|
rocksdb_cuckoo_options_set_cuckoo_block_size(cuckoo_options, 10);
|
||
|
rocksdb_cuckoo_options_set_identity_as_first_hash(cuckoo_options, 1);
|
||
|
rocksdb_cuckoo_options_set_use_module_hash(cuckoo_options, 0);
|
||
|
rocksdb_options_set_cuckoo_table_factory(options, cuckoo_options);
|
||
|
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_cuckoo_options_destroy(cuckoo_options);
|
||
|
}
|
||
|
|
||
|
StartPhase("iterate_upper_bound");
|
||
|
{
|
||
|
// Create new empty database
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_options_set_prefix_extractor(options, ptr::null_mut());
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_put(db, woptions, cstrp!("a"), 1, cstrp!("0"), 1, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("foo"), 3, cstrp!("bar"), 3, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("foo1"), 4, cstrp!("bar1"), 4, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
rocksdb_put(db, woptions, cstrp!("g1"), 2, cstrp!("0"), 1, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
// testing basic case with no iterate_upper_bound and no prefix_extractor
|
||
|
{
|
||
|
rocksdb_readoptions_set_iterate_upper_bound(roptions, ptr::null(), 0);
|
||
|
let mut iter = rocksdb_create_iterator(db, roptions);
|
||
|
|
||
|
rocksdb_iter_seek(iter, cstrp!("foo"), 3);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
CheckIter(iter, cstrp!("foo"), cstrp!("bar"));
|
||
|
|
||
|
rocksdb_iter_next(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
CheckIter(iter, cstrp!("foo1"), cstrp!("bar1"));
|
||
|
|
||
|
rocksdb_iter_next(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
CheckIter(iter, cstrp!("g1"), cstrp!("0"));
|
||
|
|
||
|
rocksdb_iter_destroy(iter);
|
||
|
}
|
||
|
|
||
|
// testing iterate_upper_bound and forward iterator
|
||
|
// to make sure it stops at bound
|
||
|
{
|
||
|
// iterate_upper_bound points beyond the last expected entry
|
||
|
rocksdb_readoptions_set_iterate_upper_bound(roptions, cstrp!("foo2"), 4);
|
||
|
|
||
|
let mut iter = rocksdb_create_iterator(db, roptions);
|
||
|
|
||
|
rocksdb_iter_seek(iter, cstrp!("foo"), 3);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
CheckIter(iter, cstrp!("foo"), cstrp!("bar"));
|
||
|
|
||
|
rocksdb_iter_next(iter);
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) != 0);
|
||
|
CheckIter(iter, cstrp!("foo1"), cstrp!("bar1"));
|
||
|
|
||
|
rocksdb_iter_next(iter);
|
||
|
// should stop here...
|
||
|
CheckCondition!(rocksdb_iter_valid(iter) == 0);
|
||
|
|
||
|
rocksdb_iter_destroy(iter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Simple sanity check that setting memtable rep works.
|
||
|
StartPhase("memtable_reps");
|
||
|
{
|
||
|
// Create database with vector memtable.
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
rocksdb_options_set_memtable_vector_rep(options);
|
||
|
db = rocksdb_open(options, dbname, &mut err);
|
||
|
CheckNoError!(err);
|
||
|
|
||
|
// // Create database with hash skiplist memtable.
|
||
|
// rocksdb_close(db);
|
||
|
// rocksdb_destroy_db(options, dbname, &mut err);
|
||
|
// CheckNoError!(err);
|
||
|
//
|
||
|
// rocksdb_options_set_hash_skip_list_rep(options, 5000, 4, 4);
|
||
|
// db = rocksdb_open(options, dbname, &mut err);
|
||
|
// CheckNoError!(err);
|
||
|
}
|
||
|
|
||
|
StartPhase("cleanup");
|
||
|
rocksdb_close(db);
|
||
|
rocksdb_options_destroy(options);
|
||
|
rocksdb_block_based_options_destroy(table_options);
|
||
|
rocksdb_readoptions_destroy(roptions);
|
||
|
rocksdb_writeoptions_destroy(woptions);
|
||
|
rocksdb_cache_destroy(cache);
|
||
|
rocksdb_comparator_destroy(cmp);
|
||
|
rocksdb_env_destroy(env);
|
||
|
|
||
|
err_println!("PASS");
|
||
|
}
|
||
|
}
|