Merge pull request #87 from alexreg/cleanup

Performed lots of clean-up on code.
master
Tyler Neely 8 years ago committed by GitHub
commit 27210b42bc
  1. 8
      Cargo.toml
  2. 4
      rocksdb-sys/Cargo.toml
  3. 3
      rocksdb-sys/build.rs
  4. 500
      rocksdb-sys/src/ffi.rs
  5. 691
      rocksdb-sys/src/lib.rs
  6. 87
      rocksdb-sys/src/test.rs
  7. 966
      rocksdb-sys/tests/ffi.rs
  8. 35
      src/comparator.rs
  9. 31
      src/lib.rs
  10. 101
      src/merge_operator.rs
  11. 560
      src/rocksdb.rs
  12. 233
      src/rocksdb_options.rs

@ -1,7 +1,6 @@
[package] [package]
name = "rocksdb" 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" version = "0.4.1"
authors = ["Tyler Neely <t@jujit.su>", "David Greenberg <dsg123456789@gmail.com>"] authors = ["Tyler Neely <t@jujit.su>", "David Greenberg <dsg123456789@gmail.com>"]
license = "Apache-2.0" license = "Apache-2.0"
@ -15,11 +14,10 @@ exclude = [
] ]
[features] [features]
default=[] default = []
valgrind=[] valgrind = []
[[test]] [[test]]
name = "test" name = "test"
path = "test/test.rs" path = "test/test.rs"

@ -18,5 +18,9 @@ static = []
[dependencies] [dependencies]
libc = "0.2" libc = "0.2"
[dev-dependencies]
const-cstr = "0.2"
[build-dependencies] [build-dependencies]
gcc = { version = "0.3", features = ["parallel"] } gcc = { version = "0.3", features = ["parallel"] }
make-cmd = "0.1"

@ -14,6 +14,9 @@ fn link(name: &str, bundled: bool) {
} }
fn build_rocksdb() { fn build_rocksdb() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=rocksdb/");
let mut config = gcc::Config::new(); let mut config = gcc::Config::new();
config.include("rocksdb/include/"); config.include("rocksdb/include/");
config.include("rocksdb/"); config.include("rocksdb/");

@ -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<extern "C" fn(*mut c_void,
value: *const c_char,
value_len: *mut size_t
) -> ()>,
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());
}
}

@ -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"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with 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 // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
pub use ffi as rocksdb_ffi;
pub use ffi::{DBCompactionStyle, DBComparator, DBCompressionType, DBRecoveryMode, new_bloom_filter}; //! Raw bindings for RocksDB.
pub mod ffi; //!
//! 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<unsafe extern "C" fn(state: *mut c_void, k: *const c_char, klen: size_t, v: *const c_char, vlen: size_t)>, deleted: Option<unsafe extern "C" fn(state: *mut c_void, k: *const c_char, klen: size_t)>);
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<unsafe extern "C" fn(state: *mut c_void)>, filter: Option<unsafe extern "C" fn(state: *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 c_uchar) -> c_uchar>, name: Option<unsafe extern "C" fn(state: *mut c_void) -> *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<unsafe extern "C" fn(state: *mut c_void)>, create_compaction_filter: Option<unsafe extern "C" fn(state: *mut c_void, context: *mut rocksdb_compactionfiltercontext_t) -> *mut rocksdb_compactionfilter_t>, name: Option<unsafe extern "C" fn(state: *mut c_void) -> *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<unsafe extern "C" fn(state: *mut c_void)>, compare: Option<unsafe extern "C" fn(state: *mut c_void, a: *const c_char, alen: size_t, b: *const c_char, blen: size_t) -> c_int>, name: Option<unsafe extern "C" fn(state: *mut c_void) -> *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<unsafe extern "C" fn(state: *mut c_void)>, create_filter: Option<unsafe extern "C" fn(state: *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>, key_may_match: Option<unsafe extern "C" fn(state: *mut c_void, key: *const c_char, length: size_t, filter: *const c_char, filter_length: size_t) -> c_uchar>, delete_filter: Option<unsafe extern "C" fn(state: *mut c_void, filter: *const c_char, filter_length: size_t)>, name: Option<unsafe extern "C" fn(state: *mut c_void) -> *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<unsafe extern "C" fn(state: *mut c_void)>, full_merge: Option<unsafe extern "C" fn(state: *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 c_uchar, new_value_length: *mut size_t) -> *mut c_char>, partial_merge: Option<unsafe extern "C" fn(state: *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 c_uchar, new_value_length: *mut size_t) -> *mut c_char>, delete_value: Option<unsafe extern "C" fn(state: *mut c_void, value: *const c_char, value_length: size_t)>, name: Option<unsafe extern "C" fn(state: *mut c_void) -> *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<unsafe extern "C" fn(state: *mut c_void)>, transform: Option<unsafe extern "C" fn(state: *mut c_void, key: *const c_char, length: size_t, dst_length: *mut size_t) -> *mut c_char>, in_domain: Option<unsafe extern "C" fn(state: *mut c_void, key: *const c_char, length: size_t) -> c_uchar>, in_range: Option<unsafe extern "C" fn(state: *mut c_void, key: *const c_char, length: size_t) -> c_uchar>, name: Option<unsafe extern "C" fn(state: *mut c_void) -> *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 { }

@ -0,0 +1,87 @@
//
// 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());
}
}

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

@ -12,44 +12,31 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
extern crate libc;
use self::libc::{c_char, c_int, c_void, size_t};
use std::ffi::CString; use std::ffi::CString;
use std::mem; use std::mem;
use std::slice; use std::slice;
use libc::{c_char, c_int, c_void, size_t};
pub struct ComparatorCallback { pub struct ComparatorCallback {
pub name: CString, pub name: CString,
pub f: fn(&[u8], &[u8]) -> i32, pub f: fn(&[u8], &[u8]) -> i32,
} }
pub extern "C" fn destructor_callback(raw_cb: *mut c_void) { pub unsafe extern "C" fn destructor_callback(raw_cb: *mut c_void) {
// turn this back into a local variable so rust will reclaim it let _: Box<ComparatorCallback> = mem::transmute(raw_cb);
let _: Box<ComparatorCallback> = unsafe { mem::transmute(raw_cb) };
} }
pub extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char { pub unsafe 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 cb: &mut ComparatorCallback =
&mut *(raw_cb as *mut ComparatorCallback);
let ptr = cb.name.as_ptr(); let ptr = cb.name.as_ptr();
ptr as *const c_char ptr as *const c_char
}
} }
pub extern "C" fn compare_callback(raw_cb: *mut c_void, 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 {
a_raw: *const c_char, let cb: &mut ComparatorCallback = &mut *(raw_cb as *mut ComparatorCallback);
a_len: size_t, let a: &[u8] = slice::from_raw_parts(a_raw as *const u8, a_len as usize);
b_raw: *const c_char, let b: &[u8] = slice::from_raw_parts(b_raw as *const u8, b_len as usize);
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) (cb.f)(a, b)
}
} }

@ -12,14 +12,27 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
extern crate rocksdb_sys;
pub use rocksdb_sys::rocksdb_ffi as rocksdb_ffi; extern crate libc;
pub use rocksdb_ffi::{DBCompactionStyle, DBComparator, DBCompressionType, DBRecoveryMode, new_bloom_filter}; extern crate rocksdb_sys as ffi;
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;
pub mod merge_operator; pub mod merge_operator;
pub mod comparator; 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,
}

