1use crate::ffi;
14use crate::ffi_util::{from_cstr_and_free, raw_data, raw_data_and_free};
15use libc::{c_char, c_uchar};
16use std::borrow::Cow;
17use std::ffi::CStr;
18use std::fmt;
19use std::iter::FusedIterator;
20use std::ops::Range;
21use std::sync::Arc;
22
23unsafe fn borrowed_cstr<'a>(ptr: *const c_char) -> &'a [u8] {
28 if ptr.is_null() {
29 return &[];
30 }
31 unsafe { CStr::from_ptr(ptr.cast()) }.to_bytes()
32}
33
34struct CfMetaDataRoot {
43 inner: *mut ffi::rocksdb_column_family_metadata_t,
44}
45
46impl Drop for CfMetaDataRoot {
47 fn drop(&mut self) {
48 unsafe { ffi::rocksdb_column_family_metadata_destroy(self.inner) }
49 }
50}
51
52unsafe impl Send for CfMetaDataRoot {}
57unsafe impl Sync for CfMetaDataRoot {}
58
59pub struct LevelMetaData {
65 inner: *mut ffi::rocksdb_level_metadata_t,
66 root: Option<Arc<CfMetaDataRoot>>,
68}
69
70impl LevelMetaData {
71 pub fn level(&self) -> i32 {
77 unsafe { ffi::rocksdb_level_metadata_get_level(self.inner) }
78 }
79
80 pub fn size(&self) -> u64 {
82 unsafe { ffi::rocksdb_level_metadata_get_size(self.inner) }
83 }
84
85 pub fn file_count(&self) -> usize {
87 unsafe { ffi::rocksdb_level_metadata_get_file_count(self.inner) }
88 }
89
90 pub fn sst_file(&self, index: usize) -> Option<SstFileMetaData> {
96 let inner = unsafe { ffi::rocksdb_level_metadata_get_sst_file_metadata(self.inner, index) };
97 if inner.is_null() {
98 return None;
99 }
100 Some(SstFileMetaData {
101 inner,
102 _root: self.root.clone(),
103 })
104 }
105
106 pub fn sst_files(&self) -> impl Iterator<Item = SstFileMetaData> + '_ {
108 (0..self.file_count()).filter_map(|index| self.sst_file(index))
109 }
110}
111
112impl Drop for LevelMetaData {
113 fn drop(&mut self) {
114 unsafe { ffi::rocksdb_level_metadata_destroy(self.inner) }
117 }
118}
119
120impl fmt::Debug for LevelMetaData {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("LevelMetaData")
123 .field("level", &self.level())
124 .field("size", &self.size())
125 .field("file_count", &self.file_count())
126 .finish()
127 }
128}
129
130unsafe impl Send for LevelMetaData {}
135
136pub struct SstFileMetaData {
138 inner: *mut ffi::rocksdb_sst_file_metadata_t,
139 _root: Option<Arc<CfMetaDataRoot>>,
141}
142
143impl SstFileMetaData {
144 pub fn relative_filename(&self) -> String {
146 unsafe {
148 from_cstr_and_free(ffi::rocksdb_sst_file_metadata_get_relative_filename(
149 self.inner,
150 ))
151 }
152 }
153
154 pub fn directory(&self) -> String {
157 unsafe { from_cstr_and_free(ffi::rocksdb_sst_file_metadata_get_directory(self.inner)) }
159 }
160
161 pub fn size(&self) -> u64 {
163 unsafe { ffi::rocksdb_sst_file_metadata_get_size(self.inner) }
164 }
165
166 pub fn smallest_key(&self) -> Vec<u8> {
168 let mut len: usize = 0;
169 let ptr =
171 unsafe { ffi::rocksdb_sst_file_metadata_get_smallestkey(self.inner, &raw mut len) };
172 unsafe { raw_data_and_free(ptr, len) }.unwrap_or_default()
173 }
174
175 pub fn largest_key(&self) -> Vec<u8> {
177 let mut len: usize = 0;
178 let ptr =
180 unsafe { ffi::rocksdb_sst_file_metadata_get_largestkey(self.inner, &raw mut len) };
181 unsafe { raw_data_and_free(ptr, len) }.unwrap_or_default()
182 }
183}
184
185impl Drop for SstFileMetaData {
186 fn drop(&mut self) {
187 unsafe { ffi::rocksdb_sst_file_metadata_destroy(self.inner) }
190 }
191}
192
193impl fmt::Debug for SstFileMetaData {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 f.debug_struct("SstFileMetaData")
196 .field("relative_filename", &self.relative_filename())
197 .field("directory", &self.directory())
198 .field("size", &self.size())
199 .finish_non_exhaustive()
200 }
201}
202
203unsafe impl Send for SstFileMetaData {}
205
206pub(crate) unsafe fn levels_from_cf_metadata_owned(
216 ptr: *mut ffi::rocksdb_column_family_metadata_t,
217) -> Vec<LevelMetaData> {
218 if ptr.is_null() {
219 return Vec::new();
220 }
221 let root = Arc::new(CfMetaDataRoot { inner: ptr });
222 unsafe { collect_levels(ptr, Some(root)) }
223}
224
225unsafe fn collect_levels(
226 ptr: *mut ffi::rocksdb_column_family_metadata_t,
227 root: Option<Arc<CfMetaDataRoot>>,
228) -> Vec<LevelMetaData> {
229 if ptr.is_null() {
230 return Vec::new();
231 }
232 let count = unsafe { ffi::rocksdb_column_family_metadata_get_level_count(ptr) };
233 let mut levels = Vec::with_capacity(count);
234 for i in 0..count {
235 let inner = unsafe { ffi::rocksdb_column_family_metadata_get_level_metadata(ptr, i) };
236 if inner.is_null() {
237 continue;
238 }
239 levels.push(LevelMetaData {
240 inner,
241 root: root.clone(),
242 });
243 }
244 levels
245}
246
247pub struct ColumnFamilyMetaDataOptions {
263 pub(crate) inner: *mut ffi::rocksdb_column_family_metadata_options_t,
264}
265
266impl ColumnFamilyMetaDataOptions {
267 pub fn new() -> Self {
269 Self {
270 inner: unsafe { ffi::rocksdb_column_family_metadata_options_create() },
271 }
272 }
273
274 pub fn set_level(&mut self, level: i32) {
276 unsafe { ffi::rocksdb_column_family_metadata_options_set_level(self.inner, level) }
277 }
278
279 pub fn get_level(&self) -> i32 {
281 unsafe { ffi::rocksdb_column_family_metadata_options_get_level(self.inner) }
282 }
283
284 pub fn set_start_key(&mut self, key: impl AsRef<[u8]>) {
286 let key = key.as_ref();
287 unsafe {
288 ffi::rocksdb_column_family_metadata_options_set_start_key(
289 self.inner,
290 key.as_ptr().cast::<c_char>(),
291 key.len(),
292 );
293 }
294 }
295
296 pub fn clear_start_key(&mut self) {
298 unsafe {
299 ffi::rocksdb_column_family_metadata_options_set_start_key(
300 self.inner,
301 std::ptr::null(),
302 0,
303 );
304 }
305 }
306
307 pub fn get_start_key(&self) -> Option<Vec<u8>> {
312 let mut len: usize = 0;
313 let ptr = unsafe {
314 ffi::rocksdb_column_family_metadata_options_get_start_key(
315 self.inner.cast_const(),
316 &raw mut len,
317 )
318 };
319 unsafe { raw_data(ptr, len) }
320 }
321
322 pub fn set_end_key(&mut self, key: impl AsRef<[u8]>) {
324 let key = key.as_ref();
325 unsafe {
326 ffi::rocksdb_column_family_metadata_options_set_end_key(
327 self.inner,
328 key.as_ptr().cast::<c_char>(),
329 key.len(),
330 );
331 }
332 }
333
334 pub fn clear_end_key(&mut self) {
336 unsafe {
337 ffi::rocksdb_column_family_metadata_options_set_end_key(
338 self.inner,
339 std::ptr::null(),
340 0,
341 );
342 }
343 }
344
345 pub fn get_end_key(&self) -> Option<Vec<u8>> {
350 let mut len: usize = 0;
351 let ptr = unsafe {
352 ffi::rocksdb_column_family_metadata_options_get_end_key(
353 self.inner.cast_const(),
354 &raw mut len,
355 )
356 };
357 unsafe { raw_data(ptr, len) }
358 }
359}
360
361impl Default for ColumnFamilyMetaDataOptions {
362 fn default() -> Self {
363 Self::new()
364 }
365}
366
367impl Drop for ColumnFamilyMetaDataOptions {
368 fn drop(&mut self) {
369 unsafe { ffi::rocksdb_column_family_metadata_options_destroy(self.inner) }
370 }
371}
372
373impl fmt::Debug for ColumnFamilyMetaDataOptions {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 f.debug_struct("ColumnFamilyMetaDataOptions")
376 .field("level", &self.get_level())
377 .field("start_key", &self.get_start_key())
378 .field("end_key", &self.get_end_key())
379 .finish()
380 }
381}
382
383unsafe impl Send for ColumnFamilyMetaDataOptions {}
386unsafe impl Sync for ColumnFamilyMetaDataOptions {}
387
388#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
393pub enum FileType {
394 WalFile,
396 DBLockFile,
398 TableFile,
400 DescriptorFile,
402 CurrentFile,
404 TempFile,
406 InfoLogFile,
408 MetaDatabase,
410 IdentityFile,
412 OptionsFile,
414 BlobFile,
416 CompactionProgressFile,
418 Unknown,
420}
421
422impl From<i32> for FileType {
423 fn from(value: i32) -> Self {
424 for candidate in [
425 FileType::WalFile,
426 FileType::DBLockFile,
427 FileType::TableFile,
428 FileType::DescriptorFile,
429 FileType::CurrentFile,
430 FileType::TempFile,
431 FileType::InfoLogFile,
432 FileType::MetaDatabase,
433 FileType::IdentityFile,
434 FileType::OptionsFile,
435 FileType::BlobFile,
436 FileType::CompactionProgressFile,
437 ] {
438 if value == candidate as i32 {
439 return candidate;
440 }
441 }
442 FileType::Unknown
443 }
444}
445
446impl FileType {
447 pub fn as_str(self) -> &'static str {
448 match self {
449 FileType::WalFile => "WalFile",
450 FileType::DBLockFile => "DBLockFile",
451 FileType::TableFile => "TableFile",
452 FileType::DescriptorFile => "DescriptorFile",
453 FileType::CurrentFile => "CurrentFile",
454 FileType::TempFile => "TempFile",
455 FileType::InfoLogFile => "InfoLogFile",
456 FileType::MetaDatabase => "MetaDatabase",
457 FileType::IdentityFile => "IdentityFile",
458 FileType::OptionsFile => "OptionsFile",
459 FileType::BlobFile => "BlobFile",
460 FileType::CompactionProgressFile => "CompactionProgressFile",
461 FileType::Unknown => "Unknown",
462 }
463 }
464}
465
466#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
478#[repr(i32)]
479pub enum Temperature {
480 Unknown = 0,
482 Hot = 0x04,
484 Warm = 0x08,
486 Cool = 0x0A,
488 Cold = 0x0C,
490 Ice = 0x10,
492}
493
494impl From<i32> for Temperature {
495 fn from(value: i32) -> Self {
496 match value {
497 0x04 => Temperature::Hot,
498 0x08 => Temperature::Warm,
499 0x0A => Temperature::Cool,
500 0x0C => Temperature::Cold,
501 0x10 => Temperature::Ice,
502 _ => Temperature::Unknown,
503 }
504 }
505}
506
507impl Temperature {
508 pub fn as_str(self) -> &'static str {
509 match self {
510 Temperature::Unknown => "Unknown",
511 Temperature::Hot => "Hot",
512 Temperature::Warm => "Warm",
513 Temperature::Cool => "Cool",
514 Temperature::Cold => "Cold",
515 Temperature::Ice => "Ice",
516 }
517 }
518}
519
520pub struct LiveFilesStorageInfoOptions {
522 pub(crate) inner: *mut ffi::rocksdb_livefiles_storage_info_options_t,
523}
524
525impl LiveFilesStorageInfoOptions {
526 pub fn new() -> Self {
529 Self {
530 inner: unsafe { ffi::rocksdb_livefiles_storage_info_options_create() },
531 }
532 }
533
534 pub fn set_include_checksum_info(&mut self, val: bool) {
539 unsafe {
540 ffi::rocksdb_livefiles_storage_info_options_set_include_checksum_info(
541 self.inner,
542 c_uchar::from(val),
543 );
544 }
545 }
546
547 pub fn get_include_checksum_info(&self) -> bool {
549 unsafe {
550 ffi::rocksdb_livefiles_storage_info_options_get_include_checksum_info(self.inner) != 0
551 }
552 }
553
554 pub fn set_wal_size_for_flush(&mut self, val: u64) {
559 unsafe {
560 ffi::rocksdb_livefiles_storage_info_options_set_wal_size_for_flush(self.inner, val);
561 }
562 }
563
564 pub fn get_wal_size_for_flush(&self) -> u64 {
566 unsafe { ffi::rocksdb_livefiles_storage_info_options_get_wal_size_for_flush(self.inner) }
567 }
568
569 pub fn set_atomic_flush(&mut self, val: bool) {
577 unsafe {
578 ffi::rocksdb_livefiles_storage_info_options_set_atomic_flush(
579 self.inner,
580 c_uchar::from(val),
581 );
582 }
583 }
584
585 pub fn get_atomic_flush(&self) -> bool {
587 unsafe { ffi::rocksdb_livefiles_storage_info_options_get_atomic_flush(self.inner) != 0 }
588 }
589}
590
591impl Default for LiveFilesStorageInfoOptions {
592 fn default() -> Self {
593 Self::new()
594 }
595}
596
597impl Drop for LiveFilesStorageInfoOptions {
598 fn drop(&mut self) {
599 unsafe { ffi::rocksdb_livefiles_storage_info_options_destroy(self.inner) }
600 }
601}
602
603impl fmt::Debug for LiveFilesStorageInfoOptions {
604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605 f.debug_struct("LiveFilesStorageInfoOptions")
606 .field("include_checksum_info", &self.get_include_checksum_info())
607 .field("wal_size_for_flush", &self.get_wal_size_for_flush())
608 .field("atomic_flush", &self.get_atomic_flush())
609 .finish()
610 }
611}
612
613unsafe impl Send for LiveFilesStorageInfoOptions {}
616unsafe impl Sync for LiveFilesStorageInfoOptions {}
617
618pub struct LiveFilesStorageInfo {
625 inner: *mut ffi::rocksdb_livefiles_storage_info_t,
626 len: usize,
629}
630
631impl LiveFilesStorageInfo {
632 pub(crate) unsafe fn from_ptr(ptr: *mut ffi::rocksdb_livefiles_storage_info_t) -> Self {
639 let len = unsafe { ffi::rocksdb_livefiles_storage_info_count(ptr.cast_const()) };
640 Self { inner: ptr, len }
641 }
642
643 pub fn len(&self) -> usize {
645 self.len
646 }
647
648 pub fn is_empty(&self) -> bool {
650 self.len() == 0
651 }
652
653 pub fn get(&self, index: usize) -> Option<LiveFileStorageInfoEntry<'_>> {
659 if index >= self.len {
660 return None;
661 }
662 Some(LiveFileStorageInfoEntry { info: self, index })
663 }
664
665 pub fn iter(&self) -> LiveFilesStorageInfoIter<'_> {
667 LiveFilesStorageInfoIter {
668 info: self,
669 range: 0..self.len,
670 }
671 }
672}
673
674impl Drop for LiveFilesStorageInfo {
675 fn drop(&mut self) {
676 unsafe { ffi::rocksdb_livefiles_storage_info_destroy(self.inner) }
677 }
678}
679
680impl fmt::Debug for LiveFilesStorageInfo {
681 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
682 f.debug_list().entries(self.iter()).finish()
683 }
684}
685
686impl<'a> IntoIterator for &'a LiveFilesStorageInfo {
687 type Item = LiveFileStorageInfoEntry<'a>;
688 type IntoIter = LiveFilesStorageInfoIter<'a>;
689
690 fn into_iter(self) -> Self::IntoIter {
691 self.iter()
692 }
693}
694
695unsafe impl Send for LiveFilesStorageInfo {}
700unsafe impl Sync for LiveFilesStorageInfo {}
701
702pub struct LiveFilesStorageInfoIter<'a> {
704 info: &'a LiveFilesStorageInfo,
705 range: Range<usize>,
706}
707
708impl<'a> Iterator for LiveFilesStorageInfoIter<'a> {
709 type Item = LiveFileStorageInfoEntry<'a>;
710
711 fn next(&mut self) -> Option<Self::Item> {
712 let index = self.range.next()?;
713 Some(LiveFileStorageInfoEntry {
714 info: self.info,
715 index,
716 })
717 }
718
719 fn size_hint(&self) -> (usize, Option<usize>) {
720 self.range.size_hint()
721 }
722}
723
724impl DoubleEndedIterator for LiveFilesStorageInfoIter<'_> {
725 fn next_back(&mut self) -> Option<Self::Item> {
726 let index = self.range.next_back()?;
727 Some(LiveFileStorageInfoEntry {
728 info: self.info,
729 index,
730 })
731 }
732}
733
734impl ExactSizeIterator for LiveFilesStorageInfoIter<'_> {}
735
736impl FusedIterator for LiveFilesStorageInfoIter<'_> {}
737
738#[derive(Copy, Clone)]
744pub struct LiveFileStorageInfoEntry<'a> {
745 info: &'a LiveFilesStorageInfo,
746 index: usize,
747}
748
749impl<'a> LiveFileStorageInfoEntry<'a> {
750 pub fn index(&self) -> usize {
752 self.index
753 }
754
755 pub fn relative_filename(&self) -> &'a [u8] {
757 unsafe {
758 borrowed_cstr(ffi::rocksdb_livefiles_storage_info_relative_filename(
759 self.info.inner.cast_const(),
760 self.index,
761 ))
762 }
763 }
764
765 pub fn relative_filename_lossy(&self) -> Cow<'a, str> {
768 String::from_utf8_lossy(self.relative_filename())
769 }
770
771 pub fn directory(&self) -> &'a [u8] {
774 unsafe {
775 borrowed_cstr(ffi::rocksdb_livefiles_storage_info_directory(
776 self.info.inner.cast_const(),
777 self.index,
778 ))
779 }
780 }
781
782 pub fn directory_lossy(&self) -> Cow<'a, str> {
784 String::from_utf8_lossy(self.directory())
785 }
786
787 pub fn file_number(&self) -> u64 {
790 unsafe {
791 ffi::rocksdb_livefiles_storage_info_file_number(
792 self.info.inner.cast_const(),
793 self.index,
794 )
795 }
796 }
797
798 pub fn file_type(&self) -> FileType {
800 FileType::from(unsafe {
801 ffi::rocksdb_livefiles_storage_info_file_type(self.info.inner.cast_const(), self.index)
802 })
803 }
804
805 pub fn size(&self) -> u64 {
809 unsafe {
810 ffi::rocksdb_livefiles_storage_info_size(self.info.inner.cast_const(), self.index)
811 }
812 }
813
814 pub fn trim_to_size(&self) -> bool {
818 unsafe {
819 ffi::rocksdb_livefiles_storage_info_trim_to_size(
820 self.info.inner.cast_const(),
821 self.index,
822 ) != 0
823 }
824 }
825
826 pub fn replacement_contents(&self) -> &'a [u8] {
833 let mut size: usize = 0;
834 let ptr = unsafe {
835 ffi::rocksdb_livefiles_storage_info_replacement_contents(
836 self.info.inner.cast_const(),
837 self.index,
838 &raw mut size,
839 )
840 };
841 if ptr.is_null() || size == 0 {
842 return &[];
843 }
844 unsafe { std::slice::from_raw_parts(ptr.cast::<u8>(), size) }
845 }
846
847 pub fn file_checksum_func_name(&self) -> &'a [u8] {
860 unsafe {
861 borrowed_cstr(ffi::rocksdb_livefiles_storage_info_file_checksum_func_name(
862 self.info.inner.cast_const(),
863 self.index,
864 ))
865 }
866 }
867
868 pub fn file_checksum_func_name_lossy(&self) -> Cow<'a, str> {
871 String::from_utf8_lossy(self.file_checksum_func_name())
872 }
873
874 pub fn temperature(&self) -> Temperature {
876 Temperature::from(unsafe {
877 ffi::rocksdb_livefiles_storage_info_temperature(
878 self.info.inner.cast_const(),
879 self.index,
880 )
881 })
882 }
883}
884
885impl fmt::Debug for LiveFileStorageInfoEntry<'_> {
886 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
887 f.debug_struct("LiveFileStorageInfoEntry")
888 .field("relative_filename", &self.relative_filename_lossy())
889 .field("directory", &self.directory_lossy())
890 .field("file_number", &self.file_number())
891 .field("file_type", &self.file_type())
892 .field("size", &self.size())
893 .field("trim_to_size", &self.trim_to_size())
894 .field("temperature", &self.temperature())
895 .finish_non_exhaustive()
896 }
897}