1use std::any::Any;
16use std::fmt::Debug;
17use std::sync::atomic::{AtomicUsize, Ordering};
18use std::sync::{Arc, Mutex};
19use std::time::Duration;
20
21use common_error::ext::BoxedError;
22use common_meta::cache_invalidator::KvCacheInvalidator;
23use common_meta::error::Error::CacheNotGet;
24use common_meta::error::{
25 CacheNotGetSnafu, Error, ExternalSnafu, GetKvCacheSnafu, Result, UnsupportedSnafu,
26};
27use common_meta::kv_backend::read_only::ReadOnlyKvBackend;
28use common_meta::kv_backend::txn::{Txn, TxnResponse};
29use common_meta::kv_backend::{KvBackend, KvBackendRef, TxnService};
30use common_meta::rpc::KeyValue;
31use common_meta::rpc::store::{
32 BatchDeleteRequest, BatchDeleteResponse, BatchGetRequest, BatchGetResponse, BatchPutRequest,
33 BatchPutResponse, CompareAndPutRequest, CompareAndPutResponse, DeleteRangeRequest,
34 DeleteRangeResponse, PutRequest, PutResponse, RangeRequest, RangeResponse,
35};
36use common_telemetry::debug;
37use meta_client::client::MetaClient;
38use moka::future::{Cache, CacheBuilder};
39use snafu::{OptionExt, ResultExt};
40
41use crate::metrics::{
42 METRIC_CATALOG_KV_BATCH_GET, METRIC_CATALOG_KV_GET, METRIC_CATALOG_KV_REMOTE_GET,
43};
44
45const DEFAULT_CACHE_MAX_CAPACITY: u64 = 10000;
46const DEFAULT_CACHE_TTL: Duration = Duration::from_secs(10 * 60);
47const DEFAULT_CACHE_TTI: Duration = Duration::from_secs(5 * 60);
48
49pub struct CachedKvBackendBuilder {
50 cache_max_capacity: Option<u64>,
51 cache_ttl: Option<Duration>,
52 cache_tti: Option<Duration>,
53 inner: KvBackendRef,
54}
55
56impl CachedKvBackendBuilder {
57 pub fn new(inner: KvBackendRef) -> Self {
58 Self {
59 cache_max_capacity: None,
60 cache_ttl: None,
61 cache_tti: None,
62 inner,
63 }
64 }
65
66 pub fn cache_max_capacity(mut self, cache_max_capacity: u64) -> Self {
67 self.cache_max_capacity.replace(cache_max_capacity);
68 self
69 }
70
71 pub fn cache_ttl(mut self, cache_ttl: Duration) -> Self {
72 self.cache_ttl.replace(cache_ttl);
73 self
74 }
75
76 pub fn cache_tti(mut self, cache_tti: Duration) -> Self {
77 self.cache_tti.replace(cache_tti);
78 self
79 }
80
81 pub fn build(self) -> CachedKvBackend {
82 let cache_max_capacity = self
83 .cache_max_capacity
84 .unwrap_or(DEFAULT_CACHE_MAX_CAPACITY);
85 let cache_ttl = self.cache_ttl.unwrap_or(DEFAULT_CACHE_TTL);
86 let cache_tti = self.cache_tti.unwrap_or(DEFAULT_CACHE_TTI);
87
88 let cache = CacheBuilder::new(cache_max_capacity)
89 .time_to_live(cache_ttl)
90 .time_to_idle(cache_tti)
91 .build();
92 let kv_backend = self.inner;
93 let name = format!("CachedKvBackend({})", kv_backend.name());
94 let version = AtomicUsize::new(0);
95
96 CachedKvBackend {
97 kv_backend,
98 cache,
99 name,
100 version,
101 }
102 }
103}
104
105pub type CacheBackend = Cache<Vec<u8>, KeyValue>;
106
107pub struct CachedKvBackend {
117 kv_backend: KvBackendRef,
118 cache: CacheBackend,
119 name: String,
120 version: AtomicUsize,
121}
122
123#[async_trait::async_trait]
124impl TxnService for CachedKvBackend {
125 type Error = Error;
126
127 async fn txn(&self, txn: Txn) -> std::result::Result<TxnResponse, Self::Error> {
128 self.kv_backend.txn(txn).await
130 }
131
132 fn max_txn_ops(&self) -> usize {
133 self.kv_backend.max_txn_ops()
134 }
135}
136
137#[async_trait::async_trait]
138impl KvBackend for CachedKvBackend {
139 fn name(&self) -> &str {
140 &self.name
141 }
142
143 fn as_any(&self) -> &dyn Any {
144 self
145 }
146
147 async fn range(&self, req: RangeRequest) -> Result<RangeResponse> {
148 self.kv_backend.range(req).await
149 }
150
151 async fn put(&self, req: PutRequest) -> Result<PutResponse> {
152 let key = &req.key.clone();
153
154 let ret = self.kv_backend.put(req).await;
155
156 if ret.is_ok() {
157 self.invalidate_key(key).await;
158 }
159
160 ret
161 }
162
163 async fn batch_put(&self, req: BatchPutRequest) -> Result<BatchPutResponse> {
164 let keys = req
165 .kvs
166 .iter()
167 .map(|kv| kv.key().to_vec())
168 .collect::<Vec<_>>();
169
170 let resp = self.kv_backend.batch_put(req).await;
171
172 if resp.is_ok() {
173 for key in keys {
174 self.invalidate_key(&key).await;
175 }
176 }
177
178 resp
179 }
180
181 async fn batch_get(&self, req: BatchGetRequest) -> Result<BatchGetResponse> {
182 let _timer = METRIC_CATALOG_KV_BATCH_GET.start_timer();
183
184 let mut kvs = Vec::with_capacity(req.keys.len());
185 let mut miss_keys = Vec::with_capacity(req.keys.len());
186
187 for key in req.keys {
188 if let Some(val) = self.cache.get(&key).await {
189 kvs.push(val);
190 } else {
191 miss_keys.push(key);
192 }
193 }
194
195 if miss_keys.is_empty() {
196 return Ok(BatchGetResponse { kvs });
197 }
198
199 let batch_get_req = BatchGetRequest::new().with_keys(miss_keys.clone());
200
201 let pre_version = self.version();
202
203 let unhit_kvs = self.kv_backend.batch_get(batch_get_req).await?.kvs;
204
205 for kv in unhit_kvs.iter() {
206 self.cache.insert(kv.key().to_vec(), kv.clone()).await;
207 }
208
209 if !self.validate_version(pre_version) {
210 for key in miss_keys.iter() {
211 self.cache.invalidate(key).await;
212 }
213 }
214
215 kvs.extend(unhit_kvs);
216
217 Ok(BatchGetResponse { kvs })
218 }
219
220 async fn compare_and_put(&self, req: CompareAndPutRequest) -> Result<CompareAndPutResponse> {
221 let key = &req.key.clone();
222
223 let ret = self.kv_backend.compare_and_put(req).await;
224
225 if ret.is_ok() {
226 self.invalidate_key(key).await;
227 }
228
229 ret
230 }
231
232 async fn delete_range(&self, mut req: DeleteRangeRequest) -> Result<DeleteRangeResponse> {
233 let prev_kv = req.prev_kv;
234
235 req.prev_kv = true;
236 let resp = self.kv_backend.delete_range(req).await;
237 match resp {
238 Ok(mut resp) => {
239 for prev_kv in resp.prev_kvs.iter() {
240 self.invalidate_key(prev_kv.key()).await;
241 }
242
243 if !prev_kv {
244 resp.prev_kvs = vec![];
245 }
246 Ok(resp)
247 }
248 Err(e) => Err(e),
249 }
250 }
251
252 async fn batch_delete(&self, mut req: BatchDeleteRequest) -> Result<BatchDeleteResponse> {
253 let prev_kv = req.prev_kv;
254
255 req.prev_kv = true;
256 let resp = self.kv_backend.batch_delete(req).await;
257 match resp {
258 Ok(mut resp) => {
259 for prev_kv in resp.prev_kvs.iter() {
260 self.invalidate_key(prev_kv.key()).await;
261 }
262
263 if !prev_kv {
264 resp.prev_kvs = vec![];
265 }
266 Ok(resp)
267 }
268 Err(e) => Err(e),
269 }
270 }
271
272 async fn get(&self, key: &[u8]) -> Result<Option<KeyValue>> {
273 let _timer = METRIC_CATALOG_KV_GET.start_timer();
274
275 let pre_version = Arc::new(Mutex::new(None));
276
277 let init = async {
278 let version_clone = pre_version.clone();
279 let _timer = METRIC_CATALOG_KV_REMOTE_GET.start_timer();
280
281 version_clone.lock().unwrap().replace(self.version());
282
283 self.kv_backend.get(key).await.map(|val| {
284 val.with_context(|| CacheNotGetSnafu {
285 key: String::from_utf8_lossy(key),
286 })
287 })?
288 };
289
290 let ret = match self.cache.try_get_with_by_ref(key, init).await {
294 Ok(val) => Ok(Some(val)),
295 Err(e) => match e.as_ref() {
296 CacheNotGet { .. } => Ok(None),
297 _ => Err(e),
298 },
299 }
300 .map_err(|e| {
301 GetKvCacheSnafu {
302 err_msg: e.to_string(),
303 }
304 .build()
305 });
306
307 if pre_version
310 .lock()
311 .unwrap()
312 .as_ref()
313 .is_some_and(|v| !self.validate_version(*v))
314 {
315 self.cache.invalidate(key).await;
316 }
317
318 ret
319 }
320}
321
322#[async_trait::async_trait]
323impl KvCacheInvalidator for CachedKvBackend {
324 async fn invalidate_key(&self, key: &[u8]) {
325 self.create_new_version();
326 self.cache.invalidate(key).await;
327 debug!("invalidated cache key: {}", String::from_utf8_lossy(key));
328 }
329}
330
331impl CachedKvBackend {
332 #[cfg(test)]
334 fn wrap(kv_backend: KvBackendRef) -> Self {
335 let cache = CacheBuilder::new(DEFAULT_CACHE_MAX_CAPACITY)
336 .time_to_live(DEFAULT_CACHE_TTL)
337 .time_to_idle(DEFAULT_CACHE_TTI)
338 .build();
339
340 let name = format!("CachedKvBackend({})", kv_backend.name());
341 Self {
342 kv_backend,
343 cache,
344 name,
345 version: AtomicUsize::new(0),
346 }
347 }
348
349 pub fn cache(&self) -> &CacheBackend {
350 &self.cache
351 }
352
353 fn version(&self) -> usize {
354 self.version.load(Ordering::Relaxed)
355 }
356
357 fn validate_version(&self, pre_version: usize) -> bool {
358 self.version() == pre_version
359 }
360
361 fn create_new_version(&self) -> usize {
362 self.version.fetch_add(1, Ordering::Relaxed) + 1
363 }
364}
365
366#[derive(Debug)]
367pub(crate) struct MetaKvBackend {
368 client: Arc<MetaClient>,
369}
370
371impl MetaKvBackend {
372 fn new(client: Arc<MetaClient>) -> MetaKvBackend {
374 MetaKvBackend { client }
375 }
376}
377
378pub fn new_read_only_meta_kv_backend(client: Arc<MetaClient>) -> KvBackendRef {
379 Arc::new(ReadOnlyKvBackend::new(Arc::new(MetaKvBackend::new(client))))
380}
381
382#[async_trait::async_trait]
383impl TxnService for MetaKvBackend {
384 type Error = Error;
385
386 async fn txn(&self, _txn: Txn) -> Result<TxnResponse> {
387 UnsupportedSnafu {
388 operation: "MetaKvBackend txn",
389 }
390 .fail()
391 }
392
393 fn max_txn_ops(&self) -> usize {
394 usize::MAX
395 }
396}
397
398#[async_trait::async_trait]
402impl KvBackend for MetaKvBackend {
403 fn name(&self) -> &str {
404 "MetaKvBackend"
405 }
406
407 fn as_any(&self) -> &dyn Any {
408 self
409 }
410
411 async fn range(&self, req: RangeRequest) -> Result<RangeResponse> {
412 self.client
413 .range(req)
414 .await
415 .map_err(BoxedError::new)
416 .context(ExternalSnafu)
417 }
418
419 async fn put(&self, req: PutRequest) -> Result<PutResponse> {
420 self.client
421 .put(req)
422 .await
423 .map_err(BoxedError::new)
424 .context(ExternalSnafu)
425 }
426
427 async fn batch_put(&self, req: BatchPutRequest) -> Result<BatchPutResponse> {
428 self.client
429 .batch_put(req)
430 .await
431 .map_err(BoxedError::new)
432 .context(ExternalSnafu)
433 }
434
435 async fn batch_get(&self, req: BatchGetRequest) -> Result<BatchGetResponse> {
436 self.client
437 .batch_get(req)
438 .await
439 .map_err(BoxedError::new)
440 .context(ExternalSnafu)
441 }
442
443 async fn compare_and_put(
444 &self,
445 request: CompareAndPutRequest,
446 ) -> Result<CompareAndPutResponse> {
447 self.client
448 .compare_and_put(request)
449 .await
450 .map_err(BoxedError::new)
451 .context(ExternalSnafu)
452 }
453
454 async fn delete_range(&self, req: DeleteRangeRequest) -> Result<DeleteRangeResponse> {
455 self.client
456 .delete_range(req)
457 .await
458 .map_err(BoxedError::new)
459 .context(ExternalSnafu)
460 }
461
462 async fn batch_delete(&self, req: BatchDeleteRequest) -> Result<BatchDeleteResponse> {
463 self.client
464 .batch_delete(req)
465 .await
466 .map_err(BoxedError::new)
467 .context(ExternalSnafu)
468 }
469
470 async fn get(&self, key: &[u8]) -> Result<Option<KeyValue>> {
471 let mut response = self
472 .client
473 .range(RangeRequest::new().with_key(key))
474 .await
475 .map_err(BoxedError::new)
476 .context(ExternalSnafu)?;
477 Ok(response.take_kvs().get_mut(0).map(|kv| KeyValue {
478 key: kv.take_key(),
479 value: kv.take_value(),
480 }))
481 }
482}
483
484#[cfg(test)]
485mod tests {
486 use std::any::Any;
487 use std::sync::Arc;
488 use std::sync::atomic::{AtomicU32, Ordering};
489
490 use async_trait::async_trait;
491 use common_meta::kv_backend::memory::MemoryKvBackend;
492 use common_meta::kv_backend::read_only::ReadOnlyKvBackend;
493 use common_meta::kv_backend::txn::{Txn, TxnOp};
494 use common_meta::kv_backend::{KvBackend, TxnService};
495 use common_meta::rpc::KeyValue;
496 use common_meta::rpc::store::{
497 BatchDeleteRequest, BatchDeleteResponse, BatchGetRequest, BatchGetResponse,
498 BatchPutRequest, BatchPutResponse, DeleteRangeRequest, DeleteRangeResponse, PutRequest,
499 PutResponse, RangeRequest, RangeResponse,
500 };
501 use dashmap::DashMap;
502 use meta_client::client::MetaClientBuilder;
503
504 use super::{CachedKvBackend, new_read_only_meta_kv_backend};
505
506 #[derive(Default)]
507 pub struct SimpleKvBackend {
508 inner_map: DashMap<Vec<u8>, Vec<u8>>,
509 get_execute_times: Arc<AtomicU32>,
510 batch_get_execute_times: Arc<AtomicU32>,
511 }
512
513 impl TxnService for SimpleKvBackend {
514 type Error = common_meta::error::Error;
515 }
516
517 #[async_trait]
518 impl KvBackend for SimpleKvBackend {
519 fn name(&self) -> &str {
520 "SimpleKvBackend"
521 }
522
523 fn as_any(&self) -> &dyn Any {
524 self
525 }
526
527 async fn batch_get(&self, req: BatchGetRequest) -> Result<BatchGetResponse, Self::Error> {
528 self.batch_get_execute_times.fetch_add(1, Ordering::SeqCst);
529 let mut kvs = Vec::with_capacity(req.keys.len());
530 for key in req.keys.iter() {
531 if let Some(kv) = self.get(key).await? {
532 kvs.push(kv);
533 }
534 }
535 Ok(BatchGetResponse { kvs })
536 }
537
538 async fn put(&self, req: PutRequest) -> Result<PutResponse, Self::Error> {
539 self.inner_map.insert(req.key, req.value);
540 Ok(PutResponse { prev_kv: None })
542 }
543
544 async fn get(&self, key: &[u8]) -> Result<Option<KeyValue>, Self::Error> {
545 self.get_execute_times
546 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
547 Ok(self.inner_map.get(key).map(|v| KeyValue {
548 key: key.to_vec(),
549 value: v.value().clone(),
550 }))
551 }
552
553 async fn range(&self, _req: RangeRequest) -> Result<RangeResponse, Self::Error> {
554 unimplemented!()
555 }
556
557 async fn batch_put(&self, _req: BatchPutRequest) -> Result<BatchPutResponse, Self::Error> {
558 unimplemented!()
559 }
560
561 async fn delete_range(
562 &self,
563 _req: DeleteRangeRequest,
564 ) -> Result<DeleteRangeResponse, Self::Error> {
565 unimplemented!()
566 }
567
568 async fn batch_delete(
569 &self,
570 _req: BatchDeleteRequest,
571 ) -> Result<BatchDeleteResponse, Self::Error> {
572 unimplemented!()
573 }
574 }
575
576 #[tokio::test]
577 async fn test_cached_kv_backend() {
578 let simple_kv = Arc::new(SimpleKvBackend::default());
579 let get_execute_times = simple_kv.get_execute_times.clone();
580 let batch_get_execute_times = simple_kv.batch_get_execute_times.clone();
581 let cached_kv = CachedKvBackend::wrap(simple_kv);
582
583 add_some_vals(&cached_kv).await;
584
585 let batch_get_req = BatchGetRequest {
586 keys: vec![b"k1".to_vec(), b"k2".to_vec()],
587 };
588
589 assert_eq!(get_execute_times.load(Ordering::SeqCst), 0);
590
591 for _ in 0..10 {
592 let batch_get_resp = cached_kv.batch_get(batch_get_req.clone()).await.unwrap();
593
594 assert_eq!(batch_get_resp.kvs.len(), 2);
595 assert_eq!(get_execute_times.load(Ordering::SeqCst), 2);
596 assert_eq!(batch_get_execute_times.load(Ordering::SeqCst), 1);
597 }
598
599 let batch_get_req = BatchGetRequest {
600 keys: vec![b"k1".to_vec(), b"k2".to_vec(), b"k3".to_vec()],
601 };
602
603 let _batch_get_resp = cached_kv.batch_get(batch_get_req.clone()).await.unwrap();
604
605 assert_eq!(get_execute_times.load(Ordering::SeqCst), 3);
606 assert_eq!(batch_get_execute_times.load(Ordering::SeqCst), 2);
607
608 for _ in 0..10 {
609 let batch_get_resp = cached_kv.batch_get(batch_get_req.clone()).await.unwrap();
610
611 assert_eq!(batch_get_resp.kvs.len(), 3);
612 assert_eq!(get_execute_times.load(Ordering::SeqCst), 3);
613 assert_eq!(batch_get_execute_times.load(Ordering::SeqCst), 2);
614 }
615 }
616
617 #[tokio::test]
618 async fn test_cached_kv_backend_empty_batch_get() {
619 let simple_kv = Arc::new(SimpleKvBackend::default());
620 let cached_kv = CachedKvBackend::wrap(simple_kv.clone());
621
622 let response = cached_kv.batch_get(BatchGetRequest::new()).await.unwrap();
623
624 assert!(response.kvs.is_empty());
625 assert_eq!(simple_kv.batch_get_execute_times.load(Ordering::SeqCst), 0);
626 assert_eq!(simple_kv.get_execute_times.load(Ordering::SeqCst), 0);
627 }
628
629 #[tokio::test]
630 async fn test_cached_kv_backend_rejects_writes_with_read_only_inner() {
631 let inner = Arc::new(MemoryKvBackend::<common_meta::error::Error>::new());
632 let cached_kv = CachedKvBackend::wrap(Arc::new(ReadOnlyKvBackend::new(inner)));
633
634 let err = cached_kv
635 .put(PutRequest {
636 key: b"k1".to_vec(),
637 value: b"v1".to_vec(),
638 prev_kv: false,
639 })
640 .await
641 .unwrap_err();
642
643 assert!(matches!(
644 err,
645 common_meta::error::Error::ReadOnlyKvBackend { .. }
646 ));
647 }
648
649 #[tokio::test]
650 async fn test_read_only_meta_kv_backend_rejects_writes() {
651 let meta_client = Arc::new(MetaClientBuilder::frontend_default_options().build());
652 let backend = new_read_only_meta_kv_backend(meta_client);
653
654 let err = backend
655 .put(PutRequest {
656 key: b"k1".to_vec(),
657 value: b"v1".to_vec(),
658 prev_kv: false,
659 })
660 .await
661 .unwrap_err();
662
663 assert!(matches!(
664 err,
665 common_meta::error::Error::ReadOnlyKvBackend { .. }
666 ));
667 }
668
669 #[tokio::test]
670 async fn test_read_only_meta_kv_backend_does_not_emulate_txn() {
671 let meta_client = Arc::new(MetaClientBuilder::frontend_default_options().build());
672 let backend = new_read_only_meta_kv_backend(meta_client);
673
674 let result = backend
675 .txn(Txn::new().and_then(vec![TxnOp::Get(b"k1".to_vec())]))
676 .await;
677 let err = match result {
678 Ok(_) => panic!("expected unsupported txn error"),
679 Err(err) => err,
680 };
681
682 assert!(matches!(err, common_meta::error::Error::Unsupported { .. }));
683 }
684
685 async fn add_some_vals(kv_backend: &impl KvBackend) {
686 kv_backend
687 .put(PutRequest {
688 key: b"k1".to_vec(),
689 value: b"v1".to_vec(),
690 prev_kv: false,
691 })
692 .await
693 .unwrap();
694
695 kv_backend
696 .put(PutRequest {
697 key: b"k2".to_vec(),
698 value: b"v2".to_vec(),
699 prev_kv: false,
700 })
701 .await
702 .unwrap();
703
704 kv_backend
705 .put(PutRequest {
706 key: b"k3".to_vec(),
707 value: b"v3".to_vec(),
708 prev_kv: false,
709 })
710 .await
711 .unwrap();
712 }
713}