use crate::ffi;
use crate::ffi_util::{from_cstr_and_free, raw_data, raw_data_and_free};
use libc::{c_char, c_uchar};
use std::borrow::Cow;
use std::ffi::CStr;
use std::fmt;
use std::iter::FusedIterator;
use std::ops::Range;
use std::sync::Arc;
unsafe fn borrowed_cstr<'a>(ptr: *const c_char) -> &'a [u8] {
if ptr.is_null() {
return &[];
}
unsafe { CStr::from_ptr(ptr.cast()) }.to_bytes()
}
struct CfMetaDataRoot {
inner: *mut ffi::rocksdb_column_family_metadata_t,
}
impl Drop for CfMetaDataRoot {
fn drop(&mut self) {
unsafe { ffi::rocksdb_column_family_metadata_destroy(self.inner) }
}
}
unsafe impl Send for CfMetaDataRoot {}
unsafe impl Sync for CfMetaDataRoot {}
pub struct LevelMetaData {
inner: *mut ffi::rocksdb_level_metadata_t,
root: Option<Arc<CfMetaDataRoot>>,
}
impl LevelMetaData {
pub fn level(&self) -> i32 {
unsafe { ffi::rocksdb_level_metadata_get_level(self.inner) }
}
pub fn size(&self) -> u64 {
unsafe { ffi::rocksdb_level_metadata_get_size(self.inner) }
}
pub fn file_count(&self) -> usize {
unsafe { ffi::rocksdb_level_metadata_get_file_count(self.inner) }
}
pub fn sst_file(&self, index: usize) -> Option<SstFileMetaData> {
let inner = unsafe { ffi::rocksdb_level_metadata_get_sst_file_metadata(self.inner, index) };
if inner.is_null() {
return None;
}
Some(SstFileMetaData {
inner,
_root: self.root.clone(),
})
}
pub fn sst_files(&self) -> impl Iterator<Item = SstFileMetaData> + '_ {
(0..self.file_count()).filter_map(|index| self.sst_file(index))
}
}
impl Drop for LevelMetaData {
fn drop(&mut self) {
unsafe { ffi::rocksdb_level_metadata_destroy(self.inner) }
}
}
impl fmt::Debug for LevelMetaData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LevelMetaData")
.field("level", &self.level())
.field("size", &self.size())
.field("file_count", &self.file_count())
.finish()
}
}
unsafe impl Send for LevelMetaData {}
pub struct SstFileMetaData {
inner: *mut ffi::rocksdb_sst_file_metadata_t,
_root: Option<Arc<CfMetaDataRoot>>,
}
impl SstFileMetaData {
pub fn relative_filename(&self) -> String {
unsafe {
from_cstr_and_free(ffi::rocksdb_sst_file_metadata_get_relative_filename(
self.inner,
))
}
}
pub fn directory(&self) -> String {
unsafe { from_cstr_and_free(ffi::rocksdb_sst_file_metadata_get_directory(self.inner)) }
}
pub fn size(&self) -> u64 {
unsafe { ffi::rocksdb_sst_file_metadata_get_size(self.inner) }
}
pub fn smallest_key(&self) -> Vec<u8> {
let mut len: usize = 0;
let ptr =
unsafe { ffi::rocksdb_sst_file_metadata_get_smallestkey(self.inner, &raw mut len) };
unsafe { raw_data_and_free(ptr, len) }.unwrap_or_default()
}
pub fn largest_key(&self) -> Vec<u8> {
let mut len: usize = 0;
let ptr =
unsafe { ffi::rocksdb_sst_file_metadata_get_largestkey(self.inner, &raw mut len) };
unsafe { raw_data_and_free(ptr, len) }.unwrap_or_default()
}
}
impl Drop for SstFileMetaData {
fn drop(&mut self) {
unsafe { ffi::rocksdb_sst_file_metadata_destroy(self.inner) }
}
}
impl fmt::Debug for SstFileMetaData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SstFileMetaData")
.field("relative_filename", &self.relative_filename())
.field("directory", &self.directory())
.field("size", &self.size())
.finish_non_exhaustive()
}
}
unsafe impl Send for SstFileMetaData {}
pub(crate) unsafe fn levels_from_cf_metadata_owned(
ptr: *mut ffi::rocksdb_column_family_metadata_t,
) -> Vec<LevelMetaData> {
if ptr.is_null() {
return Vec::new();
}
let root = Arc::new(CfMetaDataRoot { inner: ptr });
unsafe { collect_levels(ptr, Some(root)) }
}
unsafe fn collect_levels(
ptr: *mut ffi::rocksdb_column_family_metadata_t,
root: Option<Arc<CfMetaDataRoot>>,
) -> Vec<LevelMetaData> {
if ptr.is_null() {
return Vec::new();
}
let count = unsafe { ffi::rocksdb_column_family_metadata_get_level_count(ptr) };
let mut levels = Vec::with_capacity(count);
for i in 0..count {
let inner = unsafe { ffi::rocksdb_column_family_metadata_get_level_metadata(ptr, i) };
if inner.is_null() {
continue;
}
levels.push(LevelMetaData {
inner,
root: root.clone(),
});
}
levels
}
pub struct ColumnFamilyMetaDataOptions {
pub(crate) inner: *mut ffi::rocksdb_column_family_metadata_options_t,
}
impl ColumnFamilyMetaDataOptions {
pub fn new() -> Self {
Self {
inner: unsafe { ffi::rocksdb_column_family_metadata_options_create() },
}
}
pub fn set_level(&mut self, level: i32) {
unsafe { ffi::rocksdb_column_family_metadata_options_set_level(self.inner, level) }
}
pub fn get_level(&self) -> i32 {
unsafe { ffi::rocksdb_column_family_metadata_options_get_level(self.inner) }
}
pub fn set_start_key(&mut self, key: impl AsRef<[u8]>) {
let key = key.as_ref();
unsafe {
ffi::rocksdb_column_family_metadata_options_set_start_key(
self.inner,
key.as_ptr().cast::<c_char>(),
key.len(),
);
}
}
pub fn clear_start_key(&mut self) {
unsafe {
ffi::rocksdb_column_family_metadata_options_set_start_key(
self.inner,
std::ptr::null(),
0,
);
}
}
pub fn get_start_key(&self) -> Option<Vec<u8>> {
let mut len: usize = 0;
let ptr = unsafe {
ffi::rocksdb_column_family_metadata_options_get_start_key(
self.inner.cast_const(),
&raw mut len,
)
};
unsafe { raw_data(ptr, len) }
}
pub fn set_end_key(&mut self, key: impl AsRef<[u8]>) {
let key = key.as_ref();
unsafe {
ffi::rocksdb_column_family_metadata_options_set_end_key(
self.inner,
key.as_ptr().cast::<c_char>(),
key.len(),
);
}
}
pub fn clear_end_key(&mut self) {
unsafe {
ffi::rocksdb_column_family_metadata_options_set_end_key(
self.inner,
std::ptr::null(),
0,
);
}
}
pub fn get_end_key(&self) -> Option<Vec<u8>> {
let mut len: usize = 0;
let ptr = unsafe {
ffi::rocksdb_column_family_metadata_options_get_end_key(
self.inner.cast_const(),
&raw mut len,
)
};
unsafe { raw_data(ptr, len) }
}
}
impl Default for ColumnFamilyMetaDataOptions {
fn default() -> Self {
Self::new()
}
}
impl Drop for ColumnFamilyMetaDataOptions {
fn drop(&mut self) {
unsafe { ffi::rocksdb_column_family_metadata_options_destroy(self.inner) }
}
}
impl fmt::Debug for ColumnFamilyMetaDataOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ColumnFamilyMetaDataOptions")
.field("level", &self.get_level())
.field("start_key", &self.get_start_key())
.field("end_key", &self.get_end_key())
.finish()
}
}
unsafe impl Send for ColumnFamilyMetaDataOptions {}
unsafe impl Sync for ColumnFamilyMetaDataOptions {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FileType {
WalFile,
DBLockFile,
TableFile,
DescriptorFile,
CurrentFile,
TempFile,
InfoLogFile,
MetaDatabase,
IdentityFile,
OptionsFile,
BlobFile,
CompactionProgressFile,
Unknown,
}
impl From<i32> for FileType {
fn from(value: i32) -> Self {
for candidate in [
FileType::WalFile,
FileType::DBLockFile,
FileType::TableFile,
FileType::DescriptorFile,
FileType::CurrentFile,
FileType::TempFile,
FileType::InfoLogFile,
FileType::MetaDatabase,
FileType::IdentityFile,
FileType::OptionsFile,
FileType::BlobFile,
FileType::CompactionProgressFile,
] {
if value == candidate as i32 {
return candidate;
}
}
FileType::Unknown
}
}
impl FileType {
pub fn as_str(self) -> &'static str {
match self {
FileType::WalFile => "WalFile",
FileType::DBLockFile => "DBLockFile",
FileType::TableFile => "TableFile",
FileType::DescriptorFile => "DescriptorFile",
FileType::CurrentFile => "CurrentFile",
FileType::TempFile => "TempFile",
FileType::InfoLogFile => "InfoLogFile",
FileType::MetaDatabase => "MetaDatabase",
FileType::IdentityFile => "IdentityFile",
FileType::OptionsFile => "OptionsFile",
FileType::BlobFile => "BlobFile",
FileType::CompactionProgressFile => "CompactionProgressFile",
FileType::Unknown => "Unknown",
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum Temperature {
Unknown = 0,
Hot = 0x04,
Warm = 0x08,
Cool = 0x0A,
Cold = 0x0C,
Ice = 0x10,
}
impl From<i32> for Temperature {
fn from(value: i32) -> Self {
match value {
0x04 => Temperature::Hot,
0x08 => Temperature::Warm,
0x0A => Temperature::Cool,
0x0C => Temperature::Cold,
0x10 => Temperature::Ice,
_ => Temperature::Unknown,
}
}
}
impl Temperature {
pub fn as_str(self) -> &'static str {
match self {
Temperature::Unknown => "Unknown",
Temperature::Hot => "Hot",
Temperature::Warm => "Warm",
Temperature::Cool => "Cool",
Temperature::Cold => "Cold",
Temperature::Ice => "Ice",
}
}
}
pub struct LiveFilesStorageInfoOptions {
pub(crate) inner: *mut ffi::rocksdb_livefiles_storage_info_options_t,
}
impl LiveFilesStorageInfoOptions {
pub fn new() -> Self {
Self {
inner: unsafe { ffi::rocksdb_livefiles_storage_info_options_create() },
}
}
pub fn set_include_checksum_info(&mut self, val: bool) {
unsafe {
ffi::rocksdb_livefiles_storage_info_options_set_include_checksum_info(
self.inner,
c_uchar::from(val),
);
}
}
pub fn get_include_checksum_info(&self) -> bool {
unsafe {
ffi::rocksdb_livefiles_storage_info_options_get_include_checksum_info(self.inner) != 0
}
}
pub fn set_wal_size_for_flush(&mut self, val: u64) {
unsafe {
ffi::rocksdb_livefiles_storage_info_options_set_wal_size_for_flush(self.inner, val);
}
}
pub fn get_wal_size_for_flush(&self) -> u64 {
unsafe { ffi::rocksdb_livefiles_storage_info_options_get_wal_size_for_flush(self.inner) }
}
pub fn set_atomic_flush(&mut self, val: bool) {
unsafe {
ffi::rocksdb_livefiles_storage_info_options_set_atomic_flush(
self.inner,
c_uchar::from(val),
);
}
}
pub fn get_atomic_flush(&self) -> bool {
unsafe { ffi::rocksdb_livefiles_storage_info_options_get_atomic_flush(self.inner) != 0 }
}
}
impl Default for LiveFilesStorageInfoOptions {
fn default() -> Self {
Self::new()
}
}
impl Drop for LiveFilesStorageInfoOptions {
fn drop(&mut self) {
unsafe { ffi::rocksdb_livefiles_storage_info_options_destroy(self.inner) }
}
}
impl fmt::Debug for LiveFilesStorageInfoOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LiveFilesStorageInfoOptions")
.field("include_checksum_info", &self.get_include_checksum_info())
.field("wal_size_for_flush", &self.get_wal_size_for_flush())
.field("atomic_flush", &self.get_atomic_flush())
.finish()
}
}
unsafe impl Send for LiveFilesStorageInfoOptions {}
unsafe impl Sync for LiveFilesStorageInfoOptions {}
pub struct LiveFilesStorageInfo {
inner: *mut ffi::rocksdb_livefiles_storage_info_t,
len: usize,
}
impl LiveFilesStorageInfo {
pub(crate) unsafe fn from_ptr(ptr: *mut ffi::rocksdb_livefiles_storage_info_t) -> Self {
let len = unsafe { ffi::rocksdb_livefiles_storage_info_count(ptr.cast_const()) };
Self { inner: ptr, len }
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, index: usize) -> Option<LiveFileStorageInfoEntry<'_>> {
if index >= self.len {
return None;
}
Some(LiveFileStorageInfoEntry { info: self, index })
}
pub fn iter(&self) -> LiveFilesStorageInfoIter<'_> {
LiveFilesStorageInfoIter {
info: self,
range: 0..self.len,
}
}
}
impl Drop for LiveFilesStorageInfo {
fn drop(&mut self) {
unsafe { ffi::rocksdb_livefiles_storage_info_destroy(self.inner) }
}
}
impl fmt::Debug for LiveFilesStorageInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<'a> IntoIterator for &'a LiveFilesStorageInfo {
type Item = LiveFileStorageInfoEntry<'a>;
type IntoIter = LiveFilesStorageInfoIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
unsafe impl Send for LiveFilesStorageInfo {}
unsafe impl Sync for LiveFilesStorageInfo {}
pub struct LiveFilesStorageInfoIter<'a> {
info: &'a LiveFilesStorageInfo,
range: Range<usize>,
}
impl<'a> Iterator for LiveFilesStorageInfoIter<'a> {
type Item = LiveFileStorageInfoEntry<'a>;
fn next(&mut self) -> Option<Self::Item> {
let index = self.range.next()?;
Some(LiveFileStorageInfoEntry {
info: self.info,
index,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl DoubleEndedIterator for LiveFilesStorageInfoIter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let index = self.range.next_back()?;
Some(LiveFileStorageInfoEntry {
info: self.info,
index,
})
}
}
impl ExactSizeIterator for LiveFilesStorageInfoIter<'_> {}
impl FusedIterator for LiveFilesStorageInfoIter<'_> {}
#[derive(Copy, Clone)]
pub struct LiveFileStorageInfoEntry<'a> {
info: &'a LiveFilesStorageInfo,
index: usize,
}
impl<'a> LiveFileStorageInfoEntry<'a> {
pub fn index(&self) -> usize {
self.index
}
pub fn relative_filename(&self) -> &'a [u8] {
unsafe {
borrowed_cstr(ffi::rocksdb_livefiles_storage_info_relative_filename(
self.info.inner.cast_const(),
self.index,
))
}
}
pub fn relative_filename_lossy(&self) -> Cow<'a, str> {
String::from_utf8_lossy(self.relative_filename())
}
pub fn directory(&self) -> &'a [u8] {
unsafe {
borrowed_cstr(ffi::rocksdb_livefiles_storage_info_directory(
self.info.inner.cast_const(),
self.index,
))
}
}
pub fn directory_lossy(&self) -> Cow<'a, str> {
String::from_utf8_lossy(self.directory())
}
pub fn file_number(&self) -> u64 {
unsafe {
ffi::rocksdb_livefiles_storage_info_file_number(
self.info.inner.cast_const(),
self.index,
)
}
}
pub fn file_type(&self) -> FileType {
FileType::from(unsafe {
ffi::rocksdb_livefiles_storage_info_file_type(self.info.inner.cast_const(), self.index)
})
}
pub fn size(&self) -> u64 {
unsafe {
ffi::rocksdb_livefiles_storage_info_size(self.info.inner.cast_const(), self.index)
}
}
pub fn trim_to_size(&self) -> bool {
unsafe {
ffi::rocksdb_livefiles_storage_info_trim_to_size(
self.info.inner.cast_const(),
self.index,
) != 0
}
}
pub fn replacement_contents(&self) -> &'a [u8] {
let mut size: usize = 0;
let ptr = unsafe {
ffi::rocksdb_livefiles_storage_info_replacement_contents(
self.info.inner.cast_const(),
self.index,
&raw mut size,
)
};
if ptr.is_null() || size == 0 {
return &[];
}
unsafe { std::slice::from_raw_parts(ptr.cast::<u8>(), size) }
}
pub fn file_checksum_func_name(&self) -> &'a [u8] {
unsafe {
borrowed_cstr(ffi::rocksdb_livefiles_storage_info_file_checksum_func_name(
self.info.inner.cast_const(),
self.index,
))
}
}
pub fn file_checksum_func_name_lossy(&self) -> Cow<'a, str> {
String::from_utf8_lossy(self.file_checksum_func_name())
}
pub fn temperature(&self) -> Temperature {
Temperature::from(unsafe {
ffi::rocksdb_livefiles_storage_info_temperature(
self.info.inner.cast_const(),
self.index,
)
})
}
}
impl fmt::Debug for LiveFileStorageInfoEntry<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LiveFileStorageInfoEntry")
.field("relative_filename", &self.relative_filename_lossy())
.field("directory", &self.directory_lossy())
.field("file_number", &self.file_number())
.field("file_type", &self.file_type())
.field("size", &self.size())
.field("trim_to_size", &self.trim_to_size())
.field("temperature", &self.temperature())
.finish_non_exhaustive()
}
}