// Copyright 2016 Alex Regueiro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This code is based on , 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 emerald_librocksdb_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(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 } // I comment it because geteuid() does not work on Windows // // #[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 as i32); // 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 mut cf_names: [*const c_char; 2] = [cstrp!("default"), cstrp!("cf1")]; // let mut 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_mut_ptr(), // cf_opts.as_mut_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); // rocksdb_options_set_allow_concurrent_memtable_write(options, 0); // 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"); // } // }