foundationdb/
mapped_key_values.rs

1// Copyright 2022 foundationdb-rs developers, https://github.com/Clikengo/foundationdb-rs/graphs/contributors
2// Copyright 2013-2018 Apple, Inc and the FoundationDB project authors.
3//
4// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
5// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
6// http://opensource.org/licenses/MIT>, at your option. This file may not be
7// copied, modified, or distributed except according to those terms.
8
9//! Definitions of MappedKeyValues, used in api version 710 and more.
10//!
11//! GetMappedRange is an experimental feature introduced in FDB 7.1. It is intended to improve the
12//! client throughput and reduce latency for a commonly used traffic pattern.
13//! An experiment with Record Layer shows that this optimization can get 4x client throughput on a certain workload.
14//!
15//! More info can be found in the [relevant documentation](https://github.com/apple/foundationdb/wiki/Everything-about-GetMappedRange).
16
17use crate::from_raw_fdb_slice;
18use crate::future::{FdbFutureHandle, FdbKeyValue};
19use crate::{error, KeySelector};
20use crate::{FdbError, FdbResult};
21use foundationdb_sys as fdb_sys;
22use std::borrow::Cow;
23use std::fmt;
24
25use std::ops::Deref;
26use std::sync::Arc;
27
28/// An slice of mapped keyvalues owned by a foundationDB future produced by the `get_mapped` method.
29pub struct MappedKeyValues {
30    _f: FdbFutureHandle,
31    mapped_keyvalues: *const FdbMappedKeyValue,
32    len: i32,
33    more: bool,
34}
35unsafe impl Sync for MappedKeyValues {}
36unsafe impl Send for MappedKeyValues {}
37
38impl MappedKeyValues {
39    /// `true` if there is another range after this one
40    pub fn more(&self) -> bool {
41        self.more
42    }
43}
44
45impl TryFrom<FdbFutureHandle> for MappedKeyValues {
46    type Error = FdbError;
47    fn try_from(f: FdbFutureHandle) -> FdbResult<Self> {
48        let mut mapped_keyvalues = std::ptr::null();
49        let mut len = 0;
50        let mut more = 0;
51
52        unsafe {
53            error::eval(fdb_sys::fdb_future_get_mappedkeyvalue_array(
54                f.as_ptr(),
55                &mut mapped_keyvalues,
56                &mut len,
57                &mut more,
58            ))?
59        }
60
61        Ok(MappedKeyValues {
62            _f: f,
63            mapped_keyvalues: mapped_keyvalues as *const FdbMappedKeyValue,
64            len,
65            more: more != 0,
66        })
67    }
68}
69
70#[repr(packed)]
71/// A KeyValue produced by a mapped operation, ownder by a Foundation Future.
72pub struct FdbMappedKeyValue(fdb_sys::FDBMappedKeyValue);
73
74impl PartialEq for FdbMappedKeyValue {
75    fn eq(&self, other: &Self) -> bool {
76        (self.parent_key(), self.parent_value()) == (other.parent_key(), other.parent_value())
77    }
78}
79impl Eq for FdbMappedKeyValue {}
80impl fmt::Debug for FdbMappedKeyValue {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        write!(
83            f,
84            "({:?}, {:?})",
85            crate::tuple::Bytes::from(self.parent_key()),
86            crate::tuple::Bytes::from(self.parent_value())
87        )
88    }
89}
90
91impl FdbMappedKeyValue {
92    /// Retrieves the "parent" key that generated the secondary scan.
93    pub fn parent_key(&self) -> &[u8] {
94        from_raw_fdb_slice(self.0.key.key, self.0.key.key_length as usize)
95    }
96
97    /// Retrieves the "parent" value that generated the secondary scan.
98    pub fn parent_value(&self) -> &[u8] {
99        from_raw_fdb_slice(self.0.value.key, self.0.value.key_length as usize)
100    }
101
102    /// Retrieves the beginning of the range
103    pub fn begin_range(&self) -> &[u8] {
104        from_raw_fdb_slice(
105            self.0.getRange.begin.key.key,
106            self.0.getRange.begin.key.key_length as usize,
107        )
108    }
109
110    /// Retrieves the end of the range
111    pub fn end_range(&self) -> &[u8] {
112        from_raw_fdb_slice(
113            self.0.getRange.end.key.key,
114            self.0.getRange.end.key.key_length as usize,
115        )
116    }
117
118    /// Retrieves the beginning of the range as a [`KeySelector`]
119    pub fn begin_selector(&self) -> KeySelector {
120        KeySelector::new(Cow::from(self.begin_range()), false, 0)
121    }
122
123    /// Retrieves the end of the range as a [`KeySelector`]
124    pub fn end_selector(&self) -> KeySelector {
125        KeySelector::new(Cow::from(self.end_range()), false, 0)
126    }
127
128    /// retrieves the associated slice of [`FdbKeyValue`]
129    pub fn key_values(&self) -> &[FdbKeyValue] {
130        from_raw_fdb_slice(
131            self.0.getRange.data as *const FdbKeyValue,
132            self.0.getRange.m_size as usize,
133        )
134    }
135}
136
137impl Deref for MappedKeyValues {
138    type Target = [FdbMappedKeyValue];
139
140    fn deref(&self) -> &Self::Target {
141        assert_eq_size!(FdbMappedKeyValue, fdb_sys::FDBMappedKeyValue);
142        assert_eq_align!(FdbMappedKeyValue, u8);
143        from_raw_fdb_slice(self.mapped_keyvalues, self.len as usize)
144    }
145}
146
147impl AsRef<[FdbMappedKeyValue]> for MappedKeyValues {
148    fn as_ref(&self) -> &[FdbMappedKeyValue] {
149        self.deref()
150    }
151}
152
153impl<'a> IntoIterator for &'a MappedKeyValues {
154    type Item = &'a FdbMappedKeyValue;
155    type IntoIter = std::slice::Iter<'a, FdbMappedKeyValue>;
156
157    fn into_iter(self) -> Self::IntoIter {
158        self.deref().iter()
159    }
160}
161
162/// An FdbMappedValue that you can own.
163pub struct FdbMappedValue {
164    _f: Arc<FdbFutureHandle>,
165    mapped_keyvalue: *const FdbMappedKeyValue,
166}
167
168impl IntoIterator for MappedKeyValues {
169    type Item = FdbMappedValue;
170    type IntoIter = FdbMappedValuesIter;
171
172    fn into_iter(self) -> Self::IntoIter {
173        FdbMappedValuesIter {
174            f: Arc::new(self._f),
175            mapped_keyvalues: self.mapped_keyvalues,
176            len: self.len,
177            pos: 0,
178        }
179    }
180}
181
182unsafe impl Send for FdbMappedValue {}
183
184impl Deref for FdbMappedValue {
185    type Target = FdbMappedKeyValue;
186    fn deref(&self) -> &Self::Target {
187        assert_eq_size!(FdbMappedKeyValue, fdb_sys::FDBMappedKeyValue);
188        assert_eq_align!(FdbMappedKeyValue, u8);
189        unsafe { &*self.mapped_keyvalue }
190    }
191}
192impl AsRef<FdbMappedKeyValue> for FdbMappedValue {
193    fn as_ref(&self) -> &FdbMappedKeyValue {
194        self.deref()
195    }
196}
197impl PartialEq for FdbMappedValue {
198    fn eq(&self, other: &Self) -> bool {
199        self.deref() == other.deref()
200    }
201}
202impl Eq for FdbMappedValue {}
203
204/// An iterator of mapped keyvalues owned by a foundationDB future
205pub struct FdbMappedValuesIter {
206    f: Arc<FdbFutureHandle>,
207    mapped_keyvalues: *const FdbMappedKeyValue,
208    len: i32,
209    pos: i32,
210}
211
212unsafe impl Send for FdbMappedValuesIter {}
213
214impl Iterator for FdbMappedValuesIter {
215    type Item = FdbMappedValue;
216    fn next(&mut self) -> Option<Self::Item> {
217        #[allow(clippy::iter_nth_zero)]
218        self.nth(0)
219    }
220
221    fn nth(&mut self, n: usize) -> Option<Self::Item> {
222        let pos = (self.pos as usize).checked_add(n);
223        match pos {
224            Some(pos) if pos < self.len as usize => {
225                // safe because pos < self.len
226                let mapped_keyvalue = unsafe { self.mapped_keyvalues.add(pos) };
227                self.pos = pos as i32 + 1;
228
229                Some(FdbMappedValue {
230                    _f: self.f.clone(),
231                    mapped_keyvalue,
232                })
233            }
234            _ => {
235                self.pos = self.len;
236                None
237            }
238        }
239    }
240
241    fn size_hint(&self) -> (usize, Option<usize>) {
242        let rem = (self.len - self.pos) as usize;
243        (rem, Some(rem))
244    }
245}
246impl ExactSizeIterator for FdbMappedValuesIter {
247    #[inline]
248    fn len(&self) -> usize {
249        (self.len - self.pos) as usize
250    }
251}
252impl DoubleEndedIterator for FdbMappedValuesIter {
253    fn next_back(&mut self) -> Option<Self::Item> {
254        self.nth_back(0)
255    }
256
257    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
258        if n < self.len() {
259            self.len -= 1 + n as i32;
260            // safe because len < original len
261            let keyvalue = unsafe { self.mapped_keyvalues.add(self.len as usize) };
262            Some(FdbMappedValue {
263                _f: self.f.clone(),
264                mapped_keyvalue: keyvalue,
265            })
266        } else {
267            self.pos = self.len;
268            None
269        }
270    }
271}