1use std::fmt::{Debug, Formatter};
16use std::sync::Arc;
17use std::time::Duration;
18
19use common_grpc::channel_manager::{ChannelConfig, ChannelManager};
20use common_meta::node_manager::{DatanodeManager, DatanodeRef, FlownodeManager, FlownodeRef};
21use common_meta::peer::Peer;
22use moka::future::{Cache, CacheBuilder};
23
24use crate::Client;
25use crate::flow::FlowRequester;
26use crate::region::RegionRequester;
27
28pub struct NodeClients {
29 query_channel_manager: ChannelManager,
33 control_channel_manager: ChannelManager,
34 clients: Cache<Peer, Client>,
35}
36
37impl Default for NodeClients {
38 fn default() -> Self {
39 Self::new(ChannelConfig::new())
40 }
41}
42
43impl Debug for NodeClients {
44 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
45 f.debug_struct("NodeClients")
46 .field("query_channel_manager", &self.query_channel_manager)
47 .field("control_channel_manager", &self.control_channel_manager)
48 .finish()
49 }
50}
51
52#[async_trait::async_trait]
53impl DatanodeManager for NodeClients {
54 async fn datanode(&self, datanode: &Peer) -> DatanodeRef {
55 let client = self.get_client(datanode).await;
56
57 let ChannelConfig {
58 send_compression,
59 accept_compression,
60 ..
61 } = self.control_channel_manager.config();
62 Arc::new(RegionRequester::new(
63 client,
64 *send_compression,
65 *accept_compression,
66 ))
67 }
68}
69
70#[async_trait::async_trait]
71impl FlownodeManager for NodeClients {
72 async fn flownode(&self, flownode: &Peer) -> FlownodeRef {
73 let client = self.get_client(flownode).await;
74
75 Arc::new(FlowRequester::new(client))
76 }
77}
78
79impl NodeClients {
80 pub fn new(config: ChannelConfig) -> Self {
81 Self {
82 query_channel_manager: ChannelManager::with_config(config.clone(), None),
83 control_channel_manager: ChannelManager::with_config(config, None),
84 clients: CacheBuilder::new(1024)
85 .time_to_live(Duration::from_secs(30 * 60))
86 .time_to_idle(Duration::from_secs(5 * 60))
87 .build(),
88 }
89 }
90
91 pub async fn get_client(&self, datanode: &Peer) -> Client {
92 self.clients
93 .get_with_by_ref(datanode, async move {
94 Client::with_managers_and_urls(
95 self.query_channel_manager.clone(),
96 self.control_channel_manager.clone(),
97 vec![datanode.addr.clone()],
98 )
99 })
100 .await
101 }
102
103 #[cfg(feature = "testing")]
104 pub async fn insert_client(&self, datanode: Peer, client: Client) {
105 self.clients.insert(datanode, client).await
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use common_grpc::channel_manager::ChannelManager;
112 use common_meta::peer::Peer;
113
114 use super::{ChannelConfig, NodeClients};
115 use crate::Client;
116
117 const PEER_ADDR: &str = "127.0.0.1:3001";
118
119 fn assert_pool_has_one_address(manager: &ChannelManager) {
120 let mut count = 0;
121 let mut addresses = Vec::new();
122 manager.retain_channel(|addr, _| {
123 count += 1;
124 addresses.push(addr.clone());
125 true
126 });
127 assert_eq!(1, count);
128 assert_eq!([PEER_ADDR], addresses.as_slice());
129 }
130
131 #[tokio::test]
132 async fn test_node_clients_use_isolated_reused_channel_pools() {
133 let node_clients = NodeClients::new(ChannelConfig::default());
134 let peer = Peer {
135 id: 1,
136 addr: PEER_ADDR.to_string(),
137 };
138 let client = node_clients.get_client(&peer).await;
139
140 client.make_flight_client(false, false).unwrap();
141 client.make_flight_client(false, false).unwrap();
142 assert_pool_has_one_address(&node_clients.query_channel_manager);
143 let mut control_count = 0;
144 node_clients.control_channel_manager.retain_channel(|_, _| {
145 control_count += 1;
146 true
147 });
148 assert_eq!(0, control_count);
149
150 client.make_control_flight_client(false, false).unwrap();
151 client.make_control_flight_client(false, false).unwrap();
152 assert_pool_has_one_address(&node_clients.query_channel_manager);
153 assert_pool_has_one_address(&node_clients.control_channel_manager);
154
155 let manager = ChannelManager::new();
156 let legacy = Client::with_manager_and_urls(manager.clone(), [PEER_ADDR]);
157 legacy.make_flight_client(false, false).unwrap();
158 legacy.make_control_flight_client(false, false).unwrap();
159 assert_pool_has_one_address(&manager);
160 }
161}