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    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}