Skip to content

Commit edaf42d

Browse files
authored
chore: add KVPbApi::get_pb_stream() but it is not yet ready for production use (#15471)
1 parent 6981624 commit edaf42d

File tree

1 file changed

+267
-0
lines changed
  • src/meta/api/src/kv_pb_api

1 file changed

+267
-0
lines changed

src/meta/api/src/kv_pb_api/mod.rs

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,112 @@ pub trait KVPbApi: KVApi {
127127
}
128128
}
129129

130+
/// Same as `get_pb_stream` but does not return keys, only values.
131+
#[deprecated(note = "stream may be closed. The caller must check it")]
132+
fn get_pb_values<K, I>(
133+
&self,
134+
keys: I,
135+
) -> impl Future<
136+
Output = Result<
137+
BoxStream<
138+
'static, //
139+
Result<Option<SeqV<K::ValueType>>, Self::Error>,
140+
>,
141+
Self::Error,
142+
>,
143+
> + Send
144+
where
145+
K: kvapi::Key + 'static,
146+
K::ValueType: FromToProto + Send + 'static,
147+
I: IntoIterator<Item = K>,
148+
Self::Error: From<PbApiReadError<Self::Error>>,
149+
{
150+
self.get_pb_stream_low(keys)
151+
// This `map()` handles Future result
152+
.map(|r| match r {
153+
Ok(strm) => {
154+
// These two `map_xx()` handles Stream result
155+
Ok(strm.map_ok(|(_k, v)| v).map_err(Self::Error::from).boxed())
156+
}
157+
Err(e) => Err(e),
158+
})
159+
}
160+
161+
/// Get protobuf encoded values by a series of kvapi::Key.
162+
///
163+
/// The key will be converted to string and the returned value is decoded by `FromToProto`.
164+
/// It returns the same error as `KVApi::Error`,
165+
/// thus it requires KVApi::Error can describe a decoding error, i.e., `impl From<PbApiReadError>`.
166+
#[deprecated(note = "stream may be closed. The caller must check it")]
167+
fn get_pb_stream<K, I>(
168+
&self,
169+
keys: I,
170+
) -> impl Future<
171+
Output = Result<
172+
BoxStream<
173+
'static, //
174+
Result<(K, Option<SeqV<K::ValueType>>), Self::Error>,
175+
>,
176+
Self::Error,
177+
>,
178+
> + Send
179+
where
180+
K: kvapi::Key + 'static,
181+
K::ValueType: FromToProto + Send + 'static,
182+
I: IntoIterator<Item = K>,
183+
Self::Error: From<PbApiReadError<Self::Error>>,
184+
{
185+
self.get_pb_stream_low(keys).map(|r| match r {
186+
Ok(strm) => Ok(strm.map_err(Self::Error::from).boxed()),
187+
Err(e) => Err(e),
188+
})
189+
}
190+
191+
/// Same as `get_pb_stream` but returns [`PbApiReadError`]. No require of `From<PbApiReadError>` for `Self::Error`.
192+
fn get_pb_stream_low<K, I>(
193+
&self,
194+
keys: I,
195+
) -> impl Future<
196+
Output = Result<
197+
BoxStream<
198+
'static, //
199+
Result<(K, Option<SeqV<K::ValueType>>), PbApiReadError<Self::Error>>,
200+
>,
201+
Self::Error,
202+
>,
203+
> + Send
204+
where
205+
K: kvapi::Key + 'static,
206+
K::ValueType: FromToProto + Send + 'static,
207+
I: IntoIterator<Item = K>,
208+
{
209+
let keys = keys
210+
.into_iter()
211+
.map(|k| kvapi::Key::to_string_key(&k))
212+
.collect::<Vec<_>>();
213+
214+
async move {
215+
let strm = self.get_kv_stream(&keys).await?;
216+
217+
let strm = strm.map(|r: Result<StreamItem, Self::Error>| {
218+
let item = r.map_err(PbApiReadError::KvApiError)?;
219+
220+
let k = K::from_str_key(&item.key).map_err(PbApiReadError::KeyError)?;
221+
222+
let v = if let Some(pb_seqv) = item.value {
223+
let seqv = decode_seqv::<K::ValueType>(SeqV::from(pb_seqv))?;
224+
Some(seqv)
225+
} else {
226+
None
227+
};
228+
229+
Ok((k, v))
230+
});
231+
232+
Ok(strm.boxed())
233+
}
234+
}
235+
130236
/// Same as `list_pb` but does not return values, only keys.
131237
fn list_pb_keys<K>(
132238
&self,
@@ -216,3 +322,164 @@ pub trait KVPbApi: KVApi {
216322
}
217323

218324
impl<T> KVPbApi for T where T: KVApi + ?Sized {}
325+
326+
#[cfg(test)]
327+
mod tests {
328+
use std::collections::BTreeMap;
329+
330+
use async_trait::async_trait;
331+
use chrono::DateTime;
332+
use chrono::Utc;
333+
use databend_common_meta_app::schema::CatalogIdIdent;
334+
use databend_common_meta_app::schema::CatalogMeta;
335+
use databend_common_meta_app::schema::CatalogOption;
336+
use databend_common_meta_app::schema::HiveCatalogOption;
337+
use databend_common_meta_app::storage::StorageS3Config;
338+
use databend_common_meta_app::tenant::Tenant;
339+
use databend_common_meta_kvapi::kvapi::KVApi;
340+
use databend_common_meta_kvapi::kvapi::KVStream;
341+
use databend_common_meta_kvapi::kvapi::UpsertKVReply;
342+
use databend_common_meta_kvapi::kvapi::UpsertKVReq;
343+
use databend_common_meta_types::protobuf::StreamItem;
344+
use databend_common_meta_types::MetaError;
345+
use databend_common_meta_types::SeqV;
346+
use databend_common_meta_types::SeqValue;
347+
use databend_common_meta_types::TxnReply;
348+
use databend_common_meta_types::TxnRequest;
349+
use databend_common_proto_conv::FromToProto;
350+
use futures::StreamExt;
351+
use futures::TryStreamExt;
352+
use prost::Message;
353+
354+
use crate::kv_pb_api::KVPbApi;
355+
356+
//
357+
struct Foo {
358+
kvs: BTreeMap<String, SeqV>,
359+
}
360+
361+
#[async_trait]
362+
impl KVApi for Foo {
363+
type Error = MetaError;
364+
365+
async fn upsert_kv(&self, _req: UpsertKVReq) -> Result<UpsertKVReply, Self::Error> {
366+
todo!()
367+
}
368+
369+
async fn get_kv_stream(
370+
&self,
371+
keys: &[String],
372+
) -> Result<KVStream<Self::Error>, Self::Error> {
373+
let mut res = Vec::with_capacity(keys.len());
374+
for key in keys {
375+
let k = key.clone();
376+
let v = self.kvs.get(key).cloned();
377+
378+
let item = StreamItem::new(k, v.map(|v| v.into()));
379+
res.push(Ok(item));
380+
}
381+
382+
let strm = futures::stream::iter(res);
383+
Ok(strm.boxed())
384+
}
385+
386+
async fn list_kv(&self, _prefix: &str) -> Result<KVStream<Self::Error>, Self::Error> {
387+
todo!()
388+
}
389+
390+
async fn transaction(&self, _txn: TxnRequest) -> Result<TxnReply, Self::Error> {
391+
todo!()
392+
}
393+
}
394+
395+
// TODO: test upsert_kv
396+
// TODO: test upsert_kv
397+
// TODO: test list_kv
398+
399+
#[tokio::test]
400+
async fn test_mget() -> anyhow::Result<()> {
401+
let catalog_meta = CatalogMeta {
402+
catalog_option: CatalogOption::Hive(HiveCatalogOption {
403+
address: "127.0.0.1:10000".to_string(),
404+
storage_params: Some(Box::new(
405+
databend_common_meta_app::storage::StorageParams::S3(StorageS3Config {
406+
endpoint_url: "http://127.0.0.1:9900".to_string(),
407+
region: "hello".to_string(),
408+
bucket: "world".to_string(),
409+
access_key_id: "databend_has_super_power".to_string(),
410+
secret_access_key: "databend_has_super_power".to_string(),
411+
..Default::default()
412+
}),
413+
)),
414+
}),
415+
created_on: DateTime::<Utc>::MIN_UTC,
416+
};
417+
let v = catalog_meta.to_pb()?.encode_to_vec();
418+
419+
let foo = Foo {
420+
kvs: vec![
421+
(s("__fd_catalog_by_id/1"), SeqV::new(1, v.clone())),
422+
(s("__fd_catalog_by_id/2"), SeqV::new(2, v.clone())),
423+
(s("__fd_catalog_by_id/3"), SeqV::new(3, v.clone())),
424+
]
425+
.into_iter()
426+
.collect(),
427+
};
428+
429+
let tenant = Tenant::new_literal("dummy");
430+
431+
// Get key value pairs
432+
{
433+
#[allow(deprecated)]
434+
let strm = foo
435+
.get_pb_stream([
436+
CatalogIdIdent::new(&tenant, 1),
437+
CatalogIdIdent::new(&tenant, 2),
438+
CatalogIdIdent::new(&tenant, 4),
439+
])
440+
.await?;
441+
442+
let got = strm.try_collect::<Vec<_>>().await?;
443+
444+
assert_eq!(CatalogIdIdent::new(&tenant, 1), got[0].0);
445+
assert_eq!(CatalogIdIdent::new(&tenant, 2), got[1].0);
446+
assert_eq!(CatalogIdIdent::new(&tenant, 4), got[2].0);
447+
448+
assert_eq!(1, got[0].1.seq());
449+
assert_eq!(2, got[1].1.seq());
450+
assert_eq!(0, got[2].1.seq());
451+
452+
assert_eq!(Some(&catalog_meta), got[0].1.value());
453+
assert_eq!(Some(&catalog_meta), got[1].1.value());
454+
assert_eq!(None, got[2].1.value());
455+
}
456+
457+
// Get values
458+
{
459+
#[allow(deprecated)]
460+
let strm = foo
461+
.get_pb_values([
462+
CatalogIdIdent::new(&tenant, 1),
463+
CatalogIdIdent::new(&tenant, 2),
464+
CatalogIdIdent::new(&tenant, 4),
465+
])
466+
.await?;
467+
468+
let got = strm.try_collect::<Vec<_>>().await?;
469+
470+
assert_eq!(1, got[0].seq());
471+
assert_eq!(2, got[1].seq());
472+
assert_eq!(0, got[2].seq());
473+
474+
assert_eq!(Some(&catalog_meta), got[0].value());
475+
assert_eq!(Some(&catalog_meta), got[1].value());
476+
assert_eq!(None, got[2].value());
477+
}
478+
479+
Ok(())
480+
}
481+
482+
fn s(x: impl ToString) -> String {
483+
x.to_string()
484+
}
485+
}

0 commit comments

Comments
 (0)