Skip to main content

rust_rocksdb/
db_iterator.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    Error, ReadOptions, WriteBatch,
17    db::{DB, DBAccess},
18    ffi,
19};
20use libc::{c_char, c_uchar, size_t};
21use std::mem::ManuallyDrop;
22use std::sync::Arc;
23use std::{marker::PhantomData, ops::ControlFlow, slice};
24
25/// A type alias to keep compatibility. See [`DBRawIteratorWithThreadMode`] for details
26pub type DBRawIterator<'a> = DBRawIteratorWithThreadMode<'a, DB>;
27
28/// Keeps an iterator's [`ReadOptions`] alive for as long as the iterator is.
29///
30/// `rocksdb_create_iterators` builds N iterators from one options object, so
31/// that case needs a shared owner. Every other constructor makes one iterator
32/// from one options object and keeps it outright, which costs nothing.
33pub(crate) enum IterReadOptions {
34    Owned(ReadOptions),
35    Shared(Arc<ReadOptions>),
36}
37
38impl IterReadOptions {
39    #[inline]
40    pub(crate) fn as_ptr(&self) -> *mut ffi::rocksdb_readoptions_t {
41        match self {
42            Self::Owned(readopts) => readopts.inner,
43            Self::Shared(readopts) => readopts.inner,
44        }
45    }
46}
47
48impl From<ReadOptions> for IterReadOptions {
49    fn from(readopts: ReadOptions) -> Self {
50        Self::Owned(readopts)
51    }
52}
53
54impl From<Arc<ReadOptions>> for IterReadOptions {
55    fn from(readopts: Arc<ReadOptions>) -> Self {
56        Self::Shared(readopts)
57    }
58}
59
60/// A low-level iterator over a database or column family, created by [`DB::raw_iterator`]
61/// and other `raw_iterator_*` methods.
62///
63/// This iterator replicates RocksDB's API. It should provide better
64/// performance and more features than [`DBIteratorWithThreadMode`], which is a standard
65/// Rust [`std::iter::Iterator`].
66///
67/// ```
68/// use rust_rocksdb::{DB, Options};
69///
70/// let tempdir = tempfile::Builder::new()
71///     .prefix("_path_for_rocksdb_storage4")
72///     .tempdir()
73///     .expect("Failed to create temporary path for the _path_for_rocksdb_storage4.");
74/// let path = tempdir.path();
75/// {
76///     let db = DB::open_default(path).unwrap();
77///     let mut iter = db.raw_iterator();
78///
79///     // Forwards iteration
80///     iter.seek_to_first();
81///     while iter.valid() {
82///         println!("Saw {:?} {:?}", iter.key(), iter.value());
83///         iter.next();
84///     }
85///
86///     // Reverse iteration
87///     iter.seek_to_last();
88///     while iter.valid() {
89///         println!("Saw {:?} {:?}", iter.key(), iter.value());
90///         iter.prev();
91///     }
92///
93///     // Seeking
94///     iter.seek(b"my key");
95///     while iter.valid() {
96///         println!("Saw {:?} {:?}", iter.key(), iter.value());
97///         iter.next();
98///     }
99///
100///     // Reverse iteration from key
101///     // Note, use seek_for_prev when reversing because if this key doesn't exist,
102///     // this will make the iterator start from the previous key rather than the next.
103///     iter.seek_for_prev(b"my key");
104///     while iter.valid() {
105///         println!("Saw {:?} {:?}", iter.key(), iter.value());
106///         iter.prev();
107///     }
108/// }
109/// let _ = DB::destroy(&Options::default(), path);
110/// ```
111pub struct DBRawIteratorWithThreadMode<'a, D: DBAccess> {
112    inner: std::ptr::NonNull<ffi::rocksdb_iterator_t>,
113
114    /// When iterate_lower_bound or iterate_upper_bound are set, the inner
115    /// C iterator keeps a pointer to the upper bound inside `_readopts`.
116    /// Storing this makes sure the upper bound is always alive when the
117    /// iterator is being used.
118    ///
119    /// And yes, we need to store the entire ReadOptions structure since C++
120    /// ReadOptions keep reference to C rocksdb_readoptions_t wrapper which
121    /// point to vectors we own.  See issue #660.
122    ///
123    /// This is deliberately not an `Option`. An iterator without its options
124    /// is the bug in issue #660, so the type does not let one be built.
125    readopts: IterReadOptions,
126
127    db: PhantomData<&'a D>,
128}
129
130impl<'a, D: DBAccess> DBRawIteratorWithThreadMode<'a, D> {
131    pub(crate) fn new(db: &D, readopts: ReadOptions) -> Self {
132        let inner = unsafe { db.create_iterator(&readopts) };
133        Self::from_inner(inner, readopts)
134    }
135
136    pub(crate) fn new_cf(
137        db: &'a D,
138        cf_handle: *mut ffi::rocksdb_column_family_handle_t,
139        readopts: ReadOptions,
140    ) -> Self {
141        let inner = unsafe { db.create_iterator_cf(cf_handle, &readopts) };
142        Self::from_inner(inner, readopts)
143    }
144
145    pub(crate) fn from_inner(
146        inner: *mut ffi::rocksdb_iterator_t,
147        readopts: impl Into<IterReadOptions>,
148    ) -> Self {
149        // This unwrap will never fail since rocksdb_create_iterator and
150        // rocksdb_create_iterator_cf functions always return non-null. They
151        // use new and deference the result so any nulls would end up with SIGSEGV
152        // there and we would have a bigger issue.
153        let inner = std::ptr::NonNull::new(inner).unwrap();
154        Self {
155            inner,
156            readopts: readopts.into(),
157            db: PhantomData,
158        }
159    }
160
161    pub(crate) fn into_inner(
162        self,
163    ) -> (std::ptr::NonNull<ffi::rocksdb_iterator_t>, IterReadOptions) {
164        let value = ManuallyDrop::new(self);
165        // SAFETY: value won't be used beyond this point
166        let inner = unsafe { std::ptr::read(&raw const value.inner) };
167        let readopts = unsafe { std::ptr::read(&raw const value.readopts) };
168
169        (inner, readopts)
170    }
171
172    /// The options object this iterator was created from, for tests that need
173    /// to assert which iterators share one owner.
174    #[cfg(test)]
175    pub(crate) fn readopts_ptr(&self) -> *mut ffi::rocksdb_readoptions_t {
176        self.readopts.as_ptr()
177    }
178
179    /// Returns `true` if the iterator is valid. An iterator is invalidated when
180    /// it reaches the end of its defined range, or when it encounters an error.
181    ///
182    /// To check whether the iterator encountered an error after `valid` has
183    /// returned `false`, use the [`status`](DBRawIteratorWithThreadMode::status) method. `status` will never
184    /// return an error when `valid` is `true`.
185    pub fn valid(&self) -> bool {
186        unsafe { ffi::rocksdb_iter_valid(self.inner.as_ptr()) != 0 }
187    }
188
189    /// Returns an error `Result` if the iterator has encountered an error
190    /// during operation. When an error is encountered, the iterator is
191    /// invalidated and [`valid`](DBRawIteratorWithThreadMode::valid) will return `false` when called.
192    ///
193    /// Performing a seek will discard the current status.
194    pub fn status(&self) -> Result<(), Error> {
195        unsafe {
196            ffi_try!(ffi::rocksdb_iter_get_error(self.inner.as_ptr()));
197        }
198        Ok(())
199    }
200
201    /// Refreshes the iterator to represent the latest state of the DB.
202    /// The iterator is invalidated after this call and must be re-sought
203    /// before use.
204    ///
205    /// If the iterator was created with a snapshot, the refreshed iterator
206    /// will no longer use that snapshot and will instead read the latest
207    /// DB state. The snapshot itself is not released; it remains valid and
208    /// will be released when the owning [`crate::SnapshotWithThreadMode`] is dropped.
209    pub fn refresh(&mut self) -> Result<(), Error> {
210        unsafe {
211            ffi_try!(ffi::rocksdb_iter_refresh(self.inner.as_ptr()));
212        }
213        Ok(())
214    }
215
216    /// Seeks to the first key in the database.
217    ///
218    /// # Examples
219    ///
220    /// ```rust
221    /// use rust_rocksdb::{DB, Options};
222    ///
223    /// let tempdir = tempfile::Builder::new()
224    ///     .prefix("_path_for_rocksdb_storage5")
225    ///     .tempdir()
226    ///     .expect("Failed to create temporary path for the _path_for_rocksdb_storage5.");
227    /// let path = tempdir.path();
228    /// {
229    ///     let db = DB::open_default(path).unwrap();
230    ///     let mut iter = db.raw_iterator();
231    ///
232    ///     // Iterate all keys from the start in lexicographic order
233    ///     iter.seek_to_first();
234    ///
235    ///     while iter.valid() {
236    ///         println!("{:?} {:?}", iter.key(), iter.value());
237    ///         iter.next();
238    ///     }
239    ///
240    ///     // Read just the first key
241    ///     iter.seek_to_first();
242    ///
243    ///     if iter.valid() {
244    ///         println!("{:?} {:?}", iter.key(), iter.value());
245    ///     } else {
246    ///         // There are no keys in the database
247    ///     }
248    /// }
249    /// let _ = DB::destroy(&Options::default(), path);
250    /// ```
251    pub fn seek_to_first(&mut self) {
252        unsafe {
253            ffi::rocksdb_iter_seek_to_first(self.inner.as_ptr());
254        }
255    }
256
257    /// Seeks to the last key in the database.
258    ///
259    /// # Examples
260    ///
261    /// ```rust
262    /// use rust_rocksdb::{DB, Options};
263    ///
264    /// let tempdir = tempfile::Builder::new()
265    ///     .prefix("_path_for_rocksdb_storage6")
266    ///     .tempdir()
267    ///     .expect("Failed to create temporary path for the _path_for_rocksdb_storage6.");
268    /// let path = tempdir.path();
269    /// {
270    ///     let db = DB::open_default(path).unwrap();
271    ///     let mut iter = db.raw_iterator();
272    ///
273    ///     // Iterate all keys from the end in reverse lexicographic order
274    ///     iter.seek_to_last();
275    ///
276    ///     while iter.valid() {
277    ///         println!("{:?} {:?}", iter.key(), iter.value());
278    ///         iter.prev();
279    ///     }
280    ///
281    ///     // Read just the last key
282    ///     iter.seek_to_last();
283    ///
284    ///     if iter.valid() {
285    ///         println!("{:?} {:?}", iter.key(), iter.value());
286    ///     } else {
287    ///         // There are no keys in the database
288    ///     }
289    /// }
290    /// let _ = DB::destroy(&Options::default(), path);
291    /// ```
292    pub fn seek_to_last(&mut self) {
293        unsafe {
294            ffi::rocksdb_iter_seek_to_last(self.inner.as_ptr());
295        }
296    }
297
298    /// Seeks to the specified key or the first key that lexicographically follows it.
299    ///
300    /// This method will attempt to seek to the specified key. If that key does not exist, it will
301    /// find and seek to the key that lexicographically follows it instead.
302    ///
303    /// # Examples
304    ///
305    /// ```rust
306    /// use rust_rocksdb::{DB, Options};
307    ///
308    /// let tempdir = tempfile::Builder::new()
309    ///     .prefix("_path_for_rocksdb_storage7")
310    ///     .tempdir()
311    ///     .expect("Failed to create temporary path for the _path_for_rocksdb_storage7.");
312    /// let path = tempdir.path();
313    /// {
314    ///     let db = DB::open_default(path).unwrap();
315    ///     let mut iter = db.raw_iterator();
316    ///
317    ///     // Read the first key that starts with 'a'
318    ///     iter.seek(b"a");
319    ///
320    ///     if iter.valid() {
321    ///         println!("{:?} {:?}", iter.key(), iter.value());
322    ///     } else {
323    ///         // There are no keys in the database
324    ///     }
325    /// }
326    /// let _ = DB::destroy(&Options::default(), path);
327    /// ```
328    pub fn seek<K: AsRef<[u8]>>(&mut self, key: K) {
329        let key = key.as_ref();
330
331        unsafe {
332            ffi::rocksdb_iter_seek(
333                self.inner.as_ptr(),
334                key.as_ptr() as *const c_char,
335                key.len() as size_t,
336            );
337        }
338    }
339
340    /// Seeks to the specified key, or the first key that lexicographically precedes it.
341    ///
342    /// Like ``.seek()`` this method will attempt to seek to the specified key.
343    /// The difference with ``.seek()`` is that if the specified key do not exist, this method will
344    /// seek to key that lexicographically precedes it instead.
345    ///
346    /// # Examples
347    ///
348    /// ```rust
349    /// use rust_rocksdb::{DB, Options};
350    ///
351    /// let tempdir = tempfile::Builder::new()
352    ///     .prefix("_path_for_rocksdb_storage8")
353    ///     .tempdir()
354    ///     .expect("Failed to create temporary path for the _path_for_rocksdb_storage8.");
355    /// let path = tempdir.path();
356    /// {
357    ///     let db = DB::open_default(path).unwrap();
358    ///     let mut iter = db.raw_iterator();
359    ///
360    ///     // Read the last key that starts with 'a'
361    ///     iter.seek_for_prev(b"b");
362    ///
363    ///     if iter.valid() {
364    ///         println!("{:?} {:?}", iter.key(), iter.value());
365    ///     } else {
366    ///         // There are no keys in the database
367    ///     }
368    /// }
369    /// let _ = DB::destroy(&Options::default(), path);
370    /// ```
371    pub fn seek_for_prev<K: AsRef<[u8]>>(&mut self, key: K) {
372        let key = key.as_ref();
373
374        unsafe {
375            ffi::rocksdb_iter_seek_for_prev(
376                self.inner.as_ptr(),
377                key.as_ptr() as *const c_char,
378                key.len() as size_t,
379            );
380        }
381    }
382
383    /// Seeks to the next key.
384    pub fn next(&mut self) {
385        if self.valid() {
386            // SAFETY: The validity check above guarantees that RocksDB permits
387            // advancing the iterator.
388            unsafe { self.next_unchecked() }
389        }
390    }
391
392    /// Advances to the next key without checking iterator validity.
393    ///
394    /// # Safety
395    ///
396    /// The iterator must be valid.
397    #[inline]
398    unsafe fn next_unchecked(&mut self) {
399        unsafe {
400            ffi::rocksdb_iter_next(self.inner.as_ptr());
401        }
402    }
403
404    /// Seeks to the previous key.
405    pub fn prev(&mut self) {
406        if self.valid() {
407            // SAFETY: The validity check above guarantees that RocksDB permits
408            // advancing the iterator.
409            unsafe { self.prev_unchecked() }
410        }
411    }
412
413    /// Advances to the previous key without checking iterator validity.
414    ///
415    /// # Safety
416    ///
417    /// The iterator must be valid.
418    #[inline]
419    unsafe fn prev_unchecked(&mut self) {
420        unsafe {
421            ffi::rocksdb_iter_prev(self.inner.as_ptr());
422        }
423    }
424
425    /// Returns a slice of the current key.
426    pub fn key(&self) -> Option<&[u8]> {
427        if self.valid() {
428            // SAFETY: We just checked that the iterator is valid.
429            Some(unsafe { self.key_impl() })
430        } else {
431            None
432        }
433    }
434
435    /// Returns a slice of the current value.
436    pub fn value(&self) -> Option<&[u8]> {
437        if self.valid() {
438            // SAFETY: We just checked that the iterator is valid.
439            Some(unsafe { self.value_impl() })
440        } else {
441            None
442        }
443    }
444
445    /// Returns pair with slice of the current key and current value.
446    pub fn item(&self) -> Option<(&[u8], &[u8])> {
447        if self.valid() {
448            // SAFETY: We just checked that the iterator is valid.
449            Some(unsafe { (self.key_impl(), self.value_impl()) })
450        } else {
451            None
452        }
453    }
454
455    /// Returns a slice of the current key.
456    ///
457    /// # Safety
458    ///
459    /// The iterator must be valid (i.e., `valid()` returns true). Calling this
460    /// method when the iterator is invalid is undefined behavior, as RocksDB
461    /// may return an invalid pointer.
462    ///
463    /// Uses `rocksdb_iter_key_slice` which returns a `rocksdb_slice_t` by value,
464    /// avoiding the overhead of output parameters compared to `rocksdb_iter_key`.
465    #[inline]
466    unsafe fn key_impl(&self) -> &[u8] {
467        unsafe {
468            let slice = ffi::rocksdb_iter_key_slice(self.inner.as_ptr());
469            if slice.size == 0 {
470                // Empty keys and values are legal in RocksDB, and
471                // `slice::from_raw_parts` requires a dereferenceable pointer
472                // even for a zero length, so do not build a slice from
473                // whatever `data` happens to be.
474                return &[];
475            }
476            slice::from_raw_parts(slice.data as *const c_uchar, slice.size)
477        }
478    }
479
480    /// Returns a slice of the current value.
481    ///
482    /// # Safety
483    ///
484    /// The iterator must be valid (i.e., `valid()` returns true). Calling this
485    /// method when the iterator is invalid is undefined behavior, as RocksDB
486    /// may return an invalid pointer.
487    ///
488    /// Uses `rocksdb_iter_value_slice` which returns a `rocksdb_slice_t` by value,
489    /// avoiding the overhead of output parameters compared to `rocksdb_iter_value`.
490    #[inline]
491    unsafe fn value_impl(&self) -> &[u8] {
492        unsafe {
493            let slice = ffi::rocksdb_iter_value_slice(self.inner.as_ptr());
494            if slice.size == 0 {
495                // Empty keys and values are legal in RocksDB, and
496                // `slice::from_raw_parts` requires a dereferenceable pointer
497                // even for a zero length, so do not build a slice from
498                // whatever `data` happens to be.
499                return &[];
500            }
501            slice::from_raw_parts(slice.data as *const c_uchar, slice.size)
502        }
503    }
504
505    /// Returns a slice of the current entry's timestamp.
506    pub fn timestamp(&self) -> Option<&[u8]> {
507        if self.valid() {
508            // SAFETY: We just checked that the iterator is valid.
509            Some(unsafe { self.timestamp_unchecked() })
510        } else {
511            None
512        }
513    }
514
515    /// Returns the timestamp of the current entry without checking iterator validity.
516    ///
517    /// # Safety
518    ///
519    /// The iterator must be valid (i.e., `valid()` returns true). Calling this
520    /// method when the iterator is invalid is undefined behavior, as RocksDB
521    /// may return an invalid pointer.
522    ///
523    /// Uses `rocksdb_iter_timestamp_slice` which returns a `rocksdb_slice_t` by value,
524    /// avoiding the overhead of output parameters compared to `rocksdb_iter_timestamp`.
525    pub unsafe fn timestamp_unchecked(&self) -> &[u8] {
526        unsafe {
527            let slice = ffi::rocksdb_iter_timestamp_slice(self.inner.as_ptr());
528            if slice.size == 0 {
529                return &[];
530            }
531            slice::from_raw_parts(slice.data as *const c_uchar, slice.size)
532        }
533    }
534}
535
536impl<D: DBAccess> Drop for DBRawIteratorWithThreadMode<'_, D> {
537    fn drop(&mut self) {
538        unsafe {
539            ffi::rocksdb_iter_destroy(self.inner.as_ptr());
540        }
541    }
542}
543
544unsafe impl<D: DBAccess> Send for DBRawIteratorWithThreadMode<'_, D> {}
545unsafe impl<D: DBAccess> Sync for DBRawIteratorWithThreadMode<'_, D> {}
546
547/// A type alias to keep compatibility. See [`DBIteratorWithThreadMode`] for details
548pub type DBIterator<'a> = DBIteratorWithThreadMode<'a, DB>;
549
550/// A standard Rust [`Iterator`] over a database or column family.
551///
552/// As an alternative, [`DBRawIteratorWithThreadMode`] is a low level wrapper around
553/// RocksDB's API, which can provide better performance and more features.
554///
555/// ```
556/// use rust_rocksdb::{DB, Direction, IteratorMode, Options};
557///
558/// let tempdir = tempfile::Builder::new()
559///     .prefix("_path_for_rocksdb_storage2")
560///     .tempdir()
561///     .expect("Failed to create temporary path for the _path_for_rocksdb_storage2.");
562/// let path = tempdir.path();
563/// {
564///     let db = DB::open_default(path).unwrap();
565///     let mut iter = db.iterator(IteratorMode::Start); // Always iterates forward
566///     for item in iter {
567///         let (key, value) = item.unwrap();
568///         println!("Saw {:?} {:?}", key, value);
569///     }
570///     iter = db.iterator(IteratorMode::End);  // Always iterates backward
571///     for item in iter {
572///         let (key, value) = item.unwrap();
573///         println!("Saw {:?} {:?}", key, value);
574///     }
575///     iter = db.iterator(IteratorMode::From(b"my key", Direction::Forward)); // From a key in Direction::{forward,reverse}
576///     for item in iter {
577///         let (key, value) = item.unwrap();
578///         println!("Saw {:?} {:?}", key, value);
579///     }
580///
581///     // You can seek with an existing Iterator instance, too
582///     iter = db.iterator(IteratorMode::Start);
583///     iter.set_mode(IteratorMode::From(b"another key", Direction::Reverse));
584///     for item in iter {
585///         let (key, value) = item.unwrap();
586///         println!("Saw {:?} {:?}", key, value);
587///     }
588/// }
589/// let _ = DB::destroy(&Options::default(), path);
590/// ```
591///
592/// An iterator must not outlive the `DB` it iterates over:
593///
594/// ```compile_fail,E0597
595/// use rust_rocksdb::{IteratorMode, DB};
596///
597/// let _iter = {
598///     let db = DB::open_default("foo").unwrap();
599///     db.iterator(IteratorMode::Start)
600/// };
601/// ```
602pub struct DBIteratorWithThreadMode<'a, D: DBAccess> {
603    raw: DBRawIteratorWithThreadMode<'a, D>,
604    direction: Direction,
605    done: bool,
606}
607
608#[derive(Copy, Clone)]
609pub enum Direction {
610    Forward,
611    Reverse,
612}
613
614pub type KVBytes = (Box<[u8]>, Box<[u8]>);
615
616#[derive(Copy, Clone)]
617pub enum IteratorMode<'a> {
618    Start,
619    End,
620    From(&'a [u8], Direction),
621}
622
623impl<'a, D: DBAccess> DBIteratorWithThreadMode<'a, D> {
624    pub(crate) fn new(db: &D, readopts: ReadOptions, mode: IteratorMode) -> Self {
625        Self::from_raw(DBRawIteratorWithThreadMode::new(db, readopts), mode)
626    }
627
628    pub(crate) fn new_cf(
629        db: &'a D,
630        cf_handle: *mut ffi::rocksdb_column_family_handle_t,
631        readopts: ReadOptions,
632        mode: IteratorMode,
633    ) -> Self {
634        Self::from_raw(
635            DBRawIteratorWithThreadMode::new_cf(db, cf_handle, readopts),
636            mode,
637        )
638    }
639
640    fn from_raw(raw: DBRawIteratorWithThreadMode<'a, D>, mode: IteratorMode) -> Self {
641        let mut rv = DBIteratorWithThreadMode {
642            raw,
643            direction: Direction::Forward, // blown away by set_mode()
644            done: false,
645        };
646        rv.set_mode(mode);
647        rv
648    }
649
650    pub fn set_mode(&mut self, mode: IteratorMode) {
651        self.done = false;
652        self.direction = match mode {
653            IteratorMode::Start => {
654                self.raw.seek_to_first();
655                Direction::Forward
656            }
657            IteratorMode::End => {
658                self.raw.seek_to_last();
659                Direction::Reverse
660            }
661            IteratorMode::From(key, Direction::Forward) => {
662                self.raw.seek(key);
663                Direction::Forward
664            }
665            IteratorMode::From(key, Direction::Reverse) => {
666                self.raw.seek_for_prev(key);
667                Direction::Reverse
668            }
669        };
670    }
671
672    /// Refreshes the iterator, then re-seeks using the given mode.
673    ///
674    /// After a refresh the underlying iterator is invalidated, so a mode
675    /// must be provided to reposition it.
676    pub fn refresh(&mut self, mode: IteratorMode) -> Result<(), Error> {
677        self.raw.refresh()?;
678        self.set_mode(mode);
679        Ok(())
680    }
681
682    /// Visits the remaining entries without allocating key or value buffers.
683    ///
684    /// The key and value slices are valid only for the duration of each callback.
685    /// Returning [`ControlFlow::Break`] stops the scan after consuming the current
686    /// entry. The iterator can then resume at the following entry. Callback errors
687    /// and RocksDB iterator errors are returned through `E`.
688    ///
689    /// # Examples
690    ///
691    /// ```
692    /// use std::ops::ControlFlow;
693    ///
694    /// use rust_rocksdb::{DB, Error, IteratorMode};
695    ///
696    /// # let tempdir = tempfile::tempdir().unwrap();
697    /// let db = DB::open_default(tempdir.path()).unwrap();
698    /// db.put(b"k1", b"value").unwrap();
699    ///
700    /// let mut total_bytes = 0;
701    /// let mut iter = db.iterator(IteratorMode::Start);
702    /// let outcome: Result<ControlFlow<()>, Error> = iter.try_for_each_ref(|key, value| {
703    ///     total_bytes += key.len() + value.len();
704    ///     Ok(ControlFlow::Continue(()))
705    /// });
706    ///
707    /// assert!(matches!(outcome, Ok(ControlFlow::Continue(()))));
708    /// assert_eq!(total_bytes, 7);
709    /// ```
710    ///
711    /// Borrowed entries cannot escape the callback:
712    ///
713    /// ```compile_fail,E0521
714    /// use std::ops::ControlFlow;
715    ///
716    /// use rust_rocksdb::{DB, Error, IteratorMode};
717    ///
718    /// # let tempdir = tempfile::tempdir().unwrap();
719    /// let db = DB::open_default(tempdir.path()).unwrap();
720    /// let mut iter = db.iterator(IteratorMode::Start);
721    /// let mut saved_key = None;
722    ///
723    /// let _: Result<ControlFlow<()>, Error> = iter.try_for_each_ref(|key, _| {
724    ///     saved_key = Some(key);
725    ///     Ok(ControlFlow::Break(()))
726    /// });
727    /// ```
728    #[inline]
729    pub fn try_for_each_ref<B, E, F>(&mut self, mut visit: F) -> Result<ControlFlow<B>, E>
730    where
731        E: From<Error>,
732        F: FnMut(&[u8], &[u8]) -> Result<ControlFlow<B>, E>,
733    {
734        loop {
735            let item = self
736                .next_with(|key, value| visit(key, value))
737                .map_err(E::from)?;
738            match item {
739                Some(Ok(ControlFlow::Continue(()))) => {}
740                Some(Ok(ControlFlow::Break(value))) => return Ok(ControlFlow::Break(value)),
741                Some(Err(error)) => return Err(error),
742                None => return Ok(ControlFlow::Continue(())),
743            }
744        }
745    }
746
747    #[inline]
748    fn next_with<T>(&mut self, visit: impl FnOnce(&[u8], &[u8]) -> T) -> Result<Option<T>, Error> {
749        if self.done {
750            return Ok(None);
751        }
752
753        let Some((key, value)) = self.raw.item() else {
754            self.done = true;
755            self.raw.status()?;
756            return Ok(None);
757        };
758
759        let item = visit(key, value);
760        // SAFETY: `raw.item()` returned an entry, which proves that the
761        // iterator is valid until it is advanced.
762        unsafe { self.advance_unchecked() };
763        Ok(Some(item))
764    }
765
766    /// Advances in the configured direction without checking iterator validity.
767    ///
768    /// # Safety
769    ///
770    /// The raw iterator must be valid.
771    #[inline]
772    unsafe fn advance_unchecked(&mut self) {
773        match self.direction {
774            Direction::Forward => unsafe { self.raw.next_unchecked() },
775            Direction::Reverse => unsafe { self.raw.prev_unchecked() },
776        }
777    }
778}
779
780impl<D: DBAccess> Iterator for DBIteratorWithThreadMode<'_, D> {
781    type Item = Result<KVBytes, Error>;
782
783    fn next(&mut self) -> Option<Result<KVBytes, Error>> {
784        match self.next_with(|key, value| (Box::from(key), Box::from(value))) {
785            Ok(Some(item)) => Some(Ok(item)),
786            Ok(None) => None,
787            Err(error) => Some(Err(error)),
788        }
789    }
790}
791
792impl<D: DBAccess> std::iter::FusedIterator for DBIteratorWithThreadMode<'_, D> {}
793
794impl<'a, D: DBAccess> Into<DBRawIteratorWithThreadMode<'a, D>> for DBIteratorWithThreadMode<'a, D> {
795    fn into(self) -> DBRawIteratorWithThreadMode<'a, D> {
796        self.raw
797    }
798}
799
800/// Iterates the batches of writes since a given sequence number.
801///
802/// `DBWALIterator` is returned by `DB::get_updates_since()` and will return the
803/// batches of write operations that have occurred since a given sequence number
804/// (see `DB::latest_sequence_number()`). This iterator cannot be constructed by
805/// the application.
806///
807/// The iterator item type is a tuple of (`u64`, `WriteBatch`) where the first
808/// value is the sequence number of the associated write batch.
809///
810pub struct DBWALIterator {
811    pub(crate) inner: *mut ffi::rocksdb_wal_iterator_t,
812    pub(crate) start_seq_number: u64,
813}
814
815impl DBWALIterator {
816    /// Returns `true` if the iterator is valid. An iterator is invalidated when
817    /// it reaches the end of its defined range, or when it encounters an error.
818    ///
819    /// To check whether the iterator encountered an error after `valid` has
820    /// returned `false`, use the [`status`](DBWALIterator::status) method.
821    /// `status` will never return an error when `valid` is `true`.
822    pub fn valid(&self) -> bool {
823        unsafe { ffi::rocksdb_wal_iter_valid(self.inner) != 0 }
824    }
825
826    /// Returns an error `Result` if the iterator has encountered an error
827    /// during operation. When an error is encountered, the iterator is
828    /// invalidated and [`valid`](DBWALIterator::valid) will return `false` when
829    /// called.
830    pub fn status(&self) -> Result<(), Error> {
831        unsafe {
832            ffi_try!(ffi::rocksdb_wal_iter_status(self.inner));
833        }
834        Ok(())
835    }
836}
837
838impl Iterator for DBWALIterator {
839    type Item = Result<(u64, WriteBatch), Error>;
840
841    fn next(&mut self) -> Option<Self::Item> {
842        if !self.valid() {
843            return None;
844        }
845
846        let mut seq: u64 = 0;
847        let mut batch = WriteBatch {
848            inner: unsafe { ffi::rocksdb_wal_iter_get_batch(self.inner, &raw mut seq) },
849        };
850
851        // if the initial sequence number is what was requested we skip it to
852        // only provide changes *after* it
853        while seq <= self.start_seq_number {
854            unsafe {
855                ffi::rocksdb_wal_iter_next(self.inner);
856            }
857
858            if !self.valid() {
859                return None;
860            }
861
862            // this drops which in turn frees the skipped batch
863            batch = WriteBatch {
864                inner: unsafe { ffi::rocksdb_wal_iter_get_batch(self.inner, &raw mut seq) },
865            };
866        }
867
868        if !self.valid() {
869            return self.status().err().map(Result::Err);
870        }
871
872        // Seek to the next write batch.
873        // Note that WriteBatches live independently of the WAL iterator so this is safe to do
874        unsafe {
875            ffi::rocksdb_wal_iter_next(self.inner);
876        }
877
878        Some(Ok((seq, batch)))
879    }
880}
881
882impl Drop for DBWALIterator {
883    fn drop(&mut self) {
884        unsafe {
885            ffi::rocksdb_wal_iter_destroy(self.inner);
886        }
887    }
888}