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