ckb_rocksdb/
secondary_db.rs1use crate::ffi;
17use crate::ffi_util;
18
19use crate::{
20 ColumnFamily, Error,
21 db_iterator::DBRawIterator,
22 db_options::{OptionsMustOutliveDB, ReadOptions},
23 handle::Handle,
24 open_raw::{OpenRaw, OpenRawFFI},
25 ops,
26};
27
28use std::collections::BTreeMap;
29use std::fmt;
30use std::marker::PhantomData;
31use std::path::{Path, PathBuf};
32
33pub struct SecondaryDB {
34 pub(crate) inner: *mut ffi::rocksdb_t,
35 cfs: BTreeMap<String, ColumnFamily>,
36 path: PathBuf,
37 _outlive: Vec<OptionsMustOutliveDB>,
38}
39
40impl SecondaryDB {
41 pub fn path(&self) -> &Path {
42 self.path.as_path()
43 }
44
45 pub fn try_catch_up_with_primary(&self) -> Result<(), Error> {
46 unsafe { ffi_try!(ffi::rocksdb_try_catch_up_with_primary(self.inner,)) };
47 Ok(())
48 }
49}
50
51pub struct SecondaryOpenDescriptor {
52 secondary_path: String,
53}
54
55impl Default for SecondaryOpenDescriptor {
56 fn default() -> Self {
57 SecondaryOpenDescriptor {
58 secondary_path: "".to_string(),
59 }
60 }
61}
62
63impl SecondaryOpenDescriptor {
64 pub fn new(secondary_path: String) -> Self {
65 Self { secondary_path }
66 }
67}
68
69impl ops::Open for SecondaryDB {}
70impl ops::OpenCF for SecondaryDB {}
71
72impl OpenRaw for SecondaryDB {
73 type Pointer = ffi::rocksdb_t;
74 type Descriptor = SecondaryOpenDescriptor;
75
76 fn open_ffi(input: OpenRawFFI<'_, Self::Descriptor>) -> Result<*mut Self::Pointer, Error> {
77 if input.open_descriptor.secondary_path.is_empty() {
78 return Err(Error::new(
79 "Secondary DB must have secondary path provided!".to_string(),
80 ));
81 }
82 let secondary_path = ffi_util::to_cpath(
83 &input.open_descriptor.secondary_path,
84 "Failed to convert path to CString when opening database.",
85 )?;
86 let pointer = unsafe {
87 if input.num_column_families <= 0 {
88 ffi_try!(ffi::rocksdb_open_as_secondary(
89 input.options,
90 input.path,
91 secondary_path.as_ptr(),
92 ))
93 } else {
94 ffi_try!(ffi::rocksdb_open_as_secondary_column_families(
95 input.options,
96 input.path,
97 secondary_path.as_ptr(),
98 input.num_column_families,
99 input.column_family_names,
100 input.column_family_options,
101 input.column_family_handles,
102 ))
103 }
104 };
105
106 Ok(pointer)
107 }
108
109 fn build<I>(
110 path: PathBuf,
111 _open_descriptor: Self::Descriptor,
112 pointer: *mut Self::Pointer,
113 column_families: I,
114 outlive: Vec<OptionsMustOutliveDB>,
115 ) -> Result<Self, Error>
116 where
117 I: IntoIterator<Item = (String, *mut ffi::rocksdb_column_family_handle_t)>,
118 {
119 let cfs: BTreeMap<_, _> = column_families
120 .into_iter()
121 .map(|(k, h)| (k, ColumnFamily::new(h)))
122 .collect();
123 Ok(SecondaryDB {
124 inner: pointer,
125 cfs,
126 path,
127 _outlive: outlive,
128 })
129 }
130}
131
132impl Handle<ffi::rocksdb_t> for SecondaryDB {
133 fn handle(&self) -> *mut ffi::rocksdb_t {
134 self.inner
135 }
136}
137
138impl ops::Iterate for SecondaryDB {
139 fn get_raw_iter<'a: 'b, 'b>(&'a self, readopts: &ReadOptions) -> DBRawIterator<'b> {
140 unsafe {
141 DBRawIterator {
142 inner: ffi::rocksdb_create_iterator(self.inner, readopts.handle()),
143 db: PhantomData,
144 }
145 }
146 }
147}
148
149impl ops::IterateCF for SecondaryDB {
150 fn get_raw_iter_cf<'a: 'b, 'b>(
151 &'a self,
152 cf_handle: &ColumnFamily,
153 readopts: &ReadOptions,
154 ) -> Result<DBRawIterator<'b>, Error> {
155 unsafe {
156 Ok(DBRawIterator {
157 inner: ffi::rocksdb_create_iterator_cf(
158 self.inner,
159 readopts.handle(),
160 cf_handle.inner,
161 ),
162 db: PhantomData,
163 })
164 }
165 }
166}
167
168impl ops::GetColumnFamilys for SecondaryDB {
169 fn get_cfs(&self) -> &BTreeMap<String, ColumnFamily> {
170 &self.cfs
171 }
172 fn get_mut_cfs(&mut self) -> &mut BTreeMap<String, ColumnFamily> {
173 &mut self.cfs
174 }
175}
176
177impl ops::Read for SecondaryDB {}
178
179unsafe impl Send for SecondaryDB {}
180unsafe impl Sync for SecondaryDB {}
181
182impl Drop for SecondaryDB {
183 fn drop(&mut self) {
184 unsafe {
185 for cf in self.cfs.values() {
186 ffi::rocksdb_column_family_handle_destroy(cf.inner);
187 }
188 ffi::rocksdb_close(self.inner);
189 }
190 }
191}
192
193impl fmt::Debug for SecondaryDB {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 write!(f, "Read-only RocksDB {{ path: {:?} }}", self.path())
196 }
197}