ckb_rocksdb/
read_only_db.rs

1// Copyright 2019 Tyler Neely
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;
17
18use crate::{
19    db_iterator::DBRawIterator,
20    db_options::{OptionsMustOutliveDB, ReadOptions},
21    handle::Handle,
22    open_raw::{OpenRaw, OpenRawFFI},
23    ops, ColumnFamily, Error,
24};
25
26use libc::c_uchar;
27use std::collections::BTreeMap;
28use std::fmt;
29use std::marker::PhantomData;
30use std::path::{Path, PathBuf};
31
32pub struct ReadOnlyDB {
33    pub(crate) inner: *mut ffi::rocksdb_t,
34    cfs: BTreeMap<String, ColumnFamily>,
35    path: PathBuf,
36    _outlive: Vec<OptionsMustOutliveDB>,
37}
38
39impl ReadOnlyDB {
40    pub fn path(&self) -> &Path {
41        self.path.as_path()
42    }
43}
44
45#[derive(Default)]
46pub struct ReadOnlyOpenDescriptor {
47    error_if_log_file_exists: bool,
48}
49
50impl ops::Open for ReadOnlyDB {}
51impl ops::OpenCF for ReadOnlyDB {}
52
53impl OpenRaw for ReadOnlyDB {
54    type Pointer = ffi::rocksdb_t;
55    type Descriptor = ReadOnlyOpenDescriptor;
56
57    fn open_ffi(input: OpenRawFFI<'_, Self::Descriptor>) -> Result<*mut Self::Pointer, Error> {
58        let error_if_log_file_exists = input.open_descriptor.error_if_log_file_exists as c_uchar;
59        let pointer = unsafe {
60            if input.num_column_families <= 0 {
61                ffi_try!(ffi::rocksdb_open_for_read_only(
62                    input.options,
63                    input.path,
64                    error_if_log_file_exists,
65                ))
66            } else {
67                ffi_try!(ffi::rocksdb_open_for_read_only_column_families(
68                    input.options,
69                    input.path,
70                    input.num_column_families,
71                    input.column_family_names,
72                    input.column_family_options,
73                    input.column_family_handles,
74                    error_if_log_file_exists,
75                ))
76            }
77        };
78
79        Ok(pointer)
80    }
81
82    fn build<I>(
83        path: PathBuf,
84        _open_descriptor: Self::Descriptor,
85        pointer: *mut Self::Pointer,
86        column_families: I,
87        outlive: Vec<OptionsMustOutliveDB>,
88    ) -> Result<Self, Error>
89    where
90        I: IntoIterator<Item = (String, *mut ffi::rocksdb_column_family_handle_t)>,
91    {
92        let cfs: BTreeMap<_, _> = column_families
93            .into_iter()
94            .map(|(k, h)| (k, ColumnFamily::new(h)))
95            .collect();
96        Ok(ReadOnlyDB {
97            inner: pointer,
98            cfs,
99            path,
100            _outlive: outlive,
101        })
102    }
103}
104
105impl Handle<ffi::rocksdb_t> for ReadOnlyDB {
106    fn handle(&self) -> *mut ffi::rocksdb_t {
107        self.inner
108    }
109}
110
111impl ops::Iterate for ReadOnlyDB {
112    fn get_raw_iter<'a: 'b, 'b>(&'a self, readopts: &ReadOptions) -> DBRawIterator<'b> {
113        unsafe {
114            DBRawIterator {
115                inner: ffi::rocksdb_create_iterator(self.inner, readopts.handle()),
116                db: PhantomData,
117            }
118        }
119    }
120}
121
122impl ops::IterateCF for ReadOnlyDB {
123    fn get_raw_iter_cf<'a: 'b, 'b>(
124        &'a self,
125        cf_handle: &ColumnFamily,
126        readopts: &ReadOptions,
127    ) -> Result<DBRawIterator<'b>, Error> {
128        unsafe {
129            Ok(DBRawIterator {
130                inner: ffi::rocksdb_create_iterator_cf(
131                    self.inner,
132                    readopts.handle(),
133                    cf_handle.inner,
134                ),
135                db: PhantomData,
136            })
137        }
138    }
139}
140
141impl ops::GetColumnFamilys for ReadOnlyDB {
142    fn get_cfs(&self) -> &BTreeMap<String, ColumnFamily> {
143        &self.cfs
144    }
145    fn get_mut_cfs(&mut self) -> &mut BTreeMap<String, ColumnFamily> {
146        &mut self.cfs
147    }
148}
149
150impl ops::Read for ReadOnlyDB {}
151
152unsafe impl Send for ReadOnlyDB {}
153unsafe impl Sync for ReadOnlyDB {}
154
155impl Drop for ReadOnlyDB {
156    fn drop(&mut self) {
157        unsafe {
158            for cf in self.cfs.values() {
159                ffi::rocksdb_column_family_handle_destroy(cf.inner);
160            }
161            ffi::rocksdb_close(self.inner);
162        }
163    }
164}
165
166impl fmt::Debug for ReadOnlyDB {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        write!(f, "Read-only RocksDB {{ path: {:?} }}", self.path())
169    }
170}