tuwunel_database/map/
seek.rs1use std::sync::Arc;
2
3use futures::{FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::Either};
4use rocksdb::Direction;
5use tokio::task;
6use tuwunel_core::Result;
7
8use super::{Map, cache_iter_options_default, iter_options_default};
9use crate::{
10 pool::{Seek, into_send_seek},
11 stream,
12};
13
14pub(super) fn seek_stream<'a, C, T>(
21 map: &'a Arc<Map>,
22 dir: Direction,
23 from: Option<&[u8]>,
24) -> impl Stream<Item = Result<T>> + Send + use<'a, C, T>
25where
26 C: From<stream::State<'a>> + Stream<Item = Result<T>> + Send,
27{
28 let opts = iter_options_default(&map.engine);
29 let state = stream::State::new(map, opts);
30 if is_cached(map, dir, from) {
31 let state = init(state, dir, from);
32 return Either::Left(
33 task::consume_budget()
34 .map(move |()| C::from(state))
35 .into_stream()
36 .flatten(),
37 );
38 }
39
40 let seek = Seek {
41 map: map.clone(),
42 state: into_send_seek(state),
43 dir,
44 key: from.map(Into::into),
45 res: None,
46 };
47
48 Either::Right(
49 map.engine
50 .pool
51 .execute_iter(seek)
52 .ok_into::<C>()
53 .into_stream()
54 .try_flatten(),
55 )
56}
57
58#[tracing::instrument(
63 name = "cached",
64 level = "trace",
65 skip_all,
66 fields(%map),
67)]
68fn is_cached(map: &Arc<Map>, dir: Direction, from: Option<&[u8]>) -> bool {
69 let opts = cache_iter_options_default(&map.engine);
70 let state = init(stream::State::new(map, opts), dir, from);
71
72 !state.is_incomplete()
73}
74
75fn init<'a>(state: stream::State<'a>, dir: Direction, from: Option<&[u8]>) -> stream::State<'a> {
80 match dir {
81 | Direction::Forward => state.init_fwd(from),
82 | Direction::Reverse => state.init_rev(from),
83 }
84}