leveldb/database/
db.rs

1use super::bytes::Bytes;
2use super::comparator::{create_comparator, Comparator};
3use super::error::Error;
4use super::key::IntoLevelDBKey;
5use super::options::*;
6use cruzbit_leveldb_sys::*;
7use libc::{c_char, size_t};
8use std::ffi::CString;
9use std::path::Path;
10use std::ptr;
11
12#[allow(missing_docs)]
13#[derive(Debug)]
14pub(crate) struct RawDB {
15    pub(crate) ptr: *mut leveldb_t,
16}
17
18#[allow(missing_docs)]
19impl Drop for RawDB {
20    fn drop(&mut self) {
21        unsafe {
22            leveldb_close(self.ptr);
23        }
24    }
25}
26
27#[allow(missing_docs)]
28#[derive(Debug)]
29pub(crate) struct RawComparator {
30    ptr: *mut leveldb_comparator_t,
31}
32
33#[allow(missing_docs)]
34impl Drop for RawComparator {
35    fn drop(&mut self) {
36        unsafe {
37            leveldb_comparator_destroy(self.ptr);
38        }
39    }
40}
41
42#[derive(Debug)]
43pub struct Database {
44    pub(crate) database: RawDB,
45    // this holds a reference passed into leveldb
46    // it is never read from Rust, but must be kept around
47    #[allow(dead_code)]
48    pub(crate) comparator: Option<RawComparator>,
49}
50
51unsafe impl Sync for Database {}
52unsafe impl Send for Database {}
53
54impl Database {
55    fn new(database: *mut leveldb_t, comparator: Option<*mut leveldb_comparator_t>) -> Database {
56        let raw_comp = comparator.map(|p| RawComparator { ptr: p });
57
58        Database {
59            database: RawDB { ptr: database },
60            comparator: raw_comp,
61        }
62    }
63
64    /// Open a new database
65    ///
66    /// If the database is missing, the behaviour depends on `options.create_if_missing`.
67    /// The database will be created using the settings given in `options`.
68    pub fn open(name: &Path, options: &Options) -> Result<Database, Error> {
69        let mut error = ptr::null_mut();
70
71        unsafe {
72            let c_string = CString::new(name.to_str().unwrap()).unwrap();
73            let c_options = c_options(options, None);
74            let db = leveldb_open(
75                c_options as *const leveldb_options_t,
76                c_string.as_bytes_with_nul().as_ptr() as *const c_char,
77                &mut error,
78            );
79            leveldb_options_destroy(c_options);
80
81            if error.is_null() {
82                Ok(Database::new(db, None))
83            } else {
84                Err(Error::new_from_char(error))
85            }
86        }
87    }
88
89    /// Open a new database with a custom comparator
90    ///
91    /// If the database is missing, the behaviour depends on `options.create_if_missing`.
92    /// The database will be created using the settings given in `options`.
93    ///
94    /// The comparator must implement a total ordering over the keyspace.
95    ///
96    /// For keys that implement Ord, consider the `OrdComparator`.
97    pub fn open_with_comparator<C: Comparator>(
98        name: &Path,
99        options: &Options,
100        comparator: C,
101    ) -> Result<Database, Error> {
102        let mut error = ptr::null_mut();
103        let comp_ptr = create_comparator(Box::new(comparator));
104        unsafe {
105            let c_string = CString::new(name.to_str().unwrap()).unwrap();
106            let c_options = c_options(options, Some(comp_ptr));
107            let db = leveldb_open(
108                c_options as *const leveldb_options_t,
109                c_string.as_bytes_with_nul().as_ptr() as *const c_char,
110                &mut error,
111            );
112            leveldb_options_destroy(c_options);
113
114            if error.is_null() {
115                Ok(Database::new(db, Some(comp_ptr)))
116            } else {
117                Err(Error::new_from_char(error))
118            }
119        }
120    }
121
122    pub fn put(
123        &self,
124        options: &WriteOptions,
125        key: &dyn IntoLevelDBKey,
126        value: &[u8],
127    ) -> Result<(), Error> {
128        key.as_u8_slice_for_write(&|k| self.put_u8(options, k, value))
129    }
130
131    pub fn put_u8(&self, options: &WriteOptions, key: &[u8], value: &[u8]) -> Result<(), Error> {
132        unsafe {
133            let mut error = ptr::null_mut();
134            let c_writeoptions = c_writeoptions(options);
135
136            leveldb_put(
137                self.database.ptr,
138                c_writeoptions,
139                key.as_ptr() as *mut c_char,
140                key.len() as size_t,
141                value.as_ptr() as *mut c_char,
142                value.len() as size_t,
143                &mut error,
144            );
145
146            leveldb_writeoptions_destroy(c_writeoptions);
147
148            if error.is_null() {
149                Ok(())
150            } else {
151                Err(Error::new_from_char(error))
152            }
153        }
154    }
155
156    pub fn get(
157        &self,
158        options: &ReadOptions,
159        key: &dyn IntoLevelDBKey,
160    ) -> Result<Option<Vec<u8>>, Error> {
161        key.as_u8_slice_for_get(&|k| self.get_u8(options, k))
162    }
163
164    pub fn get_u8(&self, options: &ReadOptions, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
165        unsafe {
166            let mut error = ptr::null_mut();
167            let mut length: size_t = 0;
168            let c_readoptions = c_readoptions(options);
169            let result = leveldb_get(
170                self.database.ptr,
171                c_readoptions,
172                key.as_ptr() as *mut c_char,
173                key.len() as size_t,
174                &mut length,
175                &mut error,
176            );
177            leveldb_readoptions_destroy(c_readoptions);
178
179            if error.is_null() {
180                let bytes_opt = Bytes::from_raw(result as *mut u8, length);
181
182                Ok(bytes_opt.map(|val| val.into()))
183            } else {
184                Err(Error::new_from_char(error))
185            }
186        }
187    }
188
189    pub fn delete(&self, options: &WriteOptions, key: &dyn IntoLevelDBKey) -> Result<(), Error> {
190        key.as_u8_slice_for_write(&|k| self.delete_u8(options, k))
191    }
192
193    pub fn delete_u8(&self, options: &WriteOptions, key: &[u8]) -> Result<(), Error> {
194        unsafe {
195            let mut error = ptr::null_mut();
196            let c_writeoptions = c_writeoptions(options);
197
198            leveldb_delete(
199                self.database.ptr,
200                c_writeoptions,
201                key.as_ptr() as *mut c_char,
202                key.len() as size_t,
203                &mut error,
204            );
205
206            leveldb_writeoptions_destroy(c_writeoptions);
207
208            if error.is_null() {
209                Ok(())
210            } else {
211                Err(Error::new_from_char(error))
212            }
213        }
214    }
215}
216
217/// Helpful when building interfaces that read from either DB or Snapshot
218pub trait DatabaseReader {
219    fn get(
220        &self,
221        options: &ReadOptions,
222        key: &dyn IntoLevelDBKey,
223    ) -> Result<Option<Vec<u8>>, Error>;
224
225    fn get_u8(
226        &self,
227        options: &ReadOptions,
228        key: &[u8],
229    ) -> Result<Option<Vec<u8>>, Error>;
230}
231
232impl DatabaseReader for Database {
233    fn get(
234        &self,
235        options: &ReadOptions,
236        key: &dyn IntoLevelDBKey,
237    ) -> Result<Option<Vec<u8>>, Error> {
238        self.get(options, key)
239    }
240
241    fn get_u8(
242        &self,
243        options: &ReadOptions,
244        key: &[u8],
245    ) -> Result<Option<Vec<u8>>, Error> {
246        self.get_u8(options, key)
247    }
248}