/home/runner/work/feoxdb/feoxdb/src/core/store/range.rs
Line | Count | Source |
1 | | use crossbeam_epoch as epoch; |
2 | | use std::ops::Bound; |
3 | | |
4 | | use crate::constants::MAX_KEY_SIZE; |
5 | | use crate::error::{FeoxError, Result}; |
6 | | |
7 | | use super::FeoxStore; |
8 | | |
9 | | const RANGE_PREALLOC_LIMIT: usize = 1024; |
10 | | const RANGE_REPIN_INTERVAL: usize = 256; |
11 | | |
12 | | impl FeoxStore { |
13 | | /// Perform a range query on the store. |
14 | | /// |
15 | | /// Returns all key-value pairs where the key is >= `start_key` and <= `end_key`. |
16 | | /// Both bounds are inclusive. |
17 | | /// |
18 | | /// # Arguments |
19 | | /// |
20 | | /// * `start_key` - Inclusive lower bound |
21 | | /// * `end_key` - Inclusive upper bound |
22 | | /// * `limit` - Maximum number of results to return |
23 | | /// |
24 | | /// # Returns |
25 | | /// |
26 | | /// Returns a vector of (key, value) pairs in sorted order. |
27 | | /// |
28 | | /// # Example |
29 | | /// |
30 | | /// ```rust |
31 | | /// # use feoxdb::FeoxStore; |
32 | | /// # fn main() -> feoxdb::Result<()> { |
33 | | /// # let store = FeoxStore::new(None)?; |
34 | | /// store.insert(b"user:001", b"Alice")?; |
35 | | /// store.insert(b"user:002", b"Bob")?; |
36 | | /// store.insert(b"user:003", b"Charlie")?; |
37 | | /// store.insert(b"user:004", b"David")?; |
38 | | /// |
39 | | /// // Get users 001 through 003 (inclusive) |
40 | | /// let results = store.range_query(b"user:001", b"user:003", 10)?; |
41 | | /// assert_eq!(results.len(), 3); |
42 | | /// # Ok(()) |
43 | | /// # } |
44 | | /// ``` |
45 | 105 | pub fn range_query( |
46 | 105 | &self, |
47 | 105 | start_key: &[u8], |
48 | 105 | end_key: &[u8], |
49 | 105 | limit: usize, |
50 | 105 | ) -> Result<Vec<(Vec<u8>, Vec<u8>)>> { |
51 | 105 | if start_key.len() > MAX_KEY_SIZE || end_key.len() > MAX_KEY_SIZE { |
52 | 0 | return Err(FeoxError::InvalidKeySize); |
53 | 105 | } |
54 | | |
55 | 105 | if limit == 0 { |
56 | 0 | return Ok(Vec::new()); |
57 | 105 | } |
58 | 105 | let mut results = Vec::with_capacity(limit.min(self.tree.len()).min(RANGE_PREALLOC_LIMIT)); |
59 | | |
60 | 105 | let mut guard = epoch::pin(); |
61 | 105 | let mut entries_since_repin = 0; |
62 | 105 | let mut cursor = self.tree.lower_bound(Bound::Included(start_key)); |
63 | | |
64 | 6.82k | while let Some(entry6.72k ) = cursor { |
65 | 6.72k | if results.len() >= limit || entry.key().as_slice() > end_key6.72k { |
66 | 4 | break; |
67 | 6.71k | } |
68 | | |
69 | 6.71k | let value = { |
70 | 6.71k | let record = entry.value().load(&guard); |
71 | 6.71k | self.resolve_value_ref(entry.key(), record) |
72 | | }; |
73 | 6.71k | entries_since_repin += 1; |
74 | 6.71k | if entries_since_repin == RANGE_REPIN_INTERVAL { |
75 | 1 | guard.repin(); |
76 | 1 | entries_since_repin = 0; |
77 | 6.71k | } |
78 | 6.71k | let value = match value0 { |
79 | 6.71k | Ok(value) => value.to_vec(), |
80 | | Err(FeoxError::StaleExtent) | Err(FeoxError::KeyNotFound) => { |
81 | 0 | cursor = entry.next(); |
82 | 0 | continue; |
83 | | } |
84 | 0 | Err(error) => return Err(error), |
85 | | }; |
86 | | |
87 | 6.71k | results.push((entry.key().clone(), value)); |
88 | 6.71k | cursor = entry.next(); |
89 | | } |
90 | | |
91 | 105 | Ok(results) |
92 | 105 | } |
93 | | } |