1use std::sync::Arc;
16use std::sync::atomic::{AtomicBool, Ordering};
17use std::time::Duration;
18
19use common_telemetry::{error, info, warn};
20use common_time::Timestamp;
21use snafu::{OptionExt, ResultExt, ensure};
22use sqlx::mysql::{MySqlArguments, MySqlRow};
23use sqlx::pool::PoolConnection;
24use sqlx::query::Query;
25use sqlx::{AssertSqlSafe, MySql, MySqlPool, MySqlTransaction, Row};
26use tokio::sync::{Mutex, MutexGuard, broadcast};
27use tokio::time::MissedTickBehavior;
28
29use crate::election::rds::{LEASE_SEP, Lease, RdsLeaderKey, parse_value_and_expire_time};
30use crate::election::{
31 Election, ElectionRef, LeaderChangeMessage, LeaderValue, MetasrvNodeInfo, listen_leader_change,
32 send_leader_change_and_set_flags,
33};
34use crate::error::{
35 AcquireMySqlClientSnafu, DecodeSqlValueSnafu, DeserializeFromJsonSnafu,
36 ElectionLeaderLeaseChangedSnafu, ElectionLeaderLeaseExpiredSnafu, ElectionNoLeaderSnafu,
37 MySqlExecutionSnafu, Result, SerializeToJsonSnafu, SqlExecutionTimeoutSnafu, UnexpectedSnafu,
38};
39use crate::key::{CANDIDATES_ROOT, ELECTION_KEY};
40
41fn template_query(sql: &str) -> Query<'_, MySql, MySqlArguments> {
49 sqlx::query(AssertSqlSafe(sql))
50}
51
52struct ElectionSqlFactory<'a> {
53 table_name: &'a str,
54}
55
56struct ElectionSqlSet {
57 campaign: String,
58 put_value_with_lease: String,
68 update_value_with_lease: String,
76 get_value_with_lease: String,
81 get_value_with_lease_by_prefix: String,
90 delete_value: String,
98}
99
100impl<'a> ElectionSqlFactory<'a> {
101 fn new(table_name: &'a str) -> Self {
102 Self { table_name }
103 }
104
105 fn build(self) -> ElectionSqlSet {
106 ElectionSqlSet {
107 campaign: self.campaign_sql(),
108 put_value_with_lease: self.put_value_with_lease_sql(),
109 update_value_with_lease: self.update_value_with_lease_sql(),
110 get_value_with_lease: self.get_value_with_lease_sql(),
111 get_value_with_lease_by_prefix: self.get_value_with_lease_by_prefix_sql(),
112 delete_value: self.delete_value_sql(),
113 }
114 }
115
116 fn campaign_sql(&self) -> String {
119 format!("SELECT * FROM `{}` FOR UPDATE;", self.table_name)
120 }
121
122 fn put_value_with_lease_sql(&self) -> String {
123 format!(
124 r#"
125 INSERT INTO `{}` (k, v) VALUES (
126 ?,
127 CONCAT(
128 ?,
129 '{}',
130 DATE_FORMAT(DATE_ADD(NOW(4), INTERVAL ? SECOND), '%Y-%m-%d %T.%f')
131 )
132 )
133 ON DUPLICATE KEY UPDATE v = VALUES(v);
134 "#,
135 self.table_name, LEASE_SEP
136 )
137 }
138
139 fn update_value_with_lease_sql(&self) -> String {
140 format!(
141 r#"UPDATE `{}`
142 SET v = CONCAT(?, '{}', DATE_FORMAT(DATE_ADD(NOW(4), INTERVAL ? SECOND), '%Y-%m-%d %T.%f'))
143 WHERE k = ? AND v = ?"#,
144 self.table_name, LEASE_SEP
145 )
146 }
147
148 fn get_value_with_lease_sql(&self) -> String {
149 format!(
150 r#"SELECT v, DATE_FORMAT(NOW(4), '%Y-%m-%d %T.%f') FROM `{}` WHERE k = ?"#,
151 self.table_name
152 )
153 }
154
155 fn get_value_with_lease_by_prefix_sql(&self) -> String {
156 format!(
157 r#"SELECT v, DATE_FORMAT(NOW(4), '%Y-%m-%d %T.%f') FROM `{}` WHERE k LIKE ?"#,
158 self.table_name
159 )
160 }
161
162 fn delete_value_sql(&self) -> String {
163 format!("DELETE FROM `{}` WHERE k = ?;", self.table_name)
164 }
165}
166
167enum Executor<'a> {
168 Default(MutexGuard<'a, ElectionMysqlClient>),
169 Txn(TransactionWithExecutionTimeout<'a>),
170}
171
172impl Executor<'_> {
173 async fn query(
174 &mut self,
175 query: Query<'_, MySql, MySqlArguments>,
176 sql: &str,
177 ) -> Result<Vec<MySqlRow>> {
178 match self {
179 Executor::Default(client) => client.query(query, sql).await,
180 Executor::Txn(txn) => txn.query(query, sql).await,
181 }
182 }
183
184 async fn execute(&mut self, query: Query<'_, MySql, MySqlArguments>, sql: &str) -> Result<u64> {
185 match self {
186 Executor::Default(client) => client.execute(query, sql).await,
187 Executor::Txn(txn) => txn.execute(query, sql).await,
188 }
189 }
190
191 async fn commit(self) -> Result<()> {
192 match self {
193 Executor::Txn(txn) => txn.commit().await,
194 _ => Ok(()),
195 }
196 }
197}
198
199pub struct ElectionMysqlClient {
201 current: Option<PoolConnection<MySql>>,
202 pool: MySqlPool,
203
204 execution_timeout: Duration,
209
210 max_execution_time: Duration,
215
216 innode_lock_wait_timeout: Duration,
221
222 wait_timeout: Duration,
228
229 table_for_election: String,
231}
232
233impl ElectionMysqlClient {
234 pub fn new(
235 pool: MySqlPool,
236 execution_timeout: Duration,
237 max_execution_time: Duration,
238 innode_lock_wait_timeout: Duration,
239 wait_timeout: Duration,
240 table_for_election: &str,
241 ) -> Self {
242 Self {
243 current: None,
244 pool,
245 execution_timeout,
246 max_execution_time,
247 innode_lock_wait_timeout,
248 wait_timeout,
249 table_for_election: table_for_election.to_string(),
250 }
251 }
252
253 fn create_table_sql(&self) -> String {
254 format!(
255 r#"
256 CREATE TABLE IF NOT EXISTS `{}` (
257 k VARBINARY(3072) PRIMARY KEY,
258 v BLOB
259 );"#,
260 self.table_for_election
261 )
262 }
263
264 fn insert_once_sql(&self) -> String {
265 format!(
266 "INSERT IGNORE INTO `{}` (k, v) VALUES ('__place_holder_for_lock', '');",
267 self.table_for_election
268 )
269 }
270
271 fn check_version_sql(&self) -> String {
272 "SELECT @@version;".to_string()
273 }
274
275 async fn reset_client(&mut self) -> Result<()> {
276 self.current = None;
277 self.maybe_init_client().await
278 }
279
280 async fn ensure_table_exists(&mut self) -> Result<()> {
281 let create_table_sql = self.create_table_sql();
282 let query = template_query(&create_table_sql);
283 self.execute(query, &create_table_sql).await?;
284 let insert_once_sql = self.insert_once_sql();
286 let query = template_query(&insert_once_sql);
287 self.execute(query, &insert_once_sql).await?;
288 Ok(())
289 }
290
291 async fn maybe_init_client(&mut self) -> Result<()> {
292 if self.current.is_none() {
293 let client = self.pool.acquire().await.context(AcquireMySqlClientSnafu)?;
294
295 self.current = Some(client);
296 let (query, sql) = if !self.wait_timeout.is_zero() {
297 let sql = "SET SESSION wait_timeout = ?, innodb_lock_wait_timeout = ?, max_execution_time = ?;";
298 (
299 sqlx::query(sql)
300 .bind(self.wait_timeout.as_secs())
301 .bind(self.innode_lock_wait_timeout.as_secs())
302 .bind(self.max_execution_time.as_millis() as u64),
303 sql,
304 )
305 } else {
306 let sql = "SET SESSION innodb_lock_wait_timeout = ?, max_execution_time = ?;";
307 (
308 sqlx::query(sql)
309 .bind(self.innode_lock_wait_timeout.as_secs())
310 .bind(self.max_execution_time.as_millis() as u64),
311 sql,
312 )
313 };
314 self.set_session_isolation_level().await?;
315 self.execute(query, sql).await?;
316 self.check_version(&self.check_version_sql()).await?;
317 }
318 Ok(())
319 }
320
321 async fn set_session_isolation_level(&mut self) -> Result<()> {
326 let sql = "SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE";
327 let query = sqlx::query(sql);
328 self.execute(query, sql).await?;
329 Ok(())
330 }
331
332 async fn check_version(&mut self, sql: &str) -> Result<()> {
337 let query = template_query(sql);
339 let client = self.current.as_mut().unwrap();
341 let row = tokio::time::timeout(self.execution_timeout, query.fetch_one(&mut **client))
342 .await
343 .map_err(|_| {
344 SqlExecutionTimeoutSnafu {
345 sql,
346 duration: self.execution_timeout,
347 }
348 .build()
349 })?;
350 match row {
351 Ok(row) => {
352 let version: String = row.try_get(0).context(DecodeSqlValueSnafu {})?;
353 if !version.starts_with("8.0") && !version.starts_with("5.7") {
354 warn!(
355 "Unsupported MySQL version: {}, expected: [5.7, 8.0]",
356 version
357 );
358 }
359 }
360 Err(e) => {
361 warn!(e; "Failed to check MySQL version through sql: {}", sql);
362 }
363 }
364 Ok(())
365 }
366
367 async fn execute(&mut self, query: Query<'_, MySql, MySqlArguments>, sql: &str) -> Result<u64> {
372 let client = self.current.as_mut().unwrap();
374 let future = query.execute(&mut **client);
375 let rows_affected = tokio::time::timeout(self.execution_timeout, future)
376 .await
377 .map_err(|_| {
378 SqlExecutionTimeoutSnafu {
379 sql,
380 duration: self.execution_timeout,
381 }
382 .build()
383 })?
384 .context(MySqlExecutionSnafu { sql })?
385 .rows_affected();
386 Ok(rows_affected)
387 }
388
389 async fn query(
394 &mut self,
395 query: Query<'_, MySql, MySqlArguments>,
396 sql: &str,
397 ) -> Result<Vec<MySqlRow>> {
398 let client = self.current.as_mut().unwrap();
400 let future = query.fetch_all(&mut **client);
401 tokio::time::timeout(self.execution_timeout, future)
402 .await
403 .map_err(|_| {
404 SqlExecutionTimeoutSnafu {
405 sql,
406 duration: self.execution_timeout,
407 }
408 .build()
409 })?
410 .context(MySqlExecutionSnafu { sql })
411 }
412
413 async fn transaction(&mut self) -> Result<TransactionWithExecutionTimeout<'_>> {
414 use sqlx::Acquire;
415 let client = self.current.as_mut().unwrap();
416 let transaction = client
417 .begin()
418 .await
419 .context(MySqlExecutionSnafu { sql: "BEGIN" })?;
420
421 Ok(TransactionWithExecutionTimeout {
422 transaction,
423 execution_timeout: self.execution_timeout,
424 })
425 }
426}
427
428struct TransactionWithExecutionTimeout<'a> {
429 transaction: MySqlTransaction<'a>,
430 execution_timeout: Duration,
431}
432
433impl TransactionWithExecutionTimeout<'_> {
434 async fn query(
435 &mut self,
436 query: Query<'_, MySql, MySqlArguments>,
437 sql: &str,
438 ) -> Result<Vec<MySqlRow>> {
439 let res = tokio::time::timeout(
440 self.execution_timeout,
441 query.fetch_all(&mut *self.transaction),
442 )
443 .await
444 .map_err(|_| {
445 SqlExecutionTimeoutSnafu {
446 sql,
447 duration: self.execution_timeout,
448 }
449 .build()
450 })?
451 .context(MySqlExecutionSnafu { sql })?;
452 Ok(res)
453 }
454
455 async fn execute(&mut self, query: Query<'_, MySql, MySqlArguments>, sql: &str) -> Result<u64> {
456 let res = tokio::time::timeout(
457 self.execution_timeout,
458 query.execute(&mut *self.transaction),
459 )
460 .await
461 .map_err(|_| {
462 SqlExecutionTimeoutSnafu {
463 sql,
464 duration: self.execution_timeout,
465 }
466 .build()
467 })?
468 .context(MySqlExecutionSnafu { sql })?;
469 Ok(res.rows_affected())
470 }
471
472 async fn commit(self) -> Result<()> {
473 tokio::time::timeout(self.execution_timeout, self.transaction.commit())
474 .await
475 .map_err(|_| {
476 SqlExecutionTimeoutSnafu {
477 sql: "COMMIT",
478 duration: self.execution_timeout,
479 }
480 .build()
481 })?
482 .context(MySqlExecutionSnafu { sql: "COMMIT" })?;
483 Ok(())
484 }
485}
486
487pub struct MySqlElection {
489 leader_value: String,
490 client: Mutex<ElectionMysqlClient>,
491 is_leader: AtomicBool,
492 leader_infancy: AtomicBool,
493 leader_watcher: broadcast::Sender<LeaderChangeMessage>,
494 store_key_prefix: String,
495 candidate_lease_ttl: Duration,
496 meta_lease_ttl: Duration,
497 sql_set: ElectionSqlSet,
498}
499
500impl MySqlElection {
501 pub async fn with_mysql_client(
502 leader_value: String,
503 mut client: ElectionMysqlClient,
504 store_key_prefix: String,
505 candidate_lease_ttl: Duration,
506 meta_lease_ttl: Duration,
507 table_name: &str,
508 ) -> Result<ElectionRef> {
509 let sql_factory = ElectionSqlFactory::new(table_name);
510 client.maybe_init_client().await?;
511 client.ensure_table_exists().await?;
512 let tx = listen_leader_change(leader_value.clone());
513 Ok(Arc::new(Self {
514 leader_value,
515 client: Mutex::new(client),
516 is_leader: AtomicBool::new(false),
517 leader_infancy: AtomicBool::new(false),
518 leader_watcher: tx,
519 store_key_prefix,
520 candidate_lease_ttl,
521 meta_lease_ttl,
522 sql_set: sql_factory.build(),
523 }))
524 }
525
526 fn election_key(&self) -> String {
527 format!("{}{}", self.store_key_prefix, ELECTION_KEY)
528 }
529
530 fn candidate_root(&self) -> String {
531 format!("{}{}", self.store_key_prefix, CANDIDATES_ROOT)
532 }
533
534 fn candidate_key(&self) -> String {
535 format!("{}{}", self.candidate_root(), self.leader_value)
536 }
537
538 async fn maybe_init_client(&self) -> Result<()> {
539 let mut client = self.client.lock().await;
540 client.maybe_init_client().await?;
541 Ok(())
542 }
543}
544
545#[async_trait::async_trait]
546impl Election for MySqlElection {
547 type Leader = LeaderValue;
548
549 fn is_leader(&self) -> bool {
550 self.is_leader.load(Ordering::Relaxed)
551 }
552
553 fn in_leader_infancy(&self) -> bool {
554 self.leader_infancy
555 .compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire)
556 .is_ok()
557 }
558
559 async fn register_candidate(&self, node_info: &MetasrvNodeInfo) -> Result<()> {
560 self.maybe_init_client().await?;
561 let key = self.candidate_key();
562 let node_info =
563 serde_json::to_string(node_info).with_context(|_| SerializeToJsonSnafu {
564 input: format!("{node_info:?}"),
565 })?;
566
567 {
568 let client = self.client.lock().await;
569 let mut executor = Executor::Default(client);
570 let res = self
571 .put_value_with_lease(
572 &key,
573 &node_info,
574 self.candidate_lease_ttl.as_secs(),
575 &mut executor,
576 )
577 .await?;
578 if !res {
580 warn!("Candidate already registered, update the lease");
581 self.delete_value(&key, &mut executor).await?;
582 self.put_value_with_lease(
583 &key,
584 &node_info,
585 self.candidate_lease_ttl.as_secs(),
586 &mut executor,
587 )
588 .await?;
589 }
590 }
591
592 let mut keep_alive_interval = tokio::time::interval(self.candidate_lease_ttl / 2);
594 loop {
595 let _ = keep_alive_interval.tick().await;
596 let client = self.client.lock().await;
597 let mut executor = Executor::Default(client);
598 let lease = self
599 .get_value_with_lease(&key, &mut executor)
600 .await?
601 .unwrap_or_default();
602
603 ensure!(
604 lease.expire_time > lease.current,
605 UnexpectedSnafu {
606 err_msg: format!(
607 "Candidate lease expired at {:?} (current time: {:?}), key: {:?}",
608 lease.expire_time,
609 lease.current,
610 String::from_utf8_lossy(&key.into_bytes())
611 ),
612 }
613 );
614
615 self.update_value_with_lease(
616 &key,
617 &lease.origin,
618 &node_info,
619 self.candidate_lease_ttl.as_secs(),
620 &mut executor,
621 )
622 .await?;
623 std::mem::drop(executor);
624 }
625 }
626
627 async fn all_candidates(&self) -> Result<Vec<MetasrvNodeInfo>> {
628 self.maybe_init_client().await?;
629 let key_prefix = self.candidate_root();
630 let client = self.client.lock().await;
631 let mut executor = Executor::Default(client);
632 let (mut candidates, current) = self
633 .get_value_with_lease_by_prefix(&key_prefix, &mut executor)
634 .await?;
635 candidates.retain(|c| c.1 > current);
637 let mut valid_candidates = Vec::with_capacity(candidates.len());
638 for (c, _) in candidates {
639 let node_info: MetasrvNodeInfo =
640 serde_json::from_str(&c).with_context(|_| DeserializeFromJsonSnafu {
641 input: format!("{:?}", c),
642 })?;
643 valid_candidates.push(node_info);
644 }
645 Ok(valid_candidates)
646 }
647
648 async fn campaign(&self) -> Result<()> {
649 self.maybe_init_client().await?;
650 let mut keep_alive_interval = tokio::time::interval(self.meta_lease_ttl / 2);
651 keep_alive_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
652 loop {
653 self.do_campaign().await?;
654 keep_alive_interval.tick().await;
655 }
656 }
657
658 async fn reset_campaign(&self) {
659 info!("Resetting campaign");
660 if self.is_leader.load(Ordering::Relaxed) {
661 if let Err(err) = self.step_down_without_lock().await {
662 error!(err; "Failed to step down without lock");
663 }
664 info!("Step down without lock successfully, due to reset campaign");
665 }
666 if let Err(err) = self.client.lock().await.reset_client().await {
667 error!(err; "Failed to reset client");
668 }
669 }
670
671 async fn leader(&self) -> Result<Self::Leader> {
672 self.maybe_init_client().await?;
673 if self.is_leader.load(Ordering::Relaxed) {
674 Ok(self.leader_value.as_bytes().into())
675 } else {
676 let key = self.election_key();
677
678 let client = self.client.lock().await;
679 let mut executor = Executor::Default(client);
680 if let Some(lease) = self.get_value_with_lease(&key, &mut executor).await? {
681 ensure!(lease.expire_time > lease.current, ElectionNoLeaderSnafu);
682 Ok(lease.leader_value.as_bytes().into())
683 } else {
684 ElectionNoLeaderSnafu.fail()
685 }
686 }
687 }
688
689 async fn resign(&self) -> Result<()> {
690 todo!()
691 }
692
693 fn subscribe_leader_change(&self) -> broadcast::Receiver<LeaderChangeMessage> {
694 self.leader_watcher.subscribe()
695 }
696}
697
698impl MySqlElection {
699 async fn get_value_with_lease(
701 &self,
702 key: &str,
703 executor: &mut Executor<'_>,
704 ) -> Result<Option<Lease>> {
705 let key = key.as_bytes();
706 let query = template_query(&self.sql_set.get_value_with_lease).bind(key);
707 let res = executor
708 .query(query, &self.sql_set.get_value_with_lease)
709 .await?;
710
711 if res.is_empty() {
712 return Ok(None);
713 }
714 let current_time_str = String::from_utf8_lossy(res[0].try_get(1).unwrap());
716 let current_time = match Timestamp::from_str(¤t_time_str, None) {
717 Ok(ts) => ts,
718 Err(_) => UnexpectedSnafu {
719 err_msg: format!("Invalid timestamp: {}", current_time_str),
720 }
721 .fail()?,
722 };
723 let value_and_expire_time = String::from_utf8_lossy(res[0].try_get(0).unwrap_or_default());
725 let (value, expire_time) = parse_value_and_expire_time(&value_and_expire_time)?;
726
727 Ok(Some(Lease {
728 leader_value: value,
729 expire_time,
730 current: current_time,
731 origin: value_and_expire_time.to_string(),
732 }))
733 }
734
735 async fn get_value_with_lease_by_prefix(
737 &self,
738 key_prefix: &str,
739 executor: &mut Executor<'_>,
740 ) -> Result<(Vec<(String, Timestamp)>, Timestamp)> {
741 let key_prefix = format!("{}%", key_prefix).as_bytes().to_vec();
742 let query = template_query(&self.sql_set.get_value_with_lease_by_prefix).bind(key_prefix);
743 let res = executor
744 .query(query, &self.sql_set.get_value_with_lease_by_prefix)
745 .await?;
746
747 let mut values_with_leases = vec![];
748 let mut current = Timestamp::default();
749 for row in res {
750 let current_time_str = row.try_get(1).unwrap_or_default();
751 current = match Timestamp::from_str(current_time_str, None) {
752 Ok(ts) => ts,
753 Err(_) => UnexpectedSnafu {
754 err_msg: format!("Invalid timestamp: {}", current_time_str),
755 }
756 .fail()?,
757 };
758
759 let value_and_expire_time = String::from_utf8_lossy(row.try_get(0).unwrap_or_default());
760 let (value, expire_time) = parse_value_and_expire_time(&value_and_expire_time)?;
761
762 values_with_leases.push((value, expire_time));
763 }
764 Ok((values_with_leases, current))
765 }
766
767 async fn update_value_with_lease(
768 &self,
769 key: &str,
770 prev: &str,
771 updated: &str,
772 lease_ttl: u64,
773 executor: &mut Executor<'_>,
774 ) -> Result<()> {
775 let key = key.as_bytes();
776 let prev = prev.as_bytes();
777 let updated = updated.as_bytes();
778
779 let query = template_query(&self.sql_set.update_value_with_lease)
780 .bind(updated)
781 .bind(lease_ttl as f64)
782 .bind(key)
783 .bind(prev);
784 let res = executor
785 .execute(query, &self.sql_set.update_value_with_lease)
786 .await?;
787
788 ensure!(
789 res == 1,
790 UnexpectedSnafu {
791 err_msg: format!("Failed to update key: {}", String::from_utf8_lossy(key)),
792 }
793 );
794
795 Ok(())
796 }
797
798 async fn put_value_with_lease(
800 &self,
801 key: &str,
802 value: &str,
803 lease_ttl_secs: u64,
804 executor: &mut Executor<'_>,
805 ) -> Result<bool> {
806 let key = key.as_bytes();
807 let lease_ttl_secs = lease_ttl_secs as f64;
808 let query = template_query(&self.sql_set.put_value_with_lease)
809 .bind(key)
810 .bind(value)
811 .bind(lease_ttl_secs);
812 let res = executor
813 .execute(query, &self.sql_set.put_value_with_lease)
814 .await?;
815 Ok(res == 1)
816 }
817
818 async fn delete_value(&self, key: &str, executor: &mut Executor<'_>) -> Result<bool> {
821 let key = key.as_bytes();
822 let query = template_query(&self.sql_set.delete_value).bind(key);
823 let res = executor.execute(query, &self.sql_set.delete_value).await?;
824
825 Ok(res == 1)
826 }
827
828 async fn do_campaign(&self) -> Result<()> {
831 let lease = {
832 let client = self.client.lock().await;
833 let mut executor = Executor::Default(client);
834 self.get_value_with_lease(&self.election_key(), &mut executor)
835 .await?
836 };
837
838 let is_leader = self.is_leader();
839 let is_current_leader = lease
842 .as_ref()
843 .map(|lease| lease.leader_value == self.leader_value)
844 .unwrap_or(false);
845 match (self.lease_check(&lease), is_leader, is_current_leader) {
846 (Ok(_), true, true) => {
848 let mut client = self.client.lock().await;
849 let txn = client.transaction().await?;
850 let mut executor = Executor::Txn(txn);
851 let query = template_query(&self.sql_set.campaign);
852 executor.query(query, &self.sql_set.campaign).await?;
853 self.renew_lease(executor, lease.unwrap()).await?;
855 }
856 (Err(err), true, _) => {
859 warn!(err; "Leader lease expired, step down...");
860 self.step_down_without_lock().await?;
861 }
862 (Ok(_), true, false) => {
863 warn!("Leader lease expired, step down...");
864 self.step_down_without_lock().await?;
865 }
866 (Err(err), false, _) => {
868 warn!(err; "Leader lease expired, elect myself.");
869 let mut client = self.client.lock().await;
870 let txn = client.transaction().await?;
871 let mut executor = Executor::Txn(txn);
872 let query = template_query(&self.sql_set.campaign);
873 executor.query(query, &self.sql_set.campaign).await?;
874 self.elected(executor, lease).await?;
875 }
876 (Ok(_), false, true) => {
879 warn!("I should be the leader, but I don't think so. Something went wrong.");
880 let mut client = self.client.lock().await;
881 let txn = client.transaction().await?;
882 let mut executor = Executor::Txn(txn);
883 let query = template_query(&self.sql_set.campaign);
884 executor.query(query, &self.sql_set.campaign).await?;
885 self.renew_lease(executor, lease.unwrap()).await?;
887 }
888 (Ok(_), false, false) => {}
890 }
891 Ok(())
892 }
893
894 async fn renew_lease(&self, mut executor: Executor<'_>, lease: Lease) -> Result<()> {
896 let key = self.election_key();
897 self.update_value_with_lease(
898 &key,
899 &lease.origin,
900 &self.leader_value,
901 self.meta_lease_ttl.as_secs(),
902 &mut executor,
903 )
904 .await?;
905 executor.commit().await?;
906
907 if !self.is_leader() {
908 let key = self.election_key();
909 let leader_key = RdsLeaderKey {
910 name: self.leader_value.clone().into_bytes(),
911 key: key.clone().into_bytes(),
912 ..Default::default()
913 };
914 send_leader_change_and_set_flags(
915 &self.is_leader,
916 &self.leader_infancy,
917 &self.leader_watcher,
918 LeaderChangeMessage::Elected(Arc::new(leader_key)),
919 );
920 }
921
922 Ok(())
923 }
924
925 fn lease_check(&self, lease: &Option<Lease>) -> Result<Lease> {
934 let lease = lease.as_ref().context(ElectionNoLeaderSnafu)?;
935 ensure!(
937 lease.expire_time > lease.current,
938 ElectionLeaderLeaseExpiredSnafu
939 );
940 Ok(lease.clone())
942 }
943
944 async fn step_down_without_lock(&self) -> Result<()> {
946 let key = self.election_key().into_bytes();
947 let leader_key = RdsLeaderKey {
948 name: self.leader_value.clone().into_bytes(),
949 key: key.clone(),
950 ..Default::default()
951 };
952 send_leader_change_and_set_flags(
953 &self.is_leader,
954 &self.leader_infancy,
955 &self.leader_watcher,
956 LeaderChangeMessage::StepDown(Arc::new(leader_key)),
957 );
958 Ok(())
959 }
960
961 async fn elected(
964 &self,
965 mut executor: Executor<'_>,
966 expected_lease: Option<Lease>,
967 ) -> Result<()> {
968 let key = self.election_key();
969 let leader_key = RdsLeaderKey {
970 name: self.leader_value.clone().into_bytes(),
971 key: key.clone().into_bytes(),
972 ..Default::default()
973 };
974 let remote_lease = self.get_value_with_lease(&key, &mut executor).await?;
975 ensure!(
976 expected_lease.map(|lease| lease.origin) == remote_lease.map(|lease| lease.origin),
977 ElectionLeaderLeaseChangedSnafu
978 );
979 self.delete_value(&key, &mut executor).await?;
980 self.put_value_with_lease(
981 &key,
982 &self.leader_value,
983 self.meta_lease_ttl.as_secs(),
984 &mut executor,
985 )
986 .await?;
987 executor.commit().await?;
988
989 send_leader_change_and_set_flags(
990 &self.is_leader,
991 &self.leader_infancy,
992 &self.leader_watcher,
993 LeaderChangeMessage::Elected(Arc::new(leader_key)),
994 );
995 Ok(())
996 }
997}
998
999#[cfg(test)]
1000mod tests {
1001 use std::{assert_matches, env};
1002
1003 use common_telemetry::init_default_ut_logging;
1004 use sqlx::MySqlPool;
1005
1006 use super::*;
1007 use crate::{error, maybe_skip_mysql_integration_test};
1008
1009 async fn create_mysql_client(
1010 table_name: Option<&str>,
1011 execution_timeout: Duration,
1012 wait_timeout: Duration,
1013 ) -> Result<Mutex<ElectionMysqlClient>> {
1014 init_default_ut_logging();
1015 let endpoint = env::var("GT_MYSQL_ENDPOINTS").unwrap_or_default();
1016 if endpoint.is_empty() {
1017 return UnexpectedSnafu {
1018 err_msg: "MySQL endpoint is empty".to_string(),
1019 }
1020 .fail();
1021 }
1022 let pool = MySqlPool::connect(&endpoint).await.unwrap();
1023 let mut client = ElectionMysqlClient::new(
1024 pool,
1025 execution_timeout,
1026 execution_timeout,
1027 Duration::from_secs(1),
1028 wait_timeout,
1029 table_name.unwrap_or("default_greptime_metakv-election"),
1030 );
1031 client.maybe_init_client().await?;
1032 if table_name.is_some() {
1033 client.ensure_table_exists().await?;
1034 }
1035 Ok(Mutex::new(client))
1036 }
1037
1038 async fn drop_table(client: &Mutex<ElectionMysqlClient>, table_name: &str) {
1039 let mut client = client.lock().await;
1040 let sql = format!("DROP TABLE IF EXISTS `{}`;", table_name);
1041 client.execute(template_query(&sql), &sql).await.unwrap();
1042 }
1043
1044 #[tokio::test]
1045 async fn test_mysql_crud() {
1046 maybe_skip_mysql_integration_test!();
1047 let key = "test_key".to_string();
1048 let value = "test_value".to_string();
1049
1050 let uuid = uuid::Uuid::new_v4().to_string();
1051 let table_name = "test_mysql_crud_greptime-metakv";
1052 let candidate_lease_ttl = Duration::from_secs(10);
1053 let meta_lease_ttl = Duration::from_secs(2);
1054
1055 let execution_timeout = Duration::from_secs(10);
1056 let idle_session_timeout = Duration::from_secs(0);
1057 let client = create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1058 .await
1059 .unwrap();
1060
1061 {
1062 let mut a = client.lock().await;
1063 let txn = a.transaction().await.unwrap();
1064 let mut executor = Executor::Txn(txn);
1065 let raw_query = format!("SELECT * FROM `{}` FOR UPDATE;", table_name);
1066 let query = template_query(&raw_query);
1067 let _ = executor.query(query, &raw_query).await.unwrap();
1068 }
1069
1070 let (tx, _) = broadcast::channel(100);
1071 let mysql_election = MySqlElection {
1072 leader_value: "test_leader".to_string(),
1073 client,
1074 is_leader: AtomicBool::new(false),
1075 leader_infancy: AtomicBool::new(true),
1076 leader_watcher: tx,
1077 store_key_prefix: uuid,
1078 candidate_lease_ttl,
1079 meta_lease_ttl,
1080 sql_set: ElectionSqlFactory::new(table_name).build(),
1081 };
1082 let client = mysql_election.client.lock().await;
1083 let mut executor = Executor::Default(client);
1084 let res = mysql_election
1085 .put_value_with_lease(&key, &value, 10, &mut executor)
1086 .await
1087 .unwrap();
1088 assert!(res);
1089
1090 let lease = mysql_election
1091 .get_value_with_lease(&key, &mut executor)
1092 .await
1093 .unwrap()
1094 .unwrap();
1095 assert_eq!(lease.leader_value, value);
1096
1097 mysql_election
1098 .update_value_with_lease(&key, &lease.origin, &value, 10, &mut executor)
1099 .await
1100 .unwrap();
1101
1102 let res = mysql_election
1103 .delete_value(&key, &mut executor)
1104 .await
1105 .unwrap();
1106 assert!(res);
1107
1108 let res = mysql_election
1109 .get_value_with_lease(&key, &mut executor)
1110 .await
1111 .unwrap();
1112 assert!(res.is_none());
1113
1114 for i in 0..10 {
1115 let key = format!("test_key_{}", i);
1116 let value = format!("test_value_{}", i);
1117 mysql_election
1118 .put_value_with_lease(&key, &value, 10, &mut executor)
1119 .await
1120 .unwrap();
1121 }
1122
1123 let key_prefix = "test_key".to_string();
1124 let (res, _) = mysql_election
1125 .get_value_with_lease_by_prefix(&key_prefix, &mut executor)
1126 .await
1127 .unwrap();
1128 assert_eq!(res.len(), 10);
1129
1130 for i in 0..10 {
1131 let key = format!("test_key_{}", i);
1132 let res = mysql_election
1133 .delete_value(&key, &mut executor)
1134 .await
1135 .unwrap();
1136 assert!(res);
1137 }
1138
1139 let (res, current) = mysql_election
1140 .get_value_with_lease_by_prefix(&key_prefix, &mut executor)
1141 .await
1142 .unwrap();
1143 assert!(res.is_empty());
1144 assert!(current == Timestamp::default());
1145
1146 std::mem::drop(executor);
1148 drop_table(&mysql_election.client, table_name).await;
1149 }
1150
1151 async fn candidate(
1152 leader_value: String,
1153 candidate_lease_ttl: Duration,
1154 store_key_prefix: String,
1155 table_name: String,
1156 ) {
1157 let meta_lease_ttl = Duration::from_secs(2);
1158 let execution_timeout = Duration::from_secs(10);
1159 let idle_session_timeout = Duration::from_secs(0);
1160 let client =
1161 create_mysql_client(Some(&table_name), execution_timeout, idle_session_timeout)
1162 .await
1163 .unwrap();
1164
1165 let (tx, _) = broadcast::channel(100);
1166 let mysql_election = MySqlElection {
1167 leader_value,
1168 client,
1169 is_leader: AtomicBool::new(false),
1170 leader_infancy: AtomicBool::new(true),
1171 leader_watcher: tx,
1172 store_key_prefix,
1173 candidate_lease_ttl,
1174 meta_lease_ttl,
1175 sql_set: ElectionSqlFactory::new(&table_name).build(),
1176 };
1177
1178 let node_info = MetasrvNodeInfo {
1179 addr: "test_addr".to_string(),
1180 version: "test_version".to_string(),
1181 git_commit: "test_git_commit".to_string(),
1182 start_time_ms: 0,
1183 total_cpu_millicores: 0,
1184 total_memory_bytes: 0,
1185 cpu_usage_millicores: 0,
1186 memory_usage_bytes: 0,
1187 hostname: "test_hostname".to_string(),
1188 };
1189 mysql_election.register_candidate(&node_info).await.unwrap();
1190 }
1191
1192 #[tokio::test]
1193 async fn test_candidate_registration() {
1194 maybe_skip_mysql_integration_test!();
1195 let leader_value_prefix = "test_leader".to_string();
1196 let candidate_lease_ttl = Duration::from_secs(2);
1197 let execution_timeout = Duration::from_secs(10);
1198 let meta_lease_ttl = Duration::from_secs(2);
1199 let idle_session_timeout = Duration::from_secs(0);
1200 let uuid = uuid::Uuid::new_v4().to_string();
1201 let table_name = "test_candidate_registration_greptime-metakv";
1202 let mut handles = vec![];
1203 let client = create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1204 .await
1205 .unwrap();
1206
1207 for i in 0..10 {
1208 let leader_value = format!("{}{}", leader_value_prefix, i);
1209 let handle = tokio::spawn(candidate(
1210 leader_value,
1211 candidate_lease_ttl,
1212 uuid.clone(),
1213 table_name.to_string(),
1214 ));
1215 handles.push(handle);
1216 }
1217 tokio::time::sleep(candidate_lease_ttl / 2 + Duration::from_secs(1)).await;
1219
1220 let (tx, _) = broadcast::channel(100);
1221 let leader_value = "test_leader".to_string();
1222 let mysql_election = MySqlElection {
1223 leader_value,
1224 client,
1225 is_leader: AtomicBool::new(false),
1226 leader_infancy: AtomicBool::new(true),
1227 leader_watcher: tx,
1228 store_key_prefix: uuid.clone(),
1229 candidate_lease_ttl,
1230 meta_lease_ttl,
1231 sql_set: ElectionSqlFactory::new(table_name).build(),
1232 };
1233
1234 let candidates = mysql_election.all_candidates().await.unwrap();
1235 assert_eq!(candidates.len(), 10);
1236
1237 for handle in handles {
1238 handle.abort();
1239 }
1240
1241 tokio::time::sleep(candidate_lease_ttl + Duration::from_secs(1)).await;
1243 let candidates = mysql_election.all_candidates().await.unwrap();
1244 assert!(candidates.is_empty());
1245
1246 let client = mysql_election.client.lock().await;
1248 let mut executor = Executor::Default(client);
1249 for i in 0..10 {
1250 let key = format!("{}{}{}{}", uuid, CANDIDATES_ROOT, leader_value_prefix, i);
1251 let res = mysql_election
1252 .delete_value(&key, &mut executor)
1253 .await
1254 .unwrap();
1255 assert!(res);
1256 }
1257
1258 std::mem::drop(executor);
1260 drop_table(&mysql_election.client, table_name).await;
1261 }
1262
1263 async fn elected(
1264 election: &MySqlElection,
1265 table_name: &str,
1266 expected_lease: Option<Lease>,
1267 ) -> Result<()> {
1268 let mut client = election.client.lock().await;
1269 let txn = client.transaction().await.unwrap();
1270 let mut executor = Executor::Txn(txn);
1271 let raw_query = format!("SELECT * FROM `{}` FOR UPDATE;", table_name);
1272 let query = template_query(&raw_query);
1273 let _ = executor.query(query, &raw_query).await.unwrap();
1274 election.elected(executor, expected_lease).await
1275 }
1276
1277 async fn get_lease(election: &MySqlElection) -> Option<Lease> {
1278 let client = election.client.lock().await;
1279 let mut executor = Executor::Default(client);
1280 election
1281 .get_value_with_lease(&election.election_key(), &mut executor)
1282 .await
1283 .unwrap()
1284 }
1285
1286 #[tokio::test]
1287 async fn test_elected_with_incorrect_lease_fails() {
1288 maybe_skip_mysql_integration_test!();
1289 let leader_value = "test_leader".to_string();
1290 let candidate_lease_ttl = Duration::from_secs(5);
1291 let meta_lease_ttl = Duration::from_secs(2);
1292 let execution_timeout = Duration::from_secs(10);
1293 let idle_session_timeout = Duration::from_secs(0);
1294 let uuid = uuid::Uuid::new_v4().to_string();
1295 let table_name = "test_elected_failed_greptime-metakv";
1296 let client = create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1297 .await
1298 .unwrap();
1299
1300 let (tx, _) = broadcast::channel(100);
1301 let leader_mysql_election = MySqlElection {
1302 leader_value: leader_value.clone(),
1303 client,
1304 is_leader: AtomicBool::new(false),
1305 leader_infancy: AtomicBool::new(true),
1306 leader_watcher: tx,
1307 store_key_prefix: uuid,
1308 candidate_lease_ttl,
1309 meta_lease_ttl,
1310 sql_set: ElectionSqlFactory::new(table_name).build(),
1311 };
1312
1313 let incorrect_lease = Lease::default();
1314 let err = elected(&leader_mysql_election, table_name, Some(incorrect_lease))
1315 .await
1316 .unwrap_err();
1317 assert_matches!(err, error::Error::ElectionLeaderLeaseChanged { .. });
1318 let lease = get_lease(&leader_mysql_election).await;
1319 assert!(lease.is_none());
1320 drop_table(&leader_mysql_election.client, table_name).await;
1321 }
1322
1323 #[tokio::test]
1324 async fn test_reelection_with_idle_session_timeout() {
1325 maybe_skip_mysql_integration_test!();
1326 let leader_value = "test_leader".to_string();
1327 let uuid = uuid::Uuid::new_v4().to_string();
1328 let table_name = "test_reelection_greptime-metakv";
1329 let candidate_lease_ttl = Duration::from_secs(5);
1330 let meta_lease_ttl = Duration::from_secs(5);
1331 let execution_timeout = Duration::from_secs(10);
1332 let idle_session_timeout = Duration::from_secs(2);
1333 let client = create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1334 .await
1335 .unwrap();
1336
1337 let (tx, _) = broadcast::channel(100);
1338 let leader_mysql_election = MySqlElection {
1339 leader_value: leader_value.clone(),
1340 client,
1341 is_leader: AtomicBool::new(false),
1342 leader_infancy: AtomicBool::new(true),
1343 leader_watcher: tx,
1344 store_key_prefix: uuid,
1345 candidate_lease_ttl,
1346 meta_lease_ttl,
1347 sql_set: ElectionSqlFactory::new(table_name).build(),
1348 };
1349
1350 elected(&leader_mysql_election, table_name, None)
1351 .await
1352 .unwrap();
1353 let lease = get_lease(&leader_mysql_election).await.unwrap();
1354 assert_eq!(lease.leader_value, leader_value);
1355 assert!(lease.expire_time > lease.current);
1356 assert!(leader_mysql_election.is_leader());
1357 tokio::time::sleep(Duration::from_millis(2100)).await;
1359 leader_mysql_election
1361 .client
1362 .lock()
1363 .await
1364 .query(sqlx::query("SELECT 1"), "SELECT 1")
1365 .await
1366 .unwrap_err();
1367 leader_mysql_election
1369 .client
1370 .lock()
1371 .await
1372 .reset_client()
1373 .await
1374 .unwrap();
1375
1376 elected(&leader_mysql_election, table_name, Some(lease.clone()))
1378 .await
1379 .unwrap();
1380 let lease = get_lease(&leader_mysql_election).await.unwrap();
1381 assert_eq!(lease.leader_value, leader_value);
1382 assert!(lease.expire_time > lease.current);
1383 assert!(leader_mysql_election.is_leader());
1384 drop_table(&leader_mysql_election.client, table_name).await;
1385 }
1386
1387 #[tokio::test]
1388 async fn test_elected_and_step_down() {
1389 maybe_skip_mysql_integration_test!();
1390 let leader_value = "test_leader".to_string();
1391 let candidate_lease_ttl = Duration::from_secs(5);
1392 let meta_lease_ttl = Duration::from_secs(2);
1393 let execution_timeout = Duration::from_secs(10);
1394 let idle_session_timeout = Duration::from_secs(0);
1395 let uuid = uuid::Uuid::new_v4().to_string();
1396 let table_name = "test_elected_and_step_down_greptime-metakv";
1397 let client = create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1398 .await
1399 .unwrap();
1400
1401 let (tx, mut rx) = broadcast::channel(100);
1402 let leader_mysql_election = MySqlElection {
1403 leader_value: leader_value.clone(),
1404 client,
1405 is_leader: AtomicBool::new(false),
1406 leader_infancy: AtomicBool::new(true),
1407 leader_watcher: tx,
1408 store_key_prefix: uuid,
1409 candidate_lease_ttl,
1410 meta_lease_ttl,
1411 sql_set: ElectionSqlFactory::new(table_name).build(),
1412 };
1413
1414 elected(&leader_mysql_election, table_name, None)
1415 .await
1416 .unwrap();
1417 let lease = get_lease(&leader_mysql_election).await.unwrap();
1418 assert_eq!(lease.leader_value, leader_value);
1419 assert!(lease.expire_time > lease.current);
1420 assert!(leader_mysql_election.is_leader());
1421
1422 match rx.recv().await {
1423 Ok(LeaderChangeMessage::Elected(key)) => {
1424 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1425 assert_eq!(
1426 String::from_utf8_lossy(key.key()),
1427 leader_mysql_election.election_key()
1428 );
1429 assert_eq!(key.lease_id(), i64::default());
1430 assert_eq!(key.revision(), i64::default());
1431 }
1432 _ => panic!("Expected LeaderChangeMessage::Elected"),
1433 }
1434
1435 leader_mysql_election
1436 .step_down_without_lock()
1437 .await
1438 .unwrap();
1439 let lease = get_lease(&leader_mysql_election).await.unwrap();
1440 assert_eq!(lease.leader_value, leader_value);
1441 assert!(!leader_mysql_election.is_leader());
1442
1443 match rx.recv().await {
1444 Ok(LeaderChangeMessage::StepDown(key)) => {
1445 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1446 assert_eq!(
1447 String::from_utf8_lossy(key.key()),
1448 leader_mysql_election.election_key()
1449 );
1450 assert_eq!(key.lease_id(), i64::default());
1451 assert_eq!(key.revision(), i64::default());
1452 }
1453 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1454 }
1455
1456 elected(&leader_mysql_election, table_name, Some(lease.clone()))
1457 .await
1458 .unwrap();
1459 let lease = get_lease(&leader_mysql_election).await.unwrap();
1460 assert_eq!(lease.leader_value, leader_value);
1461 assert!(lease.expire_time > lease.current);
1462 assert!(leader_mysql_election.is_leader());
1463
1464 match rx.recv().await {
1465 Ok(LeaderChangeMessage::Elected(key)) => {
1466 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1467 assert_eq!(
1468 String::from_utf8_lossy(key.key()),
1469 leader_mysql_election.election_key()
1470 );
1471 assert_eq!(key.lease_id(), i64::default());
1472 assert_eq!(key.revision(), i64::default());
1473 }
1474 _ => panic!("Expected LeaderChangeMessage::Elected"),
1475 }
1476
1477 drop_table(&leader_mysql_election.client, table_name).await;
1478 }
1479
1480 #[tokio::test]
1481 async fn test_campaign() {
1482 maybe_skip_mysql_integration_test!();
1483 let leader_value = "test_leader".to_string();
1484 let uuid = uuid::Uuid::new_v4().to_string();
1485 let table_name = "test_leader_action_greptime-metakv";
1486 let candidate_lease_ttl = Duration::from_secs(5);
1487 let meta_lease_ttl = Duration::from_secs(2);
1488 let execution_timeout = Duration::from_secs(10);
1489 let idle_session_timeout = Duration::from_secs(0);
1490 let client = create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1491 .await
1492 .unwrap();
1493
1494 let (tx, mut rx) = broadcast::channel(100);
1495 let leader_mysql_election = MySqlElection {
1496 leader_value: leader_value.clone(),
1497 client,
1498 is_leader: AtomicBool::new(false),
1499 leader_infancy: AtomicBool::new(true),
1500 leader_watcher: tx,
1501 store_key_prefix: uuid,
1502 candidate_lease_ttl,
1503 meta_lease_ttl,
1504 sql_set: ElectionSqlFactory::new(table_name).build(),
1505 };
1506
1507 leader_mysql_election.do_campaign().await.unwrap();
1509 let lease = get_lease(&leader_mysql_election).await.unwrap();
1510 assert_eq!(lease.leader_value, leader_value);
1511 assert!(lease.expire_time > lease.current);
1512 assert!(leader_mysql_election.is_leader());
1513
1514 match rx.recv().await {
1515 Ok(LeaderChangeMessage::Elected(key)) => {
1516 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1517 assert_eq!(
1518 String::from_utf8_lossy(key.key()),
1519 leader_mysql_election.election_key()
1520 );
1521 assert_eq!(key.lease_id(), i64::default());
1522 assert_eq!(key.revision(), i64::default());
1523 }
1524 _ => panic!("Expected LeaderChangeMessage::Elected"),
1525 }
1526
1527 leader_mysql_election.do_campaign().await.unwrap();
1529 let new_lease = get_lease(&leader_mysql_election).await.unwrap();
1530 assert_eq!(lease.leader_value, leader_value);
1531 assert!(new_lease.expire_time > lease.expire_time);
1533 assert!(new_lease.expire_time > new_lease.current);
1534 assert!(leader_mysql_election.is_leader());
1535
1536 tokio::time::sleep(meta_lease_ttl + Duration::from_secs(1)).await;
1538 leader_mysql_election.do_campaign().await.unwrap();
1539 let lease = get_lease(&leader_mysql_election).await.unwrap();
1540 assert_eq!(lease.leader_value, leader_value);
1541 assert!(lease.expire_time <= lease.current);
1542 assert!(!leader_mysql_election.is_leader());
1543
1544 match rx.recv().await {
1545 Ok(LeaderChangeMessage::StepDown(key)) => {
1546 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1547 assert_eq!(
1548 String::from_utf8_lossy(key.key()),
1549 leader_mysql_election.election_key()
1550 );
1551 assert_eq!(key.lease_id(), i64::default());
1552 assert_eq!(key.revision(), i64::default());
1553 }
1554 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1555 }
1556
1557 leader_mysql_election.do_campaign().await.unwrap();
1559 let lease = get_lease(&leader_mysql_election).await.unwrap();
1560 assert_eq!(lease.leader_value, leader_value);
1561 assert!(lease.expire_time > lease.current);
1562 assert!(leader_mysql_election.is_leader());
1563
1564 match rx.recv().await {
1565 Ok(LeaderChangeMessage::Elected(key)) => {
1566 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1567 assert_eq!(
1568 String::from_utf8_lossy(key.key()),
1569 leader_mysql_election.election_key()
1570 );
1571 assert_eq!(key.lease_id(), i64::default());
1572 assert_eq!(key.revision(), i64::default());
1573 }
1574 _ => panic!("Expected LeaderChangeMessage::Elected"),
1575 }
1576
1577 {
1579 let client = leader_mysql_election.client.lock().await;
1580 let mut executor = Executor::Default(client);
1581 leader_mysql_election
1582 .delete_value(&leader_mysql_election.election_key(), &mut executor)
1583 .await
1584 .unwrap();
1585 }
1586 leader_mysql_election.do_campaign().await.unwrap();
1587 let res = get_lease(&leader_mysql_election).await;
1588 assert!(res.is_none());
1589 assert!(!leader_mysql_election.is_leader());
1590
1591 match rx.recv().await {
1592 Ok(LeaderChangeMessage::StepDown(key)) => {
1593 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1594 assert_eq!(
1595 String::from_utf8_lossy(key.key()),
1596 leader_mysql_election.election_key()
1597 );
1598 assert_eq!(key.lease_id(), i64::default());
1599 assert_eq!(key.revision(), i64::default());
1600 }
1601 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1602 }
1603
1604 leader_mysql_election.do_campaign().await.unwrap();
1606 let lease = get_lease(&leader_mysql_election).await.unwrap();
1607 assert_eq!(lease.leader_value, leader_value);
1608 assert!(lease.expire_time > lease.current);
1609 assert!(leader_mysql_election.is_leader());
1610
1611 match rx.recv().await {
1612 Ok(LeaderChangeMessage::Elected(key)) => {
1613 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1614 assert_eq!(
1615 String::from_utf8_lossy(key.key()),
1616 leader_mysql_election.election_key()
1617 );
1618 assert_eq!(key.lease_id(), i64::default());
1619 assert_eq!(key.revision(), i64::default());
1620 }
1621 _ => panic!("Expected LeaderChangeMessage::Elected"),
1622 }
1623
1624 let another_leader_key = "another_leader";
1626 {
1627 let client = leader_mysql_election.client.lock().await;
1628 let mut executor = Executor::Default(client);
1629 leader_mysql_election
1630 .delete_value(&leader_mysql_election.election_key(), &mut executor)
1631 .await
1632 .unwrap();
1633 leader_mysql_election
1634 .put_value_with_lease(
1635 &leader_mysql_election.election_key(),
1636 another_leader_key,
1637 10,
1638 &mut executor,
1639 )
1640 .await
1641 .unwrap();
1642 }
1643 leader_mysql_election.do_campaign().await.unwrap();
1644 let lease = get_lease(&leader_mysql_election).await.unwrap();
1645 assert_eq!(lease.leader_value, another_leader_key);
1647 assert!(lease.expire_time > lease.current);
1648 assert!(!leader_mysql_election.is_leader());
1649
1650 match rx.recv().await {
1651 Ok(LeaderChangeMessage::StepDown(key)) => {
1652 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1653 assert_eq!(
1654 String::from_utf8_lossy(key.key()),
1655 leader_mysql_election.election_key()
1656 );
1657 assert_eq!(key.lease_id(), i64::default());
1658 assert_eq!(key.revision(), i64::default());
1659 }
1660 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1661 }
1662
1663 drop_table(&leader_mysql_election.client, table_name).await;
1664 }
1665
1666 #[tokio::test]
1667 async fn test_reset_campaign() {
1668 maybe_skip_mysql_integration_test!();
1669 common_telemetry::init_default_ut_logging();
1670 let leader_value = "test_leader".to_string();
1671 let uuid = uuid::Uuid::new_v4().to_string();
1672 let table_name = "test_reset_campaign_greptime-metakv";
1673 let candidate_lease_ttl = Duration::from_secs(5);
1674 let meta_lease_ttl = Duration::from_secs(2);
1675 let execution_timeout = Duration::from_secs(10);
1676 let idle_session_timeout = Duration::from_secs(0);
1677 let client = create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1678 .await
1679 .unwrap();
1680
1681 let (tx, _) = broadcast::channel(100);
1682 let leader_mysql_election = MySqlElection {
1683 leader_value,
1684 client,
1685 is_leader: AtomicBool::new(false),
1686 leader_infancy: AtomicBool::new(true),
1687 leader_watcher: tx,
1688 store_key_prefix: uuid,
1689 candidate_lease_ttl,
1690 meta_lease_ttl,
1691 sql_set: ElectionSqlFactory::new(table_name).build(),
1692 };
1693 leader_mysql_election
1694 .is_leader
1695 .store(true, Ordering::Relaxed);
1696 leader_mysql_election.reset_campaign().await;
1697 assert!(!leader_mysql_election.is_leader());
1698 drop_table(&leader_mysql_election.client, table_name).await;
1699 }
1700
1701 #[tokio::test]
1702 async fn test_follower_action() {
1703 maybe_skip_mysql_integration_test!();
1704 common_telemetry::init_default_ut_logging();
1705 let candidate_lease_ttl = Duration::from_secs(5);
1706 let meta_lease_ttl = Duration::from_secs(1);
1707 let execution_timeout = Duration::from_secs(10);
1708 let idle_session_timeout = Duration::from_secs(0);
1709 let uuid = uuid::Uuid::new_v4().to_string();
1710 let table_name = "test_follower_action_greptime-metakv";
1711
1712 let follower_client =
1713 create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1714 .await
1715 .unwrap();
1716 let (tx, mut rx) = broadcast::channel(100);
1717 let follower_mysql_election = MySqlElection {
1718 leader_value: "test_follower".to_string(),
1719 client: follower_client,
1720 is_leader: AtomicBool::new(false),
1721 leader_infancy: AtomicBool::new(true),
1722 leader_watcher: tx,
1723 store_key_prefix: uuid.clone(),
1724 candidate_lease_ttl,
1725 meta_lease_ttl,
1726 sql_set: ElectionSqlFactory::new(table_name).build(),
1727 };
1728
1729 let leader_client =
1730 create_mysql_client(Some(table_name), execution_timeout, idle_session_timeout)
1731 .await
1732 .unwrap();
1733 let (tx, _) = broadcast::channel(100);
1734 let leader_mysql_election = MySqlElection {
1735 leader_value: "test_leader".to_string(),
1736 client: leader_client,
1737 is_leader: AtomicBool::new(false),
1738 leader_infancy: AtomicBool::new(true),
1739 leader_watcher: tx,
1740 store_key_prefix: uuid,
1741 candidate_lease_ttl,
1742 meta_lease_ttl,
1743 sql_set: ElectionSqlFactory::new(table_name).build(),
1744 };
1745
1746 leader_mysql_election.do_campaign().await.unwrap();
1747
1748 follower_mysql_election.do_campaign().await.unwrap();
1750
1751 tokio::time::sleep(meta_lease_ttl + Duration::from_secs(1)).await;
1753 follower_mysql_election.do_campaign().await.unwrap();
1754 assert!(follower_mysql_election.is_leader());
1755
1756 match rx.recv().await {
1757 Ok(LeaderChangeMessage::Elected(key)) => {
1758 assert_eq!(String::from_utf8_lossy(key.name()), "test_follower");
1759 assert_eq!(
1760 String::from_utf8_lossy(key.key()),
1761 follower_mysql_election.election_key()
1762 );
1763 assert_eq!(key.lease_id(), i64::default());
1764 assert_eq!(key.revision(), i64::default());
1765 }
1766 _ => panic!("Expected LeaderChangeMessage::Elected"),
1767 }
1768
1769 drop_table(&follower_mysql_election.client, table_name).await;
1770 }
1771
1772 #[tokio::test]
1773 async fn test_wait_timeout() {
1774 maybe_skip_mysql_integration_test!();
1775 common_telemetry::init_default_ut_logging();
1776 let execution_timeout = Duration::from_secs(10);
1777 let idle_session_timeout = Duration::from_secs(1);
1778
1779 let client = create_mysql_client(None, execution_timeout, idle_session_timeout)
1780 .await
1781 .unwrap();
1782 tokio::time::sleep(Duration::from_millis(1100)).await;
1783 let err = client
1785 .lock()
1786 .await
1787 .query(sqlx::query("SELECT 1"), "SELECT 1")
1788 .await
1789 .unwrap_err();
1790 assert_matches!(err, error::Error::MySqlExecution { .. });
1791 client.lock().await.reset_client().await.unwrap();
1793 let _ = client
1794 .lock()
1795 .await
1796 .query(sqlx::query("SELECT 1"), "SELECT 1")
1797 .await
1798 .unwrap();
1799 }
1800}