ckb_rocksdb/
db_iterator.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::ops::Iterate;
17use libc::{c_char, c_uchar, size_t};
18use std::marker::PhantomData;
19use std::slice;
20
21/// An iterator over a database or column family, with specifiable
22/// ranges and direction.
23///
24/// This iterator is different to the standard ``DBIterator`` as it aims Into
25/// replicate the underlying iterator API within RocksDB itself. This should
26/// give access to more performance and flexibility but departs from the
27/// widely recognised Rust idioms.
28///
29/// ```
30/// use ckb_rocksdb::prelude::*;
31/// # use ckb_rocksdb::TemporaryDBPath;
32///
33/// let path = "_path_for_rocksdb_storage4";
34/// # let path = TemporaryDBPath::new();
35/// # {
36/// #
37///
38/// let db = DB::open_default(&path).unwrap();
39/// let mut iter = db.raw_iterator();
40///
41/// // Forwards iteration
42/// iter.seek_to_first();
43/// while iter.valid() {
44///     println!("Saw {:?} {:?}", iter.key(), iter.value());
45///     iter.next();
46/// }
47///
48/// // Reverse iteration
49/// iter.seek_to_last();
50/// while iter.valid() {
51///     println!("Saw {:?} {:?}", iter.key(), iter.value());
52///     iter.prev();
53/// }
54///
55/// // Seeking
56/// iter.seek(b"my key");
57/// while iter.valid() {
58///     println!("Saw {:?} {:?}", iter.key(), iter.value());
59///     iter.next();
60/// }
61///
62/// // Reverse iteration from key
63/// // Note, use seek_for_prev when reversing because if this key doesn't exist,
64/// // this will make the iterator start from the previous key rather than the next.
65/// iter.seek_for_prev(b"my key");
66/// while iter.valid() {
67///     println!("Saw {:?} {:?}", iter.key(), iter.value());
68///     iter.prev();
69/// }
70
71/// # }
72/// ```
73unsafe impl<'a> Sync for DBRawIterator<'a> {}
74
75pub struct DBRawIterator<'a> {
76    pub(crate) inner: *mut ffi::rocksdb_iterator_t,
77    pub(crate) db: PhantomData<&'a dyn Iterate>,
78}
79
80/// An iterator over a database or column family, with specifiable
81/// ranges and direction.
82///
83/// ```
84/// use ckb_rocksdb::{prelude::*, Direction, IteratorMode};
85/// # use ckb_rocksdb::TemporaryDBPath;
86
87/// let path = "_path_for_rocksdb_storage2";
88/// # let path = TemporaryDBPath::new();
89/// # {
90
91/// let db = DB::open_default(&path).unwrap();
92/// let mut iter = db.iterator(IteratorMode::Start); // Always iterates forward
93/// for (key, value) in iter {
94///     println!("Saw {:?} {:?}", key, value);
95/// }
96///
97/// iter = db.iterator(IteratorMode::End);  // Always iterates backward
98/// for (key, value) in iter {
99///     println!("Saw {:?} {:?}", key, value);
100/// }
101///
102/// iter = db.iterator(IteratorMode::From(b"my key", Direction::Forward)); // From a key in Direction::{forward,reverse}
103/// for (key, value) in iter {
104///     println!("Saw {:?} {:?}", key, value);
105/// }
106///
107/// // You can seek with an existing Iterator instance, too
108/// iter = db.iterator(IteratorMode::Start);
109/// iter.set_mode(IteratorMode::From(b"another key", Direction::Reverse));
110/// for (key, value) in iter {
111///     println!("Saw {:?} {:?}", key, value);
112/// }
113
114/// # }
115/// ```
116pub struct DBIterator<'a> {
117    pub(crate) raw: DBRawIterator<'a>,
118    pub(crate) direction: Direction,
119    pub(crate) just_seeked: bool,
120}
121
122unsafe impl<'a> Send for DBIterator<'a> {}
123
124pub enum Direction {
125    Forward,
126    Reverse,
127}
128
129pub type KVBytes = (Box<[u8]>, Box<[u8]>);
130
131pub enum IteratorMode<'a> {
132    Start,
133    End,
134    From(&'a [u8], Direction),
135}
136
137impl<'a> DBRawIterator<'a> {
138    /// Returns true if the iterator is valid.
139    pub fn valid(&self) -> bool {
140        unsafe { ffi::rocksdb_iter_valid(self.inner) != 0 }
141    }
142
143    /// Seeks to the first key in the database.
144    ///
145    /// # Examples
146    ///
147    /// ```rust
148    /// use ckb_rocksdb::prelude::*;
149    /// # use ckb_rocksdb::TemporaryDBPath;
150    ///
151    /// let path = "_path_for_rocksdb_storage5";
152    /// # let path = TemporaryDBPath::new();
153    /// # {
154    ///
155    /// let db = DB::open_default(&path).unwrap();
156    /// let mut iter = db.raw_iterator();
157    ///
158    /// // Iterate all keys from the start in lexicographic order
159    /// iter.seek_to_first();
160    ///
161    /// while iter.valid() {
162    ///     println!("{:?} {:?}", iter.key(), iter.value());
163    ///     iter.next();
164    /// }
165    ///
166    /// // Read just the first key
167    /// iter.seek_to_first();
168    ///
169    /// if iter.valid() {
170    ///     println!("{:?} {:?}", iter.key(), iter.value());
171    /// } else {
172    ///     // There are no keys in the database
173    /// }
174
175    /// # }
176    /// ```
177    pub fn seek_to_first(&mut self) {
178        unsafe {
179            ffi::rocksdb_iter_seek_to_first(self.inner);
180        }
181    }
182
183    /// Seeks to the last key in the database.
184    ///
185    /// # Examples
186    ///
187    /// ```rust
188    /// use ckb_rocksdb::prelude::*;
189    /// # use ckb_rocksdb::TemporaryDBPath;
190    ///
191    /// let path = "_path_for_rocksdb_storage6";
192    /// # let path = TemporaryDBPath::new();
193    /// # {
194    ///
195    /// let db = DB::open_default(&path).unwrap();
196    /// let mut iter = db.raw_iterator();
197    ///
198    /// // Iterate all keys from the end in reverse lexicographic order
199    /// iter.seek_to_last();
200    ///
201    /// while iter.valid() {
202    ///     println!("{:?} {:?}", iter.key(), iter.value());
203    ///     iter.prev();
204    /// }
205    ///
206    /// // Read just the last key
207    /// iter.seek_to_last();
208    ///
209    /// if iter.valid() {
210    ///     println!("{:?} {:?}", iter.key(), iter.value());
211    /// } else {
212    ///     // There are no keys in the database
213    /// }
214
215    /// # }
216    /// ```
217    pub fn seek_to_last(&mut self) {
218        unsafe {
219            ffi::rocksdb_iter_seek_to_last(self.inner);
220        }
221    }
222
223    /// Seeks to the specified key or the first key that lexicographically follows it.
224    ///
225    /// This method will attempt to seek to the specified key. If that key does not exist, it will
226    /// find and seek to the key that lexicographically follows it instead.
227    ///
228    /// # Examples
229    ///
230    /// ```rust
231    /// use ckb_rocksdb::prelude::*;
232    /// # use ckb_rocksdb::TemporaryDBPath;
233    ///
234    /// let path = "_path_for_rocksdb_storage7";
235    /// # let path = TemporaryDBPath::new();
236    /// # {
237    ///
238    /// let db = DB::open_default(&path).unwrap();
239    /// let mut iter = db.raw_iterator();
240    ///
241    /// // Read the first key that starts with 'a'
242    /// iter.seek(b"a");
243    ///
244    /// if iter.valid() {
245    ///     println!("{:?} {:?}", iter.key(), iter.value());
246    /// } else {
247    ///     // There are no keys in the database
248    /// }
249
250    /// # }
251    /// ```
252    pub fn seek<K: AsRef<[u8]>>(&mut self, key: K) {
253        let key = key.as_ref();
254
255        unsafe {
256            ffi::rocksdb_iter_seek(
257                self.inner,
258                key.as_ptr() as *const c_char,
259                key.len() as size_t,
260            );
261        }
262    }
263
264    /// Seeks to the specified key, or the first key that lexicographically precedes it.
265    ///
266    /// Like ``.seek()`` this method will attempt to seek to the specified key.
267    /// The difference with ``.seek()`` is that if the specified key do not exist, this method will
268    /// seek to key that lexicographically precedes it instead.
269    ///
270    /// # Examples
271    ///
272    /// ```rust
273    /// use ckb_rocksdb::prelude::*;
274    /// # use ckb_rocksdb::TemporaryDBPath;
275    ///
276    /// let path = "_path_for_rocksdb_storage8";
277    /// # let path = TemporaryDBPath::new();
278    /// # {
279    ///
280    /// let db = DB::open_default(&path).unwrap();
281    /// let mut iter = db.raw_iterator();
282    ///
283    /// // Read the last key that starts with 'a'
284    /// iter.seek_for_prev(b"b");
285    ///
286    /// if iter.valid() {
287    ///     println!("{:?} {:?}", iter.key(), iter.value());
288    /// } else {
289    ///     // There are no keys in the database
290    /// }
291
292    /// # }
293    /// ```
294    pub fn seek_for_prev<K: AsRef<[u8]>>(&mut self, key: K) {
295        let key = key.as_ref();
296
297        unsafe {
298            ffi::rocksdb_iter_seek_for_prev(
299                self.inner,
300                key.as_ptr() as *const c_char,
301                key.len() as size_t,
302            );
303        }
304    }
305
306    /// Seeks to the next key.
307    ///
308    /// Returns true if the iterator is valid after this operation.
309    pub fn next(&mut self) {
310        unsafe {
311            ffi::rocksdb_iter_next(self.inner);
312        }
313    }
314
315    /// Seeks to the previous key.
316    ///
317    /// Returns true if the iterator is valid after this operation.
318    pub fn prev(&mut self) {
319        unsafe {
320            ffi::rocksdb_iter_prev(self.inner);
321        }
322    }
323
324    /// Returns a slice of the current key.
325    pub fn key(&self) -> Option<&[u8]> {
326        if self.valid() {
327            // Safety Note: This is safe as all methods that may invalidate the buffer returned
328            // take `&mut self`, so borrow checker will prevent use of buffer after seek.
329            unsafe {
330                let mut key_len: size_t = 0;
331                let key_len_ptr: *mut size_t = &mut key_len;
332                let key_ptr = ffi::rocksdb_iter_key(self.inner, key_len_ptr) as *const c_uchar;
333                Some(slice::from_raw_parts(key_ptr, key_len))
334            }
335        } else {
336            None
337        }
338    }
339
340    /// Returns a slice of the current value.
341    pub fn value(&self) -> Option<&[u8]> {
342        if self.valid() {
343            // Safety Note: This is safe as all methods that may invalidate the buffer returned
344            // take `&mut self`, so borrow checker will prevent use of buffer after seek.
345            unsafe {
346                let mut val_len: size_t = 0;
347                let val_len_ptr: *mut size_t = &mut val_len;
348                let val_ptr = ffi::rocksdb_iter_value(self.inner, val_len_ptr) as *const c_uchar;
349
350                Some(slice::from_raw_parts(val_ptr, val_len))
351            }
352        } else {
353            None
354        }
355    }
356}
357
358impl<'a> Drop for DBRawIterator<'a> {
359    fn drop(&mut self) {
360        unsafe {
361            ffi::rocksdb_iter_destroy(self.inner);
362        }
363    }
364}
365
366impl<'a> DBIterator<'a> {
367    pub fn set_mode(&mut self, mode: IteratorMode) {
368        match mode {
369            IteratorMode::Start => {
370                self.raw.seek_to_first();
371                self.direction = Direction::Forward;
372            }
373            IteratorMode::End => {
374                self.raw.seek_to_last();
375                self.direction = Direction::Reverse;
376            }
377            IteratorMode::From(key, Direction::Forward) => {
378                self.raw.seek(key);
379                self.direction = Direction::Forward;
380            }
381            IteratorMode::From(key, Direction::Reverse) => {
382                self.raw.seek_for_prev(key);
383                self.direction = Direction::Reverse;
384            }
385        };
386
387        self.just_seeked = true;
388    }
389
390    pub fn valid(&self) -> bool {
391        self.raw.valid()
392    }
393}
394
395impl<'a> Iterator for DBIterator<'a> {
396    type Item = KVBytes;
397
398    fn next(&mut self) -> Option<KVBytes> {
399        if !self.raw.valid() {
400            return None;
401        }
402        // Initial call to next() after seeking should not move the iterator
403        // or the first item will not be returned
404        if !self.just_seeked {
405            match self.direction {
406                Direction::Forward => self.raw.next(),
407                Direction::Reverse => self.raw.prev(),
408            }
409        } else {
410            self.just_seeked = false;
411        }
412
413        if self.raw.valid() {
414            // .key() and .value() only ever return None if valid == false, which we've just cheked
415            Some((
416                Box::from(self.raw.key().unwrap()),
417                Box::from(self.raw.value().unwrap()),
418            ))
419        } else {
420            None
421        }
422    }
423}
424
425impl<'a> From<DBIterator<'a>> for DBRawIterator<'a> {
426    fn from(iter: DBIterator<'a>) -> DBRawIterator<'a> {
427        iter.raw
428    }
429}