@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
extern crate libc;
use self::libc::{c_char, c_int, c_void, size_t};
use std::ffi::CString; use std::ffi::CString;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
use libc::{self, c_char, c_int, c_void, size_t};
pub type MergeFn = fn(&[u8], Option<&[u8]>, &mut MergeOperands) -> Vec<u8>; pub type MergeFn = fn(&[u8], Option<&[u8]>, &mut MergeOperands) -> Vec<u8>;
pub struct MergeOperatorCallback { pub struct MergeOperatorCallback {
@ -26,42 +27,20 @@ pub struct MergeOperatorCallback {
pub merge_fn: MergeFn, pub merge_fn: MergeFn,
} }
pub extern "C" fn destructor_callback(raw_cb: *mut c_void) { pub unsafe extern "C" fn destructor_callback(raw_cb: *mut c_void) {
// turn this back into a local variable so rust will reclaim it let _: Box<MergeOperatorCallback> = mem::transmute(raw_cb);
let _: Box<MergeOperatorCallback> = unsafe { mem::transmute(raw_cb) };
} }
pub extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char { pub unsafe extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char {
unsafe { let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
let cb: &mut MergeOperatorCallback = cb.name.as_ptr()
&mut *(raw_cb as *mut MergeOperatorCallback);
let ptr = cb.name.as_ptr();
ptr as *const c_char
}
} }
pub extern "C" fn full_merge_callback(raw_cb: *mut c_void, 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 {
raw_key: *const c_char, let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
key_len: size_t, let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands);
existing_value: *const c_char, let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize);
existing_value_len: size_t, let oldval = slice::from_raw_parts(existing_value as *const u8, existing_value_len as usize);
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); let mut result = (cb.merge_fn)(key, Some(oldval), operands);
result.shrink_to_fit(); result.shrink_to_fit();
// TODO(tan) investigate zero-copy techniques to improve performance // TODO(tan) investigate zero-copy techniques to improve performance
@ -70,27 +49,13 @@ pub extern "C" fn full_merge_callback(raw_cb: *mut c_void,
*new_value_length = result.len() as size_t; *new_value_length = result.len() as size_t;
*success = 1 as u8; *success = 1 as u8;
ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len()); ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len());
buf as *const c_char buf as *mut c_char
}
} }
pub extern "C" fn partial_merge_callback(raw_cb: *mut c_void, 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 {
raw_key: *const c_char, let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
key_len: size_t, let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands);
operands_list: *const *const c_char, let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize);
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); let mut result = (cb.merge_fn)(key, None, operands);
result.shrink_to_fit(); result.shrink_to_fit();
// TODO(tan) investigate zero-copy techniques to improve performance // TODO(tan) investigate zero-copy techniques to improve performance
@ -99,8 +64,7 @@ pub extern "C" fn partial_merge_callback(raw_cb: *mut c_void,
*new_value_length = 1 as size_t; *new_value_length = 1 as size_t;
*success = 1 as u8; *success = 1 as u8;
ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len()); ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len());
buf as *const c_char buf as *mut c_char
}
} }
@ -112,10 +76,7 @@ pub struct MergeOperands {
} }
impl MergeOperands { impl MergeOperands {
fn new(operands_list: *const *const c_char, fn new(operands_list: *const *const c_char, operands_list_len: *const size_t, num_operands: c_int) -> MergeOperands {
operands_list_len: *const size_t,
num_operands: c_int)
-> MergeOperands {
assert!(num_operands >= 0); assert!(num_operands >= 0);
MergeOperands { MergeOperands {
operands_list: operands_list, operands_list: operands_list,
@ -128,6 +89,7 @@ impl MergeOperands {
impl<'a> Iterator for &'a mut MergeOperands { impl<'a> Iterator for &'a mut MergeOperands {
type Item = &'a [u8]; type Item = &'a [u8];
fn next(&mut self) -> Option<&'a [u8]> { fn next(&mut self) -> Option<&'a [u8]> {
if self.cursor == self.num_operands { if self.cursor == self.num_operands {
None None
@ -137,13 +99,11 @@ impl<'a> Iterator for &'a mut MergeOperands {
let base_len = self.operands_list_len as usize; let base_len = self.operands_list_len as usize;
let spacing = mem::size_of::<*const *const u8>(); let spacing = mem::size_of::<*const *const u8>();
let spacing_len = mem::size_of::<*const size_t>(); let spacing_len = mem::size_of::<*const size_t>();
let len_ptr = let len_ptr = (base_len + (spacing_len * self.cursor)) as *const size_t;
(base_len + (spacing_len * self.cursor)) as *const size_t;
let len = *len_ptr as usize; let len = *len_ptr as usize;
let ptr = base + (spacing * self.cursor); let ptr = base + (spacing * self.cursor);
self.cursor += 1; self.cursor += 1;
Some(mem::transmute(slice::from_raw_parts(*(ptr as *const *const u8) Some(mem::transmute(slice::from_raw_parts(*(ptr as *const *const u8) as *const u8, len)))
as *const u8, len)))
} }
} }
} }
@ -154,12 +114,9 @@ impl<'a> Iterator for &'a mut MergeOperands {
} }
} }
#[cfg(test)]
#[allow(unused_variables)] #[allow(unused_variables)]
#[allow(dead_code)] fn test_provided_merge(new_key: &[u8], existing_val: Option<&[u8]>, operands: &mut MergeOperands) -> Vec<u8> {
fn test_provided_merge(new_key: &[u8],
existing_val: Option<&[u8]>,
operands: &mut MergeOperands)
-> Vec<u8> {
let nops = operands.size_hint().0; let nops = operands.size_hint().0;
let mut result: Vec<u8> = Vec::with_capacity(nops); let mut result: Vec<u8> = Vec::with_capacity(nops);
if let Some(v) = existing_val { if let Some(v) = existing_val {
@ -175,12 +132,10 @@ fn test_provided_merge(new_key: &[u8],
result result
} }
#[allow(dead_code)]
#[test] #[test]
fn mergetest() { fn mergetest() {
use rocksdb_options::Options; use {Options};
use rocksdb::{DB, DBVector, Writable}; use rocksdb::{DB, Writable};
let path = "_rust_rocksdb_mergetest"; let path = "_rust_rocksdb_mergetest";
let mut opts = Options::default(); let mut opts = Options::default();
@ -203,7 +158,7 @@ fn mergetest() {
None => println!("did not read valid utf-8 out of the db"), 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"), _ => panic!("value not present"),
} }

@ -13,46 +13,87 @@
// limitations under the License. // limitations under the License.
// //
extern crate libc;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::ffi::CString; use std::ffi::{CStr, CString};
use std::fs; use std::fs;
use std::ops::Deref; use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::ptr;
use std::slice; use std::slice;
use std::str::from_utf8; use std::str::from_utf8;
use std::fmt; use std::fmt;
use self::libc::size_t; use libc::{self, c_char, c_uchar, c_int, c_void, size_t};
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) }
}
use rocksdb_ffi::{self, DBCFHandle, error_message}; pub fn new_cache(capacity: size_t) -> *mut ffi::rocksdb_cache_t {
use rocksdb_options::{Options, WriteOptions}; unsafe { ffi::rocksdb_cache_create_lru(capacity) }
}
pub struct DB { pub struct DB {
inner: rocksdb_ffi::DBInstance, inner: *mut ffi::rocksdb_t,
cfs: BTreeMap<String, DBCFHandle>, cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>,
path: PathBuf, path: PathBuf,
} }
unsafe impl Send for DB {} unsafe impl Send for DB { }
unsafe impl Sync 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 { pub struct WriteBatch {
inner: rocksdb_ffi::DBWriteBatch, inner: *mut ffi::rocksdb_writebatch_t,
} }
pub struct ReadOptions { pub struct ReadOptions {
inner: rocksdb_ffi::DBReadOptions, inner: *mut ffi::rocksdb_readoptions_t,
} }
pub struct Snapshot<'a> { pub struct Snapshot<'a> {
db: &'a DB, db: &'a DB,
inner: rocksdb_ffi::DBSnapshot, inner: *const ffi::rocksdb_snapshot_t,
} }
pub struct DBIterator { pub struct DBIterator {
inner: rocksdb_ffi::DBIterator, inner: *mut ffi::rocksdb_iterator_t,
direction: Direction, direction: Direction,
just_seeked: bool, just_seeked: bool,
} }
@ -98,34 +139,23 @@ impl Iterator for DBIterator {
let native_iter = self.inner; let native_iter = self.inner;
if !self.just_seeked { if !self.just_seeked {
match self.direction { match self.direction {
Direction::Forward => unsafe { Direction::Forward => unsafe { ffi::rocksdb_iter_next(native_iter) },
rocksdb_ffi::rocksdb_iter_next(native_iter) Direction::Reverse => unsafe { ffi::rocksdb_iter_prev(native_iter) },
},
Direction::Reverse => unsafe {
rocksdb_ffi::rocksdb_iter_prev(native_iter)
},
} }
} else { } else {
self.just_seeked = false; 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 mut key_len: size_t = 0;
let key_len_ptr: *mut size_t = &mut key_len; let key_len_ptr: *mut size_t = &mut key_len;
let mut val_len: size_t = 0; let mut val_len: size_t = 0;
let val_len_ptr: *mut size_t = &mut val_len; let val_len_ptr: *mut size_t = &mut val_len;
let key_ptr = unsafe { let key_ptr = unsafe { ffi::rocksdb_iter_key(native_iter, key_len_ptr) as *const c_uchar };
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 { ffi::rocksdb_iter_value(native_iter, val_len_ptr) as *const c_uchar };
let key = let val = unsafe { slice::from_raw_parts(val_ptr, val_len as usize) };
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) };
Some((key.to_vec().into_boxed_slice(), Some((key.to_vec().into_boxed_slice(), val.to_vec().into_boxed_slice()))
val.to_vec().into_boxed_slice()))
} else { } else {
None None
} }
@ -138,21 +168,17 @@ pub enum IteratorMode<'a> {
From(&'a [u8], Direction), From(&'a [u8], Direction),
} }
impl DBIterator { impl DBIterator {
fn new(db: &DB, readopts: &ReadOptions, mode: IteratorMode) -> DBIterator { fn new(db: &DB, readopts: &ReadOptions, mode: IteratorMode) -> DBIterator {
unsafe { unsafe {
let iterator = rocksdb_ffi::rocksdb_create_iterator(db.inner, let iterator = ffi::rocksdb_create_iterator(db.inner, readopts.inner);
readopts.inner);
let mut rv = DBIterator { let mut rv = DBIterator {
inner: iterator, inner: iterator,
direction: Direction::Forward, // blown away by set_mode() direction: Direction::Forward, // blown away by set_mode()
just_seeked: false, just_seeked: false,
}; };
rv.set_mode(mode); rv.set_mode(mode);
rv rv
} }
} }
@ -161,17 +187,15 @@ impl DBIterator {
unsafe { unsafe {
match mode { match mode {
IteratorMode::Start => { IteratorMode::Start => {
rocksdb_ffi::rocksdb_iter_seek_to_first(self.inner); ffi::rocksdb_iter_seek_to_first(self.inner);
self.direction = Direction::Forward; self.direction = Direction::Forward;
} }
IteratorMode::End => { IteratorMode::End => {
rocksdb_ffi::rocksdb_iter_seek_to_last(self.inner); ffi::rocksdb_iter_seek_to_last(self.inner);
self.direction = Direction::Reverse; self.direction = Direction::Reverse;
} }
IteratorMode::From(key, dir) => { IteratorMode::From(key, dir) => {
rocksdb_ffi::rocksdb_iter_seek(self.inner, ffi::rocksdb_iter_seek(self.inner, key.as_ptr() as *const c_char, key.len() as size_t);
key.as_ptr(),
key.len() as size_t);
self.direction = dir; self.direction = dir;
} }
}; };
@ -180,28 +204,19 @@ impl DBIterator {
} }
pub fn valid(&self) -> bool { 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, fn new_cf(db: &DB, cf_handle: *mut ffi::rocksdb_column_family_handle_t, readopts: &ReadOptions, mode: IteratorMode) -> Result<DBIterator, Error> {
cf_handle: DBCFHandle,
readopts: &ReadOptions,
mode: IteratorMode)
-> Result<DBIterator, Error> {
unsafe { unsafe {
let iterator = let iterator = ffi::rocksdb_create_iterator_cf(db.inner, readopts.inner, cf_handle);
rocksdb_ffi::rocksdb_create_iterator_cf(db.inner,
readopts.inner,
cf_handle);
let mut rv = DBIterator { let mut rv = DBIterator {
inner: iterator, inner: iterator,
direction: Direction::Forward, // blown away by set_mode() direction: Direction::Forward, // blown away by set_mode()
just_seeked: false, just_seeked: false,
}; };
rv.set_mode(mode); rv.set_mode(mode);
Ok(rv) Ok(rv)
} }
} }
@ -210,15 +225,14 @@ impl DBIterator {
impl Drop for DBIterator { impl Drop for DBIterator {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_iter_destroy(self.inner); ffi::rocksdb_iter_destroy(self.inner);
} }
} }
} }
impl<'a> Snapshot<'a> { impl<'a> Snapshot<'a> {
pub fn new(db: &DB) -> Snapshot { pub fn new(db: &DB) -> Snapshot {
let snapshot = let snapshot = unsafe { ffi::rocksdb_create_snapshot(db.inner) };
unsafe { rocksdb_ffi::rocksdb_create_snapshot(db.inner) };
Snapshot { Snapshot {
db: db, db: db,
inner: snapshot, inner: snapshot,
@ -231,26 +245,19 @@ impl<'a> Snapshot<'a> {
DBIterator::new(self.db, &readopts, mode) DBIterator::new(self.db, &readopts, mode)
} }
pub fn iterator_cf(&self, pub fn iterator_cf(&self, cf_handle: *mut ffi::rocksdb_column_family_handle_t, mode: IteratorMode) -> Result<DBIterator, Error> {
cf_handle: DBCFHandle,
mode: IteratorMode)
-> Result<DBIterator, Error> {
let mut readopts = ReadOptions::default(); let mut readopts = ReadOptions::default();
readopts.set_snapshot(self); readopts.set_snapshot(self);
DBIterator::new_cf(self.db, cf_handle, &readopts, mode) DBIterator::new_cf(self.db, cf_handle, &readopts, mode)
} }
pub fn get(&self, key: &[u8]) -> Result<Option<DBVector>, Error> { pub fn get(&self, key: &[u8]) -> Result<Option<DBVector>, Error> {
let mut readopts = ReadOptions::default(); let mut readopts = ReadOptions::default();
readopts.set_snapshot(self); readopts.set_snapshot(self);
self.db.get_opt(key, &readopts) self.db.get_opt(key, &readopts)
} }
pub fn get_cf(&self, pub fn get_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8]) -> Result<Option<DBVector>, Error> {
cf: DBCFHandle,
key: &[u8])
-> Result<Option<DBVector>, Error> {
let mut readopts = ReadOptions::default(); let mut readopts = ReadOptions::default();
readopts.set_snapshot(self); readopts.set_snapshot(self);
self.db.get_cf_opt(cf, key, &readopts) self.db.get_cf_opt(cf, key, &readopts)
@ -260,31 +267,23 @@ impl<'a> Snapshot<'a> {
impl<'a> Drop for Snapshot<'a> { impl<'a> Drop for Snapshot<'a> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { 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 { pub trait Writable {
fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error>; fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error>;
fn put_cf(&self, fn put_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error>;
cf: DBCFHandle,
key: &[u8],
value: &[u8])
-> Result<(), Error>;
fn merge(&self, key: &[u8], value: &[u8]) -> Result<(), Error>; fn merge(&self, key: &[u8], value: &[u8]) -> Result<(), Error>;
fn merge_cf(&self, fn merge_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error>;
cf: DBCFHandle,
key: &[u8],
value: &[u8])
-> Result<(), Error>;
fn delete(&self, key: &[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 { impl DB {
/// Open a database with default options /// Open a database with default options.
pub fn open_default<P: AsRef<Path>>(path: P) -> Result<DB, Error> { pub fn open_default<P: AsRef<Path>>(path: P) -> Result<DB, Error> {
let mut opts = Options::default(); let mut opts = Options::default();
opts.create_if_missing(true); opts.create_if_missing(true);
@ -303,82 +302,54 @@ impl DB {
/// # Panics /// # Panics
/// ///
/// * Panics if the column family doesn't exist /// * Panics if the column family doesn't exist
pub fn open_cf<P: AsRef<Path>>(opts: &Options, pub fn open_cf<P: AsRef<Path>>(opts: &Options, path: P, cfs: &[&str]) -> Result<DB, Error> {
path: P,
cfs: &[&str])
-> Result<DB, Error> {
let path = path.as_ref(); let path = path.as_ref();
let cpath = match CString::new(path.to_string_lossy().as_bytes()) { let cpath = match CString::new(path.to_string_lossy().as_bytes()) {
Ok(c) => c, Ok(c) => c,
Err(_) => { Err(_) => {
return Err(Error::new("Failed to convert path to CString \ return Err(Error::new("Failed to convert path to CString when opening rocksdb".to_owned()))
when opening rocksdb"
.to_string()))
} }
}; };
let cpath_ptr = cpath.as_ptr(); let cpath_ptr = cpath.as_ptr();
if let Err(e) = fs::create_dir_all(&path) { if let Err(e) = fs::create_dir_all(&path) {
return Err(Error::new(format!("Failed to create rocksdb \ return Err(Error::new(format!("Failed to create rocksdb directory: {:?}", e)));
directory: {:?}",
e)));
} }
let mut err: *const i8 = 0 as *const i8; let mut err: *mut c_char = ptr::null_mut();
let err_ptr: *mut *const i8 = &mut err; let db: *mut ffi::rocksdb_t;
let db: rocksdb_ffi::DBInstance;
let mut cf_map = BTreeMap::new(); let mut cf_map = BTreeMap::new();
if cfs.len() == 0 { if cfs.len() == 0 {
unsafe { unsafe {
db = rocksdb_ffi::rocksdb_open(opts.inner, db = ffi::rocksdb_open(opts.inner, cpath_ptr as *const _, &mut err);
cpath_ptr as *const _,
err_ptr);
} }
} else { } else {
let mut cfs_v = cfs.to_vec(); let mut cfs_v = cfs.to_vec();
// Always open the default column family // Always open the default column family.
if !cfs_v.contains(&"default") { if !cfs_v.contains(&"default") {
cfs_v.push("default"); cfs_v.push("default");
} }
// We need to store our CStrings in an intermediate vector // We need to store our CStrings in an intermediate vector so that their pointers remain valid.
// so that their pointers remain valid. let c_cfs: Vec<CString> = cfs_v.iter().map(|cf| CString::new(cf.as_bytes()).unwrap()).collect();
let c_cfs: Vec<CString> = cfs_v.iter()
.map(|cf| CString::new(cf.as_bytes()).unwrap())
.collect();
let cfnames: Vec<*const _> = c_cfs.iter() let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect();
.map(|cf| cf.as_ptr())
.collect();
// These handles will be populated by DB. // These handles will be populated by DB.
let cfhandles: Vec<rocksdb_ffi::DBCFHandle> = cfs_v.iter() let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect();
.map(|_| 0 as rocksdb_ffi::DBCFHandle)
.collect();
// TODO(tyler) allow options to be passed in. // TODO(tyler) allow options to be passed in.
let cfopts: Vec<rocksdb_ffi::DBOptions> = cfs_v.iter() let cfopts: Vec<_> = cfs_v.iter().map(|_| unsafe { ffi::rocksdb_options_create() as *const _ }).collect();
.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();
unsafe { unsafe {
db = rocksdb_ffi::rocksdb_open_column_families(opts.inner, cpath_ptr as *const _, 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);
nfam as libc::c_int,
cfnames.as_ptr() as *const _,
copts, handles, err_ptr);
} }
for handle in &cfhandles { for handle in &cfhandles {
if handle.is_null() { if handle.is_null() {
return Err(Error::new("Received null column family \ return Err(Error::new("Received null column family handle from DB.".to_owned()));
handle from DB."
.to_string()));
} }
} }
@ -391,8 +362,7 @@ impl DB {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
if db.is_null() { if db.is_null() {
return Err(Error::new("Could not initialize database." return Err(Error::new("Could not initialize database.".to_owned()));
.to_string()));
} }
Ok(DB { Ok(DB {
@ -404,14 +374,9 @@ impl DB {
pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> { pub fn destroy<P: AsRef<Path>>(opts: &Options, path: P) -> Result<(), Error> {
let cpath = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap(); let cpath = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap();
let cpath_ptr = cpath.as_ptr(); let mut err: *mut c_char = ptr::null_mut();
let mut err: *const i8 = 0 as *const i8;
let err_ptr: *mut *const i8 = &mut err;
unsafe { unsafe {
rocksdb_ffi::rocksdb_destroy_db(opts.inner, ffi::rocksdb_destroy_db(opts.inner, cpath.as_ptr(), &mut err);
cpath_ptr as *const _,
err_ptr);
} }
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
@ -421,14 +386,9 @@ impl DB {
pub fn repair<P: AsRef<Path>>(opts: Options, path: P) -> Result<(), Error> { pub fn repair<P: AsRef<Path>>(opts: Options, path: P) -> Result<(), Error> {
let cpath = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap(); let cpath = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap();
let cpath_ptr = cpath.as_ptr(); let mut err: *mut c_char = ptr::null_mut();
let mut err: *const i8 = 0 as *const i8;
let err_ptr: *mut *const i8 = &mut err;
unsafe { unsafe {
rocksdb_ffi::rocksdb_repair_db(opts.inner, ffi::rocksdb_repair_db(opts.inner, cpath.as_ptr(), &mut err);
cpath_ptr as *const _,
err_ptr);
} }
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
@ -440,17 +400,10 @@ impl DB {
&self.path.as_path() &self.path.as_path()
} }
pub fn write_opt(&self, pub fn write_opt(&self, batch: WriteBatch, writeopts: &WriteOptions) -> Result<(), Error> {
batch: WriteBatch, let mut err: *mut c_char = ptr::null_mut();
writeopts: &WriteOptions)
-> Result<(), Error> {
let mut err: *const i8 = 0 as *const i8;
let err_ptr: *mut *const i8 = &mut err;
unsafe { unsafe {
rocksdb_ffi::rocksdb_write(self.inner, ffi::rocksdb_write(self.inner, writeopts.inner, batch.inner, &mut err);
writeopts.inner,
batch.inner,
err_ptr);
} }
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
@ -468,31 +421,15 @@ impl DB {
self.write_opt(batch, &wo) self.write_opt(batch, &wo)
} }
pub fn get_opt(&self, pub fn get_opt(&self, key: &[u8], readopts: &ReadOptions) -> Result<Option<DBVector>, Error> {
key: &[u8],
readopts: &ReadOptions)
-> Result<Option<DBVector>, Error> {
if readopts.inner.is_null() { if readopts.inner.is_null() {
return Err(Error::new("Unable to create rocksdb read options. \ 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()));
This is a fairly trivial call, and its \
failure may be indicative of a \
mis-compiled or mis-loaded rocksdb \
library."
.to_string()));
} }
unsafe { unsafe {
let val_len: size_t = 0; let mut val_len: size_t = 0;
let val_len_ptr = &val_len as *const size_t; let mut err: *mut c_char = ptr::null_mut();
let mut err: *const i8 = 0 as *const i8; 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;
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;
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
@ -509,33 +446,15 @@ impl DB {
self.get_opt(key, &ReadOptions::default()) self.get_opt(key, &ReadOptions::default())
} }
pub fn get_cf_opt(&self, pub fn get_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], readopts: &ReadOptions) -> Result<Option<DBVector>, Error> {
cf: DBCFHandle,
key: &[u8],
readopts: &ReadOptions)
-> Result<Option<DBVector>, Error> {
if readopts.inner.is_null() { if readopts.inner.is_null() {
return Err(Error::new("Unable to create rocksdb read options. \ 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()));
This is a fairly trivial call, and its \
failure may be indicative of a \
mis-compiled or mis-loaded rocksdb \
library."
.to_string()));
} }
unsafe { unsafe {
let val_len: size_t = 0; let mut val_len: size_t = 0;
let val_len_ptr = &val_len as *const size_t; let mut err: *mut c_char = ptr::null_mut();
let mut err: *const i8 = 0 as *const i8; 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;
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;
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
@ -547,34 +466,20 @@ impl DB {
} }
} }
pub fn get_cf(&self, pub fn get_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8]) -> Result<Option<DBVector>, Error> {
cf: DBCFHandle,
key: &[u8])
-> Result<Option<DBVector>, Error> {
self.get_cf_opt(cf, key, &ReadOptions::default()) self.get_cf_opt(cf, key, &ReadOptions::default())
} }
pub fn create_cf(&mut self, pub fn create_cf(&mut self, name: &str, opts: &Options) -> Result<*mut ffi::rocksdb_column_family_handle_t, Error> {
name: &str,
opts: &Options)
-> Result<DBCFHandle, Error> {
let cname = match CString::new(name.as_bytes()) { let cname = match CString::new(name.as_bytes()) {
Ok(c) => c, Ok(c) => c,
Err(_) => { Err(_) => {
return Err(Error::new("Failed to convert path to CString \ return Err(Error::new("Failed to convert path to CString when opening rocksdb".to_owned()))
when opening rocksdb"
.to_string()))
} }
}; };
let cname_ptr = cname.as_ptr(); let mut err: *mut c_char = ptr::null_mut();
let mut err: *const i8 = 0 as *const i8;
let err_ptr: *mut *const i8 = &mut err;
let cf_handler = unsafe { let cf_handler = unsafe {
let cf_handler = let cf_handler = ffi::rocksdb_create_column_family(self.inner, opts.inner, cname.as_ptr(), &mut err);
rocksdb_ffi::rocksdb_create_column_family(self.inner,
opts.inner,
cname_ptr as *const _,
err_ptr);
self.cfs.insert(name.to_string(), cf_handler); self.cfs.insert(name.to_string(), cf_handler);
cf_handler cf_handler
}; };
@ -587,26 +492,20 @@ impl DB {
pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> { pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
let cf = self.cfs.get(name); let cf = self.cfs.get(name);
if cf.is_none() { if cf.is_none() {
return Err(Error::new(format!("Invalid column family: {}", name) return Err(Error::new(format!("Invalid column family: {}", name).to_owned()));
.to_string()));
} }
let mut err: *mut c_char = ptr::null_mut();
let mut err: *const i8 = 0 as *const i8;
let err_ptr: *mut *const i8 = &mut err;
unsafe { unsafe {
rocksdb_ffi::rocksdb_drop_column_family(self.inner, ffi::rocksdb_drop_column_family(self.inner, *cf.unwrap(), &mut err);
*cf.unwrap(),
err_ptr);
} }
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
Ok(()) Ok(())
} }
/// Return the underlying column family handle /// Return the underlying column family handle.
pub fn cf_handle(&self, name: &str) -> Option<&DBCFHandle> { pub fn cf_handle(&self, name: &str) -> Option<&*mut ffi::rocksdb_column_family_handle_t> {
self.cfs.get(name) self.cfs.get(name)
} }
@ -615,10 +514,7 @@ impl DB {
DBIterator::new(self, &opts, mode) DBIterator::new(self, &opts, mode)
} }
pub fn iterator_cf(&self, pub fn iterator_cf(&self, cf_handle: *mut ffi::rocksdb_column_family_handle_t, mode: IteratorMode) -> Result<DBIterator, Error> {
cf_handle: DBCFHandle,
mode: IteratorMode)
-> Result<DBIterator, Error> {
let opts = ReadOptions::default(); let opts = ReadOptions::default();
DBIterator::new_cf(self, cf_handle, &opts, mode) DBIterator::new_cf(self, cf_handle, &opts, mode)
} }
@ -627,21 +523,10 @@ impl DB {
Snapshot::new(self) Snapshot::new(self)
} }
pub fn put_opt(&self, pub fn put_opt(&self, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> {
key: &[u8],
value: &[u8],
writeopts: &WriteOptions)
-> Result<(), Error> {
unsafe { unsafe {
let mut err: *const i8 = 0 as *const i8; let mut err: *mut c_char = ptr::null_mut();
let err_ptr: *mut *const i8 = &mut err; 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);
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);
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
@ -649,105 +534,54 @@ impl DB {
} }
} }
pub fn put_cf_opt(&self, pub fn put_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> {
cf: DBCFHandle,
key: &[u8],
value: &[u8],
writeopts: &WriteOptions)
-> Result<(), Error> {
unsafe { unsafe {
let mut err: *const i8 = 0 as *const i8; let mut err: *mut c_char = ptr::null_mut();
let err_ptr: *mut *const i8 = &mut err; 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);
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);
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
Ok(()) Ok(())
} }
} }
pub fn merge_opt(&self,
key: &[u8], pub fn merge_opt(&self, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> {
value: &[u8],
writeopts: &WriteOptions)
-> Result<(), Error> {
unsafe { unsafe {
let mut err: *const i8 = 0 as *const i8; let mut err: *mut c_char = ptr::null_mut();
let err_ptr: *mut *const i8 = &mut err; 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);
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);
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
Ok(()) Ok(())
} }
} }
fn merge_cf_opt(&self,
cf: DBCFHandle, fn merge_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> {
key: &[u8],
value: &[u8],
writeopts: &WriteOptions)
-> Result<(), Error> {
unsafe { unsafe {
let mut err: *const i8 = 0 as *const i8; let mut err: *mut c_char = ptr::null_mut();
let err_ptr: *mut *const i8 = &mut err; 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);
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);
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
Ok(()) Ok(())
} }
} }
fn delete_opt(&self,
key: &[u8], fn delete_opt(&self, key: &[u8], writeopts: &WriteOptions) -> Result<(), Error> {
writeopts: &WriteOptions)
-> Result<(), Error> {
unsafe { unsafe {
let mut err: *const i8 = 0 as *const i8; let mut err: *mut c_char = ptr::null_mut();
let err_ptr: *mut *const i8 = &mut err; ffi::rocksdb_delete(self.inner, writeopts.inner, key.as_ptr() as *const c_char, key.len() as size_t, &mut err);
rocksdb_ffi::rocksdb_delete(self.inner,
writeopts.inner,
key.as_ptr(),
key.len() as size_t,
err_ptr);
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
Ok(()) Ok(())
} }
} }
fn delete_cf_opt(&self,
cf: DBCFHandle, fn delete_cf_opt(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], writeopts: &WriteOptions) -> Result<(), Error> {
key: &[u8],
writeopts: &WriteOptions)
-> Result<(), Error> {
unsafe { unsafe {
let mut err: *const i8 = 0 as *const i8; let mut err: *mut c_char = ptr::null_mut();
let err_ptr: *mut *const i8 = &mut err; ffi::rocksdb_delete_cf(self.inner, writeopts.inner, cf, key.as_ptr() as *const c_char, key.len() as size_t, &mut err);
rocksdb_ffi::rocksdb_delete_cf(self.inner,
writeopts.inner,
cf,
key.as_ptr(),
key.len() as size_t,
err_ptr);
if !err.is_null() { if !err.is_null() {
return Err(Error::new(error_message(err))); return Err(Error::new(error_message(err)));
} }
@ -761,11 +595,7 @@ impl Writable for DB {
self.put_opt(key, value, &WriteOptions::default()) self.put_opt(key, value, &WriteOptions::default())
} }
fn put_cf(&self, fn put_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> {
cf: DBCFHandle,
key: &[u8],
value: &[u8])
-> Result<(), Error> {
self.put_cf_opt(cf, key, value, &WriteOptions::default()) self.put_cf_opt(cf, key, value, &WriteOptions::default())
} }
@ -773,11 +603,7 @@ impl Writable for DB {
self.merge_opt(key, value, &WriteOptions::default()) self.merge_opt(key, value, &WriteOptions::default())
} }
fn merge_cf(&self, fn merge_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> {
cf: DBCFHandle,
key: &[u8],
value: &[u8])
-> Result<(), Error> {
self.merge_cf_opt(cf, key, value, &WriteOptions::default()) self.merge_cf_opt(cf, key, value, &WriteOptions::default())
} }
@ -785,14 +611,14 @@ impl Writable for DB {
self.delete_opt(key, &WriteOptions::default()) 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()) self.delete_cf_opt(cf, key, &WriteOptions::default())
} }
} }
impl WriteBatch { impl WriteBatch {
pub fn len(&self) -> usize { 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 { pub fn is_empty(&self) -> bool {
@ -803,14 +629,14 @@ impl WriteBatch {
impl Default for WriteBatch { impl Default for WriteBatch {
fn default() -> WriteBatch { fn default() -> WriteBatch {
WriteBatch { WriteBatch {
inner: unsafe { rocksdb_ffi::rocksdb_writebatch_create() }, inner: unsafe { ffi::rocksdb_writebatch_create() },
} }
} }
} }
impl Drop for WriteBatch { impl Drop for WriteBatch {
fn drop(&mut self) { 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) { fn drop(&mut self) {
unsafe { unsafe {
for cf in self.cfs.values() { 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 { 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> { fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> {
unsafe { unsafe {
rocksdb_ffi::rocksdb_writebatch_put(self.inner, 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);
key.as_ptr(),
key.len() as size_t,
value.as_ptr(),
value.len() as size_t);
Ok(()) Ok(())
} }
} }
fn put_cf(&self, fn put_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> {
cf: DBCFHandle,
key: &[u8],
value: &[u8])
-> Result<(), Error> {
unsafe { unsafe {
rocksdb_ffi::rocksdb_writebatch_put_cf(self.inner, 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);
cf,
key.as_ptr(),
key.len() as size_t,
value.as_ptr(),
value.len() as size_t);
Ok(()) Ok(())
} }
} }
fn merge(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { fn merge(&self, key: &[u8], value: &[u8]) -> Result<(), Error> {
unsafe { unsafe {
rocksdb_ffi::rocksdb_writebatch_merge(self.inner, 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);
key.as_ptr(),
key.len() as size_t,
value.as_ptr(),
value.len() as size_t);
Ok(()) Ok(())
} }
} }
fn merge_cf(&self, fn merge_cf(&self, cf: *mut ffi::rocksdb_column_family_handle_t, key: &[u8], value: &[u8]) -> Result<(), Error> {
cf: DBCFHandle,
key: &[u8],
value: &[u8])
-> Result<(), Error> {
unsafe { unsafe {
rocksdb_ffi::rocksdb_writebatch_merge_cf(self.inner, 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);
cf,
key.as_ptr(),
key.len() as size_t,
value.as_ptr(),
value.len() as size_t);
Ok(()) Ok(())
} }
} }
/// Remove the database entry for key /// Remove the database entry for key.
/// ///
/// Returns Err if the key was not found /// Returns Err if the key was not found
fn delete(&self, key: &[u8]) -> Result<(), Error> { fn delete(&self, key: &[u8]) -> Result<(), Error> {
unsafe { unsafe {
rocksdb_ffi::rocksdb_writebatch_delete(self.inner, ffi::rocksdb_writebatch_delete(self.inner, key.as_ptr() as *const i8, key.len() as size_t);
key.as_ptr(),
key.len() as size_t);
Ok(()) 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 { unsafe {
rocksdb_ffi::rocksdb_writebatch_delete_cf(self.inner, ffi::rocksdb_writebatch_delete_cf(self.inner, cf, key.as_ptr() as *const i8, key.len() as size_t);
cf,
key.as_ptr(),
key.len() as size_t);
Ok(()) Ok(())
} }
} }
@ -912,7 +707,7 @@ impl Writable for WriteBatch {
impl Drop for ReadOptions { impl Drop for ReadOptions {
fn drop(&mut self) { 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)] #[allow(dead_code)]
fn fill_cache(&mut self, v: bool) { fn fill_cache(&mut self, v: bool) {
unsafe { 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) { fn set_snapshot(&mut self, snapshot: &Snapshot) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_readoptions_set_snapshot(self.inner, ffi::rocksdb_readoptions_set_snapshot(self.inner, snapshot.inner);
snapshot.inner);
} }
} }
pub fn set_iterate_upper_bound(&mut self, key: &[u8]) { pub fn set_iterate_upper_bound(&mut self, key: &[u8]) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, ffi::rocksdb_readoptions_set_iterate_upper_bound(self.inner, key.as_ptr() as *const i8, key.len() as size_t);
key.as_ptr(),
key.len() as size_t);
} }
} }
} }
@ -946,7 +738,7 @@ impl ReadOptions {
impl Default for ReadOptions { impl Default for ReadOptions {
fn default() -> ReadOptions { fn default() -> ReadOptions {
unsafe { 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 { impl Deref for DBVector {
type Target = [u8]; type Target = [u8];
fn deref(&self) -> &[u8] { fn deref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.base, self.len) } unsafe { slice::from_raw_parts(self.base, self.len) }
} }
@ -967,7 +760,7 @@ impl Deref for DBVector {
impl Drop for DBVector { impl Drop for DBVector {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { 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 // The DB will still be open when we try to destroy and the lock should fail
match DB::destroy(&opts, path) { match DB::destroy(&opts, path) {
Err(s) => { Err(s) => {
assert!(s == assert!(s == Error::new("IO error: lock _rust_rocksdb_error/LOCK: No locks available".to_owned()))
Error::new("IO error: lock _rust_rocksdb_error/LOCK: No \
locks available"
.to_string()))
} }
Ok(_) => panic!("should fail"), Ok(_) => panic!("should fail"),
} }
@ -1067,9 +857,7 @@ fn iterator_test() {
assert!(p.is_ok()); assert!(p.is_ok());
let iter = db.iterator(IteratorMode::Start); let iter = db.iterator(IteratorMode::Start);
for (k, v) in iter { for (k, v) in iter {
println!("Hello {}: {}", println!("Hello {}: {}", from_utf8(&*k).unwrap(), from_utf8(&*v).unwrap());
from_utf8(&*k).unwrap(),
from_utf8(&*v).unwrap());
} }
} }
let opts = Options::default(); let opts = Options::default();

@ -12,32 +12,22 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
extern crate libc;
use self::libc::{c_int, size_t, c_void};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::mem; use std::mem;
use rocksdb_ffi::{self, DBCompressionType, DBRecoveryMode}; use libc::{self, c_int, c_uint, c_uchar, c_void, size_t, uint64_t};
use merge_operator::{self, MergeFn, MergeOperatorCallback,
full_merge_callback, partial_merge_callback};
use comparator::{self, ComparatorCallback, compare_callback};
pub struct BlockBasedOptions { use {Options, WriteOptions, BlockBasedOptions};
inner: rocksdb_ffi::DBBlockBasedTableOptions, use comparator::{self, ComparatorCallback};
} use ffi;
use merge_operator::{self, MergeFn, MergeOperatorCallback, full_merge_callback, partial_merge_callback};
pub struct Options { use rocksdb::{DBCompressionType, DBCompactionStyle, DBRecoveryMode, new_cache};
pub inner: rocksdb_ffi::DBOptions,
}
pub struct WriteOptions {
pub inner: rocksdb_ffi::DBWriteOptions,
}
impl Drop for Options { impl Drop for Options {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { 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 { impl Drop for BlockBasedOptions {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { 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 { impl Drop for WriteOptions {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_writeoptions_destroy(self.inner); ffi::rocksdb_writeoptions_destroy(self.inner);
} }
} }
} }
@ -61,37 +51,33 @@ impl Drop for WriteOptions {
impl BlockBasedOptions { impl BlockBasedOptions {
pub fn set_block_size(&mut self, size: usize) { pub fn set_block_size(&mut self, size: usize) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_block_based_options_set_block_size(self.inner, ffi::rocksdb_block_based_options_set_block_size(self.inner, size);
size);
} }
} }
pub fn set_lru_cache(&mut self, size: size_t) { pub fn set_lru_cache(&mut self, size: size_t) {
let cache = rocksdb_ffi::new_cache(size); let cache = new_cache(size);
unsafe { unsafe {
// because cache is wrapped in shared_ptr, so we don't need to call // Since cache is wrapped in shared_ptr, we don't need to call rocksdb_cache_destroy explicitly.
// rocksdb_cache_destroy explicitly. ffi::rocksdb_block_based_options_set_block_cache(self.inner, cache);
rocksdb_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) { pub fn set_bloom_filter(&mut self, bits_per_key: c_int, block_based: bool) {
unsafe { unsafe {
let bloom = if block_based { let bloom = if block_based {
rocksdb_ffi::rocksdb_filterpolicy_create_bloom(bits_per_key) ffi::rocksdb_filterpolicy_create_bloom(bits_per_key)
} else { } 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, ffi::rocksdb_block_based_options_set_filter_policy(self.inner, bloom);
bloom);
} }
} }
pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) { pub fn set_cache_index_and_filter_blocks(&mut self, v: bool) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(self.inner, ffi::rocksdb_block_based_options_set_cache_index_and_filter_blocks(self.inner, v as u8);
v as u8);
} }
} }
} }
@ -99,10 +85,10 @@ impl BlockBasedOptions {
impl Default for BlockBasedOptions { impl Default for BlockBasedOptions {
fn default() -> BlockBasedOptions { fn default() -> BlockBasedOptions {
let block_opts = unsafe { let block_opts = unsafe {
rocksdb_ffi::rocksdb_block_based_options_create() ffi::rocksdb_block_based_options_create()
}; };
if block_opts.is_null() { 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 } BlockBasedOptions { inner: block_opts }
} }
@ -125,16 +111,13 @@ impl Options {
/// ``` /// ```
pub fn increase_parallelism(&mut self, parallelism: i32) { pub fn increase_parallelism(&mut self, parallelism: i32) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_increase_parallelism(self.inner, ffi::rocksdb_options_increase_parallelism(self.inner, parallelism);
parallelism);
} }
} }
pub fn optimize_level_style_compaction(&mut self, pub fn optimize_level_style_compaction(&mut self, memtable_memory_budget: usize) {
memtable_memory_budget: i32) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_optimize_level_style_compaction( ffi::rocksdb_options_optimize_level_style_compaction(self.inner, memtable_memory_budget as uint64_t);
self.inner, memtable_memory_budget);
} }
} }
@ -152,8 +135,7 @@ impl Options {
/// ``` /// ```
pub fn create_if_missing(&mut self, create_if_missing: bool) { pub fn create_if_missing(&mut self, create_if_missing: bool) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_create_if_missing( ffi::rocksdb_options_set_create_if_missing(self.inner, create_if_missing as c_uchar);
self.inner, create_if_missing);
} }
} }
@ -173,7 +155,7 @@ impl Options {
/// ``` /// ```
pub fn set_compression_type(&mut self, t: DBCompressionType) { pub fn set_compression_type(&mut self, t: DBCompressionType) {
unsafe { 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]) { pub fn compression_per_level(&mut self, level_types: &[DBCompressionType]) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_compression_per_level(self.inner, let level_types: Vec<_> = level_types.iter().map(|&t| t as c_int).collect();
level_types.as_ptr(), ffi::rocksdb_options_set_compression_per_level(self.inner, level_types.as_ptr(), level_types.len() as size_t)
level_types.len() as size_t)
} }
} }
pub fn set_merge_operator(&mut self, pub fn set_merge_operator(&mut self, name: &str, merge_fn: MergeFn) {
name: &str,
merge_fn: MergeFn) {
let cb = Box::new(MergeOperatorCallback { let cb = Box::new(MergeOperatorCallback {
name: CString::new(name.as_bytes()).unwrap(), name: CString::new(name.as_bytes()).unwrap(),
merge_fn: merge_fn, merge_fn: merge_fn,
}); });
unsafe { unsafe {
let mo = rocksdb_ffi::rocksdb_mergeoperator_create( 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));
mem::transmute(cb), ffi::rocksdb_options_set_merge_operator(self.inner, mo);
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);
} }
} }
#[deprecated(since="0.5.0", note="add_merge_operator has been renamed to set_merge_operator")] #[deprecated(since="0.5.0", note="add_merge_operator has been renamed to set_merge_operator")]
pub fn add_merge_operator(&mut self, pub fn add_merge_operator(&mut self, name: &str, merge_fn: MergeFn) {
name: &str,
merge_fn: MergeFn) {
self.set_merge_operator(name, merge_fn); self.set_merge_operator(name, merge_fn);
} }
/// Sets the comparator used to define the order of keys in the table. /// Sets the comparator used to define the order of keys in the table.
/// Default: a comparator that uses lexicographic byte-wise ordering /// Default: a comparator that uses lexicographic byte-wise ordering
/// ///
/// The client must ensure that the comparator supplied here has the /// 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.
//// same name and orders keys *exactly* the same as the comparator pub fn set_comparator(&mut self, name: &str, compare_fn: fn(&[u8], &[u8]) -> i32) {
/// 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 { let cb = Box::new(ComparatorCallback {
name: CString::new(name.as_bytes()).unwrap(), name: CString::new(name.as_bytes()).unwrap(),
f: compare_fn, f: compare_fn,
}); });
unsafe { unsafe {
let cmp = rocksdb_ffi::rocksdb_comparator_create( let cmp = ffi::rocksdb_comparator_create(mem::transmute(cb), Some(comparator::destructor_callback), Some(comparator::compare_callback), Some(comparator::name_callback));
mem::transmute(cb), ffi::rocksdb_options_set_comparator(self.inner, cmp);
comparator::destructor_callback,
compare_callback,
comparator::name_callback);
rocksdb_ffi::rocksdb_options_set_comparator(self.inner, cmp);
} }
} }
#[deprecated(since="0.5.0", note="add_comparator has been renamed to set_comparator")] #[deprecated(since = "0.5.0", note = "add_comparator has been renamed to set_comparator")]
pub fn add_comparator(&mut self, pub fn add_comparator(&mut self, name: &str, compare_fn: fn(&[u8], &[u8]) -> i32) {
name: &str,
compare_fn: fn(&[u8], &[u8]) -> i32) {
self.set_comparator(name, compare_fn); self.set_comparator(name, compare_fn);
} }
pub fn optimize_for_point_lookup(&mut self, cache_size: u64) { pub fn optimize_for_point_lookup(&mut self, cache_size: u64) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_optimize_for_point_lookup(self.inner, ffi::rocksdb_options_optimize_for_point_lookup(self.inner, cache_size);
cache_size);
} }
} }
@ -290,7 +250,7 @@ impl Options {
/// ``` /// ```
pub fn set_max_open_files(&mut self, nfiles: c_int) { pub fn set_max_open_files(&mut self, nfiles: c_int) {
unsafe { 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) { pub fn set_use_fsync(&mut self, useit: bool) {
unsafe { unsafe {
if useit { ffi::rocksdb_options_set_use_fsync(self.inner, useit as c_int)
rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 1)
} else {
rocksdb_ffi::rocksdb_options_set_use_fsync(self.inner, 0)
}
} }
} }
@ -343,17 +299,13 @@ impl Options {
/// ``` /// ```
pub fn set_bytes_per_sync(&mut self, nbytes: u64) { pub fn set_bytes_per_sync(&mut self, nbytes: u64) {
unsafe { 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) { pub fn set_disable_data_sync(&mut self, disable: bool) {
unsafe { unsafe {
if disable { ffi::rocksdb_options_set_disable_data_sync(self.inner, disable as c_int)
rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner, 1)
} else {
rocksdb_ffi::rocksdb_options_set_disable_data_sync(self.inner, 0)
}
} }
} }
@ -386,8 +338,7 @@ impl Options {
/// ``` /// ```
pub fn allow_os_buffer(&mut self, is_allow: bool) { pub fn allow_os_buffer(&mut self, is_allow: bool) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_allow_os_buffer(self.inner, ffi::rocksdb_options_set_allow_os_buffer(self.inner, is_allow as c_uchar);
is_allow);
} }
} }
@ -405,8 +356,7 @@ impl Options {
/// ``` /// ```
pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) { pub fn set_table_cache_num_shard_bits(&mut self, nbits: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, ffi::rocksdb_options_set_table_cache_numshardbits(self.inner, nbits);
nbits);
} }
} }
@ -430,8 +380,7 @@ impl Options {
/// ``` /// ```
pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) { pub fn set_min_write_buffer_number(&mut self, nbuf: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge( ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, nbuf);
self.inner, nbuf);
} }
} }
@ -470,8 +419,7 @@ impl Options {
/// ``` /// ```
pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) { pub fn set_max_write_buffer_number(&mut self, nbuf: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_max_write_buffer_number(self.inner, ffi::rocksdb_options_set_max_write_buffer_number(self.inner, nbuf);
nbuf);
} }
} }
@ -502,8 +450,7 @@ impl Options {
/// ``` /// ```
pub fn set_write_buffer_size(&mut self, size: usize) { pub fn set_write_buffer_size(&mut self, size: usize) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_write_buffer_size(self.inner, ffi::rocksdb_options_set_write_buffer_size(self.inner, size);
size);
} }
} }
@ -530,7 +477,7 @@ impl Options {
/// ``` /// ```
pub fn set_max_bytes_for_level_base(&mut self, size: u64) { pub fn set_max_bytes_for_level_base(&mut self, size: u64) {
unsafe { 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) { pub fn set_max_bytes_for_level_multiplier(&mut self, mul: i32) {
unsafe { 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) { pub fn set_max_manifest_file_size(&mut self, size: usize) {
unsafe { 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) { pub fn set_target_file_size_base(&mut self, size: u64) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_target_file_size_base(self.inner, ffi::rocksdb_options_set_target_file_size_base(self.inner, size);
size);
} }
} }
@ -616,8 +562,7 @@ impl Options {
/// ``` /// ```
pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) { pub fn set_min_write_buffer_number_to_merge(&mut self, to_merge: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_min_write_buffer_number_to_merge( ffi::rocksdb_options_set_min_write_buffer_number_to_merge(self.inner, 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) { pub fn set_level_zero_file_num_compaction_trigger(&mut self, n: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_level0_file_num_compaction_trigger( ffi::rocksdb_options_set_level0_file_num_compaction_trigger(self.inner, n);
self.inner, n);
} }
} }
@ -661,8 +605,7 @@ impl Options {
/// ``` /// ```
pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) { pub fn set_level_zero_slowdown_writes_trigger(&mut self, n: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_level0_slowdown_writes_trigger( ffi::rocksdb_options_set_level0_slowdown_writes_trigger(self.inner, n);
self.inner, n);
} }
} }
@ -682,8 +625,7 @@ impl Options {
/// ``` /// ```
pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) { pub fn set_level_zero_stop_writes_trigger(&mut self, n: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_level0_stop_writes_trigger( ffi::rocksdb_options_set_level0_stop_writes_trigger(self.inner, n);
self.inner, n);
} }
} }
@ -699,11 +641,9 @@ impl Options {
/// let mut opts = Options::default(); /// let mut opts = Options::default();
/// opts.set_compaction_style(DBCompactionStyle::Universal); /// opts.set_compaction_style(DBCompactionStyle::Universal);
/// ``` /// ```
pub fn set_compaction_style(&mut self, pub fn set_compaction_style(&mut self, style: DBCompactionStyle) {
style: rocksdb_ffi::DBCompactionStyle) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_compaction_style(self.inner, ffi::rocksdb_options_set_compaction_style(self.inner, style as c_int);
style);
} }
} }
@ -731,8 +671,7 @@ impl Options {
/// ``` /// ```
pub fn set_max_background_compactions(&mut self, n: c_int) { pub fn set_max_background_compactions(&mut self, n: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_max_background_compactions( ffi::rocksdb_options_set_max_background_compactions(self.inner, n);
self.inner, n);
} }
} }
@ -763,8 +702,7 @@ impl Options {
/// ``` /// ```
pub fn set_max_background_flushes(&mut self, n: c_int) { pub fn set_max_background_flushes(&mut self, n: c_int) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_set_max_background_flushes(self.inner, ffi::rocksdb_options_set_max_background_flushes(self.inner, n);
n);
} }
} }
@ -784,20 +722,14 @@ impl Options {
/// opts.set_disable_auto_compactions(true); /// opts.set_disable_auto_compactions(true);
/// ``` /// ```
pub fn set_disable_auto_compactions(&mut self, disable: bool) { pub fn set_disable_auto_compactions(&mut self, disable: bool) {
let c_bool = if disable {
1
} else {
0
};
unsafe { 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, pub fn set_block_based_table_factory(&mut self, factory: &BlockBasedOptions) {
factory: &BlockBasedOptions) {
unsafe { 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) { pub fn set_report_bg_io_stats(&mut self, enable: bool) {
unsafe { unsafe {
if enable { ffi::rocksdb_options_set_report_bg_io_stats(self.inner, enable as c_int);
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);
}
} }
} }
@ -837,26 +765,24 @@ impl Options {
/// ``` /// ```
pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) { pub fn set_wal_recovery_mode(&mut self, mode: DBRecoveryMode) {
unsafe { 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) { pub fn enable_statistics(&mut self) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_options_enable_statistics(self.inner); ffi::rocksdb_options_enable_statistics(self.inner);
} }
} }
pub fn get_statistics(&self) -> Option<String> { pub fn get_statistics(&self) -> Option<String> {
unsafe { 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() { if value.is_null() {
return None; return None;
} }
// Must valid UTF-8 format. // Must have valid UTF-8 format.
let s = CStr::from_ptr(value).to_str().unwrap().to_owned(); let s = CStr::from_ptr(value).to_str().unwrap().to_owned();
libc::free(value as *mut c_void); libc::free(value as *mut c_void);
Some(s) Some(s)
@ -875,17 +801,16 @@ impl Options {
/// let mut opts = Options::default(); /// let mut opts = Options::default();
/// opts.set_stats_dump_period_sec(300); /// 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 { unsafe {
rocksdb_ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, ffi::rocksdb_options_set_stats_dump_period_sec(self.inner, period);
period);
} }
} }
/// Sets the number of levels for this database /// Sets the number of levels for this database
pub fn set_num_levels(&mut self, n: c_int) { pub fn set_num_levels(&mut self, n: c_int) {
unsafe { 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 { impl Default for Options {
fn default() -> Options { fn default() -> Options {
unsafe { unsafe {
let opts = rocksdb_ffi::rocksdb_options_create(); let opts = ffi::rocksdb_options_create();
if opts.is_null() { if opts.is_null() {
panic!("Could not create rocksdb options".to_string()); panic!("Could not create rocksdb options".to_owned());
} }
Options { inner: opts } Options { inner: opts }
} }
@ -910,26 +835,22 @@ impl WriteOptions {
pub fn set_sync(&mut self, sync: bool) { pub fn set_sync(&mut self, sync: bool) {
unsafe { 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) { pub fn disable_wal(&mut self, disable: bool) {
unsafe { unsafe {
if disable { ffi::rocksdb_writeoptions_disable_WAL(self.inner, disable as c_int);
rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 1);
} else {
rocksdb_ffi::rocksdb_writeoptions_disable_WAL(self.inner, 0);
}
} }
} }
} }
impl Default for WriteOptions { impl Default for WriteOptions {
fn default() -> 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() { 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 } WriteOptions { inner: write_opts }
} }
@ -937,7 +858,7 @@ impl Default for WriteOptions {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Options; use Options;
#[test] #[test]
fn test_enable_statistics() { fn test_enable_statistics() {

Loading…
Cancel
Save