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