From ffefbd0907deff260bb62178095067e18d73ef42 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 5 Nov 2016 15:39:46 +0000 Subject: [PATCH] Performed lots of clean-up on code. --- Cargo.toml | 16 +- rocksdb-sys/Cargo.toml | 4 + rocksdb-sys/build.rs | 3 + rocksdb-sys/src/ffi.rs | 500 --------------------- rocksdb-sys/src/lib.rs | 691 +++++++++++++++++++++++++++- rocksdb-sys/src/test.rs | 86 ++++ rocksdb-sys/tests/ffi.rs | 950 +++++++++++++++++++++++++++++++++++++++ src/comparator.rs | 41 +- src/lib.rs | 31 +- src/merge_operator.rs | 133 ++---- src/rocksdb.rs | 560 +++++++---------------- src/rocksdb_options.rs | 233 ++++------ 12 files changed, 2068 insertions(+), 1180 deletions(-) delete mode 100644 rocksdb-sys/src/ffi.rs create mode 100644 rocksdb-sys/src/test.rs create mode 100644 rocksdb-sys/tests/ffi.rs diff --git a/Cargo.toml b/Cargo.toml index 08dca65..74958f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,25 +1,23 @@ [package] - name = "rocksdb" -description = "A Rust wrapper for Facebook's RocksDB embeddable database." +description = "Rust wrapper for Facebook's RocksDB embeddable database" version = "0.4.1" authors = ["Tyler Neely ", "David Greenberg "] license = "Apache-2.0" keywords = ["database", "embedded", "LSM-tree", "persistence"] homepage = "https://github.com/spacejam/rust-rocksdb" exclude = [ - ".gitignore", - ".travis.yml", - "deploy.sh", - "test/**/*", + ".gitignore", + ".travis.yml", + "deploy.sh", + "test/**/*", ] [features] -default=[] -valgrind=[] +default = [] +valgrind = [] [[test]] - name = "test" path = "test/test.rs" diff --git a/rocksdb-sys/Cargo.toml b/rocksdb-sys/Cargo.toml index 0089dec..dcceeec 100644 --- a/rocksdb-sys/Cargo.toml +++ b/rocksdb-sys/Cargo.toml @@ -18,5 +18,9 @@ static = [] [dependencies] libc = "0.2" +[dev-dependencies] +const-cstr = "0.2" + [build-dependencies] gcc = { version = "0.3", features = ["parallel"] } +make-cmd = "0.1" diff --git a/rocksdb-sys/build.rs b/rocksdb-sys/build.rs index 410a5ed..7592b2a 100644 --- a/rocksdb-sys/build.rs +++ b/rocksdb-sys/build.rs @@ -14,6 +14,9 @@ fn link(name: &str, bundled: bool) { } fn build_rocksdb() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=rocksdb/"); + let mut config = gcc::Config::new(); config.include("rocksdb/include/"); config.include("rocksdb/"); diff --git a/rocksdb-sys/src/ffi.rs b/rocksdb-sys/src/ffi.rs deleted file mode 100644 index 0b26da6..0000000 --- a/rocksdb-sys/src/ffi.rs +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright 2014 Tyler Neely -// -// 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. -// -extern crate libc; -use self::libc::{c_char, c_uchar, c_int, c_void, size_t}; -use std::ffi::CStr; -use std::str::from_utf8; - -pub enum DBOptionsOpaque {} -pub type DBOptions = *const DBOptionsOpaque; - -pub enum DBInstanceOpaque {} -pub type DBInstance = *const DBInstanceOpaque; - -pub enum DBWriteOptionsOpaque {} -pub type DBWriteOptions = *const DBWriteOptionsOpaque; - -pub enum DBReadOptionsOpaque {} -pub type DBReadOptions = *const DBReadOptionsOpaque; - -pub enum DBMergeOperatorOpaque {} -pub type DBMergeOperator = *const DBMergeOperatorOpaque; - -pub enum DBBlockBasedTableOptionsOpaque {} -pub type DBBlockBasedTableOptions = *const DBBlockBasedTableOptionsOpaque; - -pub enum DBCacheOpaque {} -pub type DBCache = *const DBCacheOpaque; - -pub enum DBFilterPolicyOpaque {} -pub type DBFilterPolicy = *const DBFilterPolicyOpaque; - -pub enum DBSnapshotOpaque {} -pub type DBSnapshot = *const DBSnapshotOpaque; - -pub enum DBIteratorOpaque {} -pub type DBIterator = *const DBIteratorOpaque; - -pub enum DBCFHandleOpaque {} -pub type DBCFHandle = *const DBCFHandleOpaque; - -pub enum DBWriteBatchOpaque {} -pub type DBWriteBatch = *const DBWriteBatchOpaque; - -pub enum DBComparatorOpaque {} -pub type DBComparator = *const DBComparatorOpaque; - -pub enum DBSliceTransformOpaque {} -pub type DBSliceTransform = *const DBSliceTransformOpaque; - -pub const BLOCK_BASED_INDEX_TYPE_BINARY_SEARCH: c_int = 0; -pub const BLOCK_BASED_INDEX_TYPE_HASH_SEARCH: c_int = 1; - -pub fn new_bloom_filter(bits: c_int) -> DBFilterPolicy { - unsafe { rocksdb_filterpolicy_create_bloom(bits) } -} - -pub fn new_cache(capacity: size_t) -> DBCache { - unsafe { rocksdb_cache_create_lru(capacity) } -} - -#[derive(Copy, Clone)] -#[repr(C)] -pub enum DBCompressionType { - None = 0, - Snappy = 1, - Zlib = 2, - Bz2 = 3, - Lz4 = 4, - Lz4hc = 5, -} - -#[repr(C)] -pub enum DBCompactionStyle { - Level = 0, - Universal = 1, - Fifo = 2, -} - -#[repr(C)] -pub enum DBUniversalCompactionStyle { - rocksdb_similar_size_compaction_stop_style = 0, - rocksdb_total_size_compaction_stop_style = 1, -} - -#[derive(Copy, Clone, PartialEq)] -#[repr(C)] -pub enum DBRecoveryMode { - TolerateCorruptedTailRecords = 0, - AbsoluteConsistency = 1, - PointInTime = 2, - SkipAnyCorruptedRecords = 3, -} - -pub fn error_message(ptr: *const i8) -> String { - let c_str = unsafe { CStr::from_ptr(ptr as *const _) }; - let s = from_utf8(c_str.to_bytes()).unwrap().to_owned(); - unsafe { - libc::free(ptr as *mut libc::c_void); - } - s -} - -// TODO audit the use of boolean arguments, b/c I think they need to be u8 -// instead... -#[link(name = "rocksdb")] -extern "C" { - pub fn rocksdb_options_create() -> DBOptions; - pub fn rocksdb_options_destroy(opts: DBOptions); - pub fn rocksdb_cache_create_lru(capacity: size_t) -> DBCache; - pub fn rocksdb_cache_destroy(cache: DBCache); - pub fn rocksdb_block_based_options_create() -> DBBlockBasedTableOptions; - pub fn rocksdb_block_based_options_destroy(opts: DBBlockBasedTableOptions); - pub fn rocksdb_block_based_options_set_block_size( - block_options: DBBlockBasedTableOptions, - block_size: size_t); - pub fn rocksdb_block_based_options_set_block_size_deviation( - block_options: DBBlockBasedTableOptions, - block_size_deviation: c_int); - pub fn rocksdb_block_based_options_set_block_restart_interval( - block_options: DBBlockBasedTableOptions, - block_restart_interval: c_int); - pub fn rocksdb_block_based_options_set_cache_index_and_filter_blocks( - block_options: DBBlockBasedTableOptions, v: c_uchar); - pub fn rocksdb_block_based_options_set_filter_policy( - block_options: DBBlockBasedTableOptions, - filter_policy: DBFilterPolicy); - pub fn rocksdb_block_based_options_set_no_block_cache( - block_options: DBBlockBasedTableOptions, no_block_cache: bool); - pub fn rocksdb_block_based_options_set_block_cache( - block_options: DBBlockBasedTableOptions, block_cache: DBCache); - pub fn rocksdb_block_based_options_set_block_cache_compressed( - block_options: DBBlockBasedTableOptions, - block_cache_compressed: DBCache); - pub fn rocksdb_block_based_options_set_whole_key_filtering( - ck_options: DBBlockBasedTableOptions, doit: bool); - pub fn rocksdb_options_set_block_based_table_factory( - options: DBOptions, - block_options: DBBlockBasedTableOptions); - pub fn rocksdb_options_increase_parallelism(options: DBOptions, - threads: c_int); - pub fn rocksdb_options_optimize_level_style_compaction( - options: DBOptions, memtable_memory_budget: c_int); - pub fn rocksdb_options_set_create_if_missing(options: DBOptions, v: bool); - pub fn rocksdb_options_set_max_open_files(options: DBOptions, - files: c_int); - pub fn rocksdb_options_set_use_fsync(options: DBOptions, v: c_int); - pub fn rocksdb_options_set_bytes_per_sync(options: DBOptions, bytes: u64); - pub fn rocksdb_options_set_disable_data_sync(options: DBOptions, - v: c_int); - pub fn rocksdb_options_set_allow_os_buffer(options: DBOptions, is_allow: bool); - pub fn rocksdb_options_optimize_for_point_lookup(options: DBOptions, - block_cache_size_mb: u64); - pub fn rocksdb_options_set_table_cache_numshardbits(options: DBOptions, - bits: c_int); - pub fn rocksdb_options_set_max_write_buffer_number(options: DBOptions, - bufno: c_int); - pub fn rocksdb_options_set_min_write_buffer_number_to_merge( - options: DBOptions, bufno: c_int); - pub fn rocksdb_options_set_level0_file_num_compaction_trigger( - options: DBOptions, no: c_int); - pub fn rocksdb_options_set_level0_slowdown_writes_trigger( - options: DBOptions, no: c_int); - pub fn rocksdb_options_set_level0_stop_writes_trigger(options: DBOptions, - no: c_int); - pub fn rocksdb_options_set_write_buffer_size(options: DBOptions, - bytes: usize); - pub fn rocksdb_options_set_target_file_size_base(options: DBOptions, - bytes: u64); - pub fn rocksdb_options_set_target_file_size_multiplier(options: DBOptions, - mul: c_int); - pub fn rocksdb_options_set_max_bytes_for_level_base(options: DBOptions, bytes: u64); - pub fn rocksdb_options_set_max_bytes_for_level_multiplier(options: DBOptions, mul: c_int); - pub fn rocksdb_options_set_max_log_file_size(options: DBOptions, - bytes: usize); - pub fn rocksdb_options_set_max_manifest_file_size(options: DBOptions, - bytes: usize); - pub fn rocksdb_options_set_hash_skip_list_rep(options: DBOptions, - bytes: usize, - a1: i32, - a2: i32); - pub fn rocksdb_options_set_compaction_style(options: DBOptions, - cs: DBCompactionStyle); - pub fn rocksdb_options_set_compression(options: DBOptions, - compression_style_no: DBCompressionType); - pub fn rocksdb_options_set_compression_per_level(options: DBOptions, - level_values: *const DBCompressionType, - num_levels: size_t); - pub fn rocksdb_options_set_max_background_compactions( - options: DBOptions, max_bg_compactions: c_int); - pub fn rocksdb_options_set_max_background_flushes(options: DBOptions, - max_bg_flushes: c_int); - pub fn rocksdb_options_set_disable_auto_compactions(options: DBOptions, - v: c_int); - pub fn rocksdb_options_set_report_bg_io_stats(options: DBOptions, v: c_int); - pub fn rocksdb_options_set_wal_recovery_mode(options: DBOptions, mode: DBRecoveryMode); - pub fn rocksdb_options_enable_statistics(options: DBOptions); - pub fn rocksdb_options_statistics_get_string(options: DBOptions) -> *const c_char; - pub fn rocksdb_options_set_stats_dump_period_sec(options: DBOptions, v: usize); - pub fn rocksdb_options_set_num_levels(options: DBOptions, v: c_int); - pub fn rocksdb_filterpolicy_create_bloom_full(bits_per_key: c_int) - -> DBFilterPolicy; - pub fn rocksdb_filterpolicy_create_bloom(bits_per_key: c_int) - -> DBFilterPolicy; - pub fn rocksdb_open(options: DBOptions, - path: *const i8, - err: *mut *const i8) - -> DBInstance; - pub fn rocksdb_writeoptions_create() -> DBWriteOptions; - pub fn rocksdb_writeoptions_destroy(writeopts: DBWriteOptions); - pub fn rocksdb_writeoptions_set_sync(writeopts: DBWriteOptions, v: bool); - pub fn rocksdb_writeoptions_disable_WAL(writeopts: DBWriteOptions, - v: c_int); - pub fn rocksdb_put(db: DBInstance, - writeopts: DBWriteOptions, - k: *const u8, - kLen: size_t, - v: *const u8, - vLen: size_t, - err: *mut *const i8); - pub fn rocksdb_put_cf(db: DBInstance, - writeopts: DBWriteOptions, - cf: DBCFHandle, - k: *const u8, - kLen: size_t, - v: *const u8, - vLen: size_t, - err: *mut *const i8); - pub fn rocksdb_readoptions_create() -> DBReadOptions; - pub fn rocksdb_readoptions_destroy(readopts: DBReadOptions); - pub fn rocksdb_readoptions_set_verify_checksums(readopts: DBReadOptions, - v: bool); - pub fn rocksdb_readoptions_set_fill_cache(readopts: DBReadOptions, - v: bool); - pub fn rocksdb_readoptions_set_snapshot(readopts: DBReadOptions, - snapshot: DBSnapshot); //TODO how do I make this a const ref? - pub fn rocksdb_readoptions_set_iterate_upper_bound(readopts: DBReadOptions, - k: *const u8, - kLen: size_t); - pub fn rocksdb_readoptions_set_read_tier(readopts: DBReadOptions, - tier: c_int); - pub fn rocksdb_readoptions_set_tailing(readopts: DBReadOptions, v: bool); - - pub fn rocksdb_get(db: DBInstance, - readopts: DBReadOptions, - k: *const u8, - kLen: size_t, - valLen: *const size_t, - err: *mut *const i8) - -> *mut c_void; - pub fn rocksdb_get_cf(db: DBInstance, - readopts: DBReadOptions, - cf_handle: DBCFHandle, - k: *const u8, - kLen: size_t, - valLen: *const size_t, - err: *mut *const i8) - -> *mut c_void; - pub fn rocksdb_create_iterator(db: DBInstance, - readopts: DBReadOptions) - -> DBIterator; - pub fn rocksdb_create_iterator_cf(db: DBInstance, - readopts: DBReadOptions, - cf_handle: DBCFHandle) - -> DBIterator; - pub fn rocksdb_create_snapshot(db: DBInstance) -> DBSnapshot; - pub fn rocksdb_release_snapshot(db: DBInstance, snapshot: DBSnapshot); - - pub fn rocksdb_delete(db: DBInstance, - writeopts: DBWriteOptions, - k: *const u8, - kLen: size_t, - err: *mut *const i8) - -> *mut c_void; - pub fn rocksdb_delete_cf(db: DBInstance, - writeopts: DBWriteOptions, - cf: DBCFHandle, - k: *const u8, - kLen: size_t, - err: *mut *const i8) - -> *mut c_void; - pub fn rocksdb_close(db: DBInstance); - pub fn rocksdb_destroy_db(options: DBOptions, - path: *const i8, - err: *mut *const i8); - pub fn rocksdb_repair_db(options: DBOptions, - path: *const i8, - err: *mut *const i8); - // Merge - pub fn rocksdb_merge(db: DBInstance, - writeopts: DBWriteOptions, - k: *const u8, - kLen: size_t, - v: *const u8, - vLen: size_t, - err: *mut *const i8); - pub fn rocksdb_merge_cf(db: DBInstance, - writeopts: DBWriteOptions, - cf: DBCFHandle, - k: *const u8, - kLen: size_t, - v: *const u8, - vLen: size_t, - err: *mut *const i8); - pub fn rocksdb_mergeoperator_create( - state: *mut c_void, - destroy: extern fn(*mut c_void) -> (), - full_merge: extern fn (arg: *mut c_void, - key: *const c_char, key_len: size_t, - existing_value: *const c_char, - existing_value_len: size_t, - operands_list: *const *const c_char, - operands_list_len: *const size_t, - num_operands: c_int, success: *mut u8, - new_value_length: *mut size_t - ) -> *const c_char, - partial_merge: extern fn(arg: *mut c_void, - key: *const c_char, key_len: size_t, - operands_list: *const *const c_char, - operands_list_len: *const size_t, - num_operands: c_int, success: *mut u8, - new_value_length: *mut size_t - ) -> *const c_char, - delete_value: Option ()>, - name_fn: extern fn(*mut c_void) -> *const c_char, - ) -> DBMergeOperator; - pub fn rocksdb_mergeoperator_destroy(mo: DBMergeOperator); - pub fn rocksdb_options_set_merge_operator(options: DBOptions, - mo: DBMergeOperator); - // Iterator - pub fn rocksdb_iter_destroy(iter: DBIterator); - pub fn rocksdb_iter_valid(iter: DBIterator) -> bool; - pub fn rocksdb_iter_seek_to_first(iter: DBIterator); - pub fn rocksdb_iter_seek_to_last(iter: DBIterator); - pub fn rocksdb_iter_seek(iter: DBIterator, key: *const u8, klen: size_t); - pub fn rocksdb_iter_next(iter: DBIterator); - pub fn rocksdb_iter_prev(iter: DBIterator); - pub fn rocksdb_iter_key(iter: DBIterator, klen: *mut size_t) -> *mut u8; - pub fn rocksdb_iter_value(iter: DBIterator, vlen: *mut size_t) -> *mut u8; - pub fn rocksdb_iter_get_error(iter: DBIterator, err: *mut *const u8); - // Write batch - pub fn rocksdb_write(db: DBInstance, - writeopts: DBWriteOptions, - batch: DBWriteBatch, - err: *mut *const i8); - pub fn rocksdb_writebatch_create() -> DBWriteBatch; - pub fn rocksdb_writebatch_create_from(rep: *const u8, - size: size_t) - -> DBWriteBatch; - pub fn rocksdb_writebatch_destroy(batch: DBWriteBatch); - pub fn rocksdb_writebatch_clear(batch: DBWriteBatch); - pub fn rocksdb_writebatch_count(batch: DBWriteBatch) -> c_int; - pub fn rocksdb_writebatch_put(batch: DBWriteBatch, - key: *const u8, - klen: size_t, - val: *const u8, - vlen: size_t); - pub fn rocksdb_writebatch_put_cf(batch: DBWriteBatch, - cf: DBCFHandle, - key: *const u8, - klen: size_t, - val: *const u8, - vlen: size_t); - pub fn rocksdb_writebatch_merge(batch: DBWriteBatch, - key: *const u8, - klen: size_t, - val: *const u8, - vlen: size_t); - pub fn rocksdb_writebatch_merge_cf(batch: DBWriteBatch, - cf: DBCFHandle, - key: *const u8, - klen: size_t, - val: *const u8, - vlen: size_t); - pub fn rocksdb_writebatch_delete(batch: DBWriteBatch, - key: *const u8, - klen: size_t); - pub fn rocksdb_writebatch_delete_cf(batch: DBWriteBatch, - cf: DBCFHandle, - key: *const u8, - klen: size_t); - pub fn rocksdb_writebatch_iterate( - batch: DBWriteBatch, - state: *mut c_void, - put_fn: extern fn(state: *mut c_void, - k: *const u8, klen: size_t, - v: *const u8, vlen: size_t), - deleted_fn: extern fn(state: *mut c_void, - k: *const u8, klen: size_t)); - pub fn rocksdb_writebatch_data(batch: DBWriteBatch, - size: *mut size_t) - -> *const u8; - - // Comparator - pub fn rocksdb_options_set_comparator(options: DBOptions, - cb: DBComparator); - pub fn rocksdb_comparator_create(state: *mut c_void, - destroy: extern "C" fn(*mut c_void) -> (), - compare: extern "C" fn(arg: *mut c_void, - a: *const c_char, - alen: size_t, - b: *const c_char, - blen: size_t) - -> c_int, - name_fn: extern "C" fn(*mut c_void) - -> *const c_char) - -> DBComparator; - pub fn rocksdb_comparator_destroy(cmp: DBComparator); - - // Column Family - pub fn rocksdb_open_column_families(options: DBOptions, - path: *const i8, - num_column_families: c_int, - column_family_names: *const *const i8, - column_family_options: *const DBOptions, - column_family_handles: *const DBCFHandle, - err: *mut *const i8 - ) -> DBInstance; - pub fn rocksdb_create_column_family(db: DBInstance, - column_family_options: DBOptions, - column_family_name: *const i8, - err: *mut *const i8) - -> DBCFHandle; - pub fn rocksdb_drop_column_family(db: DBInstance, - column_family_handle: DBCFHandle, - err: *mut *const i8); - pub fn rocksdb_column_family_handle_destroy(column_family_handle: DBCFHandle); - -} - -#[test] -fn internal() { - unsafe { - use std::ffi::CString; - let opts = rocksdb_options_create(); - assert!(!opts.is_null()); - - rocksdb_options_increase_parallelism(opts, 0); - rocksdb_options_optimize_level_style_compaction(opts, 0); - rocksdb_options_set_create_if_missing(opts, true); - - let rustpath = "_rust_rocksdb_internaltest"; - let cpath = CString::new(rustpath).unwrap(); - let cpath_ptr = cpath.as_ptr(); - - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - let db = rocksdb_open(opts, cpath_ptr as *const _, err_ptr); - if !err.is_null() { - println!("failed to open rocksdb: {}", error_message(err)); - } - assert!(err.is_null()); - - let writeopts = rocksdb_writeoptions_create(); - assert!(!writeopts.is_null()); - - let key = b"name\x00"; - let val = b"spacejam\x00"; - rocksdb_put(db, - writeopts.clone(), - key.as_ptr(), - 4, - val.as_ptr(), - 8, - err_ptr); - rocksdb_writeoptions_destroy(writeopts); - assert!(err.is_null()); - - let readopts = rocksdb_readoptions_create(); - assert!(!readopts.is_null()); - - let val_len: size_t = 0; - let val_len_ptr = &val_len as *const size_t; - rocksdb_get(db, - readopts.clone(), - key.as_ptr(), - 4, - val_len_ptr, - err_ptr); - rocksdb_readoptions_destroy(readopts); - assert!(err.is_null()); - rocksdb_close(db); - rocksdb_destroy_db(opts, cpath_ptr as *const _, err_ptr); - assert!(err.is_null()); - } -} diff --git a/rocksdb-sys/src/lib.rs b/rocksdb-sys/src/lib.rs index fee943e..d6d4bb2 100644 --- a/rocksdb-sys/src/lib.rs +++ b/rocksdb-sys/src/lib.rs @@ -1,5 +1,5 @@ // -// Copyright 2014 Tyler Neely +// Copyright 2014 Tyler Neely, 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. @@ -13,6 +13,689 @@ // See the License for the specific language governing permissions and // limitations under the License. // -pub use ffi as rocksdb_ffi; -pub use ffi::{DBCompactionStyle, DBComparator, DBCompressionType, DBRecoveryMode, new_bloom_filter}; -pub mod ffi; + +//! Raw bindings for RocksDB. +//! +//! This is simply a raw interface to the RocksDB C API. It is intended to underpin a higher-level library rather than for direct use. + +#![allow(dead_code, non_camel_case_types, non_upper_case_globals, non_snake_case)] + +extern crate libc; + +#[cfg(test)] +mod test; + +use libc::*; + +extern "C" { + // Database operations + + pub fn rocksdb_open(options: *const rocksdb_options_t, name: *const c_char, errptr: *mut *mut c_char) -> *mut rocksdb_t; + + pub fn rocksdb_open_for_read_only(options: *const rocksdb_options_t, name: *const c_char, error_if_log_file_exist: c_uchar, errptr: *mut *mut c_char) -> *mut rocksdb_t; + + pub fn rocksdb_backup_engine_open(options: *const rocksdb_options_t, path: *const c_char, errptr: *mut *mut c_char) -> *mut rocksdb_backup_engine_t; + + pub fn rocksdb_backup_engine_create_new_backup(be: *mut rocksdb_backup_engine_t, db: *mut rocksdb_t, errptr: *mut *mut c_char); + + pub fn rocksdb_backup_engine_purge_old_backups(be: *mut rocksdb_backup_engine_t, num_backups_to_keep: uint32_t, errptr: *mut *mut c_char); + + pub fn rocksdb_restore_options_create() -> *mut rocksdb_restore_options_t; + + pub fn rocksdb_restore_options_destroy(opt: *mut rocksdb_restore_options_t); + + pub fn rocksdb_restore_options_set_keep_log_files(opt: *mut rocksdb_restore_options_t, v: c_int); + + pub fn rocksdb_backup_engine_restore_db_from_latest_backup(be: *mut rocksdb_backup_engine_t, db_dir: *const c_char, wal_dir: *const c_char, restore_options: *const rocksdb_restore_options_t, errptr: *mut *mut c_char); + + pub fn rocksdb_backup_engine_get_backup_info(be: *mut rocksdb_backup_engine_t) -> *const rocksdb_backup_engine_info_t; + + pub fn rocksdb_backup_engine_info_count(info: *const rocksdb_backup_engine_info_t) -> c_int; + + pub fn rocksdb_backup_engine_info_timestamp(info: *const rocksdb_backup_engine_info_t, index: c_int) -> int64_t; + + pub fn rocksdb_backup_engine_info_backup_id(info: *const rocksdb_backup_engine_info_t, index: c_int) -> uint32_t; + + pub fn rocksdb_backup_engine_info_size(info: *const rocksdb_backup_engine_info_t, index: c_int) -> uint64_t; + + pub fn rocksdb_backup_engine_info_number_files(info: *const rocksdb_backup_engine_info_t, index: c_int) -> uint32_t; + + pub fn rocksdb_backup_engine_info_destroy(info: *const rocksdb_backup_engine_info_t); + + pub fn rocksdb_backup_engine_close(be: *mut rocksdb_backup_engine_t); + + pub fn rocksdb_open_column_families(options: *const rocksdb_options_t, name: *const c_char, num_column_families: c_int, column_family_names: *const *const c_char, column_family_options: *const *const rocksdb_options_t, column_family_handles: *mut *mut rocksdb_column_family_handle_t, errptr: *mut *mut c_char) -> *mut rocksdb_t; + + pub fn rocksdb_open_for_read_only_column_families(options: *const rocksdb_options_t, name: *const c_char, num_column_families: c_int, column_family_names: *const *const c_char, column_family_options: *const *const rocksdb_options_t, column_family_handles: *mut *mut rocksdb_column_family_handle_t, error_if_log_file_exist: c_uchar, errptr: *mut *mut c_char) -> *mut rocksdb_t; + + pub fn rocksdb_list_column_families(options: *const rocksdb_options_t, name: *const c_char, lencf: *mut size_t, errptr: *mut *mut c_char) -> *mut *mut c_char; + + pub fn rocksdb_list_column_families_destroy(list: *mut *mut c_char, len: size_t); + + pub fn rocksdb_create_column_family(db: *mut rocksdb_t, column_family_options: *const rocksdb_options_t, column_family_name: *const c_char, errptr: *mut *mut c_char) -> *mut rocksdb_column_family_handle_t; + + pub fn rocksdb_drop_column_family(db: *mut rocksdb_t, handle: *mut rocksdb_column_family_handle_t, errptr: *mut *mut c_char); + + pub fn rocksdb_column_family_handle_destroy(handle: *mut rocksdb_column_family_handle_t); + + pub fn rocksdb_close(db: *mut rocksdb_t); + + pub fn rocksdb_put(db: *mut rocksdb_t, options: *const rocksdb_writeoptions_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_put_cf(db: *mut rocksdb_t, options: *const rocksdb_writeoptions_t, column_family: *mut rocksdb_column_family_handle_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_delete(db: *mut rocksdb_t, options: *const rocksdb_writeoptions_t, key: *const c_char, keylen: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_delete_cf(db: *mut rocksdb_t, options: *const rocksdb_writeoptions_t, column_family: *mut rocksdb_column_family_handle_t, key: *const c_char, keylen: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_merge(db: *mut rocksdb_t, options: *const rocksdb_writeoptions_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_merge_cf(db: *mut rocksdb_t, options: *const rocksdb_writeoptions_t, column_family: *mut rocksdb_column_family_handle_t, key: *const c_char, keylen: size_t, val: *const c_char, vallen: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_write(db: *mut rocksdb_t, options: *const rocksdb_writeoptions_t, batch: *mut rocksdb_writebatch_t, errptr: *mut *mut c_char); + + pub fn rocksdb_get(db: *mut rocksdb_t, options: *const rocksdb_readoptions_t, key: *const c_char, keylen: size_t, vallen: *mut size_t, errptr: *mut *mut c_char) -> *mut c_char; + + pub fn rocksdb_get_cf(db: *mut rocksdb_t, options: *const rocksdb_readoptions_t, column_family: *mut rocksdb_column_family_handle_t, key: *const c_char, keylen: size_t, vallen: *mut size_t, errptr: *mut *mut c_char) -> *mut c_char; + + pub fn rocksdb_multi_get(db: *mut rocksdb_t, options: *const rocksdb_readoptions_t, num_keys: size_t, keys_list: *const *const c_char, keys_list_sizes: *const size_t, values_list: *mut *mut c_char, values_list_sizes: *mut size_t, errs: *mut *mut c_char); + + pub fn rocksdb_multi_get_cf(db: *mut rocksdb_t, options: *const rocksdb_readoptions_t, column_families: *const *const rocksdb_column_family_handle_t, num_keys: size_t, keys_list: *const *const c_char, keys_list_sizes: *const size_t, values_list: *mut *mut c_char, values_list_sizes: *mut size_t, errs: *mut *mut c_char); + + pub fn rocksdb_create_iterator(db: *mut rocksdb_t, options: *const rocksdb_readoptions_t) -> *mut rocksdb_iterator_t; + + pub fn rocksdb_create_iterator_cf(db: *mut rocksdb_t, options: *const rocksdb_readoptions_t, column_family: *mut rocksdb_column_family_handle_t) -> *mut rocksdb_iterator_t; + + pub fn rocksdb_create_iterators(db: *mut rocksdb_t, opts: *mut rocksdb_readoptions_t, column_families: *mut *mut rocksdb_column_family_handle_t, iterators: *mut *mut rocksdb_iterator_t, size: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_create_snapshot(db: *mut rocksdb_t) -> *const rocksdb_snapshot_t; + + pub fn rocksdb_release_snapshot(db: *mut rocksdb_t, snapshot: *const rocksdb_snapshot_t); + + pub fn rocksdb_property_value(db: *mut rocksdb_t, propname: *const c_char) -> *mut c_char; + + pub fn rocksdb_property_value_cf(db: *mut rocksdb_t, column_family: *mut rocksdb_column_family_handle_t, propname: *const c_char) -> *mut c_char; + + pub fn rocksdb_approximate_sizes(db: *mut rocksdb_t, num_ranges: c_int, range_start_key: *const *const c_char, range_start_key_len: *const size_t, range_limit_key: *const *const c_char, range_limit_key_len: *const size_t, sizes: *mut uint64_t); + + pub fn rocksdb_approximate_sizes_cf(db: *mut rocksdb_t, column_family: *mut rocksdb_column_family_handle_t, num_ranges: c_int, range_start_key: *const *const c_char, range_start_key_len: *const size_t, range_limit_key: *const *const c_char, range_limit_key_len: *const size_t, sizes: *mut uint64_t); + + pub fn rocksdb_compact_range(db: *mut rocksdb_t, start_key: *const c_char, start_key_len: size_t, limit_key: *const c_char, limit_key_len: size_t); + + pub fn rocksdb_compact_range_cf(db: *mut rocksdb_t, column_family: *mut rocksdb_column_family_handle_t, start_key: *const c_char, start_key_len: size_t, limit_key: *const c_char, limit_key_len: size_t); + + pub fn rocksdb_delete_file(db: *mut rocksdb_t, name: *const c_char); + + pub fn rocksdb_livefiles(db: *mut rocksdb_t) -> *const rocksdb_livefiles_t; + + pub fn rocksdb_flush(db: *mut rocksdb_t, options: *const rocksdb_flushoptions_t, errptr: *mut *mut c_char); + + pub fn rocksdb_disable_file_deletions(db: *mut rocksdb_t, errptr: *mut *mut c_char); + + pub fn rocksdb_enable_file_deletions(db: *mut rocksdb_t, force: c_uchar, errptr: *mut *mut c_char); + + // Management operations + + pub fn rocksdb_destroy_db(options: *const rocksdb_options_t, name: *const c_char, errptr: *mut *mut c_char); + + pub fn rocksdb_repair_db(options: *const rocksdb_options_t, name: *const c_char, errptr: *mut *mut c_char); + + // Iterator + + pub fn rocksdb_iter_destroy(iterator: *mut rocksdb_iterator_t); + + pub fn rocksdb_iter_valid(iterator: *const rocksdb_iterator_t) -> c_uchar; + + pub fn rocksdb_iter_seek_to_first(iterator: *mut rocksdb_iterator_t); + + pub fn rocksdb_iter_seek_to_last(iterator: *mut rocksdb_iterator_t); + + pub fn rocksdb_iter_seek(iterator: *mut rocksdb_iterator_t, k: *const c_char, klen: size_t); + + pub fn rocksdb_iter_next(iterator: *mut rocksdb_iterator_t); + + pub fn rocksdb_iter_prev(iterator: *mut rocksdb_iterator_t); + + pub fn rocksdb_iter_key(iterator: *const rocksdb_iterator_t, klen: *mut size_t) -> *const c_char; + + pub fn rocksdb_iter_value(iterator: *const rocksdb_iterator_t, vlen: *mut size_t) -> *const c_char; + + pub fn rocksdb_iter_get_error(iterator: *const rocksdb_iterator_t, errptr: *mut *mut c_char); + + // Write batch + + pub fn rocksdb_writebatch_create() -> *mut rocksdb_writebatch_t; + + pub fn rocksdb_writebatch_create_from(rep: *const c_char, size: size_t) -> *mut rocksdb_writebatch_t; + + pub fn rocksdb_writebatch_destroy(batch: *mut rocksdb_writebatch_t); + + pub fn rocksdb_writebatch_clear(batch: *mut rocksdb_writebatch_t); + + pub fn rocksdb_writebatch_count(batch: *mut rocksdb_writebatch_t) -> c_int; + + pub fn rocksdb_writebatch_put(batch: *mut rocksdb_writebatch_t, key: *const c_char, klen: size_t, val: *const c_char, vlen: size_t); + + pub fn rocksdb_writebatch_put_cf(batch: *mut rocksdb_writebatch_t, column_family: *mut rocksdb_column_family_handle_t, key: *const c_char, klen: size_t, val: *const c_char, vlen: size_t); + + pub fn rocksdb_writebatch_putv(b: *mut rocksdb_writebatch_t, num_keys: c_int, keys_list: *const *const c_char, keys_list_sizes: *const size_t, num_values: c_int, values_list: *const *const c_char, values_list_sizes: *const size_t); + + pub fn rocksdb_writebatch_putv_cf(b: *mut rocksdb_writebatch_t, column_family: *mut rocksdb_column_family_handle_t, num_keys: c_int, keys_list: *const *const c_char, keys_list_sizes: *const size_t, num_values: c_int, values_list: *const *const c_char, values_list_sizes: *const size_t); + + pub fn rocksdb_writebatch_merge(batch: *mut rocksdb_writebatch_t, key: *const c_char, klen: size_t, val: *const c_char, vlen: size_t); + + pub fn rocksdb_writebatch_merge_cf(batch: *mut rocksdb_writebatch_t, column_family: *mut rocksdb_column_family_handle_t, key: *const c_char, klen: size_t, val: *const c_char, vlen: size_t); + + pub fn rocksdb_writebatch_mergev(b: *mut rocksdb_writebatch_t, num_keys: c_int, keys_list: *const *const c_char, keys_list_sizes: *const size_t, num_values: c_int, values_list: *const *const c_char, values_list_sizes: *const size_t); + + pub fn rocksdb_writebatch_mergev_cf(b: *mut rocksdb_writebatch_t, column_family: *mut rocksdb_column_family_handle_t, num_keys: c_int, keys_list: *const *const c_char, keys_list_sizes: *const size_t, num_values: c_int, values_list: *const *const c_char, values_list_sizes: *const size_t); + + pub fn rocksdb_writebatch_delete(batch: *mut rocksdb_writebatch_t, key: *const c_char, klen: size_t); + + pub fn rocksdb_writebatch_delete_cf(batch: *mut rocksdb_writebatch_t, column_family: *mut rocksdb_column_family_handle_t, key: *const c_char, klen: size_t); + + pub fn rocksdb_writebatch_deletev(b: *mut rocksdb_writebatch_t, num_keys: c_int, keys_list: *const *const c_char, keys_list_sizes: *const size_t); + + pub fn rocksdb_writebatch_deletev_cf(b: *mut rocksdb_writebatch_t, column_family: *mut rocksdb_column_family_handle_t, num_keys: c_int, keys_list: *const *const c_char, keys_list_sizes: *const size_t); + + pub fn rocksdb_writebatch_put_log_data(batch: *mut rocksdb_writebatch_t, blob: *const c_char, len: size_t); + + pub fn rocksdb_writebatch_iterate(batch: *mut rocksdb_writebatch_t, state: *mut c_void, put: Option, deleted: Option); + + pub fn rocksdb_writebatch_data(batch: *mut rocksdb_writebatch_t, size: *mut size_t) -> *const c_char; + + // Block-based table options + + pub fn rocksdb_block_based_options_create() -> *mut rocksdb_block_based_table_options_t; + + pub fn rocksdb_block_based_options_destroy(options: *mut rocksdb_block_based_table_options_t); + + pub fn rocksdb_block_based_options_set_block_size(options: *mut rocksdb_block_based_table_options_t, v: size_t); + + pub fn rocksdb_block_based_options_set_block_size_deviation(options: *mut rocksdb_block_based_table_options_t, v: c_int); + + pub fn rocksdb_block_based_options_set_block_restart_interval(options: *mut rocksdb_block_based_table_options_t, v: c_int); + + pub fn rocksdb_block_based_options_set_filter_policy(options: *mut rocksdb_block_based_table_options_t, v: *mut rocksdb_filterpolicy_t); + + pub fn rocksdb_block_based_options_set_no_block_cache(options: *mut rocksdb_block_based_table_options_t, v: c_uchar); + + pub fn rocksdb_block_based_options_set_block_cache(options: *mut rocksdb_block_based_table_options_t, v: *mut rocksdb_cache_t); + + pub fn rocksdb_block_based_options_set_block_cache_compressed(options: *mut rocksdb_block_based_table_options_t, v: *mut rocksdb_cache_t); + + pub fn rocksdb_block_based_options_set_whole_key_filtering(options: *mut rocksdb_block_based_table_options_t, v: c_uchar); + + pub fn rocksdb_block_based_options_set_format_version(options: *mut rocksdb_block_based_table_options_t, v: c_int); + + pub fn rocksdb_block_based_options_set_index_type(options: *mut rocksdb_block_based_table_options_t, v: c_int); + + pub fn rocksdb_block_based_options_set_hash_index_allow_collision(options: *mut rocksdb_block_based_table_options_t, v: c_uchar); + + pub fn rocksdb_block_based_options_set_cache_index_and_filter_blocks(options: *mut rocksdb_block_based_table_options_t, v: c_uchar); + + pub fn rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(options: *mut rocksdb_block_based_table_options_t, v: c_uchar); + + pub fn rocksdb_block_based_options_set_skip_table_builder_flush(options: *mut rocksdb_block_based_table_options_t, skip_table_builder_flush: c_uchar); + + pub fn rocksdb_options_set_block_based_table_factory(opt: *mut rocksdb_options_t, table_options: *mut rocksdb_block_based_table_options_t); + + // Cuckoo table options + + pub fn rocksdb_cuckoo_options_create() -> *mut rocksdb_cuckoo_table_options_t; + + pub fn rocksdb_cuckoo_options_destroy(options: *mut rocksdb_cuckoo_table_options_t); + + pub fn rocksdb_cuckoo_options_set_hash_ratio(options: *mut rocksdb_cuckoo_table_options_t, v: f64); + + pub fn rocksdb_cuckoo_options_set_max_search_depth(options: *mut rocksdb_cuckoo_table_options_t, v: uint32_t); + + pub fn rocksdb_cuckoo_options_set_cuckoo_block_size(options: *mut rocksdb_cuckoo_table_options_t, v: uint32_t); + + pub fn rocksdb_cuckoo_options_set_identity_as_first_hash(options: *mut rocksdb_cuckoo_table_options_t, v: c_uchar); + + pub fn rocksdb_cuckoo_options_set_use_module_hash(options: *mut rocksdb_cuckoo_table_options_t, v: c_uchar); + + pub fn rocksdb_options_set_cuckoo_table_factory(opt: *mut rocksdb_options_t, table_options: *mut rocksdb_cuckoo_table_options_t); + + // Options + + pub fn rocksdb_options_create() -> *mut rocksdb_options_t; + + pub fn rocksdb_options_destroy(opt: *mut rocksdb_options_t); + + pub fn rocksdb_options_increase_parallelism(opt: *mut rocksdb_options_t, total_threads: c_int); + + pub fn rocksdb_options_optimize_for_point_lookup(opt: *mut rocksdb_options_t, block_cache_size_mb: uint64_t); + + pub fn rocksdb_options_optimize_level_style_compaction(opt: *mut rocksdb_options_t, memtable_memory_budget: uint64_t); + + pub fn rocksdb_options_optimize_universal_style_compaction(opt: *mut rocksdb_options_t, memtable_memory_budget: uint64_t); + + pub fn rocksdb_options_set_compaction_filter(opt: *mut rocksdb_options_t, filter: *mut rocksdb_compactionfilter_t); + + pub fn rocksdb_options_set_compaction_filter_factory(opt: *mut rocksdb_options_t, factory: *mut rocksdb_compactionfilterfactory_t); + + pub fn rocksdb_options_compaction_readahead_size(opt: *mut rocksdb_options_t, s: size_t); + + pub fn rocksdb_options_set_comparator(opt: *mut rocksdb_options_t, cmp: *mut rocksdb_comparator_t); + + pub fn rocksdb_options_set_merge_operator(opt: *mut rocksdb_options_t, merge_operator: *mut rocksdb_mergeoperator_t); + + pub fn rocksdb_options_set_uint64add_merge_operator(opt: *mut rocksdb_options_t); + + pub fn rocksdb_options_set_compression_per_level(opt: *mut rocksdb_options_t, level_values: *const c_int, num_levels: size_t); + + pub fn rocksdb_options_set_create_if_missing(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_create_missing_column_families(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_error_if_exists(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_paranoid_checks(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_env(opt: *mut rocksdb_options_t, env: *mut rocksdb_env_t); + + pub fn rocksdb_options_set_info_log(opt: *mut rocksdb_options_t, l: *mut rocksdb_logger_t); + + pub fn rocksdb_options_set_info_log_level(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_write_buffer_size(opt: *mut rocksdb_options_t, s: size_t); + + pub fn rocksdb_options_set_db_write_buffer_size(opt: *mut rocksdb_options_t, s: size_t); + + pub fn rocksdb_options_set_max_open_files(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_max_total_wal_size(opt: *mut rocksdb_options_t, n: uint64_t); + + pub fn rocksdb_options_set_compression_options(opt: *mut rocksdb_options_t, w_bits: c_int, level: c_int, strategy: c_int, max_dict_bytes: c_int); + + pub fn rocksdb_options_set_prefix_extractor(opt: *mut rocksdb_options_t, prefix_extractor: *mut rocksdb_slicetransform_t); + + pub fn rocksdb_options_set_num_levels(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_level0_file_num_compaction_trigger(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_level0_slowdown_writes_trigger(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_level0_stop_writes_trigger(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_max_mem_compaction_level(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_target_file_size_base(opt: *mut rocksdb_options_t, n: uint64_t); + + pub fn rocksdb_options_set_target_file_size_multiplier(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_max_bytes_for_level_base(opt: *mut rocksdb_options_t, n: uint64_t); + + pub fn rocksdb_options_set_max_bytes_for_level_multiplier(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_expanded_compaction_factor(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_max_grandparent_overlap_factor(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_max_bytes_for_level_multiplier_additional(opt: *mut rocksdb_options_t, level_values: *mut c_int, num_levels: size_t); + + pub fn rocksdb_options_enable_statistics(opt: *mut rocksdb_options_t); + + pub fn rocksdb_options_statistics_get_string(opt: *mut rocksdb_options_t) -> *mut c_char; + + pub fn rocksdb_options_set_max_write_buffer_number(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_min_write_buffer_number_to_merge(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_max_write_buffer_number_to_maintain(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_max_background_compactions(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_max_background_flushes(opt: *mut rocksdb_options_t, n: c_int); + + pub fn rocksdb_options_set_max_log_file_size(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_log_file_time_to_roll(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_keep_log_file_num(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_recycle_log_file_num(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_soft_rate_limit(opt: *mut rocksdb_options_t, v: f64); + + pub fn rocksdb_options_set_hard_rate_limit(opt: *mut rocksdb_options_t, v: f64); + + pub fn rocksdb_options_set_rate_limit_delay_max_milliseconds(opt: *mut rocksdb_options_t, v: c_uint); + + pub fn rocksdb_options_set_max_manifest_file_size(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_table_cache_numshardbits(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_table_cache_remove_scan_count_limit(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_arena_block_size(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_use_fsync(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_db_log_dir(opt: *mut rocksdb_options_t, v: *const c_char); + + pub fn rocksdb_options_set_wal_dir(opt: *mut rocksdb_options_t, v: *const c_char); + + pub fn rocksdb_options_set_WAL_ttl_seconds(opt: *mut rocksdb_options_t, ttl: uint64_t); + + pub fn rocksdb_options_set_WAL_size_limit_MB(opt: *mut rocksdb_options_t, limit: uint64_t); + + pub fn rocksdb_options_set_manifest_preallocation_size(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_purge_redundant_kvs_while_flush(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_allow_os_buffer(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_allow_mmap_reads(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_allow_mmap_writes(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_is_fd_close_on_exec(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_skip_log_error_on_recovery(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_stats_dump_period_sec(opt: *mut rocksdb_options_t, v: c_uint); + + pub fn rocksdb_options_set_advise_random_on_open(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_access_hint_on_compaction_start(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_use_adaptive_mutex(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_bytes_per_sync(opt: *mut rocksdb_options_t, v: uint64_t); + + pub fn rocksdb_options_set_verify_checksums_in_compaction(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_filter_deletes(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_max_sequential_skip_in_iterations(opt: *mut rocksdb_options_t, v: uint64_t); + + pub fn rocksdb_options_set_disable_data_sync(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_disable_auto_compactions(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_delete_obsolete_files_period_micros(opt: *mut rocksdb_options_t, v: uint64_t); + + pub fn rocksdb_options_set_source_compaction_factor(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_prepare_for_bulk_load(opt: *mut rocksdb_options_t); + + pub fn rocksdb_options_set_memtable_vector_rep(opt: *mut rocksdb_options_t); + + pub fn rocksdb_options_set_hash_skip_list_rep(opt: *mut rocksdb_options_t, bucket_count: size_t, skiplist_height: int32_t, skiplist_branching_factor: int32_t); + + pub fn rocksdb_options_set_hash_link_list_rep(opt: *mut rocksdb_options_t, bucket_count: size_t); + + pub fn rocksdb_options_set_plain_table_factory(opt: *mut rocksdb_options_t, user_key_len: uint32_t, bloom_bits_per_key: c_int, hash_table_ratio: f64, index_sparseness: size_t); + + pub fn rocksdb_options_set_min_level_to_compress(opt: *mut rocksdb_options_t, level: c_int); + + pub fn rocksdb_options_set_memtable_prefix_bloom_bits(opt: *mut rocksdb_options_t, v: uint32_t); + + pub fn rocksdb_options_set_memtable_prefix_bloom_probes(opt: *mut rocksdb_options_t, v: uint32_t); + + pub fn rocksdb_options_set_memtable_huge_page_size(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_max_successive_merges(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_min_partial_merge_operands(opt: *mut rocksdb_options_t, v: uint32_t); + + pub fn rocksdb_options_set_bloom_locality(opt: *mut rocksdb_options_t, v: uint32_t); + + pub fn rocksdb_options_set_inplace_update_support(opt: *mut rocksdb_options_t, v: c_uchar); + + pub fn rocksdb_options_set_inplace_update_num_locks(opt: *mut rocksdb_options_t, v: size_t); + + pub fn rocksdb_options_set_report_bg_io_stats(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_wal_recovery_mode(opt: *mut rocksdb_options_t, v: c_int); + + pub fn rocksdb_options_set_compression(opt: *mut rocksdb_options_t, t: c_int); + + pub fn rocksdb_options_set_compaction_style(opt: *mut rocksdb_options_t, style: c_int); + + pub fn rocksdb_options_set_universal_compaction_options(opt: *mut rocksdb_options_t, uco: *mut rocksdb_universal_compaction_options_t); + + pub fn rocksdb_options_set_fifo_compaction_options(opt: *mut rocksdb_options_t, fifo: *mut rocksdb_fifo_compaction_options_t); + + // Compaction filter + + pub fn rocksdb_compactionfilter_create(state: *mut c_void, destructor: Option, filter: Option c_uchar>, name: Option *const c_char>) -> *mut rocksdb_compactionfilter_t; + + pub fn rocksdb_compactionfilter_set_ignore_snapshots(filter: *mut rocksdb_compactionfilter_t, v: c_uchar); + + pub fn rocksdb_compactionfilter_destroy(filter: *mut rocksdb_compactionfilter_t); + + // Compaction Filter context + + pub fn rocksdb_compactionfiltercontext_is_full_compaction(context: *mut rocksdb_compactionfiltercontext_t) -> c_uchar; + + pub fn rocksdb_compactionfiltercontext_is_manual_compaction(context: *mut rocksdb_compactionfiltercontext_t) -> c_uchar; + + // Compaction Filter factory + + pub fn rocksdb_compactionfilterfactory_create(state: *mut c_void, destructor: Option, create_compaction_filter: Option *mut rocksdb_compactionfilter_t>, name: Option *const c_char>) -> *mut rocksdb_compactionfilterfactory_t; + + pub fn rocksdb_compactionfilterfactory_destroy(factory: *mut rocksdb_compactionfilterfactory_t); + + // Comparator + + pub fn rocksdb_comparator_create(state: *mut c_void, destructor: Option, compare: Option c_int>, name: Option *const c_char>) -> *mut rocksdb_comparator_t; + + pub fn rocksdb_comparator_destroy(cmp: *mut rocksdb_comparator_t); + + // Filter policy + + pub fn rocksdb_filterpolicy_create(state: *mut c_void, destructor: Option, create_filter: Option *mut c_char>, key_may_match: Option c_uchar>, delete_filter: Option, name: Option *const c_char>) -> *mut rocksdb_filterpolicy_t; + + pub fn rocksdb_filterpolicy_destroy(filter: *mut rocksdb_filterpolicy_t); + + pub fn rocksdb_filterpolicy_create_bloom(bits_per_key: c_int) -> *mut rocksdb_filterpolicy_t; + + pub fn rocksdb_filterpolicy_create_bloom_full(bits_per_key: c_int) -> *mut rocksdb_filterpolicy_t; + + // Merge Operator + + pub fn rocksdb_mergeoperator_create(state: *mut c_void, destructor: Option, full_merge: Option *mut c_char>, partial_merge: Option *mut c_char>, delete_value: Option, name: Option *const c_char>) -> *mut rocksdb_mergeoperator_t; + + pub fn rocksdb_mergeoperator_destroy(merge_operator: *mut rocksdb_mergeoperator_t); + + // Read options + + pub fn rocksdb_readoptions_create() -> *mut rocksdb_readoptions_t; + + pub fn rocksdb_readoptions_destroy(opt: *mut rocksdb_readoptions_t); + + pub fn rocksdb_readoptions_set_verify_checksums(opt: *mut rocksdb_readoptions_t, v: c_uchar); + + pub fn rocksdb_readoptions_set_fill_cache(opt: *mut rocksdb_readoptions_t, v: c_uchar); + + pub fn rocksdb_readoptions_set_snapshot(opt: *mut rocksdb_readoptions_t, v: *const rocksdb_snapshot_t); + + pub fn rocksdb_readoptions_set_iterate_upper_bound(opt: *mut rocksdb_readoptions_t, key: *const c_char, keylen: size_t); + + pub fn rocksdb_readoptions_set_read_tier(opt: *mut rocksdb_readoptions_t, v: c_int); + + pub fn rocksdb_readoptions_set_tailing(opt: *mut rocksdb_readoptions_t, v: c_uchar); + + pub fn rocksdb_readoptions_set_readahead_size(opt: *mut rocksdb_readoptions_t, v: size_t); + + // Write options + + pub fn rocksdb_writeoptions_create() -> *mut rocksdb_writeoptions_t; + + pub fn rocksdb_writeoptions_destroy(opt: *mut rocksdb_writeoptions_t); + + pub fn rocksdb_writeoptions_set_sync(opt: *mut rocksdb_writeoptions_t, v: c_uchar); + + pub fn rocksdb_writeoptions_disable_WAL(opt: *mut rocksdb_writeoptions_t, disable: c_int); + + // Flush options + + pub fn rocksdb_flushoptions_create() -> *mut rocksdb_flushoptions_t; + + pub fn rocksdb_flushoptions_destroy(opt: *mut rocksdb_flushoptions_t); + + pub fn rocksdb_flushoptions_set_wait(opt: *mut rocksdb_flushoptions_t, v: c_uchar); + + // Cache + + pub fn rocksdb_cache_create_lru(capacity: size_t) -> *mut rocksdb_cache_t; + + pub fn rocksdb_cache_destroy(cache: *mut rocksdb_cache_t); + + pub fn rocksdb_cache_set_capacity(cache: *mut rocksdb_cache_t, capacity: size_t); + + // Environment + + pub fn rocksdb_create_default_env() -> *mut rocksdb_env_t; + + pub fn rocksdb_create_mem_env() -> *mut rocksdb_env_t; + + pub fn rocksdb_env_set_background_threads(env: *mut rocksdb_env_t, n: c_int); + + pub fn rocksdb_env_set_high_priority_background_threads(env: *mut rocksdb_env_t, n: c_int); + + pub fn rocksdb_env_join_all_threads(env: *mut rocksdb_env_t); + + pub fn rocksdb_env_destroy(env: *mut rocksdb_env_t); + + // Slice Transform + + pub fn rocksdb_slicetransform_create(state: *mut c_void, destructor: Option, transform: Option *mut c_char>, in_domain: Option c_uchar>, in_range: Option c_uchar>, name: Option *const c_char>) -> *mut rocksdb_slicetransform_t; + + pub fn rocksdb_slicetransform_create_fixed_prefix(len: size_t) -> *mut rocksdb_slicetransform_t; + + pub fn rocksdb_slicetransform_create_noop() -> *mut rocksdb_slicetransform_t; + + pub fn rocksdb_slicetransform_destroy(st: *mut rocksdb_slicetransform_t); + + // Universal Compaction options + + pub fn rocksdb_universal_compaction_options_create() -> *mut rocksdb_universal_compaction_options_t; + + pub fn rocksdb_universal_compaction_options_set_size_ratio(uco: *mut rocksdb_universal_compaction_options_t, ratio: c_int); + + pub fn rocksdb_universal_compaction_options_set_min_merge_width(uco: *mut rocksdb_universal_compaction_options_t, w: c_int); + + pub fn rocksdb_universal_compaction_options_set_max_merge_width(uco: *mut rocksdb_universal_compaction_options_t, w: c_int); + + pub fn rocksdb_universal_compaction_options_set_max_size_amplification_percent(uco: *mut rocksdb_universal_compaction_options_t, p: c_int); + + pub fn rocksdb_universal_compaction_options_set_compression_size_percent(uco: *mut rocksdb_universal_compaction_options_t, p: c_int); + + pub fn rocksdb_universal_compaction_options_set_stop_style(uco: *mut rocksdb_universal_compaction_options_t, style: c_int); + + pub fn rocksdb_universal_compaction_options_destroy(uco: *mut rocksdb_universal_compaction_options_t); + + pub fn rocksdb_fifo_compaction_options_create() -> *mut rocksdb_fifo_compaction_options_t; + + pub fn rocksdb_fifo_compaction_options_set_max_table_files_size(fifo_opts: *mut rocksdb_fifo_compaction_options_t, size: uint64_t); + + pub fn rocksdb_fifo_compaction_options_destroy(fifo_opts: *mut rocksdb_fifo_compaction_options_t); + + pub fn rocksdb_livefiles_count(files: *const rocksdb_livefiles_t) -> c_int; + + pub fn rocksdb_livefiles_name(files: *const rocksdb_livefiles_t, index: c_int) -> *const c_char; + + pub fn rocksdb_livefiles_level(files: *const rocksdb_livefiles_t, index: c_int) -> c_int; + + pub fn rocksdb_livefiles_size(files: *const rocksdb_livefiles_t, index: c_int) -> size_t; + + pub fn rocksdb_livefiles_smallestkey(files: *const rocksdb_livefiles_t, index: c_int, size: *mut size_t) -> *const c_char; + + pub fn rocksdb_livefiles_largestkey(files: *const rocksdb_livefiles_t, index: c_int, size: *mut size_t) -> *const c_char; + + pub fn rocksdb_livefiles_destroy(files: *const rocksdb_livefiles_t); + + // Utilities + + pub fn rocksdb_get_options_from_string(base_options: *const rocksdb_options_t, opts_str: *const c_char, new_options: *mut rocksdb_options_t, errptr: *mut *mut c_char); + + pub fn rocksdb_delete_file_in_range(db: *mut rocksdb_t, start_key: *const c_char, start_key_len: size_t, limit_key: *const c_char, limit_key_len: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_delete_file_in_range_cf(db: *mut rocksdb_t, column_family: *mut rocksdb_column_family_handle_t, start_key: *const c_char, start_key_len: size_t, limit_key: *const c_char, limit_key_len: size_t, errptr: *mut *mut c_char); + + pub fn rocksdb_free(ptr: *mut c_void); +} + +pub const rocksdb_block_based_table_index_type_binary_search: c_int = 0; +pub const rocksdb_block_based_table_index_type_hash_search: c_int = 1; + +pub const rocksdb_no_compression: c_int = 0; +pub const rocksdb_snappy_compression: c_int = 1; +pub const rocksdb_zlib_compression: c_int = 2; +pub const rocksdb_bz2_compression: c_int = 3; +pub const rocksdb_lz4_compression: c_int = 4; +pub const rocksdb_lz4hc_compression: c_int = 5; + +pub const rocksdb_level_compaction: c_int = 0; +pub const rocksdb_universal_compaction: c_int = 1; +pub const rocksdb_fifo_compaction: c_int = 2; + +pub const rocksdb_similar_size_compaction_stop_style: c_int = 0; +pub const rocksdb_total_size_compaction_stop_style: c_int = 1; + +pub enum rocksdb_t { } + +pub enum rocksdb_backup_engine_t { } + +pub enum rocksdb_backup_engine_info_t { } + +pub enum rocksdb_restore_options_t { } + +pub enum rocksdb_cache_t { } + +pub enum rocksdb_compactionfilter_t { } + +pub enum rocksdb_compactionfiltercontext_t { } + +pub enum rocksdb_compactionfilterfactory_t { } + +pub enum rocksdb_comparator_t { } + +pub enum rocksdb_env_t { } + +pub enum rocksdb_fifo_compaction_options_t { } + +pub enum rocksdb_filelock_t { } + +pub enum rocksdb_filterpolicy_t { } + +pub enum rocksdb_flushoptions_t { } + +pub enum rocksdb_iterator_t { } + +pub enum rocksdb_logger_t { } + +pub enum rocksdb_mergeoperator_t { } + +pub enum rocksdb_options_t { } + +pub enum rocksdb_block_based_table_options_t { } + +pub enum rocksdb_cuckoo_table_options_t { } + +pub enum rocksdb_randomfile_t { } + +pub enum rocksdb_readoptions_t { } + +pub enum rocksdb_seqfile_t { } + +pub enum rocksdb_slicetransform_t { } + +pub enum rocksdb_snapshot_t { } + +pub enum rocksdb_writablefile_t { } + +pub enum rocksdb_writebatch_t { } + +pub enum rocksdb_writeoptions_t { } + +pub enum rocksdb_universal_compaction_options_t { } + +pub enum rocksdb_livefiles_t { } + +pub enum rocksdb_column_family_handle_t { } diff --git a/rocksdb-sys/src/test.rs b/rocksdb-sys/src/test.rs new file mode 100644 index 0000000..6d3aa79 --- /dev/null +++ b/rocksdb-sys/src/test.rs @@ -0,0 +1,86 @@ +// Copyright 2014 Tyler Neely +// +// 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. +// + +use libc::*; +use std::ffi::{CStr, CString}; +use std::ptr; +use std::str; + +use super::*; + +pub fn error_message(ptr: *const i8) -> String { + let c_str = unsafe { CStr::from_ptr(ptr as *const _) }; + let s = str::from_utf8(c_str.to_bytes()).unwrap().to_owned(); + unsafe { + free(ptr as *mut c_void); + } + s +} + +#[test] +fn internal() { + unsafe { + let opts = rocksdb_options_create(); + assert!(!opts.is_null()); + + rocksdb_options_increase_parallelism(opts, 0); + rocksdb_options_optimize_level_style_compaction(opts, 0); + rocksdb_options_set_create_if_missing(opts, true as c_uchar); + + let rustpath = "_rust_rocksdb_internaltest"; + let cpath = CString::new(rustpath).unwrap(); + let cpath_ptr = cpath.as_ptr(); + + let mut err: *mut c_char = ptr::null_mut(); + let err_ptr: *mut *mut c_char = &mut err; + let db = rocksdb_open(opts, cpath_ptr as *const _, err_ptr); + if !err.is_null() { + println!("failed to open rocksdb: {}", error_message(err)); + } + assert!(err.is_null()); + + let writeopts = rocksdb_writeoptions_create(); + assert!(!writeopts.is_null()); + + let key = b"name\x00"; + let val = b"spacejam\x00"; + rocksdb_put(db, + writeopts.clone(), + key.as_ptr() as *const c_char, + 4, + val.as_ptr() as *const c_char, + 8, + err_ptr); + rocksdb_writeoptions_destroy(writeopts); + assert!(err.is_null()); + + let readopts = rocksdb_readoptions_create(); + assert!(!readopts.is_null()); + + let mut val_len: size_t = 0; + let val_len_ptr = &mut val_len as *mut size_t; + rocksdb_get(db, + readopts.clone(), + key.as_ptr() as *const c_char, + 4, + val_len_ptr, + err_ptr); + rocksdb_readoptions_destroy(readopts); + assert!(err.is_null()); + rocksdb_close(db); + rocksdb_destroy_db(opts, cpath_ptr as *const _, err_ptr); + assert!(err.is_null()); + } +} diff --git a/rocksdb-sys/tests/ffi.rs b/rocksdb-sys/tests/ffi.rs new file mode 100644 index 0000000..36730a8 --- /dev/null +++ b/rocksdb-sys/tests/ffi.rs @@ -0,0 +1,950 @@ +// 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 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(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"); + } +} diff --git a/src/comparator.rs b/src/comparator.rs index 9229351..9a6fda7 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -12,44 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. // -extern crate libc; -use self::libc::{c_char, c_int, c_void, size_t}; + use std::ffi::CString; use std::mem; use std::slice; +use libc::{c_char, c_int, c_void, size_t}; + pub struct ComparatorCallback { pub name: CString, pub f: fn(&[u8], &[u8]) -> i32, } -pub extern "C" fn destructor_callback(raw_cb: *mut c_void) { - // turn this back into a local variable so rust will reclaim it - let _: Box = unsafe { mem::transmute(raw_cb) }; +pub unsafe extern "C" fn destructor_callback(raw_cb: *mut c_void) { + let _: Box = mem::transmute(raw_cb); } -pub extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char { - unsafe { - let cb: &mut ComparatorCallback = - &mut *(raw_cb as *mut ComparatorCallback); - let ptr = cb.name.as_ptr(); - ptr as *const c_char - } +pub unsafe extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char { + let cb: &mut ComparatorCallback = &mut *(raw_cb as *mut ComparatorCallback); + let ptr = cb.name.as_ptr(); + ptr as *const c_char } -pub extern "C" fn compare_callback(raw_cb: *mut c_void, - a_raw: *const c_char, - a_len: size_t, - b_raw: *const c_char, - b_len: size_t) - -> c_int { - unsafe { - let cb: &mut ComparatorCallback = - &mut *(raw_cb as *mut ComparatorCallback); - let a: &[u8] = slice::from_raw_parts(a_raw as *const u8, - a_len as usize); - let b: &[u8] = slice::from_raw_parts(b_raw as *const u8, - b_len as usize); - (cb.f)(a, b) - } +pub unsafe extern "C" fn compare_callback(raw_cb: *mut c_void, a_raw: *const c_char, a_len: size_t, b_raw: *const c_char, b_len: size_t) -> c_int { + let cb: &mut ComparatorCallback = &mut *(raw_cb as *mut ComparatorCallback); + let a: &[u8] = slice::from_raw_parts(a_raw as *const u8, a_len as usize); + let b: &[u8] = slice::from_raw_parts(b_raw as *const u8, b_len as usize); + (cb.f)(a, b) } diff --git a/src/lib.rs b/src/lib.rs index da33d06..233cc91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,14 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. // -extern crate rocksdb_sys; -pub use rocksdb_sys::rocksdb_ffi as rocksdb_ffi; -pub use rocksdb_ffi::{DBCompactionStyle, DBComparator, DBCompressionType, DBRecoveryMode, new_bloom_filter}; -pub use rocksdb::{DB, DBIterator, DBVector, Direction, IteratorMode, Writable, - WriteBatch, Error}; -pub use rocksdb_options::{BlockBasedOptions, Options, WriteOptions}; -pub use merge_operator::MergeOperands; -pub mod rocksdb; -pub mod rocksdb_options; + +extern crate libc; +extern crate rocksdb_sys as ffi; + pub mod merge_operator; pub mod comparator; + +mod rocksdb; +mod rocksdb_options; + +pub use rocksdb::{DB, DBCompressionType, DBCompactionStyle, DBRecoveryMode, DBIterator, DBVector, Direction, IteratorMode, Writable, WriteBatch, Error, new_bloom_filter}; +pub use merge_operator::MergeOperands; + +pub struct BlockBasedOptions { + inner: *mut ffi::rocksdb_block_based_table_options_t, +} + +pub struct Options { + inner: *mut ffi::rocksdb_options_t, +} + +pub struct WriteOptions { + inner: *mut ffi::rocksdb_writeoptions_t, +} diff --git a/src/merge_operator.rs b/src/merge_operator.rs index d243f60..8886d7d 100644 --- a/src/merge_operator.rs +++ b/src/merge_operator.rs @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. // -extern crate libc; -use self::libc::{c_char, c_int, c_void, size_t}; + use std::ffi::CString; use std::mem; use std::ptr; use std::slice; +use libc::{self, c_char, c_int, c_void, size_t}; + pub type MergeFn = fn(&[u8], Option<&[u8]>, &mut MergeOperands) -> Vec; pub struct MergeOperatorCallback { @@ -26,81 +27,44 @@ pub struct MergeOperatorCallback { pub merge_fn: MergeFn, } -pub extern "C" fn destructor_callback(raw_cb: *mut c_void) { - // turn this back into a local variable so rust will reclaim it - let _: Box = unsafe { mem::transmute(raw_cb) }; - +pub unsafe extern "C" fn destructor_callback(raw_cb: *mut c_void) { + let _: Box = mem::transmute(raw_cb); } -pub extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char { - unsafe { - let cb: &mut MergeOperatorCallback = - &mut *(raw_cb as *mut MergeOperatorCallback); - let ptr = cb.name.as_ptr(); - ptr as *const c_char - } +pub unsafe extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char { + let cb = &mut *(raw_cb as *mut MergeOperatorCallback); + cb.name.as_ptr() } -pub extern "C" fn full_merge_callback(raw_cb: *mut c_void, - raw_key: *const c_char, - key_len: size_t, - existing_value: *const c_char, - existing_value_len: size_t, - operands_list: *const *const c_char, - operands_list_len: *const size_t, - num_operands: c_int, - success: *mut u8, - new_value_length: *mut size_t) - -> *const c_char { - unsafe { - let cb: &mut MergeOperatorCallback = - &mut *(raw_cb as *mut MergeOperatorCallback); - let operands = &mut MergeOperands::new(operands_list, - operands_list_len, - num_operands); - let key: &[u8] = slice::from_raw_parts(raw_key as *const u8, - key_len as usize); - let oldval: &[u8] = slice::from_raw_parts(existing_value as *const u8, - existing_value_len as usize); - let mut result = (cb.merge_fn)(key, Some(oldval), operands); - result.shrink_to_fit(); - // TODO(tan) investigate zero-copy techniques to improve performance - let buf = libc::malloc(result.len() as size_t); - assert!(!buf.is_null()); - *new_value_length = result.len() as size_t; - *success = 1 as u8; - ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len()); - buf as *const c_char - } +pub unsafe extern "C" fn full_merge_callback(raw_cb: *mut c_void, raw_key: *const c_char, key_len: size_t, existing_value: *const c_char, existing_value_len: size_t, operands_list: *const *const c_char, operands_list_len: *const size_t, num_operands: c_int, success: *mut u8, new_value_length: *mut size_t) -> *mut c_char { + let cb = &mut *(raw_cb as *mut MergeOperatorCallback); + let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands); + let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize); + let oldval = slice::from_raw_parts(existing_value as *const u8, existing_value_len as usize); + let mut result = (cb.merge_fn)(key, Some(oldval), operands); + result.shrink_to_fit(); + // TODO(tan) investigate zero-copy techniques to improve performance + let buf = libc::malloc(result.len() as size_t); + assert!(!buf.is_null()); + *new_value_length = result.len() as size_t; + *success = 1 as u8; + ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len()); + buf as *mut c_char } -pub extern "C" fn partial_merge_callback(raw_cb: *mut c_void, - raw_key: *const c_char, - key_len: size_t, - operands_list: *const *const c_char, - operands_list_len: *const size_t, - num_operands: c_int, - success: *mut u8, - new_value_length: *mut size_t) - -> *const c_char { - unsafe { - let cb: &mut MergeOperatorCallback = - &mut *(raw_cb as *mut MergeOperatorCallback); - let operands = &mut MergeOperands::new(operands_list, - operands_list_len, - num_operands); - let key: &[u8] = slice::from_raw_parts(raw_key as *const u8, - key_len as usize); - let mut result = (cb.merge_fn)(key, None, operands); - result.shrink_to_fit(); - // TODO(tan) investigate zero-copy techniques to improve performance - let buf = libc::malloc(result.len() as size_t); - assert!(!buf.is_null()); - *new_value_length = 1 as size_t; - *success = 1 as u8; - ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len()); - buf as *const c_char - } +pub unsafe extern "C" fn partial_merge_callback(raw_cb: *mut c_void, raw_key: *const c_char, key_len: size_t, operands_list: *const *const c_char, operands_list_len: *const size_t, num_operands: c_int, success: *mut u8, new_value_length: *mut size_t) -> *mut c_char { + let cb = &mut *(raw_cb as *mut MergeOperatorCallback); + let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands); + let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize); + let mut result = (cb.merge_fn)(key, None, operands); + result.shrink_to_fit(); + // TODO(tan) investigate zero-copy techniques to improve performance + let buf = libc::malloc(result.len() as size_t); + assert!(!buf.is_null()); + *new_value_length = 1 as size_t; + *success = 1 as u8; + ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len()); + buf as *mut c_char } @@ -112,10 +76,7 @@ pub struct MergeOperands { } impl MergeOperands { - fn new(operands_list: *const *const c_char, - operands_list_len: *const size_t, - num_operands: c_int) - -> MergeOperands { + fn new(operands_list: *const *const c_char, operands_list_len: *const size_t, num_operands: c_int) -> MergeOperands { assert!(num_operands >= 0); MergeOperands { operands_list: operands_list, @@ -128,6 +89,7 @@ impl MergeOperands { impl<'a> Iterator for &'a mut MergeOperands { type Item = &'a [u8]; + fn next(&mut self) -> Option<&'a [u8]> { if self.cursor == self.num_operands { None @@ -137,13 +99,11 @@ impl<'a> Iterator for &'a mut MergeOperands { let base_len = self.operands_list_len as usize; let spacing = mem::size_of::<*const *const u8>(); let spacing_len = mem::size_of::<*const size_t>(); - let len_ptr = - (base_len + (spacing_len * self.cursor)) as *const size_t; + let len_ptr = (base_len + (spacing_len * self.cursor)) as *const size_t; let len = *len_ptr as usize; let ptr = base + (spacing * self.cursor); self.cursor += 1; - Some(mem::transmute(slice::from_raw_parts(*(ptr as *const *const u8) - as *const u8, len))) + Some(mem::transmute(slice::from_raw_parts(*(ptr as *const *const u8) as *const u8, len))) } } } @@ -154,12 +114,9 @@ impl<'a> Iterator for &'a mut MergeOperands { } } +#[cfg(test)] #[allow(unused_variables)] -#[allow(dead_code)] -fn test_provided_merge(new_key: &[u8], - existing_val: Option<&[u8]>, - operands: &mut MergeOperands) - -> Vec { +fn test_provided_merge(new_key: &[u8], existing_val: Option<&[u8]>, operands: &mut MergeOperands) -> Vec { let nops = operands.size_hint().0; let mut result: Vec = Vec::with_capacity(nops); if let Some(v) = existing_val { @@ -175,12 +132,10 @@ fn test_provided_merge(new_key: &[u8], result } -#[allow(dead_code)] #[test] - fn mergetest() { - use rocksdb_options::Options; - use rocksdb::{DB, DBVector, Writable}; + use {Options}; + use rocksdb::{DB, Writable}; let path = "_rust_rocksdb_mergetest"; let mut opts = Options::default(); @@ -203,7 +158,7 @@ fn mergetest() { None => println!("did not read valid utf-8 out of the db"), } } - Err(e) => println!("error reading value"), + Err(_) => println!("error reading value"), _ => panic!("value not present"), } diff --git a/src/rocksdb.rs b/src/rocksdb.rs index d7e6ae6..7c105db 100644 --- a/src/rocksdb.rs +++ b/src/rocksdb.rs @@ -13,46 +13,87 @@ // limitations under the License. // -extern crate libc; - use std::collections::BTreeMap; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use std::fs; use std::ops::Deref; use std::path::{Path, PathBuf}; +use std::ptr; use std::slice; use std::str::from_utf8; use std::fmt; -use self::libc::size_t; +use libc::{self, c_char, c_uchar, c_int, c_void, size_t}; -use rocksdb_ffi::{self, DBCFHandle, error_message}; -use rocksdb_options::{Options, WriteOptions}; +use {Options, WriteOptions}; +use ffi; + +fn error_message(ptr: *const i8) -> String { + let c_str = unsafe { CStr::from_ptr(ptr as *const _) }; + let s = from_utf8(c_str.to_bytes()).unwrap().to_owned(); + unsafe { + libc::free(ptr as *mut c_void); + } + s +} + +pub fn new_bloom_filter(bits: c_int) -> *mut ffi::rocksdb_filterpolicy_t { + unsafe { ffi::rocksdb_filterpolicy_create_bloom(bits) } +} + +pub fn new_cache(capacity: size_t) -> *mut ffi::rocksdb_cache_t { + unsafe { ffi::rocksdb_cache_create_lru(capacity) } +} pub struct DB { - inner: rocksdb_ffi::DBInstance, - cfs: BTreeMap, + inner: *mut ffi::rocksdb_t, + cfs: BTreeMap, path: PathBuf, } -unsafe impl Send for DB {} -unsafe impl Sync for DB {} +unsafe impl Send for DB { } +unsafe impl Sync for DB { } + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum DBCompressionType { + None = 0, + Snappy = 1, + Zlib = 2, + Bz2 = 3, + Lz4 = 4, + Lz4hc = 5, +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum DBCompactionStyle { + Level = 0, + Universal = 1, + Fifo = 2, +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum DBRecoveryMode { + TolerateCorruptedTailRecords = 0, + AbsoluteConsistency = 1, + PointInTime = 2, + SkipAnyCorruptedRecords = 3, +} pub struct WriteBatch { - inner: rocksdb_ffi::DBWriteBatch, + inner: *mut ffi::rocksdb_writebatch_t, } pub struct ReadOptions { - inner: rocksdb_ffi::DBReadOptions, + inner: *mut ffi::rocksdb_readoptions_t, } pub struct Snapshot<'a> { db: &'a DB, - inner: rocksdb_ffi::DBSnapshot, + inner: *const ffi::rocksdb_snapshot_t, } pub struct DBIterator { - inner: rocksdb_ffi::DBIterator, + inner: *mut ffi::rocksdb_iterator_t, direction: Direction, just_seeked: bool, } @@ -98,34 +139,23 @@ impl Iterator for DBIterator { let native_iter = self.inner; if !self.just_seeked { match self.direction { - Direction::Forward => unsafe { - rocksdb_ffi::rocksdb_iter_next(native_iter) - }, - Direction::Reverse => unsafe { - rocksdb_ffi::rocksdb_iter_prev(native_iter) - }, + Direction::Forward => unsafe { ffi::rocksdb_iter_next(native_iter) }, + Direction::Reverse => unsafe { ffi::rocksdb_iter_prev(native_iter) }, } } else { self.just_seeked = false; } - if unsafe { rocksdb_ffi::rocksdb_iter_valid(native_iter) } { + if unsafe { ffi::rocksdb_iter_valid(native_iter) != 0 } { let mut key_len: size_t = 0; let key_len_ptr: *mut size_t = &mut key_len; let mut val_len: size_t = 0; let val_len_ptr: *mut size_t = &mut val_len; - let key_ptr = unsafe { - rocksdb_ffi::rocksdb_iter_key(native_iter, key_len_ptr) - }; - let key = - unsafe { slice::from_raw_parts(key_ptr, key_len as usize) }; - let val_ptr = unsafe { - rocksdb_ffi::rocksdb_iter_value(native_iter, val_len_ptr) - }; - let val = - unsafe { slice::from_raw_parts(val_ptr, val_len as usize) }; + let key_ptr = unsafe { ffi::rocksdb_iter_key(native_iter, key_len_ptr) as *const c_uchar }; + let key = unsafe { slice::from_raw_parts(key_ptr, key_len as usize) }; + let val_ptr = unsafe { ffi::rocksdb_iter_value(native_iter, val_len_ptr) as *const c_uchar }; + let val = unsafe { slice::from_raw_parts(val_ptr, val_len as usize) }; - Some((key.to_vec().into_boxed_slice(), - val.to_vec().into_boxed_slice())) + Some((key.to_vec().into_boxed_slice(), val.to_vec().into_boxed_slice())) } else { None } @@ -138,21 +168,17 @@ pub enum IteratorMode<'a> { From(&'a [u8], Direction), } - impl DBIterator { fn new(db: &DB, readopts: &ReadOptions, mode: IteratorMode) -> DBIterator { unsafe { - let iterator = rocksdb_ffi::rocksdb_create_iterator(db.inner, - readopts.inner); + let iterator = ffi::rocksdb_create_iterator(db.inner, readopts.inner); let mut rv = DBIterator { inner: iterator, direction: Direction::Forward, // blown away by set_mode() just_seeked: false, }; - rv.set_mode(mode); - rv } } @@ -161,17 +187,15 @@ impl DBIterator { unsafe { match mode { IteratorMode::Start => { - rocksdb_ffi::rocksdb_iter_seek_to_first(self.inner); + ffi::rocksdb_iter_seek_to_first(self.inner); self.direction = Direction::Forward; } IteratorMode::End => { - rocksdb_ffi::rocksdb_iter_seek_to_last(self.inner); + ffi::rocksdb_iter_seek_to_last(self.inner); self.direction = Direction::Reverse; } IteratorMode::From(key, dir) => { - rocksdb_ffi::rocksdb_iter_seek(self.inner, - key.as_ptr(), - key.len() as size_t); + ffi::rocksdb_iter_seek(self.inner, key.as_ptr() as *const c_char, key.len() as size_t); self.direction = dir; } }; @@ -180,28 +204,19 @@ impl DBIterator { } pub fn valid(&self) -> bool { - unsafe { rocksdb_ffi::rocksdb_iter_valid(self.inner) } + unsafe { ffi::rocksdb_iter_valid(self.inner) != 0 } } - fn new_cf(db: &DB, - cf_handle: DBCFHandle, - readopts: &ReadOptions, - mode: IteratorMode) - -> Result { + fn new_cf(db: &DB, cf_handle: *mut ffi::rocksdb_column_family_handle_t, readopts: &ReadOptions, mode: IteratorMode) -> Result { unsafe { - let iterator = - rocksdb_ffi::rocksdb_create_iterator_cf(db.inner, - readopts.inner, - cf_handle); + let iterator = ffi::rocksdb_create_iterator_cf(db.inner, readopts.inner, cf_handle); let mut rv = DBIterator { inner: iterator, direction: Direction::Forward, // blown away by set_mode() just_seeked: false, }; - rv.set_mode(mode); - Ok(rv) } } @@ -210,15 +225,14 @@ impl DBIterator { impl Drop for DBIterator { fn drop(&mut self) { unsafe { - rocksdb_ffi::rocksdb_iter_destroy(self.inner); + ffi::rocksdb_iter_destroy(self.inner); } } } impl<'a> Snapshot<'a> { pub fn new(db: &DB) -> Snapshot { - let snapshot = - unsafe { rocksdb_ffi::rocksdb_create_snapshot(db.inner) }; + let snapshot = unsafe { ffi::rocksdb_create_snapshot(db.inner) }; Snapshot { db: db, inner: snapshot, @@ -231,26 +245,19 @@ impl<'a> Snapshot<'a> { DBIterator::new(self.db, &readopts, mode) } - pub fn iterator_cf(&self, - cf_handle: DBCFHandle, - mode: IteratorMode) - -> Result { + pub fn iterator_cf(&self, cf_handle: *mut ffi::rocksdb_column_family_handle_t, mode: IteratorMode) -> Result { let mut readopts = ReadOptions::default(); readopts.set_snapshot(self); DBIterator::new_cf(self.db, cf_handle, &readopts, mode) } - pub fn get(&self, key: &[u8]) -> Result, Error> { let mut readopts = ReadOptions::default(); readopts.set_snapshot(self); self.db.get_opt(key, &readopts) } - pub fn get_cf(&self, - cf: DBCFHandle, - key: &[u8]) - -> Result, Error> { + pub fn get_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8]) -> Result, Error> { let mut readopts = ReadOptions::default(); readopts.set_snapshot(self); self.db.get_cf_opt(cf, key, &readopts) @@ -260,31 +267,23 @@ impl<'a> Snapshot<'a> { impl<'a> Drop for Snapshot<'a> { fn drop(&mut self) { unsafe { - rocksdb_ffi::rocksdb_release_snapshot(self.db.inner, self.inner); + ffi::rocksdb_release_snapshot(self.db.inner, self.inner); } } } -// This is for the DB and write batches to share the same API +// This is for the DB and write batches to share the same API. pub trait Writable { fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error>; - fn put_cf(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8]) - -> Result<(), Error>; + fn put_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error>; fn merge(&self, key: &[u8], value: &[u8]) -> Result<(), Error>; - fn merge_cf(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8]) - -> Result<(), Error>; + fn merge_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error>; fn delete(&self, key: &[u8]) -> Result<(), Error>; - fn delete_cf(&self, cf: DBCFHandle, key: &[u8]) -> Result<(), Error>; + fn delete_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8]) -> Result<(), Error>; } impl DB { - /// Open a database with default options + /// Open a database with default options. pub fn open_default>(path: P) -> Result { let mut opts = Options::default(); opts.create_if_missing(true); @@ -303,82 +302,54 @@ impl DB { /// # Panics /// /// * Panics if the column family doesn't exist - pub fn open_cf>(opts: &Options, - path: P, - cfs: &[&str]) - -> Result { + pub fn open_cf>(opts: &Options, path: P, cfs: &[&str]) -> Result { let path = path.as_ref(); let cpath = match CString::new(path.to_string_lossy().as_bytes()) { Ok(c) => c, Err(_) => { - return Err(Error::new("Failed to convert path to CString \ - when opening rocksdb" - .to_string())) + return Err(Error::new("Failed to convert path to CString when opening rocksdb".to_owned())) } }; let cpath_ptr = cpath.as_ptr(); if let Err(e) = fs::create_dir_all(&path) { - return Err(Error::new(format!("Failed to create rocksdb \ - directory: {:?}", - e))); + return Err(Error::new(format!("Failed to create rocksdb directory: {:?}", e))); } - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - let db: rocksdb_ffi::DBInstance; + let mut err: *mut c_char = ptr::null_mut(); + let db: *mut ffi::rocksdb_t; let mut cf_map = BTreeMap::new(); if cfs.len() == 0 { unsafe { - db = rocksdb_ffi::rocksdb_open(opts.inner, - cpath_ptr as *const _, - err_ptr); + db = ffi::rocksdb_open(opts.inner, cpath_ptr as *const _, &mut err); } } else { let mut cfs_v = cfs.to_vec(); - // Always open the default column family + // Always open the default column family. if !cfs_v.contains(&"default") { cfs_v.push("default"); } - // We need to store our CStrings in an intermediate vector - // so that their pointers remain valid. - let c_cfs: Vec = cfs_v.iter() - .map(|cf| CString::new(cf.as_bytes()).unwrap()) - .collect(); + // We need to store our CStrings in an intermediate vector so that their pointers remain valid. + let c_cfs: Vec = cfs_v.iter().map(|cf| CString::new(cf.as_bytes()).unwrap()).collect(); - let cfnames: Vec<*const _> = c_cfs.iter() - .map(|cf| cf.as_ptr()) - .collect(); + let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect(); // These handles will be populated by DB. - let cfhandles: Vec = cfs_v.iter() - .map(|_| 0 as rocksdb_ffi::DBCFHandle) - .collect(); + let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect(); // TODO(tyler) allow options to be passed in. - let cfopts: Vec = cfs_v.iter() - .map(|_| unsafe { rocksdb_ffi::rocksdb_options_create() }) - .collect(); - - // Prepare to ship to C. - let copts: *const rocksdb_ffi::DBOptions = cfopts.as_ptr(); - let handles: *const rocksdb_ffi::DBCFHandle = cfhandles.as_ptr(); - let nfam = cfs_v.len(); + let cfopts: Vec<_> = cfs_v.iter().map(|_| unsafe { ffi::rocksdb_options_create() as *const _ }).collect(); + unsafe { - db = rocksdb_ffi::rocksdb_open_column_families(opts.inner, cpath_ptr as *const _, - nfam as libc::c_int, - cfnames.as_ptr() as *const _, - copts, handles, err_ptr); + db = ffi::rocksdb_open_column_families(opts.inner, cpath_ptr as *const _, cfs_v.len() as c_int, cfnames.as_ptr() as *const _, cfopts.as_ptr(), cfhandles.as_mut_ptr(), &mut err); } for handle in &cfhandles { if handle.is_null() { - return Err(Error::new("Received null column family \ - handle from DB." - .to_string())); + return Err(Error::new("Received null column family handle from DB.".to_owned())); } } @@ -391,8 +362,7 @@ impl DB { return Err(Error::new(error_message(err))); } if db.is_null() { - return Err(Error::new("Could not initialize database." - .to_string())); + return Err(Error::new("Could not initialize database.".to_owned())); } Ok(DB { @@ -404,14 +374,9 @@ impl DB { pub fn destroy>(opts: &Options, path: P) -> Result<(), Error> { let cpath = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap(); - let cpath_ptr = cpath.as_ptr(); - - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; + let mut err: *mut c_char = ptr::null_mut(); unsafe { - rocksdb_ffi::rocksdb_destroy_db(opts.inner, - cpath_ptr as *const _, - err_ptr); + ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr(), &mut err); } if !err.is_null() { return Err(Error::new(error_message(err))); @@ -421,14 +386,9 @@ impl DB { pub fn repair>(opts: Options, path: P) -> Result<(), Error> { let cpath = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap(); - let cpath_ptr = cpath.as_ptr(); - - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; + let mut err: *mut c_char = ptr::null_mut(); unsafe { - rocksdb_ffi::rocksdb_repair_db(opts.inner, - cpath_ptr as *const _, - err_ptr); + ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr(), &mut err); } if !err.is_null() { return Err(Error::new(error_message(err))); @@ -440,17 +400,10 @@ impl DB { &self.path.as_path() } - pub fn write_opt(&self, - batch: WriteBatch, - writeopts: &WriteOptions) - -> Result<(), Error> { - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; + pub fn write_opt(&self, batch: WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> { + let mut err: *mut c_char = ptr::null_mut(); unsafe { - rocksdb_ffi::rocksdb_write(self.inner, - writeopts.inner, - batch.inner, - err_ptr); + ffi::rocksdb_write(self.inner, writeopts.inner, batch.inner, &mut err); } if !err.is_null() { return Err(Error::new(error_message(err))); @@ -468,31 +421,15 @@ impl DB { self.write_opt(batch, &wo) } - pub fn get_opt(&self, - key: &[u8], - readopts: &ReadOptions) - -> Result, Error> { + pub fn get_opt(&self, key: &[u8], readopts: &ReadOptions) -> Result, Error> { if readopts.inner.is_null() { - return Err(Error::new("Unable to create rocksdb read options. \ - This is a fairly trivial call, and its \ - failure may be indicative of a \ - mis-compiled or mis-loaded rocksdb \ - library." - .to_string())); + return Err(Error::new("Unable to create rocksdb read options. This is a fairly trivial call, and its failure may be indicative of a mis-compiled or mis-loaded rocksdb library.".to_owned())); } unsafe { - let val_len: size_t = 0; - let val_len_ptr = &val_len as *const size_t; - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - let val = - rocksdb_ffi::rocksdb_get(self.inner, - readopts.inner, - key.as_ptr(), - key.len() as size_t, - val_len_ptr, - err_ptr) as *mut u8; + let mut val_len: size_t = 0; + let mut err: *mut c_char = ptr::null_mut(); + let val = ffi::rocksdb_get(self.inner, readopts.inner, key.as_ptr() as *const c_char, key.len() as size_t, &mut val_len, &mut err) as *mut u8; if !err.is_null() { return Err(Error::new(error_message(err))); } @@ -509,33 +446,15 @@ impl DB { self.get_opt(key, &ReadOptions::default()) } - pub fn get_cf_opt(&self, - cf: DBCFHandle, - key: &[u8], - readopts: &ReadOptions) - -> Result, Error> { + pub fn get_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], readopts: &ReadOptions) -> Result, Error> { if readopts.inner.is_null() { - return Err(Error::new("Unable to create rocksdb read options. \ - This is a fairly trivial call, and its \ - failure may be indicative of a \ - mis-compiled or mis-loaded rocksdb \ - library." - .to_string())); + return Err(Error::new("Unable to create rocksdb read options. This is a fairly trivial call, and its failure may be indicative of a mis-compiled or mis-loaded rocksdb library.".to_owned())); } unsafe { - let val_len: size_t = 0; - let val_len_ptr = &val_len as *const size_t; - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - let val = - rocksdb_ffi::rocksdb_get_cf(self.inner, - readopts.inner, - cf, - key.as_ptr(), - key.len() as size_t, - val_len_ptr, - err_ptr) as *mut u8; + let mut val_len: size_t = 0; + let mut err: *mut c_char = ptr::null_mut(); + let val = ffi::rocksdb_get_cf(self.inner, readopts.inner, cf, key.as_ptr() as *const c_char, key.len() as size_t, &mut val_len, &mut err) as *mut u8; if !err.is_null() { return Err(Error::new(error_message(err))); } @@ -547,34 +466,20 @@ impl DB { } } - pub fn get_cf(&self, - cf: DBCFHandle, - key: &[u8]) - -> Result, Error> { + pub fn get_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8]) -> Result, Error> { self.get_cf_opt(cf, key, &ReadOptions::default()) } - pub fn create_cf(&mut self, - name: &str, - opts: &Options) - -> Result { + pub fn create_cf(&mut self, name: &str, opts: &Options) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> { let cname = match CString::new(name.as_bytes()) { Ok(c) => c, Err(_) => { - return Err(Error::new("Failed to convert path to CString \ - when opening rocksdb" - .to_string())) + return Err(Error::new("Failed to convert path to CString when opening rocksdb".to_owned())) } }; - let cname_ptr = cname.as_ptr(); - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; + let mut err: *mut c_char = ptr::null_mut(); let cf_handler = unsafe { - let cf_handler = - rocksdb_ffi::rocksdb_create_column_family(self.inner, - opts.inner, - cname_ptr as *const _, - err_ptr); + let cf_handler = ffi::rocksdb_create_column_family(self.inner, opts.inner, cname.as_ptr(), &mut err); self.cfs.insert(name.to_string(), cf_handler); cf_handler }; @@ -587,26 +492,20 @@ impl DB { pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> { let cf = self.cfs.get(name); if cf.is_none() { - return Err(Error::new(format!("Invalid column family: {}", name) - .to_string())); + return Err(Error::new(format!("Invalid column family: {}", name).to_owned())); } - - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; + let mut err: *mut c_char = ptr::null_mut(); unsafe { - rocksdb_ffi::rocksdb_drop_column_family(self.inner, - *cf.unwrap(), - err_ptr); + ffi::rocksdb_drop_column_family(self.inner, *cf.unwrap(), &mut err); } if !err.is_null() { return Err(Error::new(error_message(err))); } - Ok(()) } - /// Return the underlying column family handle - pub fn cf_handle(&self, name: &str) -> Option<&DBCFHandle> { + /// Return the underlying column family handle. + pub fn cf_handle(&self, name: &str) -> Option<&*mut ffi::rocksdb_column_family_handle_t> { self.cfs.get(name) } @@ -615,10 +514,7 @@ impl DB { DBIterator::new(self, &opts, mode) } - pub fn iterator_cf(&self, - cf_handle: DBCFHandle, - mode: IteratorMode) - -> Result { + pub fn iterator_cf(&self, cf_handle: *mut ffi::rocksdb_column_family_handle_t, mode: IteratorMode) -> Result { let opts = ReadOptions::default(); DBIterator::new_cf(self, cf_handle, &opts, mode) } @@ -627,21 +523,10 @@ impl DB { Snapshot::new(self) } - pub fn put_opt(&self, - key: &[u8], - value: &[u8], - writeopts: &WriteOptions) - -> Result<(), Error> { + pub fn put_opt(&self, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { unsafe { - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - rocksdb_ffi::rocksdb_put(self.inner, - writeopts.inner, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t, - err_ptr); + let mut err: *mut c_char = ptr::null_mut(); + ffi::rocksdb_put(self.inner, writeopts.inner, key.as_ptr() as *const c_char, key.len() as size_t, value.as_ptr() as *const c_char, value.len() as size_t, &mut err); if !err.is_null() { return Err(Error::new(error_message(err))); } @@ -649,105 +534,54 @@ impl DB { } } - pub fn put_cf_opt(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8], - writeopts: &WriteOptions) - -> Result<(), Error> { + pub fn put_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { unsafe { - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - rocksdb_ffi::rocksdb_put_cf(self.inner, - writeopts.inner, - cf, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t, - err_ptr); + let mut err: *mut c_char = ptr::null_mut(); + ffi::rocksdb_put_cf(self.inner, writeopts.inner, cf, key.as_ptr() as *const c_char, key.len() as size_t, value.as_ptr() as *const c_char, value.len() as size_t, &mut err); if !err.is_null() { return Err(Error::new(error_message(err))); } Ok(()) } } - pub fn merge_opt(&self, - key: &[u8], - value: &[u8], - writeopts: &WriteOptions) - -> Result<(), Error> { + + pub fn merge_opt(&self, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { unsafe { - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - rocksdb_ffi::rocksdb_merge(self.inner, - writeopts.inner, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t, - err_ptr); + let mut err: *mut c_char = ptr::null_mut(); + ffi::rocksdb_merge(self.inner, writeopts.inner, key.as_ptr() as *const c_char, key.len() as size_t, value.as_ptr() as *const c_char, value.len() as size_t, &mut err); if !err.is_null() { return Err(Error::new(error_message(err))); } Ok(()) } } - fn merge_cf_opt(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8], - writeopts: &WriteOptions) - -> Result<(), Error> { + + fn merge_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { unsafe { - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - rocksdb_ffi::rocksdb_merge_cf(self.inner, - writeopts.inner, - cf, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t, - err_ptr); + let mut err: *mut c_char = ptr::null_mut(); + ffi::rocksdb_merge_cf(self.inner, writeopts.inner, cf, key.as_ptr() as *const i8, key.len() as size_t, value.as_ptr() as *const i8, value.len() as size_t, &mut err); if !err.is_null() { return Err(Error::new(error_message(err))); } Ok(()) } } - fn delete_opt(&self, - key: &[u8], - writeopts: &WriteOptions) - -> Result<(), Error> { + + fn delete_opt(&self, key: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { unsafe { - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - rocksdb_ffi::rocksdb_delete(self.inner, - writeopts.inner, - key.as_ptr(), - key.len() as size_t, - err_ptr); + let mut err: *mut c_char = ptr::null_mut(); + ffi::rocksdb_delete(self.inner, writeopts.inner, key.as_ptr() as *const c_char, key.len() as size_t, &mut err); if !err.is_null() { return Err(Error::new(error_message(err))); } Ok(()) } } - fn delete_cf_opt(&self, - cf: DBCFHandle, - key: &[u8], - writeopts: &WriteOptions) - -> Result<(), Error> { + + fn delete_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { unsafe { - let mut err: *const i8 = 0 as *const i8; - let err_ptr: *mut *const i8 = &mut err; - rocksdb_ffi::rocksdb_delete_cf(self.inner, - writeopts.inner, - cf, - key.as_ptr(), - key.len() as size_t, - err_ptr); + let mut err: *mut c_char = ptr::null_mut(); + ffi::rocksdb_delete_cf(self.inner, writeopts.inner, cf, key.as_ptr() as *const c_char, key.len() as size_t, &mut err); if !err.is_null() { return Err(Error::new(error_message(err))); } @@ -761,11 +595,7 @@ impl Writable for DB { self.put_opt(key, value, &WriteOptions::default()) } - fn put_cf(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8]) - -> Result<(), Error> { + fn put_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> { self.put_cf_opt(cf, key, value, &WriteOptions::default()) } @@ -773,11 +603,7 @@ impl Writable for DB { self.merge_opt(key, value, &WriteOptions::default()) } - fn merge_cf(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8]) - -> Result<(), Error> { + fn merge_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> { self.merge_cf_opt(cf, key, value, &WriteOptions::default()) } @@ -785,14 +611,14 @@ impl Writable for DB { self.delete_opt(key, &WriteOptions::default()) } - fn delete_cf(&self, cf: DBCFHandle, key: &[u8]) -> Result<(), Error> { + fn delete_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8]) -> Result<(), Error> { self.delete_cf_opt(cf, key, &WriteOptions::default()) } } impl WriteBatch { pub fn len(&self) -> usize { - unsafe { rocksdb_ffi::rocksdb_writebatch_count(self.inner) as usize } + unsafe { ffi::rocksdb_writebatch_count(self.inner) as usize } } pub fn is_empty(&self) -> bool { @@ -803,14 +629,14 @@ impl WriteBatch { impl Default for WriteBatch { fn default() -> WriteBatch { WriteBatch { - inner: unsafe { rocksdb_ffi::rocksdb_writebatch_create() }, + inner: unsafe { ffi::rocksdb_writebatch_create() }, } } } impl Drop for WriteBatch { fn drop(&mut self) { - unsafe { rocksdb_ffi::rocksdb_writebatch_destroy(self.inner) } + unsafe { ffi::rocksdb_writebatch_destroy(self.inner) } } } @@ -818,9 +644,9 @@ impl Drop for DB { fn drop(&mut self) { unsafe { for cf in self.cfs.values() { - rocksdb_ffi::rocksdb_column_family_handle_destroy(*cf); + ffi::rocksdb_column_family_handle_destroy(*cf); } - rocksdb_ffi::rocksdb_close(self.inner); + ffi::rocksdb_close(self.inner); } } } @@ -832,79 +658,48 @@ impl fmt::Debug for DB { } impl Writable for WriteBatch { - /// Insert a value into the database under the given key + /// Insert a value into the database under the given key. fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { unsafe { - rocksdb_ffi::rocksdb_writebatch_put(self.inner, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t); + ffi::rocksdb_writebatch_put(self.inner, key.as_ptr() as *const i8, key.len() as size_t, value.as_ptr() as *const i8, value.len() as size_t); Ok(()) } } - fn put_cf(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8]) - -> Result<(), Error> { + fn put_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> { unsafe { - rocksdb_ffi::rocksdb_writebatch_put_cf(self.inner, - cf, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t); + ffi::rocksdb_writebatch_put_cf(self.inner, cf, key.as_ptr() as *const i8, key.len() as size_t, value.as_ptr() as *const i8, value.len() as size_t); Ok(()) } } fn merge(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { unsafe { - rocksdb_ffi::rocksdb_writebatch_merge(self.inner, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t); + ffi::rocksdb_writebatch_merge(self.inner, key.as_ptr() as *const i8, key.len() as size_t, value.as_ptr() as *const i8, value.len() as size_t); Ok(()) } } - fn merge_cf(&self, - cf: DBCFHandle, - key: &[u8], - value: &[u8]) - -> Result<(), Error> { + fn merge_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> { unsafe { - rocksdb_ffi::rocksdb_writebatch_merge_cf(self.inner, - cf, - key.as_ptr(), - key.len() as size_t, - value.as_ptr(), - value.len() as size_t); + ffi::rocksdb_writebatch_merge_cf(self.inner, cf, key.as_ptr() as *const i8, key.len() as size_t, value.as_ptr() as *const i8, value.len() as size_t); Ok(()) } } - /// Remove the database entry for key + /// Remove the database entry for key. /// /// Returns Err if the key was not found fn delete(&self, key: &[u8]) -> Result<(), Error> { unsafe { - rocksdb_ffi::rocksdb_writebatch_delete(self.inner, - key.as_ptr(), - key.len() as size_t); + ffi::rocksdb_writebatch_delete(self.inner, key.as_ptr() as *const i8, key.len() as size_t); Ok(()) } } - fn delete_cf(&self, cf: DBCFHandle, key: &[u8]) -> Result<(), Error> { + fn delete_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8]) -> Result<(), Error> { unsafe { - rocksdb_ffi::rocksdb_writebatch_delete_cf(self.inner, - cf, - key.as_ptr(), - key.len() as size_t); + ffi::rocksdb_writebatch_delete_cf(self.inner, cf, key.as_ptr() as *const i8, key.len() as size_t); Ok(()) } } @@ -912,7 +707,7 @@ impl Writable for WriteBatch { impl Drop for ReadOptions { fn drop(&mut self) { - unsafe { rocksdb_ffi::rocksdb_readoptions_destroy(self.inner) } + unsafe { ffi::rocksdb_readoptions_destroy(self.inner) } } } @@ -923,22 +718,19 @@ impl ReadOptions { #[allow(dead_code)] fn fill_cache(&mut self, v: bool) { unsafe { - rocksdb_ffi::rocksdb_readoptions_set_fill_cache(self.inner, v); + ffi::rocksdb_readoptions_set_fill_cache(self.inner, v as c_uchar); } } fn set_snapshot(&mut self, snapshot: &Snapshot) { unsafe { - rocksdb_ffi::rocksdb_readoptions_set_snapshot(self.inner, - snapshot.inner); + ffi::rocksdb_readoptions_set_snapshot(self.inner, snapshot.inner); } } pub fn set_iterate_upper_bound(&mut self, key: &[u8]) { unsafe { - rocksdb_ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, - key.as_ptr(), - key.len() as size_t); + ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, key.as_ptr() as *const i8, key.len() as size_t); } } } @@ -946,7 +738,7 @@ impl ReadOptions { impl Default for ReadOptions { fn default() -> ReadOptions { unsafe { - ReadOptions { inner: rocksdb_ffi::rocksdb_readoptions_create() } + ReadOptions { inner: ffi::rocksdb_readoptions_create() } } } } @@ -959,6 +751,7 @@ pub struct DBVector { impl Deref for DBVector { type Target = [u8]; + fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.base, self.len) } } @@ -967,7 +760,7 @@ impl Deref for DBVector { impl Drop for DBVector { fn drop(&mut self) { unsafe { - libc::free(self.base as *mut libc::c_void); + libc::free(self.base as *mut c_void); } } } @@ -1010,10 +803,7 @@ fn errors_do_stuff() { // The DB will still be open when we try to destroy and the lock should fail match DB::destroy(&opts, path) { Err(s) => { - assert!(s == - Error::new("IO error: lock _rust_rocksdb_error/LOCK: No \ - locks available" - .to_string())) + assert!(s == Error::new("IO error: lock _rust_rocksdb_error/LOCK: No locks available".to_owned())) } Ok(_) => panic!("should fail"), } @@ -1067,9 +857,7 @@ fn iterator_test() { assert!(p.is_ok()); let iter = db.iterator(IteratorMode::Start); for (k, v) in iter { - println!("Hello {}: {}", - from_utf8(&*k).unwrap(), - from_utf8(&*v).unwrap()); + println!("Hello {}: {}", from_utf8(&*k).unwrap(), from_utf8(&*v).unwrap()); } } let opts = Options::default(); diff --git a/src/rocksdb_options.rs b/src/rocksdb_options.rs index 327bd99..50ec7de 100644 --- a/src/rocksdb_options.rs +++ b/src/rocksdb_options.rs @@ -12,32 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. // -extern crate libc; -use self::libc::{c_int, size_t, c_void}; + use std::ffi::{CStr, CString}; use std::mem; -use rocksdb_ffi::{self, DBCompressionType, DBRecoveryMode}; -use merge_operator::{self, MergeFn, MergeOperatorCallback, - full_merge_callback, partial_merge_callback}; -use comparator::{self, ComparatorCallback, compare_callback}; +use libc::{self, c_int, c_uint, c_uchar, c_void, size_t, uint64_t}; -pub struct BlockBasedOptions { - inner: rocksdb_ffi::DBBlockBasedTableOptions, -} - -pub struct Options { - pub inner: rocksdb_ffi::DBOptions, -} - -pub struct WriteOptions { - pub inner: rocksdb_ffi::DBWriteOptions, -} +use {Options, WriteOptions, BlockBasedOptions}; +use comparator::{self, ComparatorCallback}; +use ffi; +use merge_operator::{self, MergeFn, MergeOperatorCallback, full_merge_callback, partial_merge_callback}; +use rocksdb::{DBCompressionType, DBCompactionStyle, DBRecoveryMode, new_cache}; impl Drop for Options { fn drop(&mut self) { unsafe { - rocksdb_ffi::rocksdb_options_destroy(self.inner); + ffi::rocksdb_options_destroy(self.inner); } } } @@ -45,7 +35,7 @@ impl Drop for Options { impl Drop for BlockBasedOptions { fn drop(&mut self) { unsafe { - rocksdb_ffi::rocksdb_block_based_options_destroy(self.inner); + ffi::rocksdb_block_based_options_destroy(self.inner); } } } @@ -53,7 +43,7 @@ impl Drop for BlockBasedOptions { impl Drop for WriteOptions { fn drop(&mut self) { unsafe { - rocksdb_ffi::rocksdb_writeoptions_destroy(self.inner); + ffi::rocksdb_writeoptions_destroy(self.inner); } } } @@ -61,37 +51,33 @@ impl Drop for WriteOptions { impl BlockBasedOptions { pub fn set_block_size(&mut self, size: usize) { unsafe { - rocksdb_ffi::rocksdb_block_based_options_set_block_size(self.inner, - size); + ffi::rocksdb_block_based_options_set_block_size(self.inner, size); } } pub fn set_lru_cache(&mut self, size: size_t) { - let cache = rocksdb_ffi::new_cache(size); + let cache = new_cache(size); unsafe { - // because cache is wrapped in shared_ptr, so we don't need to call - // rocksdb_cache_destroy explicitly. - rocksdb_ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache); + // Since cache is wrapped in shared_ptr, we don't need to call rocksdb_cache_destroy explicitly. + ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache); } } pub fn set_bloom_filter(&mut self, bits_per_key: c_int, block_based: bool) { unsafe { let bloom = if block_based { - rocksdb_ffi::rocksdb_filterpolicy_create_bloom(bits_per_key) + ffi::rocksdb_filterpolicy_create_bloom(bits_per_key) } else { - rocksdb_ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key) + ffi::rocksdb_filterpolicy_create_bloom_full(bits_per_key) }; - rocksdb_ffi::rocksdb_block_based_options_set_filter_policy(self.inner, - bloom); + ffi::rocksdb_block_based_options_set_filter_policy(self.inner, bloom); } } pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) { unsafe { - rocksdb_ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(self.inner, - v as u8); + ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(self.inner, v as u8); } } } @@ -99,10 +85,10 @@ impl BlockBasedOptions { impl Default for BlockBasedOptions { fn default() -> BlockBasedOptions { let block_opts = unsafe { - rocksdb_ffi::rocksdb_block_based_options_create() + ffi::rocksdb_block_based_options_create() }; if block_opts.is_null() { - panic!("Could not create rocksdb block based options".to_string()); + panic!("Could not create rocksdb block based options".to_owned()); } BlockBasedOptions { inner: block_opts } } @@ -125,16 +111,13 @@ impl Options { /// ``` pub fn increase_parallelism(&mut self, parallelism: i32) { unsafe { - rocksdb_ffi::rocksdb_options_increase_parallelism(self.inner, - parallelism); + ffi::rocksdb_options_increase_parallelism(self.inner, parallelism); } } - pub fn optimize_level_style_compaction(&mut self, - memtable_memory_budget: i32) { + pub fn optimize_level_style_compaction(&mut self, memtable_memory_budget: usize) { unsafe { - rocksdb_ffi::rocksdb_options_optimize_level_style_compaction( - self.inner, memtable_memory_budget); + ffi::rocksdb_options_optimize_level_style_compaction(self.inner, memtable_memory_budget as uint64_t); } } @@ -152,8 +135,7 @@ impl Options { /// ``` pub fn create_if_missing(&mut self, create_if_missing: bool) { unsafe { - rocksdb_ffi::rocksdb_options_set_create_if_missing( - self.inner, create_if_missing); + ffi::rocksdb_options_set_create_if_missing(self.inner, create_if_missing as c_uchar); } } @@ -173,7 +155,7 @@ impl Options { /// ``` pub fn set_compression_type(&mut self, t: DBCompressionType) { unsafe { - rocksdb_ffi::rocksdb_options_set_compression(self.inner, t); + ffi::rocksdb_options_set_compression(self.inner, t as c_int); } } @@ -201,74 +183,52 @@ impl Options { /// ``` pub fn compression_per_level(&mut self, level_types: &[DBCompressionType]) { unsafe { - rocksdb_ffi::rocksdb_options_set_compression_per_level(self.inner, - level_types.as_ptr(), - level_types.len() as size_t) + let level_types: Vec<_> = level_types.iter().map(|&t| t as c_int).collect(); + ffi::rocksdb_options_set_compression_per_level(self.inner, level_types.as_ptr(), level_types.len() as size_t) } } - pub fn set_merge_operator(&mut self, - name: &str, - merge_fn: MergeFn) { + pub fn set_merge_operator(&mut self, name: &str, merge_fn: MergeFn) { let cb = Box::new(MergeOperatorCallback { name: CString::new(name.as_bytes()).unwrap(), merge_fn: merge_fn, }); unsafe { - let mo = rocksdb_ffi::rocksdb_mergeoperator_create( - mem::transmute(cb), - merge_operator::destructor_callback, - full_merge_callback, - partial_merge_callback, - None, - merge_operator::name_callback); - rocksdb_ffi::rocksdb_options_set_merge_operator(self.inner, mo); + let mo = ffi::rocksdb_mergeoperator_create(mem::transmute(cb), Some(merge_operator::destructor_callback), Some(full_merge_callback), Some(partial_merge_callback), None, Some(merge_operator::name_callback)); + ffi::rocksdb_options_set_merge_operator(self.inner, mo); } } #[deprecated(since="0.5.0", note="add_merge_operator has been renamed to set_merge_operator")] - pub fn add_merge_operator(&mut self, - name: &str, - merge_fn: MergeFn) { + pub fn add_merge_operator(&mut self, name: &str, merge_fn: MergeFn) { self.set_merge_operator(name, merge_fn); } /// Sets the comparator used to define the order of keys in the table. /// Default: a comparator that uses lexicographic byte-wise ordering /// - /// The client must ensure that the comparator supplied here has the - //// same name and orders keys *exactly* the same as the comparator - /// provided to previous open calls on the same DB. - pub fn set_comparator(&mut self, - name: &str, - compare_fn: fn(&[u8], &[u8]) -> i32) { + /// The client must ensure that the comparator supplied here has the same name and orders keys *exactly* the same as the comparator provided to previous open calls on the same DB. + pub fn set_comparator(&mut self, name: &str, compare_fn: fn(&[u8], &[u8]) -> i32) { let cb = Box::new(ComparatorCallback { name: CString::new(name.as_bytes()).unwrap(), f: compare_fn, }); unsafe { - let cmp = rocksdb_ffi::rocksdb_comparator_create( - mem::transmute(cb), - comparator::destructor_callback, - compare_callback, - comparator::name_callback); - rocksdb_ffi::rocksdb_options_set_comparator(self.inner, cmp); + let cmp = ffi::rocksdb_comparator_create(mem::transmute(cb), Some(comparator::destructor_callback), Some(comparator::compare_callback), Some(comparator::name_callback)); + ffi::rocksdb_options_set_comparator(self.inner, cmp); } } - #[deprecated(since="0.5.0", note="add_comparator has been renamed to set_comparator")] - pub fn add_comparator(&mut self, - name: &str, - compare_fn: fn(&[u8], &[u8]) -> i32) { + #[deprecated(since = "0.5.0", note = "add_comparator has been renamed to set_comparator")] + pub fn add_comparator(&mut self, name: &str, compare_fn: fn(&[u8], &[u8]) -> i32) { self.set_comparator(name, compare_fn); } pub fn optimize_for_point_lookup(&mut self, cache_size: u64) { unsafe { - rocksdb_ffi::rocksdb_options_optimize_for_point_lookup(self.inner, - cache_size); + ffi::rocksdb_options_optimize_for_point_lookup(self.inner, cache_size); } } @@ -290,7 +250,7 @@ impl Options { /// ``` pub fn set_max_open_files(&mut self, nfiles: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_max_open_files(self.inner, nfiles); + ffi::rocksdb_options_set_max_open_files(self.inner, nfiles); } } @@ -311,11 +271,7 @@ impl Options { /// ``` pub fn set_use_fsync(&mut self, useit: bool) { unsafe { - if useit { - rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 1) - } else { - rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 0) - } + ffi::rocksdb_options_set_use_fsync(self.inner, useit as c_int) } } @@ -343,17 +299,13 @@ impl Options { /// ``` pub fn set_bytes_per_sync(&mut self, nbytes: u64) { unsafe { - rocksdb_ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes); + ffi::rocksdb_options_set_bytes_per_sync(self.inner, nbytes); } } pub fn set_disable_data_sync(&mut self, disable: bool) { unsafe { - if disable { - rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner, 1) - } else { - rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner, 0) - } + ffi::rocksdb_options_set_disable_data_sync(self.inner, disable as c_int) } } @@ -386,8 +338,7 @@ impl Options { /// ``` pub fn allow_os_buffer(&mut self, is_allow: bool) { unsafe { - rocksdb_ffi::rocksdb_options_set_allow_os_buffer(self.inner, - is_allow); + ffi::rocksdb_options_set_allow_os_buffer(self.inner, is_allow as c_uchar); } } @@ -405,8 +356,7 @@ impl Options { /// ``` pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, - nbits); + ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, nbits); } } @@ -430,8 +380,7 @@ impl Options { /// ``` pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge( - self.inner, nbuf); + ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, nbuf); } } @@ -470,8 +419,7 @@ impl Options { /// ``` pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_max_write_buffer_number(self.inner, - nbuf); + ffi::rocksdb_options_set_max_write_buffer_number(self.inner, nbuf); } } @@ -502,8 +450,7 @@ impl Options { /// ``` pub fn set_write_buffer_size(&mut self, size: usize) { unsafe { - rocksdb_ffi::rocksdb_options_set_write_buffer_size(self.inner, - size); + ffi::rocksdb_options_set_write_buffer_size(self.inner, size); } } @@ -530,7 +477,7 @@ impl Options { /// ``` pub fn set_max_bytes_for_level_base(&mut self, size: u64) { unsafe { - rocksdb_ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size); + ffi::rocksdb_options_set_max_bytes_for_level_base(self.inner, size); } } @@ -546,7 +493,7 @@ impl Options { /// ``` pub fn set_max_bytes_for_level_multiplier(&mut self, mul: i32) { unsafe { - rocksdb_ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul); + ffi::rocksdb_options_set_max_bytes_for_level_multiplier(self.inner, mul); } } @@ -564,7 +511,7 @@ impl Options { /// ``` pub fn set_max_manifest_file_size(&mut self, size: usize) { unsafe { - rocksdb_ffi::rocksdb_options_set_max_manifest_file_size(self.inner, size); + ffi::rocksdb_options_set_max_manifest_file_size(self.inner, size); } } @@ -591,8 +538,7 @@ impl Options { /// ``` pub fn set_target_file_size_base(&mut self, size: u64) { unsafe { - rocksdb_ffi::rocksdb_options_set_target_file_size_base(self.inner, - size); + ffi::rocksdb_options_set_target_file_size_base(self.inner, size); } } @@ -616,8 +562,7 @@ impl Options { /// ``` pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge( - self.inner, to_merge); + ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, to_merge); } } @@ -638,8 +583,7 @@ impl Options { /// ``` pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_level0_file_num_compaction_trigger( - self.inner, n); + ffi::rocksdb_options_set_level0_file_num_compaction_trigger(self.inner, n); } } @@ -661,8 +605,7 @@ impl Options { /// ``` pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_level0_slowdown_writes_trigger( - self.inner, n); + ffi::rocksdb_options_set_level0_slowdown_writes_trigger(self.inner, n); } } @@ -682,8 +625,7 @@ impl Options { /// ``` pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_level0_stop_writes_trigger( - self.inner, n); + ffi::rocksdb_options_set_level0_stop_writes_trigger(self.inner, n); } } @@ -699,11 +641,9 @@ impl Options { /// let mut opts = Options::default(); /// opts.set_compaction_style(DBCompactionStyle::Universal); /// ``` - pub fn set_compaction_style(&mut self, - style: rocksdb_ffi::DBCompactionStyle) { + pub fn set_compaction_style(&mut self, style: DBCompactionStyle) { unsafe { - rocksdb_ffi::rocksdb_options_set_compaction_style(self.inner, - style); + ffi::rocksdb_options_set_compaction_style(self.inner, style as c_int); } } @@ -731,8 +671,7 @@ impl Options { /// ``` pub fn set_max_background_compactions(&mut self, n: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_max_background_compactions( - self.inner, n); + ffi::rocksdb_options_set_max_background_compactions(self.inner, n); } } @@ -763,8 +702,7 @@ impl Options { /// ``` pub fn set_max_background_flushes(&mut self, n: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_max_background_flushes(self.inner, - n); + ffi::rocksdb_options_set_max_background_flushes(self.inner, n); } } @@ -784,20 +722,14 @@ impl Options { /// opts.set_disable_auto_compactions(true); /// ``` pub fn set_disable_auto_compactions(&mut self, disable: bool) { - let c_bool = if disable { - 1 - } else { - 0 - }; unsafe { - rocksdb_ffi::rocksdb_options_set_disable_auto_compactions(self.inner, c_bool) + ffi::rocksdb_options_set_disable_auto_compactions(self.inner, disable as c_int) } } - pub fn set_block_based_table_factory(&mut self, - factory: &BlockBasedOptions) { + pub fn set_block_based_table_factory(&mut self, factory: &BlockBasedOptions) { unsafe { - rocksdb_ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner); + ffi::rocksdb_options_set_block_based_table_factory(self.inner, factory.inner); } } @@ -815,11 +747,7 @@ impl Options { /// ``` pub fn set_report_bg_io_stats(&mut self, enable: bool) { unsafe { - if enable { - rocksdb_ffi::rocksdb_options_set_report_bg_io_stats(self.inner, 1); - } else { - rocksdb_ffi::rocksdb_options_set_report_bg_io_stats(self.inner, 0); - } + ffi::rocksdb_options_set_report_bg_io_stats(self.inner, enable as c_int); } } @@ -837,26 +765,24 @@ impl Options { /// ``` pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) { unsafe { - rocksdb_ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode); + ffi::rocksdb_options_set_wal_recovery_mode(self.inner, mode as c_int); } } pub fn enable_statistics(&mut self) { unsafe { - rocksdb_ffi::rocksdb_options_enable_statistics(self.inner); + ffi::rocksdb_options_enable_statistics(self.inner); } } pub fn get_statistics(&self) -> Option { unsafe { - let value = rocksdb_ffi::rocksdb_options_statistics_get_string(self.inner); - - + let value = ffi::rocksdb_options_statistics_get_string(self.inner); if value.is_null() { return None; } - // Must valid UTF-8 format. + // Must have valid UTF-8 format. let s = CStr::from_ptr(value).to_str().unwrap().to_owned(); libc::free(value as *mut c_void); Some(s) @@ -875,17 +801,16 @@ impl Options { /// let mut opts = Options::default(); /// opts.set_stats_dump_period_sec(300); /// ``` - pub fn set_stats_dump_period_sec(&mut self, period: usize) { + pub fn set_stats_dump_period_sec(&mut self, period: c_uint) { unsafe { - rocksdb_ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, - period); + ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, period); } } /// Sets the number of levels for this database pub fn set_num_levels(&mut self, n: c_int) { unsafe { - rocksdb_ffi::rocksdb_options_set_num_levels(self.inner, n); + ffi::rocksdb_options_set_num_levels(self.inner, n); } } } @@ -893,9 +818,9 @@ impl Options { impl Default for Options { fn default() -> Options { unsafe { - let opts = rocksdb_ffi::rocksdb_options_create(); + let opts = ffi::rocksdb_options_create(); if opts.is_null() { - panic!("Could not create rocksdb options".to_string()); + panic!("Could not create rocksdb options".to_owned()); } Options { inner: opts } } @@ -910,26 +835,22 @@ impl WriteOptions { pub fn set_sync(&mut self, sync: bool) { unsafe { - rocksdb_ffi::rocksdb_writeoptions_set_sync(self.inner, sync); + ffi::rocksdb_writeoptions_set_sync(self.inner, sync as c_uchar); } } pub fn disable_wal(&mut self, disable: bool) { unsafe { - if disable { - rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 1); - } else { - rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 0); - } + ffi::rocksdb_writeoptions_disable_WAL(self.inner, disable as c_int); } } } impl Default for WriteOptions { fn default() -> WriteOptions { - let write_opts = unsafe { rocksdb_ffi::rocksdb_writeoptions_create() }; + let write_opts = unsafe { ffi::rocksdb_writeoptions_create() }; if write_opts.is_null() { - panic!("Could not create rocksdb write options".to_string()); + panic!("Could not create rocksdb write options".to_owned()); } WriteOptions { inner: write_opts } } @@ -937,7 +858,7 @@ impl Default for WriteOptions { #[cfg(test)] mod tests { - use super::Options; + use Options; #[test] fn test_enable_statistics() {