tuwunel_database/map/
get.rs1use std::{fmt::Debug, sync::Arc};
2
3use futures::{
4 FutureExt, TryFutureExt,
5 future::{Either, ready},
6};
7use rocksdb::{DBPinnableSlice, ReadOptions};
8use tokio::task;
9use tuwunel_core::{Err, Result, err, implement, utils::result::MapExpect};
10
11use crate::{
12 Handle,
13 util::{is_incomplete, map_err, or_else},
14};
15
16#[implement(super::Map)]
22#[tracing::instrument(skip(self, key), fields(%self), level = "trace")]
23pub fn get<K>(
24 self: &Arc<Self>,
25 key: &K,
26) -> impl Future<Output = Result<Handle<'_>>> + Send + use<'_, K>
27where
28 K: AsRef<[u8]> + Debug + ?Sized,
29{
30 use crate::pool::Get;
31
32 let cached = self.get_cached(key);
33 if matches!(cached, Err(_) | Ok(Some(_))) {
34 return Either::Left(
35 task::consume_budget().map(move |()| cached.map_expect("data found in cache")),
36 );
37 }
38
39 debug_assert!(matches!(cached, Ok(None)), "expected status Incomplete");
40 let cmd = Get {
41 map: self.clone(),
42 key: [key.as_ref().into()].into(),
43 res: None,
44 };
45
46 Either::Right(
47 self.engine
48 .pool
49 .execute_get(cmd)
50 .and_then(|mut res| ready(res.remove(0))),
51 )
52}
53
54#[implement(super::Map)]
59#[tracing::instrument(skip(self, key), name = "cache", level = "trace")]
60pub(crate) fn get_cached<K>(&self, key: &K) -> Result<Option<Handle<'_>>>
61where
62 K: AsRef<[u8]> + Debug + ?Sized,
63{
64 let res = self.get_blocking_opts(key, &self.cache_read_options);
65 cached_handle_from(res)
66}
67
68#[implement(super::Map)]
73#[tracing::instrument(skip(self, key), name = "blocking", level = "trace")]
74pub fn get_blocking<K>(&self, key: &K) -> Result<Handle<'_>>
75where
76 K: AsRef<[u8]> + ?Sized,
77{
78 let res = self.get_blocking_opts(key, &self.read_options);
79 handle_from(res)
80}
81
82#[implement(super::Map)]
87fn get_blocking_opts<K>(
88 &self,
89 key: &K,
90 read_options: &ReadOptions,
91) -> Result<Option<DBPinnableSlice<'_>>, rocksdb::Error>
92where
93 K: AsRef<[u8]> + ?Sized,
94{
95 self.engine
96 .db
97 .get_pinned_cf_opt(&self.cf(), key, read_options)
98}
99
100#[inline]
105pub(super) fn handle_from(
106 result: Result<Option<DBPinnableSlice<'_>>, rocksdb::Error>,
107) -> Result<Handle<'_>> {
108 result
109 .map_err(map_err)?
110 .map(Handle::from)
111 .ok_or(err!(Request(NotFound("Not found in database"))))
112}
113
114#[inline]
119pub(super) fn cached_handle_from(
120 result: Result<Option<DBPinnableSlice<'_>>, rocksdb::Error>,
121) -> Result<Option<Handle<'_>>> {
122 match result {
123 | Ok(None) => Err!(Request(NotFound("Not found in database"))),
125
126 | Ok(Some(result)) => Ok(Some(Handle::from(result))),
128
129 | Err(error) if is_incomplete(&error) => Ok(None),
131
132 | Err(error) => or_else(error),
134 }
135}