meta_srv/handler/
utils.rs1use std::future::Future;
16use std::sync::Arc;
17
18use api::v1::meta::{Peer, Role};
19use common_meta::instruction::CacheIdent;
20use common_meta::key::MetadataValue;
21use common_meta::key::node_address::NodeAddressValue;
22use common_meta::rpc::store::PutRequest;
23use common_telemetry::{error, info};
24use dashmap::DashMap;
25use snafu::ResultExt;
26use tokio::sync::Mutex;
27
28use crate::Result;
29use crate::error::{InvalidNodeInfoFormatSnafu, KvBackendSnafu};
30use crate::metasrv::Context;
31
32#[derive(Debug, Default)]
35pub(crate) struct NodeAddressUpdater {
36 states: DashMap<(Role, u64), Arc<Mutex<NodeAddressEpochs>>>,
37}
38
39#[derive(Debug, Default)]
40struct NodeAddressEpochs {
41 seen_epoch: Option<u64>,
43 saved_epoch: Option<u64>,
45}
46
47impl NodeAddressUpdater {
48 pub(crate) async fn update_if_needed<F, Fut>(
52 &self,
53 node: (Role, u64),
54 epoch: u64,
55 save: F,
56 ) -> Result<bool>
57 where
58 F: FnOnce() -> Fut,
59 Fut: Future<Output = Result<()>>,
60 {
61 let state = {
64 let entry = self.states.entry(node).or_default();
65 Arc::clone(entry.value())
66 };
67 let mut state = state.lock().await;
68 if state.seen_epoch.is_some_and(|seen| epoch < seen) || state.saved_epoch == Some(epoch) {
69 return Ok(false);
70 }
71
72 state.seen_epoch = Some(epoch);
75 save().await?;
76 state.saved_epoch = Some(epoch);
77 Ok(true)
78 }
79}
80
81pub(crate) async fn save_node_address(ctx: &Context, key: Vec<u8>, peer: Peer) -> Result<()> {
83 let address = NodeAddressValue::new(peer);
84 let value = address
85 .try_as_raw_value()
86 .context(InvalidNodeInfoFormatSnafu)?;
87 ctx.leader_cached_kv_backend
88 .put(PutRequest {
89 key,
90 value,
91 prev_kv: false,
92 })
93 .await
94 .context(KvBackendSnafu)?;
95 info!("Successfully updated node address: {:?}", address.peer);
96 Ok(())
97}
98
99pub(crate) async fn invalidate_address_caches(
102 ctx: &Context,
103 node_id: u64,
104 cache_idents: &[CacheIdent],
105) {
106 if let Err(e) = ctx
107 .cache_invalidator
108 .invalidate(&Default::default(), cache_idents)
109 .await
110 {
111 error!(e; "Failed to invalidate address caches for node {}: {:?}", node_id, cache_idents);
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use std::time::Duration;
118
119 use tokio::sync::Notify;
120 use tokio::time::timeout;
121
122 use super::*;
123
124 #[tokio::test]
125 async fn test_failed_save_retries_same_epoch_and_rejects_stale_heartbeats() {
126 let updater = NodeAddressUpdater::default();
127 let key = (Role::Datanode, 1);
128 assert!(
129 updater
130 .update_if_needed(key, 2, || async {
131 crate::error::UnexpectedSnafu {
132 violated: "injected save failure",
133 }
134 .fail()
135 })
136 .await
137 .is_err()
138 );
139 assert!(
140 !updater
141 .update_if_needed(key, 1, || async {
142 panic!("stale heartbeat must not save");
143 })
144 .await
145 .unwrap()
146 );
147 assert!(
148 updater
149 .update_if_needed(key, 2, || async { Ok(()) })
150 .await
151 .unwrap()
152 );
153 assert!(
154 !updater
155 .update_if_needed(key, 2, || async {
156 panic!("successful epoch must not save again");
157 })
158 .await
159 .unwrap()
160 );
161 assert!(
162 updater
163 .update_if_needed(key, 3, || async { Ok(()) })
164 .await
165 .unwrap()
166 );
167 }
168
169 #[tokio::test]
170 async fn test_cancelled_save_can_be_retried() {
171 let updater = NodeAddressUpdater::default();
172 let key = (Role::Datanode, 1);
173 let entered = Notify::new();
174 {
175 let first = updater.update_if_needed(key, 0, || async {
176 entered.notify_one();
177 std::future::pending::<Result<()>>().await
178 });
179 tokio::pin!(first);
180 tokio::select! {
181 _ = entered.notified() => {},
182 _ = &mut first => panic!("save must remain pending"),
183 }
184 }
185 assert!(
186 timeout(
187 Duration::from_secs(2),
188 updater.update_if_needed(key, 0, || async { Ok(()) })
189 )
190 .await
191 .unwrap()
192 .unwrap()
193 );
194 }
195
196 #[test]
197 fn test_same_node_serialized_other_nodes_progress() {
198 let (progress_tx, progress_rx) = std::sync::mpsc::sync_channel(1);
201 let release = Arc::new(Notify::new());
202 let finish = Arc::new(Notify::new());
203 let worker = std::thread::spawn({
204 let release = release.clone();
205 let finish = finish.clone();
206 move || {
207 tokio::runtime::Builder::new_current_thread()
208 .enable_time()
209 .build()
210 .unwrap()
211 .block_on(async move {
212 let updater = Arc::new(NodeAddressUpdater::default());
213 let entered = Arc::new(Notify::new());
214
215 let first = tokio::spawn({
216 let updater = updater.clone();
217 let entered = entered.clone();
218 let release = release.clone();
219 async move {
220 updater
221 .update_if_needed((Role::Datanode, 1), 1, || async {
222 entered.notify_one();
223 release.notified().await;
224 Ok(())
225 })
226 .await
227 }
228 });
229 entered.notified().await;
230 let second = tokio::spawn({
231 let updater = updater.clone();
232 async move {
233 updater
234 .update_if_needed((Role::Datanode, 1), 2, || async { Ok(()) })
235 .await
236 }
237 });
238 tokio::task::yield_now().await;
239 assert!(!second.is_finished());
240 timeout(Duration::from_secs(2), async {
243 for id in 0_u64..128 {
244 assert!(
245 updater
246 .update_if_needed((Role::Datanode, id + 2), 1, || async {
247 Ok(())
248 })
249 .await
250 .unwrap()
251 );
252 }
253 })
254 .await
255 .unwrap();
256 progress_tx.send(()).unwrap();
257 finish.notified().await;
258 timeout(Duration::from_secs(2), async {
259 assert!(first.await.unwrap().unwrap());
260 assert!(second.await.unwrap().unwrap());
261 })
262 .await
263 .unwrap();
264 assert!(
265 !updater
266 .update_if_needed((Role::Datanode, 1), 1, || async {
267 panic!("old epoch must not overwrite a newer one");
268 })
269 .await
270 .unwrap()
271 );
272 });
273 }
274 });
275 let progress = progress_rx.recv_timeout(Duration::from_secs(5));
276 release.notify_one();
277 finish.notify_one();
278 progress.expect("other node updates must progress while one node save is blocked");
279 worker.join().unwrap();
280 }
281}