ckb_rocksdb/
secondary_db.rs

1// Copyright 2019 Xuejie Xiao
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use 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}