1use std::any::Any;
16use std::collections::{HashMap, HashSet};
17use std::sync::Arc;
18use std::time::Duration;
19
20use api::v1::meta::cluster_client::ClusterClient;
21use api::v1::meta::{
22 BatchGetRequest as PbBatchGetRequest, BatchGetResponse as PbBatchGetResponse,
23 RangeRequest as PbRangeRequest, RangeResponse as PbRangeResponse, ResponseHeader,
24};
25use common_grpc::channel_manager::ChannelManager;
26use common_meta::datanode::{DatanodeStatKey, DatanodeStatValue};
27use common_meta::kv_backend::{KvBackend, ResettableKvBackendRef, TxnService};
28use common_meta::rpc::KeyValue;
29use common_meta::rpc::store::{
30 BatchDeleteRequest, BatchDeleteResponse, BatchGetRequest, BatchGetResponse, BatchPutRequest,
31 BatchPutResponse, CompareAndPutRequest, CompareAndPutResponse, DeleteRangeRequest,
32 DeleteRangeResponse, PutRequest, PutResponse, RangeRequest, RangeResponse,
33};
34use common_meta::util;
35use common_telemetry::warn;
36use derive_builder::Builder;
37use snafu::{OptionExt, ResultExt, ensure};
38
39use crate::error::{self, Result, match_for_io_error};
40use crate::metasrv::ElectionRef;
41
42pub type MetaPeerClientRef = Arc<MetaPeerClient>;
43
44#[derive(Builder)]
45pub struct MetaPeerClient {
46 election: Option<ElectionRef>,
47 in_memory: ResettableKvBackendRef,
48 #[builder(default = "ChannelManager::default()")]
49 channel_manager: ChannelManager,
50 #[builder(default = "3")]
51 max_retry_count: usize,
52 #[builder(default = "1000")]
53 retry_interval_ms: u64,
54}
55
56#[async_trait::async_trait]
57impl TxnService for MetaPeerClient {
58 type Error = error::Error;
59}
60
61#[async_trait::async_trait]
62impl KvBackend for MetaPeerClient {
63 fn name(&self) -> &str {
64 "MetaPeerClient"
65 }
66
67 fn as_any(&self) -> &dyn Any {
68 self
69 }
70
71 async fn range(&self, req: RangeRequest) -> Result<RangeResponse> {
72 if self.is_leader() {
73 return self
74 .in_memory
75 .range(req)
76 .await
77 .context(error::KvBackendSnafu);
78 }
79
80 let max_retry_count = self.max_retry_count;
81 let retry_interval_ms = self.retry_interval_ms;
82
83 for _ in 0..max_retry_count {
84 match self.remote_range(req.clone()).await {
85 Ok(res) => return Ok(res),
86 Err(e) => {
87 if need_retry(&e) {
88 warn!(e; "Encountered an error that need to retry");
89 tokio::time::sleep(Duration::from_millis(retry_interval_ms)).await;
90 } else {
91 return Err(e);
92 }
93 }
94 }
95 }
96
97 error::ExceededRetryLimitSnafu {
98 func_name: "range",
99 retry_num: max_retry_count,
100 }
101 .fail()
102 }
103
104 async fn put(&self, _req: PutRequest) -> Result<PutResponse> {
106 error::UnsupportedSnafu {
107 operation: "put".to_string(),
108 }
109 .fail()
110 }
111
112 async fn batch_put(&self, _req: BatchPutRequest) -> Result<BatchPutResponse> {
113 error::UnsupportedSnafu {
114 operation: "batch put".to_string(),
115 }
116 .fail()
117 }
118
119 async fn batch_get(&self, req: BatchGetRequest) -> Result<BatchGetResponse> {
121 if self.is_leader() {
122 return self
123 .in_memory
124 .batch_get(req)
125 .await
126 .context(error::KvBackendSnafu);
127 }
128
129 let max_retry_count = self.max_retry_count;
130 let retry_interval_ms = self.retry_interval_ms;
131
132 for _ in 0..max_retry_count {
133 match self.remote_batch_get(req.keys.clone()).await {
134 Ok(res) => return Ok(res),
135 Err(e) => {
136 if need_retry(&e) {
137 warn!(e; "Encountered an error that need to retry");
138 tokio::time::sleep(Duration::from_millis(retry_interval_ms)).await;
139 } else {
140 return Err(e);
141 }
142 }
143 }
144 }
145
146 error::ExceededRetryLimitSnafu {
147 func_name: "batch_get",
148 retry_num: max_retry_count,
149 }
150 .fail()
151 }
152
153 async fn delete_range(&self, _req: DeleteRangeRequest) -> Result<DeleteRangeResponse> {
154 error::UnsupportedSnafu {
155 operation: "delete range".to_string(),
156 }
157 .fail()
158 }
159
160 async fn batch_delete(&self, _req: BatchDeleteRequest) -> Result<BatchDeleteResponse> {
161 error::UnsupportedSnafu {
162 operation: "batch delete".to_string(),
163 }
164 .fail()
165 }
166
167 async fn compare_and_put(&self, _req: CompareAndPutRequest) -> Result<CompareAndPutResponse> {
168 error::UnsupportedSnafu {
169 operation: "compare and put".to_string(),
170 }
171 .fail()
172 }
173
174 async fn put_conditionally(
175 &self,
176 _key: Vec<u8>,
177 _value: Vec<u8>,
178 _if_not_exists: bool,
179 ) -> Result<bool> {
180 error::UnsupportedSnafu {
181 operation: "put conditionally".to_string(),
182 }
183 .fail()
184 }
185
186 async fn delete(&self, _key: &[u8], _prev_kv: bool) -> Result<Option<KeyValue>> {
187 error::UnsupportedSnafu {
188 operation: "delete".to_string(),
189 }
190 .fail()
191 }
192}
193
194impl MetaPeerClient {
195 async fn get_dn_key_value(&self, keys_only: bool) -> Result<Vec<KeyValue>> {
196 let key = DatanodeStatKey::prefix_key();
197 let range_end = util::get_prefix_end_key(&key);
198 let range_request = RangeRequest {
199 key,
200 range_end,
201 keys_only,
202 ..Default::default()
203 };
204 self.range(range_request).await.map(|res| res.kvs)
205 }
206
207 pub async fn get_all_dn_stat_kvs(&self) -> Result<HashMap<DatanodeStatKey, DatanodeStatValue>> {
209 let kvs = self.get_dn_key_value(false).await?;
210 to_stat_kv_map(kvs)
211 }
212
213 pub async fn get_node_cnt(&self) -> Result<i32> {
214 let kvs = self.get_dn_key_value(true).await?;
215 kvs.into_iter()
216 .map(|kv| {
217 kv.key
218 .try_into()
219 .context(error::InvalidDatanodeStatFormatSnafu {})
220 })
221 .collect::<Result<HashSet<DatanodeStatKey>>>()
222 .map(|hash_set| hash_set.len() as i32)
223 }
224
225 pub async fn get_dn_stat_kvs(
227 &self,
228 keys: Vec<DatanodeStatKey>,
229 ) -> Result<HashMap<DatanodeStatKey, DatanodeStatValue>> {
230 let stat_keys = keys.into_iter().map(|key| key.into()).collect();
231 let batch_get_req = BatchGetRequest { keys: stat_keys };
232
233 let res = self.batch_get(batch_get_req).await?;
234
235 to_stat_kv_map(res.kvs)
236 }
237
238 async fn remote_range(&self, req: RangeRequest) -> Result<RangeResponse> {
239 let election = self.election.as_ref().unwrap();
241
242 let leader_addr = election.leader().await.context(error::KvBackendSnafu)?.0;
243
244 let channel = self
245 .channel_manager
246 .get(&leader_addr)
247 .context(error::CreateChannelSnafu)?;
248
249 let request = tonic::Request::new(PbRangeRequest::from(req));
250
251 let mut client =
252 common_grpc::configure_tonic_client!(ClusterClient::new(channel), self.channel_manager);
253 let response: PbRangeResponse = client
254 .range(request)
255 .await
256 .context(error::RangeSnafu)?
257 .into_inner();
258
259 check_resp_header(&response.header, Context { addr: &leader_addr })?;
260
261 Ok(RangeResponse {
262 kvs: response.kvs.into_iter().map(KeyValue::new).collect(),
263 more: response.more,
264 })
265 }
266
267 async fn remote_batch_get(&self, keys: Vec<Vec<u8>>) -> Result<BatchGetResponse> {
268 let election = self.election.as_ref().unwrap();
270
271 let leader_addr = election.leader().await.context(error::KvBackendSnafu)?.0;
272
273 let channel = self
274 .channel_manager
275 .get(&leader_addr)
276 .context(error::CreateChannelSnafu)?;
277
278 let request = tonic::Request::new(PbBatchGetRequest {
279 keys,
280 ..Default::default()
281 });
282
283 let mut client =
284 common_grpc::configure_tonic_client!(ClusterClient::new(channel), self.channel_manager);
285 let response: PbBatchGetResponse = client
286 .batch_get(request)
287 .await
288 .context(error::BatchGetSnafu)?
289 .into_inner();
290
291 check_resp_header(&response.header, Context { addr: &leader_addr })?;
292
293 Ok(BatchGetResponse {
294 kvs: response.kvs.into_iter().map(KeyValue::new).collect(),
295 })
296 }
297
298 pub(crate) fn is_leader(&self) -> bool {
301 self.election
302 .as_ref()
303 .map(|election| election.is_leader())
304 .unwrap_or(true)
305 }
306
307 #[cfg(test)]
308 pub(crate) fn memory_backend(&self) -> ResettableKvBackendRef {
309 self.in_memory.clone()
310 }
311}
312
313fn to_stat_kv_map(kvs: Vec<KeyValue>) -> Result<HashMap<DatanodeStatKey, DatanodeStatValue>> {
314 let mut map = HashMap::with_capacity(kvs.len());
315 for kv in kvs {
316 let _ = map.insert(
317 kv.key
318 .try_into()
319 .context(error::InvalidDatanodeStatFormatSnafu {})?,
320 kv.value
321 .try_into()
322 .context(error::InvalidDatanodeStatFormatSnafu {})?,
323 );
324 }
325 Ok(map)
326}
327
328struct Context<'a> {
329 addr: &'a str,
330}
331
332fn check_resp_header(header: &Option<ResponseHeader>, ctx: Context) -> Result<()> {
333 let header = header
334 .as_ref()
335 .context(error::ResponseHeaderNotFoundSnafu)?;
336
337 ensure!(
338 !header.is_not_leader(),
339 error::IsNotLeaderSnafu {
340 node_addr: ctx.addr
341 }
342 );
343
344 Ok(())
345}
346
347fn need_retry(error: &error::Error) -> bool {
348 match error {
349 error::Error::IsNotLeader { .. } => true,
350 error::Error::Range { error, .. } | error::Error::BatchGet { error, .. } => {
351 match_for_io_error(error).is_some()
352 }
353 _ => false,
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use std::sync::Arc;
360 use std::sync::atomic::{AtomicI64, Ordering};
361
362 use api::v1::meta::cluster_server::{Cluster, ClusterServer};
363 use api::v1::meta::{
364 BatchGetRequest as PbBatchGetRequest, BatchGetResponse as PbBatchGetResponse, Error,
365 ErrorCode, MetasrvPeersRequest, MetasrvPeersResponse, RangeRequest as PbRangeRequest,
366 RangeResponse as PbRangeResponse, ResponseHeader,
367 };
368 use common_grpc::channel_manager::ChannelManager;
369 use common_meta::datanode::{DatanodeStatKey, DatanodeStatValue, Stat};
370 use common_meta::election::{Election, LeaderChangeMessage, LeaderValue, MetasrvNodeInfo};
371 use common_meta::kv_backend::KvBackend;
372 use common_meta::kv_backend::memory::MemoryKvBackend;
373 use common_meta::rpc::KeyValue;
374 use common_meta::rpc::store::RangeRequest;
375 use hyper_util::rt::TokioIo;
376 use tonic::{Request, Response, Status};
377 use tower::service_fn;
378
379 use super::{Context, MetaPeerClientBuilder, check_resp_header, to_stat_kv_map};
380 use crate::error;
381
382 struct FollowerElection {
383 leader_addr: String,
384 }
385
386 #[async_trait::async_trait]
387 impl Election for FollowerElection {
388 type Leader = LeaderValue;
389
390 fn is_leader(&self) -> bool {
391 false
392 }
393
394 fn in_leader_infancy(&self) -> bool {
395 false
396 }
397
398 async fn register_candidate(&self, _: &MetasrvNodeInfo) -> common_meta::error::Result<()> {
399 Ok(())
400 }
401
402 async fn all_candidates(&self) -> common_meta::error::Result<Vec<MetasrvNodeInfo>> {
403 Ok(vec![])
404 }
405
406 async fn campaign(&self) -> common_meta::error::Result<()> {
407 Ok(())
408 }
409
410 async fn leader(&self) -> common_meta::error::Result<Self::Leader> {
411 Ok(LeaderValue(self.leader_addr.clone()))
412 }
413
414 async fn resign(&self) -> common_meta::error::Result<()> {
415 Ok(())
416 }
417
418 fn subscribe_leader_change(&self) -> tokio::sync::broadcast::Receiver<LeaderChangeMessage> {
419 let (_, receiver) = tokio::sync::broadcast::channel(1);
420 receiver
421 }
422 }
423
424 struct RangeServer {
425 requested_limit: Arc<AtomicI64>,
426 }
427
428 #[async_trait::async_trait]
429 impl Cluster for RangeServer {
430 async fn batch_get(
431 &self,
432 _: Request<PbBatchGetRequest>,
433 ) -> std::result::Result<Response<PbBatchGetResponse>, Status> {
434 Err(Status::unimplemented("batch_get is not used in this test"))
435 }
436
437 async fn range(
438 &self,
439 request: Request<PbRangeRequest>,
440 ) -> std::result::Result<Response<PbRangeResponse>, Status> {
441 self.requested_limit
442 .store(request.into_inner().limit, Ordering::Relaxed);
443 Ok(Response::new(PbRangeResponse {
444 header: Some(ResponseHeader::success()),
445 kvs: vec![api::v1::meta::KeyValue {
446 key: b"key".to_vec(),
447 value: b"value".to_vec(),
448 }],
449 more: true,
450 }))
451 }
452
453 async fn metasrv_peers(
454 &self,
455 _: Request<MetasrvPeersRequest>,
456 ) -> std::result::Result<Response<MetasrvPeersResponse>, Status> {
457 Err(Status::unimplemented(
458 "metasrv_peers is not used in this test",
459 ))
460 }
461 }
462
463 #[tokio::test]
464 async fn test_follower_range_forwards_limit() {
465 let requested_limit = Arc::new(AtomicI64::new(0));
466 let range_server = RangeServer {
467 requested_limit: requested_limit.clone(),
468 };
469 let (client, server) = tokio::io::duplex(1024);
470 let _server_handle = tokio::spawn(async move {
471 tonic::transport::Server::builder()
472 .add_service(
473 ClusterServer::new(range_server)
474 .accept_compressed(tonic::codec::CompressionEncoding::Zstd)
475 .send_compressed(tonic::codec::CompressionEncoding::Zstd),
476 )
477 .serve_with_incoming(futures::stream::iter([Ok::<_, std::io::Error>(server)]))
478 .await
479 });
480
481 let channel_manager = ChannelManager::new();
482 let mut client = Some(client);
483 channel_manager
484 .reset_with_connector(
485 "leader:0",
486 service_fn(move |_| {
487 let client = client.take();
488 async move {
489 client
490 .map(TokioIo::new)
491 .ok_or_else(|| std::io::Error::other("client already taken"))
492 }
493 }),
494 )
495 .unwrap();
496
497 let follower = MetaPeerClientBuilder::default()
498 .election(Some(Arc::new(FollowerElection {
499 leader_addr: "leader:0".to_string(),
500 })))
501 .in_memory(Arc::new(MemoryKvBackend::new()))
502 .channel_manager(channel_manager)
503 .max_retry_count(1)
504 .build()
505 .unwrap();
506
507 let response = follower
508 .range(RangeRequest {
509 key: b"key".to_vec(),
510 limit: 1,
511 ..Default::default()
512 })
513 .await
514 .unwrap();
515
516 assert_eq!(1, requested_limit.load(Ordering::Relaxed));
517 assert_eq!(1, response.kvs.len());
518 assert!(response.more);
519 }
520
521 #[test]
522 fn test_to_stat_kv_map() {
523 let stat_key = DatanodeStatKey { node_id: 100 };
524
525 let stat = Stat {
526 id: 100,
527 addr: "127.0.0.1:3001".to_string(),
528 ..Default::default()
529 };
530 let stat_val = DatanodeStatValue { stats: vec![stat] }.try_into().unwrap();
531
532 let kv = KeyValue {
533 key: stat_key.into(),
534 value: stat_val,
535 };
536
537 let kv_map = to_stat_kv_map(vec![kv]).unwrap();
538 assert_eq!(1, kv_map.len());
539 let _ = kv_map.get(&stat_key).unwrap();
540
541 let stat_val = kv_map.get(&stat_key).unwrap();
542 let stat = stat_val.stats.first().unwrap();
543
544 assert_eq!(100, stat.id);
545 assert_eq!("127.0.0.1:3001", stat.addr);
546 }
547
548 #[test]
549 fn test_check_resp_header() {
550 let header = Some(ResponseHeader {
551 error: None,
552 ..Default::default()
553 });
554 check_resp_header(&header, mock_ctx()).unwrap();
555
556 let result = check_resp_header(&None, mock_ctx());
557 assert!(result.is_err());
558 assert!(matches!(
559 result.err().unwrap(),
560 error::Error::ResponseHeaderNotFound { .. }
561 ));
562
563 let header = Some(ResponseHeader {
564 error: Some(Error {
565 code: ErrorCode::NotLeader as i32,
566 err_msg: "The current meta is not leader".to_string(),
567 }),
568 ..Default::default()
569 });
570 let result = check_resp_header(&header, mock_ctx());
571 assert!(result.is_err());
572 assert!(matches!(
573 result.err().unwrap(),
574 error::Error::IsNotLeader { .. }
575 ));
576 }
577
578 fn mock_ctx<'a>() -> Context<'a> {
579 Context { addr: "addr" }
580 }
581}