use crate::env::Env;
use crate::env_options::EnvOptions;
use crate::ffi_util::{raw_data_and_free, to_cpath};
use crate::{AsColumnFamilyRef, Error, ffi};
use libc::c_uchar;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ops::{BitOr, BitOrAssign};
use std::path::Path;
use std::ptr;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct TraceFilter(u64);
impl TraceFilter {
pub const NONE: Self = Self(ffi::rocksdb_trace_filter_none as u64);
pub const GET: Self = Self(ffi::rocksdb_trace_filter_get as u64);
pub const WRITE: Self = Self(ffi::rocksdb_trace_filter_write as u64);
pub const ITERATOR_SEEK: Self = Self(ffi::rocksdb_trace_filter_iterator_seek as u64);
pub const ITERATOR_SEEK_FOR_PREV: Self =
Self(ffi::rocksdb_trace_filter_iterator_seek_for_prev as u64);
pub const MULTI_GET: Self = Self(ffi::rocksdb_trace_filter_multi_get as u64);
pub const fn empty() -> Self {
Self::NONE
}
pub const fn bits(self) -> u64 {
self.0
}
pub const fn from_bits_retain(bits: u64) -> Self {
Self(bits)
}
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
}
impl BitOr for TraceFilter {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
impl BitOrAssign for TraceFilter {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
pub struct TraceOptions {
pub(crate) inner: *mut ffi::rocksdb_trace_options_t,
}
impl Default for TraceOptions {
fn default() -> Self {
let opts = unsafe { ffi::rocksdb_trace_options_create() };
assert!(!opts.is_null(), "Could not create RocksDB Trace Options");
Self { inner: opts }
}
}
impl Drop for TraceOptions {
fn drop(&mut self) {
unsafe {
ffi::rocksdb_trace_options_destroy(self.inner);
}
}
}
unsafe impl Send for TraceOptions {}
unsafe impl Sync for TraceOptions {}
impl TraceOptions {
pub fn set_max_trace_file_size(&mut self, size: u64) {
unsafe {
ffi::rocksdb_trace_options_set_max_trace_file_size(self.inner, size);
}
}
pub fn get_max_trace_file_size(&self) -> u64 {
unsafe { ffi::rocksdb_trace_options_get_max_trace_file_size(self.inner) }
}
pub fn set_sampling_frequency(&mut self, frequency: u64) {
unsafe {
ffi::rocksdb_trace_options_set_sampling_frequency(self.inner, frequency);
}
}
pub fn get_sampling_frequency(&self) -> u64 {
unsafe { ffi::rocksdb_trace_options_get_sampling_frequency(self.inner) }
}
pub fn set_filter(&mut self, filter: TraceFilter) {
unsafe {
ffi::rocksdb_trace_options_set_filter(self.inner, filter.bits());
}
}
pub fn get_filter(&self) -> TraceFilter {
TraceFilter::from_bits_retain(unsafe { ffi::rocksdb_trace_options_get_filter(self.inner) })
}
pub fn set_preserve_write_order(&mut self, v: bool) {
unsafe {
ffi::rocksdb_trace_options_set_preserve_write_order(self.inner, c_uchar::from(v));
}
}
pub fn get_preserve_write_order(&self) -> bool {
unsafe { ffi::rocksdb_trace_options_get_preserve_write_order(self.inner) != 0 }
}
}
pub struct BlockCacheTraceOptions {
pub(crate) inner: *mut ffi::rocksdb_block_cache_trace_options_t,
}
impl Default for BlockCacheTraceOptions {
fn default() -> Self {
let opts = unsafe { ffi::rocksdb_block_cache_trace_options_create() };
assert!(
!opts.is_null(),
"Could not create RocksDB Block Cache Trace Options"
);
Self { inner: opts }
}
}
impl Drop for BlockCacheTraceOptions {
fn drop(&mut self) {
unsafe {
ffi::rocksdb_block_cache_trace_options_destroy(self.inner);
}
}
}
unsafe impl Send for BlockCacheTraceOptions {}
unsafe impl Sync for BlockCacheTraceOptions {}
impl BlockCacheTraceOptions {
pub fn set_sampling_frequency(&mut self, frequency: u64) {
unsafe {
ffi::rocksdb_block_cache_trace_options_set_sampling_frequency(self.inner, frequency);
}
}
pub fn get_sampling_frequency(&self) -> u64 {
unsafe { ffi::rocksdb_block_cache_trace_options_get_sampling_frequency(self.inner) }
}
}
pub struct BlockCacheTraceWriterOptions {
pub(crate) inner: *mut ffi::rocksdb_block_cache_trace_writer_options_t,
}
impl Default for BlockCacheTraceWriterOptions {
fn default() -> Self {
let opts = unsafe { ffi::rocksdb_block_cache_trace_writer_options_create() };
assert!(
!opts.is_null(),
"Could not create RocksDB Block Cache Trace Writer Options"
);
Self { inner: opts }
}
}
impl Drop for BlockCacheTraceWriterOptions {
fn drop(&mut self) {
unsafe {
ffi::rocksdb_block_cache_trace_writer_options_destroy(self.inner);
}
}
}
unsafe impl Send for BlockCacheTraceWriterOptions {}
unsafe impl Sync for BlockCacheTraceWriterOptions {}
impl BlockCacheTraceWriterOptions {
pub fn set_max_trace_file_size(&mut self, size: u64) {
unsafe {
ffi::rocksdb_block_cache_trace_writer_options_set_max_trace_file_size(self.inner, size);
}
}
pub fn get_max_trace_file_size(&self) -> u64 {
unsafe { ffi::rocksdb_block_cache_trace_writer_options_get_max_trace_file_size(self.inner) }
}
}
pub struct TraceReader {
inner: *mut ffi::rocksdb_trace_reader_t,
closed: bool,
_env: Env,
}
unsafe impl Send for TraceReader {}
impl TraceReader {
pub fn open<P: AsRef<Path>>(env: &Env, trace_path: P) -> Result<Self, Error> {
Self::open_inner(env, None, trace_path)
}
pub fn open_with_env_options<P: AsRef<Path>>(
env: &Env,
env_opts: &EnvOptions,
trace_path: P,
) -> Result<Self, Error> {
Self::open_inner(env, Some(env_opts), trace_path)
}
fn open_inner<P: AsRef<Path>>(
env: &Env,
env_opts: Option<&EnvOptions>,
trace_path: P,
) -> Result<Self, Error> {
let c_path = to_cpath(trace_path)?;
let env_opts = env_opts.map_or(ptr::null(), EnvOptions::as_ptr);
let reader = unsafe {
ffi_try!(ffi::rocksdb_trace_reader_create(
env.0.inner,
env_opts,
c_path.as_ptr(),
))
};
if reader.is_null() {
return Err(Error::new("Could not create trace reader.".to_owned()));
}
Ok(Self {
inner: reader,
closed: false,
_env: env.clone(),
})
}
pub fn read(&mut self) -> Result<Option<Vec<u8>>, Error> {
if self.closed {
return Err(Error::new("TraceReader is closed.".to_owned()));
}
let mut size: usize = 0;
let data = unsafe { ffi_try!(ffi::rocksdb_trace_reader_read(self.inner, &raw mut size)) };
Ok(unsafe { raw_data_and_free(data, size) })
}
pub fn reset(&mut self) -> Result<(), Error> {
unsafe {
ffi_try!(ffi::rocksdb_trace_reader_reset(self.inner));
}
Ok(())
}
pub fn close(&mut self) -> Result<(), Error> {
if self.closed {
return Ok(());
}
self.closed = true;
unsafe {
ffi_try!(ffi::rocksdb_trace_reader_close(self.inner));
}
Ok(())
}
}
impl Drop for TraceReader {
fn drop(&mut self) {
unsafe { ffi::rocksdb_trace_reader_destroy(self.inner) }
}
}
pub struct ReplayOptions {
pub(crate) inner: *mut ffi::rocksdb_replay_options_t,
}
impl Default for ReplayOptions {
fn default() -> Self {
let opts = unsafe { ffi::rocksdb_replay_options_create() };
assert!(!opts.is_null(), "Could not create RocksDB Replay Options");
Self { inner: opts }
}
}
impl Drop for ReplayOptions {
fn drop(&mut self) {
unsafe {
ffi::rocksdb_replay_options_destroy(self.inner);
}
}
}
unsafe impl Send for ReplayOptions {}
unsafe impl Sync for ReplayOptions {}
impl ReplayOptions {
pub fn set_num_threads(&mut self, num_threads: u32) {
unsafe {
ffi::rocksdb_replay_options_set_num_threads(self.inner, num_threads);
}
}
pub fn get_num_threads(&self) -> u32 {
unsafe { ffi::rocksdb_replay_options_get_num_threads(self.inner) }
}
pub fn set_fast_forward(&mut self, fast_forward: f64) {
unsafe {
ffi::rocksdb_replay_options_set_fast_forward(self.inner, fast_forward);
}
}
pub fn get_fast_forward(&self) -> f64 {
unsafe { ffi::rocksdb_replay_options_get_fast_forward(self.inner) }
}
}
pub struct Replayer<'a> {
inner: *mut ffi::rocksdb_replayer_t,
_db: PhantomData<&'a ()>,
}
unsafe impl Send for Replayer<'_> {}
impl Replayer<'_> {
pub(crate) unsafe fn create_default<'cf, W, I>(
db: *mut ffi::rocksdb_t,
column_families: I,
env: *mut ffi::rocksdb_env_t,
env_options: *const ffi::rocksdb_envoptions_t,
trace_path: &CStr,
) -> Result<Self, Error>
where
W: AsColumnFamilyRef + 'cf,
I: IntoIterator<Item = &'cf W>,
{
let mut cf_handles: Vec<_> = column_families
.into_iter()
.map(AsColumnFamilyRef::inner)
.collect();
let replayer = unsafe {
ffi_try!(ffi::rocksdb_new_default_replayer(
db,
cf_handles.as_mut_ptr(),
cf_handles.len(),
env,
env_options,
trace_path.as_ptr(),
))
};
if replayer.is_null() {
return Err(Error::new("Could not create replayer.".to_owned()));
}
Ok(Self {
inner: replayer,
_db: PhantomData,
})
}
pub fn prepare(&mut self) -> Result<(), Error> {
unsafe {
ffi_try!(ffi::rocksdb_replayer_prepare(self.inner));
}
Ok(())
}
pub fn replay(&mut self, options: &ReplayOptions) -> Result<(), Error> {
unsafe {
ffi_try!(ffi::rocksdb_replayer_replay(
self.inner,
options.inner.cast_const(),
));
}
Ok(())
}
pub fn header_timestamp(&self) -> u64 {
unsafe { ffi::rocksdb_replayer_get_header_timestamp(self.inner.cast_const()) }
}
}
impl Drop for Replayer<'_> {
fn drop(&mut self) {
unsafe { ffi::rocksdb_replayer_destroy(self.inner) }
}
}