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}