Skip to main content

rust_rocksdb/
snapshot.rs

1// Copyright 2020 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
15use crate::{
16    AsColumnFamilyRef, DB, DBIteratorWithThreadMode, DBPinnableSlice, DBRawIteratorWithThreadMode,
17    Error, IteratorMode, ReadOptions, db::DBAccess, ffi,
18};
19
20/// A type alias to keep compatibility. See [`SnapshotWithThreadMode`] for details
21pub type Snapshot<'a> = SnapshotWithThreadMode<'a, DB>;
22
23/// A consistent view of the database at the point of creation.
24///
25/// # Examples
26///
27/// ```
28/// use rust_rocksdb::{DB, IteratorMode, Options};
29///
30/// let tempdir = tempfile::Builder::new()
31///     .prefix("_path_for_rocksdb_storage3")
32///     .tempdir()
33///     .expect("Failed to create temporary path for the _path_for_rocksdb_storage3");
34/// let path = tempdir.path();
35/// {
36///     let db = DB::open_default(path).unwrap();
37///     let snapshot = db.snapshot(); // Creates a longer-term snapshot of the DB, but closed when goes out of scope
38///     let mut iter = snapshot.iterator(IteratorMode::Start); // Make as many iterators as you'd like from one snapshot
39/// }
40/// let _ = DB::destroy(&Options::default(), path);
41/// ```
42///
43/// A `Snapshot` must not outlive the `DB` it was created from:
44///
45/// ```compile_fail,E0597
46/// use rust_rocksdb::DB;
47///
48/// let _snapshot = {
49///     let db = DB::open_default("foo").unwrap();
50///     db.snapshot()
51/// };
52/// ```
53pub struct SnapshotWithThreadMode<'a, D: DBAccess> {
54    db: &'a D,
55    pub(crate) inner: *const ffi::rocksdb_snapshot_t,
56}
57
58impl<'a, D: DBAccess> SnapshotWithThreadMode<'a, D> {
59    /// Creates a new `SnapshotWithThreadMode` of the database `db`.
60    pub fn new(db: &'a D) -> Self {
61        let snapshot = unsafe { db.create_snapshot() };
62        Self {
63            db,
64            inner: snapshot,
65        }
66    }
67
68    /// Returns the sequence number of the snapshot.
69    pub fn sequence_number(&self) -> u64 {
70        unsafe { ffi::rocksdb_snapshot_get_sequence_number(self.inner) }
71    }
72
73    /// Creates an iterator over the data in this snapshot, using the default read options.
74    pub fn iterator(&self, mode: IteratorMode) -> DBIteratorWithThreadMode<'a, D> {
75        let readopts = ReadOptions::default();
76        self.iterator_opt(mode, readopts)
77    }
78
79    /// Creates an iterator over the data in this snapshot under the given column family, using
80    /// the default read options.
81    pub fn iterator_cf(
82        &'_ self,
83        cf_handle: &impl AsColumnFamilyRef,
84        mode: IteratorMode,
85    ) -> DBIteratorWithThreadMode<'_, D> {
86        let readopts = ReadOptions::default();
87        self.iterator_cf_opt(cf_handle, readopts, mode)
88    }
89
90    /// Creates an iterator over the data in this snapshot, using the given read options.
91    pub fn iterator_opt(
92        &self,
93        mode: IteratorMode,
94        mut readopts: ReadOptions,
95    ) -> DBIteratorWithThreadMode<'a, D> {
96        readopts.set_snapshot(self);
97        DBIteratorWithThreadMode::<D>::new(self.db, readopts, mode)
98    }
99
100    /// Creates an iterator over the data in this snapshot under the given column family, using
101    /// the given read options.
102    pub fn iterator_cf_opt(
103        &'_ self,
104        cf_handle: &impl AsColumnFamilyRef,
105        mut readopts: ReadOptions,
106        mode: IteratorMode,
107    ) -> DBIteratorWithThreadMode<'_, D> {
108        readopts.set_snapshot(self);
109        DBIteratorWithThreadMode::new_cf(self.db, cf_handle.inner(), readopts, mode)
110    }
111
112    /// Creates a raw iterator over the data in this snapshot, using the default read options.
113    pub fn raw_iterator(&'_ self) -> DBRawIteratorWithThreadMode<'_, D> {
114        let readopts = ReadOptions::default();
115        self.raw_iterator_opt(readopts)
116    }
117
118    /// Creates a raw iterator over the data in this snapshot under the given column family, using
119    /// the default read options.
120    pub fn raw_iterator_cf(
121        &'_ self,
122        cf_handle: &impl AsColumnFamilyRef,
123    ) -> DBRawIteratorWithThreadMode<'_, D> {
124        let readopts = ReadOptions::default();
125        self.raw_iterator_cf_opt(cf_handle, readopts)
126    }
127
128    /// Creates a raw iterator over the data in this snapshot, using the given read options.
129    pub fn raw_iterator_opt(
130        &'_ self,
131        mut readopts: ReadOptions,
132    ) -> DBRawIteratorWithThreadMode<'_, D> {
133        readopts.set_snapshot(self);
134        DBRawIteratorWithThreadMode::new(self.db, readopts)
135    }
136
137    /// Creates a raw iterator over the data in this snapshot under the given column family, using
138    /// the given read options.
139    pub fn raw_iterator_cf_opt(
140        &'_ self,
141        cf_handle: &impl AsColumnFamilyRef,
142        mut readopts: ReadOptions,
143    ) -> DBRawIteratorWithThreadMode<'_, D> {
144        readopts.set_snapshot(self);
145        DBRawIteratorWithThreadMode::new_cf(self.db, cf_handle.inner(), readopts)
146    }
147
148    /// Returns the bytes associated with a key value with default read options.
149    pub fn get<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Vec<u8>>, Error> {
150        let readopts = ReadOptions::default();
151        self.get_opt(key, readopts)
152    }
153
154    /// Returns the bytes associated with a key value and given column family with default read
155    /// options.
156    pub fn get_cf<K: AsRef<[u8]>>(
157        &self,
158        cf: &impl AsColumnFamilyRef,
159        key: K,
160    ) -> Result<Option<Vec<u8>>, Error> {
161        let readopts = ReadOptions::default();
162        self.get_cf_opt(cf, key.as_ref(), readopts)
163    }
164
165    /// Returns the bytes associated with a key value and given read options.
166    pub fn get_opt<K: AsRef<[u8]>>(
167        &self,
168        key: K,
169        mut readopts: ReadOptions,
170    ) -> Result<Option<Vec<u8>>, Error> {
171        readopts.set_snapshot(self);
172        self.db.get_opt(key.as_ref(), &readopts)
173    }
174
175    /// Returns the bytes associated with a key value, given column family and read options.
176    pub fn get_cf_opt<K: AsRef<[u8]>>(
177        &self,
178        cf: &impl AsColumnFamilyRef,
179        key: K,
180        mut readopts: ReadOptions,
181    ) -> Result<Option<Vec<u8>>, Error> {
182        readopts.set_snapshot(self);
183        self.db.get_cf_opt(cf, key.as_ref(), &readopts)
184    }
185
186    /// Return the value associated with a key using RocksDB's PinnableSlice
187    /// so as to avoid unnecessary memory copy. Similar to get_pinned_opt but
188    /// leverages default options.
189    pub fn get_pinned<K: AsRef<[u8]>>(
190        &'_ self,
191        key: K,
192    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
193        let readopts = ReadOptions::default();
194        self.get_pinned_opt(key, readopts)
195    }
196
197    /// Return the value associated with a key using RocksDB's PinnableSlice
198    /// so as to avoid unnecessary memory copy. Similar to get_pinned_cf_opt but
199    /// leverages default options.
200    pub fn get_pinned_cf<K: AsRef<[u8]>>(
201        &'_ self,
202        cf: &impl AsColumnFamilyRef,
203        key: K,
204    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
205        let readopts = ReadOptions::default();
206        self.get_pinned_cf_opt(cf, key.as_ref(), readopts)
207    }
208
209    /// Return the value associated with a key using RocksDB's PinnableSlice
210    /// so as to avoid unnecessary memory copy.
211    pub fn get_pinned_opt<K: AsRef<[u8]>>(
212        &'_ self,
213        key: K,
214        mut readopts: ReadOptions,
215    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
216        readopts.set_snapshot(self);
217        self.db.get_pinned_opt(key.as_ref(), &readopts)
218    }
219
220    /// Return the value associated with a key using RocksDB's PinnableSlice
221    /// so as to avoid unnecessary memory copy. Similar to get_pinned_opt but
222    /// allows specifying ColumnFamily.
223    pub fn get_pinned_cf_opt<K: AsRef<[u8]>>(
224        &'_ self,
225        cf: &impl AsColumnFamilyRef,
226        key: K,
227        mut readopts: ReadOptions,
228    ) -> Result<Option<DBPinnableSlice<'_>>, Error> {
229        readopts.set_snapshot(self);
230        self.db.get_pinned_cf_opt(cf, key.as_ref(), &readopts)
231    }
232
233    /// Returns the bytes associated with the given key values and default read options.
234    pub fn multi_get<K: AsRef<[u8]>, I>(&self, keys: I) -> Vec<Result<Option<Vec<u8>>, Error>>
235    where
236        I: IntoIterator<Item = K>,
237    {
238        let readopts = ReadOptions::default();
239        self.multi_get_opt(keys, readopts)
240    }
241
242    /// Returns the bytes associated with the given key values and default read options.
243    pub fn multi_get_cf<'b, K, I, W>(&self, keys_cf: I) -> Vec<Result<Option<Vec<u8>>, Error>>
244    where
245        K: AsRef<[u8]>,
246        I: IntoIterator<Item = (&'b W, K)>,
247        W: AsColumnFamilyRef + 'b,
248    {
249        let readopts = ReadOptions::default();
250        self.multi_get_cf_opt(keys_cf, readopts)
251    }
252
253    /// Returns the bytes associated with the given key values and given read options.
254    pub fn multi_get_opt<K, I>(
255        &self,
256        keys: I,
257        mut readopts: ReadOptions,
258    ) -> Vec<Result<Option<Vec<u8>>, Error>>
259    where
260        K: AsRef<[u8]>,
261        I: IntoIterator<Item = K>,
262    {
263        readopts.set_snapshot(self);
264        self.db.multi_get_opt(keys, &readopts)
265    }
266
267    /// Returns the bytes associated with the given key values, given column family and read options.
268    pub fn multi_get_cf_opt<'b, K, I, W>(
269        &self,
270        keys_cf: I,
271        mut readopts: ReadOptions,
272    ) -> Vec<Result<Option<Vec<u8>>, Error>>
273    where
274        K: AsRef<[u8]>,
275        I: IntoIterator<Item = (&'b W, K)>,
276        W: AsColumnFamilyRef + 'b,
277    {
278        readopts.set_snapshot(self);
279        self.db.multi_get_cf_opt(keys_cf, &readopts)
280    }
281}
282
283impl<D: DBAccess> Drop for SnapshotWithThreadMode<'_, D> {
284    fn drop(&mut self) {
285        unsafe {
286            self.db.release_snapshot(self.inner);
287        }
288    }
289}
290
291/// `Send` and `Sync` implementations for `SnapshotWithThreadMode` are safe, because `SnapshotWithThreadMode` is
292/// immutable and can be safely shared between threads.
293unsafe impl<D: DBAccess> Send for SnapshotWithThreadMode<'_, D> {}
294unsafe impl<D: DBAccess> Sync for SnapshotWithThreadMode<'_, D> {}