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 deadpool_postgres::{Manager, Pool};
22use snafu::{OptionExt, ResultExt, ensure};
23use tokio::sync::{RwLock, broadcast};
24use tokio::time::MissedTickBehavior;
25use tokio_postgres::Row;
26use tokio_postgres::types::ToSql;
27
28use crate::election::rds::{LEASE_SEP, Lease, RdsLeaderKey, parse_value_and_expire_time};
29use crate::election::{
30 Election, ElectionRef, LeaderChangeMessage, LeaderValue, MetasrvNodeInfo, listen_leader_change,
31 send_leader_change_and_set_flags,
32};
33use crate::error::{
34 DeserializeFromJsonSnafu, ElectionNoLeaderSnafu, GetPostgresClientSnafu,
35 PostgresExecutionSnafu, Result, SerializeToJsonSnafu, SqlExecutionTimeoutSnafu,
36 UnexpectedSnafu,
37};
38use crate::key::{CANDIDATES_ROOT, ELECTION_KEY};
39
40struct ElectionSqlFactory<'a> {
41 lock_id: u64,
42 schema_name: Option<&'a str>,
43 table_name: &'a str,
44}
45
46struct ElectionSqlSet {
47 campaign: String,
48 step_down: String,
49 put_value_with_lease: String,
59 update_value_with_lease: String,
67 get_value_with_lease: String,
72 get_value_with_lease_by_prefix: String,
81 delete_value: String,
90}
91
92impl<'a> ElectionSqlFactory<'a> {
93 fn new(lock_id: u64, schema_name: Option<&'a str>, table_name: &'a str) -> Self {
94 Self {
95 lock_id,
96 schema_name,
97 table_name,
98 }
99 }
100
101 fn table_ident(&self) -> String {
102 match self.schema_name {
103 Some(s) if !s.is_empty() => format!("\"{}\".\"{}\"", s, self.table_name),
104 _ => format!("\"{}\"", self.table_name),
105 }
106 }
107
108 fn build(self) -> ElectionSqlSet {
109 ElectionSqlSet {
110 campaign: self.campaign_sql(),
111 step_down: self.step_down_sql(),
112 put_value_with_lease: self.put_value_with_lease_sql(),
113 update_value_with_lease: self.update_value_with_lease_sql(),
114 get_value_with_lease: self.get_value_with_lease_sql(),
115 get_value_with_lease_by_prefix: self.get_value_with_lease_by_prefix_sql(),
116 delete_value: self.delete_value_sql(),
117 }
118 }
119
120 fn campaign_sql(&self) -> String {
121 format!("SELECT pg_try_advisory_lock({})", self.lock_id)
122 }
123
124 fn step_down_sql(&self) -> String {
125 "SELECT pg_advisory_unlock_all()".to_string()
128 }
129
130 fn put_value_with_lease_sql(&self) -> String {
131 let table = self.table_ident();
132 format!(
133 r#"WITH prev AS (
134 SELECT k, v FROM {table} WHERE k = $1
135 ), insert AS (
136 INSERT INTO {table}
137 VALUES($1, convert_to($2 || '{lease_sep}' || TO_CHAR(CURRENT_TIMESTAMP + INTERVAL '1 second' * $3, 'YYYY-MM-DD HH24:MI:SS.MS'), 'UTF8'))
138 ON CONFLICT (k) DO NOTHING
139 )
140 SELECT k, v FROM prev;
141 "#,
142 table = table,
143 lease_sep = LEASE_SEP
144 )
145 }
146
147 fn update_value_with_lease_sql(&self) -> String {
148 let table = self.table_ident();
149 format!(
150 r#"UPDATE {table}
151 SET v = convert_to($3 || '{lease_sep}' || TO_CHAR(CURRENT_TIMESTAMP + INTERVAL '1 second' * $4, 'YYYY-MM-DD HH24:MI:SS.MS'), 'UTF8')
152 WHERE k = $1 AND v = $2"#,
153 table = table,
154 lease_sep = LEASE_SEP
155 )
156 }
157
158 fn get_value_with_lease_sql(&self) -> String {
159 let table = self.table_ident();
160 format!(
161 r#"SELECT v, TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS') FROM {table} WHERE k = $1"#,
162 table = table
163 )
164 }
165
166 fn get_value_with_lease_by_prefix_sql(&self) -> String {
167 let table = self.table_ident();
168 format!(
169 r#"SELECT v, TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS') FROM {table} WHERE k LIKE $1"#,
170 table = table
171 )
172 }
173
174 fn delete_value_sql(&self) -> String {
175 let table = self.table_ident();
176 format!(
177 "DELETE FROM {table} WHERE k = $1 RETURNING k,v;",
178 table = table
179 )
180 }
181}
182
183pub struct ElectionPgClient {
188 current: Option<deadpool::managed::Object<Manager>>,
189 pool: Pool,
190 execution_timeout: Duration,
195
196 idle_session_timeout: Duration,
201
202 statement_timeout: Duration,
207}
208
209impl ElectionPgClient {
210 pub fn new(
211 pool: Pool,
212 execution_timeout: Duration,
213 idle_session_timeout: Duration,
214 statement_timeout: Duration,
215 ) -> Result<ElectionPgClient> {
216 Ok(ElectionPgClient {
217 current: None,
218 pool,
219 execution_timeout,
220 idle_session_timeout,
221 statement_timeout,
222 })
223 }
224
225 fn set_idle_session_timeout_sql(&self) -> String {
226 format!(
227 "SET idle_session_timeout = '{}s';",
228 self.idle_session_timeout.as_secs()
229 )
230 }
231
232 fn set_statement_timeout_sql(&self) -> String {
233 format!(
234 "SET statement_timeout = '{}s';",
235 self.statement_timeout.as_secs()
236 )
237 }
238
239 async fn reset_client(&mut self) -> Result<()> {
240 if let Some(client) = self.current.take() {
241 let inner = deadpool::managed::Object::<deadpool_postgres::Manager>::take(client);
244 drop(inner);
245 }
246 self.maybe_init_client().await
247 }
248
249 async fn maybe_init_client(&mut self) -> Result<()> {
250 if self.current.is_none() {
251 let client = self.pool.get().await.context(GetPostgresClientSnafu)?;
252
253 self.current = Some(client);
254 let idle_session_timeout_sql = self.set_idle_session_timeout_sql();
256 self.execute(&idle_session_timeout_sql, &[]).await?;
257 let statement_timeout_sql = self.set_statement_timeout_sql();
258 self.execute(&statement_timeout_sql, &[]).await?;
259 }
260
261 Ok(())
262 }
263
264 async fn execute(&self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<u64> {
269 let result = tokio::time::timeout(
270 self.execution_timeout,
271 self.current.as_ref().unwrap().execute(sql, params),
272 )
273 .await
274 .map_err(|_| {
275 SqlExecutionTimeoutSnafu {
276 sql: sql.to_string(),
277 duration: self.execution_timeout,
278 }
279 .build()
280 })?;
281
282 result.context(PostgresExecutionSnafu { sql })
283 }
284
285 async fn query(&self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>> {
290 let result = tokio::time::timeout(
291 self.execution_timeout,
292 self.current.as_ref().unwrap().query(sql, params),
293 )
294 .await
295 .map_err(|_| {
296 SqlExecutionTimeoutSnafu {
297 sql: sql.to_string(),
298 duration: self.execution_timeout,
299 }
300 .build()
301 })?;
302
303 result.context(PostgresExecutionSnafu { sql })
304 }
305}
306
307pub struct PgElection {
309 leader_value: String,
310 pg_client: RwLock<ElectionPgClient>,
311 is_leader: AtomicBool,
312 leader_infancy: AtomicBool,
313 leader_watcher: broadcast::Sender<LeaderChangeMessage>,
314 store_key_prefix: String,
315 candidate_lease_ttl: Duration,
316 meta_lease_ttl: Duration,
317 sql_set: ElectionSqlSet,
318}
319
320impl PgElection {
321 async fn maybe_init_client(&self) -> Result<()> {
322 if self.pg_client.read().await.current.is_none() {
323 self.pg_client.write().await.maybe_init_client().await?;
324 }
325
326 Ok(())
327 }
328
329 #[allow(clippy::too_many_arguments)]
330 pub async fn with_pg_client(
331 leader_value: String,
332 pg_client: ElectionPgClient,
333 store_key_prefix: String,
334 candidate_lease_ttl: Duration,
335 meta_lease_ttl: Duration,
336 schema_name: Option<&str>,
337 table_name: &str,
338 lock_id: u64,
339 ) -> Result<ElectionRef> {
340 if let Some(s) = schema_name {
341 common_telemetry::info!("PgElection uses schema: {}", s);
342 } else {
343 common_telemetry::info!("PgElection uses default search_path (no schema provided)");
344 }
345 let sql_factory = ElectionSqlFactory::new(lock_id, schema_name, table_name);
346
347 let tx = listen_leader_change(leader_value.clone());
348 Ok(Arc::new(Self {
349 leader_value,
350 pg_client: RwLock::new(pg_client),
351 is_leader: AtomicBool::new(false),
352 leader_infancy: AtomicBool::new(false),
353 leader_watcher: tx,
354 store_key_prefix,
355 candidate_lease_ttl,
356 meta_lease_ttl,
357 sql_set: sql_factory.build(),
358 }))
359 }
360
361 fn election_key(&self) -> String {
362 format!("{}{}", self.store_key_prefix, ELECTION_KEY)
363 }
364
365 fn candidate_root(&self) -> String {
366 format!("{}{}", self.store_key_prefix, CANDIDATES_ROOT)
367 }
368
369 fn candidate_key(&self) -> String {
370 format!("{}{}", self.candidate_root(), self.leader_value)
371 }
372}
373
374#[async_trait::async_trait]
375impl Election for PgElection {
376 type Leader = LeaderValue;
377
378 fn is_leader(&self) -> bool {
379 self.is_leader.load(Ordering::Relaxed)
380 }
381
382 fn in_leader_infancy(&self) -> bool {
383 self.leader_infancy
384 .compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire)
385 .is_ok()
386 }
387
388 async fn register_candidate(&self, node_info: &MetasrvNodeInfo) -> Result<()> {
389 let key = self.candidate_key();
390 let node_info =
391 serde_json::to_string(node_info).with_context(|_| SerializeToJsonSnafu {
392 input: format!("{node_info:?}"),
393 })?;
394 let res = self
395 .put_value_with_lease(&key, &node_info, self.candidate_lease_ttl)
396 .await?;
397 if !res {
399 self.delete_value(&key).await?;
400 self.put_value_with_lease(&key, &node_info, self.candidate_lease_ttl)
401 .await?;
402 }
403
404 let mut keep_alive_interval = tokio::time::interval(self.candidate_lease_ttl / 2);
406 loop {
407 let _ = keep_alive_interval.tick().await;
408
409 let lease = self
410 .get_value_with_lease(&key)
411 .await?
412 .context(UnexpectedSnafu {
413 err_msg: format!("Failed to get lease for key: {:?}", key),
414 })?;
415
416 ensure!(
417 lease.expire_time > lease.current,
418 UnexpectedSnafu {
419 err_msg: format!(
420 "Candidate lease expired at {:?} (current time {:?}), key: {:?}",
421 lease.expire_time, lease.current, key
422 ),
423 }
424 );
425
426 self.update_value_with_lease(&key, &lease.origin, &node_info, self.candidate_lease_ttl)
428 .await?;
429 }
430 }
431
432 async fn all_candidates(&self) -> Result<Vec<MetasrvNodeInfo>> {
433 let key_prefix = self.candidate_root();
434 let (mut candidates, current) = self.get_value_with_lease_by_prefix(&key_prefix).await?;
435 candidates.retain(|c| c.1 > current);
437 let mut valid_candidates = Vec::with_capacity(candidates.len());
438 for (c, _) in candidates {
439 let node_info: MetasrvNodeInfo =
440 serde_json::from_str(&c).with_context(|_| DeserializeFromJsonSnafu {
441 input: format!("{:?}", c),
442 })?;
443 valid_candidates.push(node_info);
444 }
445 Ok(valid_candidates)
446 }
447
448 async fn campaign(&self) -> Result<()> {
461 let mut keep_alive_interval = tokio::time::interval(self.meta_lease_ttl / 2);
462 keep_alive_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
463
464 self.maybe_init_client().await?;
465 loop {
466 let res = self
467 .pg_client
468 .read()
469 .await
470 .query(&self.sql_set.campaign, &[])
471 .await?;
472 let row = res.first().context(UnexpectedSnafu {
473 err_msg: "Failed to get the result of acquiring advisory lock".to_string(),
474 })?;
475 let is_leader = row.try_get(0).map_err(|_| {
476 UnexpectedSnafu {
477 err_msg: "Failed to get the result of get lock".to_string(),
478 }
479 .build()
480 })?;
481 if is_leader {
482 self.leader_action().await?;
483 } else {
484 self.follower_action().await?;
485 }
486 let _ = keep_alive_interval.tick().await;
487 }
488 }
489
490 async fn reset_campaign(&self) {
491 info!("Resetting campaign");
492 if self.is_leader.load(Ordering::Relaxed) {
493 if let Err(err) = self.step_down_without_lock().await {
494 error!(err; "Failed to step down without lock");
495 }
496 info!("Step down without lock successfully, due to reset campaign");
497 }
498 if let Err(err) = self.pg_client.write().await.reset_client().await {
499 error!(err; "Failed to reset client");
500 }
501 }
502
503 async fn leader(&self) -> Result<Self::Leader> {
504 if self.is_leader.load(Ordering::Relaxed) {
505 Ok(self.leader_value.as_bytes().into())
506 } else {
507 let key = self.election_key();
508 if let Some(lease) = self.get_value_with_lease(&key).await? {
509 ensure!(lease.expire_time > lease.current, ElectionNoLeaderSnafu);
510 Ok(lease.leader_value.as_bytes().into())
511 } else {
512 ElectionNoLeaderSnafu.fail()
513 }
514 }
515 }
516
517 async fn resign(&self) -> Result<()> {
518 todo!()
519 }
520
521 fn subscribe_leader_change(&self) -> broadcast::Receiver<LeaderChangeMessage> {
522 self.leader_watcher.subscribe()
523 }
524}
525
526impl PgElection {
527 async fn get_value_with_lease(&self, key: &str) -> Result<Option<Lease>> {
529 let key = key.as_bytes();
530 self.maybe_init_client().await?;
531 let res = self
532 .pg_client
533 .read()
534 .await
535 .query(&self.sql_set.get_value_with_lease, &[&key])
536 .await?;
537
538 if res.is_empty() {
539 Ok(None)
540 } else {
541 let current_time_str = res[0].try_get(1).unwrap_or_default();
543 let current_time = match Timestamp::from_str(current_time_str, None) {
544 Ok(ts) => ts,
545 Err(_) => UnexpectedSnafu {
546 err_msg: format!("Invalid timestamp: {}", current_time_str),
547 }
548 .fail()?,
549 };
550 let value_and_expire_time =
552 String::from_utf8_lossy(res[0].try_get(0).unwrap_or_default());
553 let (value, expire_time) = parse_value_and_expire_time(&value_and_expire_time)?;
554
555 Ok(Some(Lease {
556 leader_value: value,
557 expire_time,
558 current: current_time,
559 origin: value_and_expire_time.to_string(),
560 }))
561 }
562 }
563
564 async fn get_value_with_lease_by_prefix(
566 &self,
567 key_prefix: &str,
568 ) -> Result<(Vec<(String, Timestamp)>, Timestamp)> {
569 let key_prefix = format!("{}%", key_prefix).as_bytes().to_vec();
570 self.maybe_init_client().await?;
571 let res = self
572 .pg_client
573 .read()
574 .await
575 .query(&self.sql_set.get_value_with_lease_by_prefix, &[&key_prefix])
576 .await?;
577
578 let mut values_with_leases = vec![];
579 let mut current = Timestamp::default();
580 for row in res {
581 let current_time_str = row.try_get(1).unwrap_or_default();
582 current = match Timestamp::from_str(current_time_str, None) {
583 Ok(ts) => ts,
584 Err(_) => UnexpectedSnafu {
585 err_msg: format!("Invalid timestamp: {}", current_time_str),
586 }
587 .fail()?,
588 };
589
590 let value_and_expire_time = String::from_utf8_lossy(row.try_get(0).unwrap_or_default());
591 let (value, expire_time) = parse_value_and_expire_time(&value_and_expire_time)?;
592
593 values_with_leases.push((value, expire_time));
594 }
595 Ok((values_with_leases, current))
596 }
597
598 async fn update_value_with_lease(
599 &self,
600 key: &str,
601 prev: &str,
602 updated: &str,
603 lease_ttl: Duration,
604 ) -> Result<()> {
605 let key = key.as_bytes();
606 let prev = prev.as_bytes();
607 self.maybe_init_client().await?;
608 let lease_ttl_secs = lease_ttl.as_secs() as f64;
609 let res = self
610 .pg_client
611 .read()
612 .await
613 .execute(
614 &self.sql_set.update_value_with_lease,
615 &[&key, &prev, &updated, &lease_ttl_secs],
616 )
617 .await?;
618
619 ensure!(
620 res == 1,
621 UnexpectedSnafu {
622 err_msg: format!("Failed to update key: {}", String::from_utf8_lossy(key)),
623 }
624 );
625
626 Ok(())
627 }
628
629 async fn put_value_with_lease(
631 &self,
632 key: &str,
633 value: &str,
634 lease_ttl: Duration,
635 ) -> Result<bool> {
636 let key = key.as_bytes();
637 let lease_ttl_secs = lease_ttl.as_secs() as f64;
638 let params: Vec<&(dyn ToSql + Sync)> = vec![&key, &value, &lease_ttl_secs];
639 self.maybe_init_client().await?;
640 let res = self
641 .pg_client
642 .read()
643 .await
644 .query(&self.sql_set.put_value_with_lease, ¶ms)
645 .await?;
646 Ok(res.is_empty())
647 }
648
649 async fn delete_value(&self, key: &str) -> Result<bool> {
652 let key = key.as_bytes();
653 self.maybe_init_client().await?;
654 let res = self
655 .pg_client
656 .read()
657 .await
658 .query(&self.sql_set.delete_value, &[&key])
659 .await?;
660
661 Ok(res.len() == 1)
662 }
663
664 async fn leader_action(&self) -> Result<()> {
685 let key = self.election_key();
686 if self.is_leader() {
688 match self.get_value_with_lease(&key).await? {
689 Some(lease) => {
690 match (
691 lease.leader_value == self.leader_value,
692 lease.expire_time > lease.current,
693 ) {
694 (true, true) => {
696 self.update_value_with_lease(
698 &key,
699 &lease.origin,
700 &self.leader_value,
701 self.meta_lease_ttl,
702 )
703 .await?;
704 }
705 (true, false) => {
707 warn!("Leader lease expired, now stepping down.");
708 self.step_down().await?;
709 }
710 (false, _) => {
712 warn!(
713 "Leader lease not found, but still hold the lock. Now stepping down."
714 );
715 self.step_down().await?;
716 }
717 }
718 }
719 None => {
721 warn!("Leader lease not found, but still hold the lock. Now stepping down.");
722 self.step_down().await?;
723 }
724 }
725 } else {
727 self.elected().await?;
728 }
729 Ok(())
730 }
731
732 async fn follower_action(&self) -> Result<()> {
743 let key = self.election_key();
744 if self.is_leader() {
746 self.step_down_without_lock().await?;
747 }
748 let lease = self
749 .get_value_with_lease(&key)
750 .await?
751 .context(ElectionNoLeaderSnafu)?;
752 ensure!(lease.expire_time > lease.current, ElectionNoLeaderSnafu);
754 Ok(())
756 }
757
758 async fn step_down(&self) -> Result<()> {
765 let key = self.election_key();
766 let leader_key = RdsLeaderKey {
767 name: self.leader_value.clone().into_bytes(),
768 key: key.clone().into_bytes(),
769 ..Default::default()
770 };
771 self.delete_value(&key).await?;
772 self.maybe_init_client().await?;
773 self.pg_client
774 .read()
775 .await
776 .query(&self.sql_set.step_down, &[])
777 .await?;
778 send_leader_change_and_set_flags(
779 &self.is_leader,
780 &self.leader_infancy,
781 &self.leader_watcher,
782 LeaderChangeMessage::StepDown(Arc::new(leader_key)),
783 );
784 Ok(())
785 }
786
787 async fn step_down_without_lock(&self) -> Result<()> {
789 let key = self.election_key().into_bytes();
790 let leader_key = RdsLeaderKey {
791 name: self.leader_value.clone().into_bytes(),
792 key: key.clone(),
793 ..Default::default()
794 };
795 send_leader_change_and_set_flags(
796 &self.is_leader,
797 &self.leader_infancy,
798 &self.leader_watcher,
799 LeaderChangeMessage::StepDown(Arc::new(leader_key)),
800 );
801 Ok(())
802 }
803
804 async fn elected(&self) -> Result<()> {
807 let key = self.election_key();
808 let leader_key = RdsLeaderKey {
809 name: self.leader_value.clone().into_bytes(),
810 key: key.clone().into_bytes(),
811 ..Default::default()
812 };
813 self.delete_value(&key).await?;
814 self.put_value_with_lease(&key, &self.leader_value, self.meta_lease_ttl)
815 .await?;
816
817 if self
818 .is_leader
819 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
820 .is_ok()
821 {
822 self.leader_infancy.store(true, Ordering::Release);
823
824 if let Err(e) = self
825 .leader_watcher
826 .send(LeaderChangeMessage::Elected(Arc::new(leader_key)))
827 {
828 error!(e; "Failed to send leader change message");
829 }
830 }
831 Ok(())
832 }
833}
834
835#[cfg(test)]
836mod tests {
837 use std::{assert_matches, env};
838
839 use deadpool_postgres::{Config, Runtime};
840 use tokio_postgres::NoTls;
841
842 use super::*;
843 use crate::{error, maybe_skip_postgres_integration_test};
844
845 async fn create_postgres_client(
846 table_name: Option<&str>,
847 execution_timeout: Duration,
848 idle_session_timeout: Duration,
849 statement_timeout: Duration,
850 ) -> Result<ElectionPgClient> {
851 let endpoint = env::var("GT_POSTGRES_ENDPOINTS").unwrap_or_default();
852 if endpoint.is_empty() {
853 return UnexpectedSnafu {
854 err_msg: "Postgres endpoint is empty".to_string(),
855 }
856 .fail();
857 }
858 let mut cfg = Config::new();
859 cfg.url = Some(endpoint);
860 let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
861 let mut pg_client = ElectionPgClient::new(
862 pool,
863 execution_timeout,
864 idle_session_timeout,
865 statement_timeout,
866 )
867 .unwrap();
868 pg_client.maybe_init_client().await?;
869 if let Some(table_name) = table_name {
870 let create_table_sql = format!(
871 "CREATE TABLE IF NOT EXISTS \"{}\"(k bytea PRIMARY KEY, v bytea);",
872 table_name
873 );
874 pg_client.execute(&create_table_sql, &[]).await?;
875 }
876 Ok(pg_client)
877 }
878
879 async fn drop_table(pg_election: &PgElection, table_name: &str) {
880 let sql = format!("DROP TABLE IF EXISTS \"{}\";", table_name);
881 pg_election
882 .pg_client
883 .read()
884 .await
885 .execute(&sql, &[])
886 .await
887 .unwrap();
888 }
889
890 #[tokio::test]
891 async fn test_postgres_crud() {
892 maybe_skip_postgres_integration_test!();
893 let key = "test_key".to_string();
894 let value = "test_value".to_string();
895
896 let uuid = uuid::Uuid::new_v4().to_string();
897 let table_name = "test_postgres_crud_greptime_metakv";
898 let candidate_lease_ttl = Duration::from_secs(10);
899 let execution_timeout = Duration::from_secs(10);
900 let statement_timeout = Duration::from_secs(10);
901 let meta_lease_ttl = Duration::from_secs(2);
902 let idle_session_timeout = Duration::from_secs(0);
903 let client = create_postgres_client(
904 Some(table_name),
905 execution_timeout,
906 idle_session_timeout,
907 statement_timeout,
908 )
909 .await
910 .unwrap();
911
912 let (tx, _) = broadcast::channel(100);
913 let pg_election = PgElection {
914 leader_value: "test_leader".to_string(),
915 pg_client: RwLock::new(client),
916 is_leader: AtomicBool::new(false),
917 leader_infancy: AtomicBool::new(true),
918 leader_watcher: tx,
919 store_key_prefix: uuid,
920 candidate_lease_ttl,
921 meta_lease_ttl,
922 sql_set: ElectionSqlFactory::new(28319, None, table_name).build(),
923 };
924
925 let res = pg_election
926 .put_value_with_lease(&key, &value, candidate_lease_ttl)
927 .await
928 .unwrap();
929 assert!(res);
930
931 let lease = pg_election
932 .get_value_with_lease(&key)
933 .await
934 .unwrap()
935 .unwrap();
936 assert_eq!(lease.leader_value, value);
937
938 pg_election
939 .update_value_with_lease(&key, &lease.origin, &value, pg_election.meta_lease_ttl)
940 .await
941 .unwrap();
942
943 let res = pg_election.delete_value(&key).await.unwrap();
944 assert!(res);
945
946 let res = pg_election.get_value_with_lease(&key).await.unwrap();
947 assert!(res.is_none());
948
949 for i in 0..10 {
950 let key = format!("test_key_{}", i);
951 let value = format!("test_value_{}", i);
952 pg_election
953 .put_value_with_lease(&key, &value, candidate_lease_ttl)
954 .await
955 .unwrap();
956 }
957
958 let key_prefix = "test_key".to_string();
959 let (res, _) = pg_election
960 .get_value_with_lease_by_prefix(&key_prefix)
961 .await
962 .unwrap();
963 assert_eq!(res.len(), 10);
964
965 for i in 0..10 {
966 let key = format!("test_key_{}", i);
967 let res = pg_election.delete_value(&key).await.unwrap();
968 assert!(res);
969 }
970
971 let (res, current) = pg_election
972 .get_value_with_lease_by_prefix(&key_prefix)
973 .await
974 .unwrap();
975 assert!(res.is_empty());
976 assert!(current == Timestamp::default());
977
978 drop_table(&pg_election, table_name).await;
979 }
980
981 async fn candidate(
982 leader_value: String,
983 candidate_lease_ttl: Duration,
984 store_key_prefix: String,
985 table_name: String,
986 ) {
987 let execution_timeout = Duration::from_secs(10);
988 let statement_timeout = Duration::from_secs(10);
989 let meta_lease_ttl = Duration::from_secs(2);
990 let idle_session_timeout = Duration::from_secs(0);
991 let client = create_postgres_client(
992 None,
993 execution_timeout,
994 idle_session_timeout,
995 statement_timeout,
996 )
997 .await
998 .unwrap();
999
1000 let (tx, _) = broadcast::channel(100);
1001 let pg_election = PgElection {
1002 leader_value,
1003 pg_client: RwLock::new(client),
1004 is_leader: AtomicBool::new(false),
1005 leader_infancy: AtomicBool::new(true),
1006 leader_watcher: tx,
1007 store_key_prefix,
1008 candidate_lease_ttl,
1009 meta_lease_ttl,
1010 sql_set: ElectionSqlFactory::new(28319, None, &table_name).build(),
1011 };
1012
1013 let node_info = MetasrvNodeInfo {
1014 addr: "test_addr".to_string(),
1015 version: "test_version".to_string(),
1016 git_commit: "test_git_commit".to_string(),
1017 start_time_ms: 0,
1018 total_cpu_millicores: 0,
1019 total_memory_bytes: 0,
1020 cpu_usage_millicores: 0,
1021 memory_usage_bytes: 0,
1022 hostname: "test_hostname".to_string(),
1023 };
1024 pg_election.register_candidate(&node_info).await.unwrap();
1025 }
1026
1027 #[tokio::test]
1028 async fn test_candidate_registration() {
1029 maybe_skip_postgres_integration_test!();
1030 let leader_value_prefix = "test_leader".to_string();
1031 let uuid = uuid::Uuid::new_v4().to_string();
1032 let table_name = "test_candidate_registration_greptime_metakv";
1033 let mut handles = vec![];
1034 let candidate_lease_ttl = Duration::from_secs(5);
1035 let execution_timeout = Duration::from_secs(10);
1036 let statement_timeout = Duration::from_secs(10);
1037 let meta_lease_ttl = Duration::from_secs(2);
1038 let idle_session_timeout = Duration::from_secs(0);
1039 let client = create_postgres_client(
1040 Some(table_name),
1041 execution_timeout,
1042 idle_session_timeout,
1043 statement_timeout,
1044 )
1045 .await
1046 .unwrap();
1047
1048 for i in 0..10 {
1049 let leader_value = format!("{}{}", leader_value_prefix, i);
1050 let handle = tokio::spawn(candidate(
1051 leader_value,
1052 candidate_lease_ttl,
1053 uuid.clone(),
1054 table_name.to_string(),
1055 ));
1056 handles.push(handle);
1057 }
1058 tokio::time::sleep(Duration::from_secs(3)).await;
1060
1061 let (tx, _) = broadcast::channel(100);
1062 let leader_value = "test_leader".to_string();
1063 let pg_election = PgElection {
1064 leader_value,
1065 pg_client: RwLock::new(client),
1066 is_leader: AtomicBool::new(false),
1067 leader_infancy: AtomicBool::new(true),
1068 leader_watcher: tx,
1069 store_key_prefix: uuid.clone(),
1070 candidate_lease_ttl,
1071 meta_lease_ttl,
1072 sql_set: ElectionSqlFactory::new(28319, None, table_name).build(),
1073 };
1074
1075 let candidates = pg_election.all_candidates().await.unwrap();
1076 assert_eq!(candidates.len(), 10);
1077
1078 for handle in handles {
1079 handle.abort();
1080 }
1081
1082 tokio::time::sleep(Duration::from_secs(5)).await;
1084 let candidates = pg_election.all_candidates().await.unwrap();
1085 assert!(candidates.is_empty());
1086
1087 for i in 0..10 {
1089 let key = format!("{}{}{}{}", uuid, CANDIDATES_ROOT, leader_value_prefix, i);
1090 let res = pg_election.delete_value(&key).await.unwrap();
1091 assert!(res);
1092 }
1093
1094 drop_table(&pg_election, table_name).await;
1095 }
1096
1097 #[tokio::test]
1098 async fn test_elected_and_step_down() {
1099 maybe_skip_postgres_integration_test!();
1100 let leader_value = "test_leader".to_string();
1101 let uuid = uuid::Uuid::new_v4().to_string();
1102 let table_name = "test_elected_and_step_down_greptime_metakv";
1103 let candidate_lease_ttl = Duration::from_secs(5);
1104 let execution_timeout = Duration::from_secs(10);
1105 let statement_timeout = Duration::from_secs(10);
1106 let meta_lease_ttl = Duration::from_secs(2);
1107 let idle_session_timeout = Duration::from_secs(0);
1108 let client = create_postgres_client(
1109 Some(table_name),
1110 execution_timeout,
1111 idle_session_timeout,
1112 statement_timeout,
1113 )
1114 .await
1115 .unwrap();
1116
1117 let (tx, mut rx) = broadcast::channel(100);
1118 let leader_pg_election = PgElection {
1119 leader_value: leader_value.clone(),
1120 pg_client: RwLock::new(client),
1121 is_leader: AtomicBool::new(false),
1122 leader_infancy: AtomicBool::new(true),
1123 leader_watcher: tx,
1124 store_key_prefix: uuid,
1125 candidate_lease_ttl,
1126 meta_lease_ttl,
1127 sql_set: ElectionSqlFactory::new(28320, None, table_name).build(),
1128 };
1129
1130 leader_pg_election.elected().await.unwrap();
1131 let lease = leader_pg_election
1132 .get_value_with_lease(&leader_pg_election.election_key())
1133 .await
1134 .unwrap()
1135 .unwrap();
1136 assert!(lease.leader_value == leader_value);
1137 assert!(lease.expire_time > lease.current);
1138 assert!(leader_pg_election.is_leader());
1139
1140 match rx.recv().await {
1141 Ok(LeaderChangeMessage::Elected(key)) => {
1142 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1143 assert_eq!(
1144 String::from_utf8_lossy(key.key()),
1145 leader_pg_election.election_key()
1146 );
1147 assert_eq!(key.lease_id(), i64::default());
1148 assert_eq!(key.revision(), i64::default());
1149 }
1150 _ => panic!("Expected LeaderChangeMessage::Elected"),
1151 }
1152
1153 leader_pg_election.step_down_without_lock().await.unwrap();
1154 let lease = leader_pg_election
1155 .get_value_with_lease(&leader_pg_election.election_key())
1156 .await
1157 .unwrap()
1158 .unwrap();
1159 assert!(lease.leader_value == leader_value);
1160 assert!(!leader_pg_election.is_leader());
1161
1162 match rx.recv().await {
1163 Ok(LeaderChangeMessage::StepDown(key)) => {
1164 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1165 assert_eq!(
1166 String::from_utf8_lossy(key.key()),
1167 leader_pg_election.election_key()
1168 );
1169 assert_eq!(key.lease_id(), i64::default());
1170 assert_eq!(key.revision(), i64::default());
1171 }
1172 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1173 }
1174
1175 leader_pg_election.elected().await.unwrap();
1176 let lease = leader_pg_election
1177 .get_value_with_lease(&leader_pg_election.election_key())
1178 .await
1179 .unwrap()
1180 .unwrap();
1181 assert!(lease.leader_value == leader_value);
1182 assert!(lease.expire_time > lease.current);
1183 assert!(leader_pg_election.is_leader());
1184
1185 match rx.recv().await {
1186 Ok(LeaderChangeMessage::Elected(key)) => {
1187 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1188 assert_eq!(
1189 String::from_utf8_lossy(key.key()),
1190 leader_pg_election.election_key()
1191 );
1192 assert_eq!(key.lease_id(), i64::default());
1193 assert_eq!(key.revision(), i64::default());
1194 }
1195 _ => panic!("Expected LeaderChangeMessage::Elected"),
1196 }
1197
1198 leader_pg_election.step_down().await.unwrap();
1199 let res = leader_pg_election
1200 .get_value_with_lease(&leader_pg_election.election_key())
1201 .await
1202 .unwrap();
1203 assert!(res.is_none());
1204 assert!(!leader_pg_election.is_leader());
1205
1206 match rx.recv().await {
1207 Ok(LeaderChangeMessage::StepDown(key)) => {
1208 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1209 assert_eq!(
1210 String::from_utf8_lossy(key.key()),
1211 leader_pg_election.election_key()
1212 );
1213 assert_eq!(key.lease_id(), i64::default());
1214 assert_eq!(key.revision(), i64::default());
1215 }
1216 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1217 }
1218
1219 drop_table(&leader_pg_election, table_name).await;
1220 }
1221
1222 #[tokio::test]
1223 async fn test_leader_action() {
1224 maybe_skip_postgres_integration_test!();
1225 let leader_value = "test_leader".to_string();
1226 let uuid = uuid::Uuid::new_v4().to_string();
1227 let table_name = "test_leader_action_greptime_metakv";
1228 let candidate_lease_ttl = Duration::from_secs(5);
1229 let execution_timeout = Duration::from_secs(10);
1230 let statement_timeout = Duration::from_secs(10);
1231 let meta_lease_ttl = Duration::from_secs(2);
1232 let idle_session_timeout = Duration::from_secs(0);
1233 let client = create_postgres_client(
1234 Some(table_name),
1235 execution_timeout,
1236 idle_session_timeout,
1237 statement_timeout,
1238 )
1239 .await
1240 .unwrap();
1241
1242 let (tx, mut rx) = broadcast::channel(100);
1243 let leader_pg_election = PgElection {
1244 leader_value: leader_value.clone(),
1245 pg_client: RwLock::new(client),
1246 is_leader: AtomicBool::new(false),
1247 leader_infancy: AtomicBool::new(true),
1248 leader_watcher: tx,
1249 store_key_prefix: uuid,
1250 candidate_lease_ttl,
1251 meta_lease_ttl,
1252 sql_set: ElectionSqlFactory::new(28321, None, table_name).build(),
1253 };
1254
1255 let res = leader_pg_election
1257 .pg_client
1258 .read()
1259 .await
1260 .query(&leader_pg_election.sql_set.campaign, &[])
1261 .await
1262 .unwrap();
1263 let res: bool = res[0].get(0);
1264 assert!(res);
1265 leader_pg_election.leader_action().await.unwrap();
1266 let lease = leader_pg_election
1267 .get_value_with_lease(&leader_pg_election.election_key())
1268 .await
1269 .unwrap()
1270 .unwrap();
1271 assert!(lease.leader_value == leader_value);
1272 assert!(lease.expire_time > lease.current);
1273 assert!(leader_pg_election.is_leader());
1274
1275 match rx.recv().await {
1276 Ok(LeaderChangeMessage::Elected(key)) => {
1277 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1278 assert_eq!(
1279 String::from_utf8_lossy(key.key()),
1280 leader_pg_election.election_key()
1281 );
1282 assert_eq!(key.lease_id(), i64::default());
1283 assert_eq!(key.revision(), i64::default());
1284 }
1285 _ => panic!("Expected LeaderChangeMessage::Elected"),
1286 }
1287
1288 tokio::time::timeout(Duration::from_secs(1), async {
1291 loop {
1292 let current = leader_pg_election
1293 .get_value_with_lease(&leader_pg_election.election_key())
1294 .await
1295 .unwrap()
1296 .unwrap();
1297 if current.current > lease.current {
1298 break;
1299 }
1300 tokio::time::sleep(Duration::from_millis(1)).await;
1301 }
1302 })
1303 .await
1304 .unwrap();
1305
1306 let res = leader_pg_election
1308 .pg_client
1309 .read()
1310 .await
1311 .query(&leader_pg_election.sql_set.campaign, &[])
1312 .await
1313 .unwrap();
1314 let res: bool = res[0].get(0);
1315 assert!(res);
1316 leader_pg_election.leader_action().await.unwrap();
1317 let new_lease = leader_pg_election
1318 .get_value_with_lease(&leader_pg_election.election_key())
1319 .await
1320 .unwrap()
1321 .unwrap();
1322 assert!(new_lease.leader_value == leader_value);
1323 assert!(
1324 new_lease.expire_time > new_lease.current && new_lease.expire_time > lease.expire_time
1325 );
1326 assert!(leader_pg_election.is_leader());
1327
1328 tokio::time::sleep(Duration::from_secs(2)).await;
1330
1331 let res = leader_pg_election
1332 .pg_client
1333 .read()
1334 .await
1335 .query(&leader_pg_election.sql_set.campaign, &[])
1336 .await
1337 .unwrap();
1338 let res: bool = res[0].get(0);
1339 assert!(res);
1340 leader_pg_election.leader_action().await.unwrap();
1341 let res = leader_pg_election
1342 .get_value_with_lease(&leader_pg_election.election_key())
1343 .await
1344 .unwrap();
1345 assert!(res.is_none());
1346
1347 match rx.recv().await {
1348 Ok(LeaderChangeMessage::StepDown(key)) => {
1349 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1350 assert_eq!(
1351 String::from_utf8_lossy(key.key()),
1352 leader_pg_election.election_key()
1353 );
1354 assert_eq!(key.lease_id(), i64::default());
1355 assert_eq!(key.revision(), i64::default());
1356 }
1357 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1358 }
1359
1360 let res = leader_pg_election
1362 .pg_client
1363 .read()
1364 .await
1365 .query(&leader_pg_election.sql_set.campaign, &[])
1366 .await
1367 .unwrap();
1368 let res: bool = res[0].get(0);
1369 assert!(res);
1370 leader_pg_election.leader_action().await.unwrap();
1371 let lease = leader_pg_election
1372 .get_value_with_lease(&leader_pg_election.election_key())
1373 .await
1374 .unwrap()
1375 .unwrap();
1376 assert!(lease.leader_value == leader_value);
1377 assert!(lease.expire_time > lease.current);
1378 assert!(leader_pg_election.is_leader());
1379
1380 match rx.recv().await {
1381 Ok(LeaderChangeMessage::Elected(key)) => {
1382 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1383 assert_eq!(
1384 String::from_utf8_lossy(key.key()),
1385 leader_pg_election.election_key()
1386 );
1387 assert_eq!(key.lease_id(), i64::default());
1388 assert_eq!(key.revision(), i64::default());
1389 }
1390 _ => panic!("Expected LeaderChangeMessage::Elected"),
1391 }
1392
1393 leader_pg_election
1395 .delete_value(&leader_pg_election.election_key())
1396 .await
1397 .unwrap();
1398 leader_pg_election.leader_action().await.unwrap();
1399 let res = leader_pg_election
1400 .get_value_with_lease(&leader_pg_election.election_key())
1401 .await
1402 .unwrap();
1403 assert!(res.is_none());
1404 assert!(!leader_pg_election.is_leader());
1405
1406 match rx.recv().await {
1407 Ok(LeaderChangeMessage::StepDown(key)) => {
1408 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1409 assert_eq!(
1410 String::from_utf8_lossy(key.key()),
1411 leader_pg_election.election_key()
1412 );
1413 assert_eq!(key.lease_id(), i64::default());
1414 assert_eq!(key.revision(), i64::default());
1415 }
1416 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1417 }
1418
1419 let res = leader_pg_election
1421 .pg_client
1422 .read()
1423 .await
1424 .query(&leader_pg_election.sql_set.campaign, &[])
1425 .await
1426 .unwrap();
1427 let res: bool = res[0].get(0);
1428 assert!(res);
1429 leader_pg_election.leader_action().await.unwrap();
1430 let lease = leader_pg_election
1431 .get_value_with_lease(&leader_pg_election.election_key())
1432 .await
1433 .unwrap()
1434 .unwrap();
1435 assert!(lease.leader_value == leader_value);
1436 assert!(lease.expire_time > lease.current);
1437 assert!(leader_pg_election.is_leader());
1438
1439 match rx.recv().await {
1440 Ok(LeaderChangeMessage::Elected(key)) => {
1441 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1442 assert_eq!(
1443 String::from_utf8_lossy(key.key()),
1444 leader_pg_election.election_key()
1445 );
1446 assert_eq!(key.lease_id(), i64::default());
1447 assert_eq!(key.revision(), i64::default());
1448 }
1449 _ => panic!("Expected LeaderChangeMessage::Elected"),
1450 }
1451
1452 let res = leader_pg_election
1454 .pg_client
1455 .read()
1456 .await
1457 .query(&leader_pg_election.sql_set.campaign, &[])
1458 .await
1459 .unwrap();
1460 let res: bool = res[0].get(0);
1461 assert!(res);
1462 leader_pg_election
1463 .delete_value(&leader_pg_election.election_key())
1464 .await
1465 .unwrap();
1466 leader_pg_election
1467 .put_value_with_lease(
1468 &leader_pg_election.election_key(),
1469 "test",
1470 Duration::from_secs(10),
1471 )
1472 .await
1473 .unwrap();
1474 leader_pg_election.leader_action().await.unwrap();
1475 let res = leader_pg_election
1476 .get_value_with_lease(&leader_pg_election.election_key())
1477 .await
1478 .unwrap();
1479 assert!(res.is_none());
1480 assert!(!leader_pg_election.is_leader());
1481
1482 match rx.recv().await {
1483 Ok(LeaderChangeMessage::StepDown(key)) => {
1484 assert_eq!(String::from_utf8_lossy(key.name()), leader_value);
1485 assert_eq!(
1486 String::from_utf8_lossy(key.key()),
1487 leader_pg_election.election_key()
1488 );
1489 assert_eq!(key.lease_id(), i64::default());
1490 assert_eq!(key.revision(), i64::default());
1491 }
1492 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1493 }
1494
1495 leader_pg_election
1497 .pg_client
1498 .read()
1499 .await
1500 .query(&leader_pg_election.sql_set.step_down, &[])
1501 .await
1502 .unwrap();
1503
1504 drop_table(&leader_pg_election, table_name).await;
1505 }
1506
1507 #[tokio::test]
1508 async fn test_step_down_releases_reentrant_lock() {
1509 maybe_skip_postgres_integration_test!();
1510 let table_name = "test_step_down_reentrant_lock_greptime_metakv";
1511 let store_key_prefix = uuid::Uuid::new_v4().to_string();
1512 let lock_id = 28323;
1513 let other_lock_id = 28324;
1514 let timeout = Duration::from_secs(10);
1515 let mut elections = Vec::new();
1516 for leader_value in ["leader", "follower"] {
1517 let client = create_postgres_client(Some(table_name), timeout, Duration::ZERO, timeout)
1519 .await
1520 .unwrap();
1521 let (tx, _) = broadcast::channel(100);
1522 elections.push(PgElection {
1523 leader_value: leader_value.to_string(),
1524 pg_client: RwLock::new(client),
1525 is_leader: AtomicBool::new(false),
1526 leader_infancy: AtomicBool::new(false),
1527 leader_watcher: tx,
1528 store_key_prefix: store_key_prefix.clone(),
1529 candidate_lease_ttl: timeout,
1530 meta_lease_ttl: timeout,
1531 sql_set: ElectionSqlFactory::new(lock_id, None, table_name).build(),
1532 });
1533 }
1534 let leader = &elections[0];
1535 let follower = &elections[1];
1536 let mut leader_changes = leader.subscribe_leader_change();
1537 let other_lock_sql = format!("SELECT pg_try_advisory_lock({other_lock_id})");
1538 let other_unlock_sql = format!("SELECT pg_advisory_unlock({other_lock_id})");
1539 let leader_pid: i32 = leader
1540 .pg_client
1541 .read()
1542 .await
1543 .query("SELECT pg_backend_pid()", &[])
1544 .await
1545 .unwrap()[0]
1546 .get(0);
1547
1548 for acquisitions in [1, 3, 1000] {
1549 for _ in 0..acquisitions {
1551 let rows = leader
1552 .pg_client
1553 .read()
1554 .await
1555 .query(&leader.sql_set.campaign, &[])
1556 .await
1557 .unwrap();
1558 assert!(rows[0].get::<_, bool>(0));
1559 }
1560 leader.leader_action().await.unwrap();
1561 assert_matches!(
1562 leader_changes.try_recv().unwrap(),
1563 LeaderChangeMessage::Elected(_)
1564 );
1565 let rows = follower
1566 .pg_client
1567 .read()
1568 .await
1569 .query(&follower.sql_set.campaign, &[])
1570 .await
1571 .unwrap();
1572 assert!(!rows[0].get::<_, bool>(0));
1573 follower.follower_action().await.unwrap();
1574
1575 let rows = follower
1577 .pg_client
1578 .read()
1579 .await
1580 .query(&other_lock_sql, &[])
1581 .await
1582 .unwrap();
1583 assert!(rows[0].get::<_, bool>(0));
1584
1585 let key = leader.election_key();
1587 let lease = leader.get_value_with_lease(&key).await.unwrap().unwrap();
1588 leader
1589 .update_value_with_lease(&key, &lease.origin, &leader.leader_value, Duration::ZERO)
1590 .await
1591 .unwrap();
1592 leader.leader_action().await.unwrap();
1593 assert!(!leader.is_leader());
1594 assert!(leader.get_value_with_lease(&key).await.unwrap().is_none());
1595 assert_matches!(
1596 leader_changes.try_recv().unwrap(),
1597 LeaderChangeMessage::StepDown(_)
1598 );
1599 assert!(leader_changes.try_recv().is_err());
1600 let current_pid: i32 = leader
1601 .pg_client
1602 .read()
1603 .await
1604 .query("SELECT pg_backend_pid()", &[])
1605 .await
1606 .unwrap()[0]
1607 .get(0);
1608 assert_eq!(leader_pid, current_pid);
1609
1610 let rows = leader
1611 .pg_client
1612 .read()
1613 .await
1614 .query(&other_lock_sql, &[])
1615 .await
1616 .unwrap();
1617 assert!(!rows[0].get::<_, bool>(0));
1618 let rows = follower
1619 .pg_client
1620 .read()
1621 .await
1622 .query(&follower.sql_set.campaign, &[])
1623 .await
1624 .unwrap();
1625 assert!(
1626 rows[0].get::<_, bool>(0),
1627 "lock still held after {acquisitions} acquisitions"
1628 );
1629 let rows = follower
1630 .pg_client
1631 .read()
1632 .await
1633 .query(&other_unlock_sql, &[])
1634 .await
1635 .unwrap();
1636 assert!(rows[0].get::<_, bool>(0));
1637 follower.leader_action().await.unwrap();
1638 assert!(follower.is_leader());
1639 let lease = follower.get_value_with_lease(&key).await.unwrap().unwrap();
1640 assert_eq!(follower.leader_value, lease.leader_value);
1641 follower.step_down().await.unwrap();
1642 }
1643 drop_table(leader, table_name).await;
1644 }
1645
1646 #[tokio::test]
1647 async fn test_follower_action() {
1648 maybe_skip_postgres_integration_test!();
1649 common_telemetry::init_default_ut_logging();
1650 let uuid = uuid::Uuid::new_v4().to_string();
1651 let table_name = "test_follower_action_greptime_metakv";
1652
1653 let candidate_lease_ttl = Duration::from_secs(5);
1654 let execution_timeout = Duration::from_secs(10);
1655 let statement_timeout = Duration::from_secs(10);
1656 let meta_lease_ttl = Duration::from_secs(2);
1657 let idle_session_timeout = Duration::from_secs(0);
1658 let follower_client = create_postgres_client(
1659 Some(table_name),
1660 execution_timeout,
1661 idle_session_timeout,
1662 statement_timeout,
1663 )
1664 .await
1665 .unwrap();
1666 let (tx, mut rx) = broadcast::channel(100);
1667 let follower_pg_election = PgElection {
1668 leader_value: "test_follower".to_string(),
1669 pg_client: RwLock::new(follower_client),
1670 is_leader: AtomicBool::new(false),
1671 leader_infancy: AtomicBool::new(true),
1672 leader_watcher: tx,
1673 store_key_prefix: uuid.clone(),
1674 candidate_lease_ttl,
1675 meta_lease_ttl,
1676 sql_set: ElectionSqlFactory::new(28322, None, table_name).build(),
1677 };
1678
1679 let leader_client = create_postgres_client(
1680 Some(table_name),
1681 execution_timeout,
1682 idle_session_timeout,
1683 statement_timeout,
1684 )
1685 .await
1686 .unwrap();
1687 let (tx, _) = broadcast::channel(100);
1688 let leader_pg_election = PgElection {
1689 leader_value: "test_leader".to_string(),
1690 pg_client: RwLock::new(leader_client),
1691 is_leader: AtomicBool::new(false),
1692 leader_infancy: AtomicBool::new(true),
1693 leader_watcher: tx,
1694 store_key_prefix: uuid,
1695 candidate_lease_ttl,
1696 meta_lease_ttl,
1697 sql_set: ElectionSqlFactory::new(28322, None, table_name).build(),
1698 };
1699
1700 leader_pg_election
1701 .pg_client
1702 .read()
1703 .await
1704 .query(&leader_pg_election.sql_set.campaign, &[])
1705 .await
1706 .unwrap();
1707 leader_pg_election.elected().await.unwrap();
1708
1709 follower_pg_election.follower_action().await.unwrap();
1711
1712 tokio::time::sleep(Duration::from_secs(2)).await;
1714 assert!(follower_pg_election.follower_action().await.is_err());
1715
1716 leader_pg_election
1718 .delete_value(&leader_pg_election.election_key())
1719 .await
1720 .unwrap();
1721 assert!(follower_pg_election.follower_action().await.is_err());
1722
1723 follower_pg_election
1725 .is_leader
1726 .store(true, Ordering::Relaxed);
1727 assert!(follower_pg_election.follower_action().await.is_err());
1728
1729 match rx.recv().await {
1730 Ok(LeaderChangeMessage::StepDown(key)) => {
1731 assert_eq!(String::from_utf8_lossy(key.name()), "test_follower");
1732 assert_eq!(
1733 String::from_utf8_lossy(key.key()),
1734 follower_pg_election.election_key()
1735 );
1736 assert_eq!(key.lease_id(), i64::default());
1737 assert_eq!(key.revision(), i64::default());
1738 }
1739 _ => panic!("Expected LeaderChangeMessage::StepDown"),
1740 }
1741
1742 leader_pg_election
1744 .pg_client
1745 .read()
1746 .await
1747 .query(&leader_pg_election.sql_set.step_down, &[])
1748 .await
1749 .unwrap();
1750
1751 drop_table(&follower_pg_election, table_name).await;
1752 }
1753
1754 #[tokio::test]
1755 async fn test_reset_campaign() {
1756 maybe_skip_postgres_integration_test!();
1757 let leader_value = "test_leader".to_string();
1758 let uuid = uuid::Uuid::new_v4().to_string();
1759 let table_name = "test_reset_campaign_greptime_metakv";
1760 let candidate_lease_ttl = Duration::from_secs(5);
1761 let execution_timeout = Duration::from_secs(10);
1762 let statement_timeout = Duration::from_secs(10);
1763 let meta_lease_ttl = Duration::from_secs(2);
1764 let idle_session_timeout = Duration::from_secs(0);
1765 let client = create_postgres_client(
1766 Some(table_name),
1767 execution_timeout,
1768 idle_session_timeout,
1769 statement_timeout,
1770 )
1771 .await
1772 .unwrap();
1773
1774 let (tx, _) = broadcast::channel(100);
1775 let leader_pg_election = PgElection {
1776 leader_value,
1777 pg_client: RwLock::new(client),
1778 is_leader: AtomicBool::new(false),
1779 leader_infancy: AtomicBool::new(true),
1780 leader_watcher: tx,
1781 store_key_prefix: uuid,
1782 candidate_lease_ttl,
1783 meta_lease_ttl,
1784 sql_set: ElectionSqlFactory::new(28325, None, table_name).build(),
1785 };
1786 let follower_client = create_postgres_client(
1787 None,
1788 execution_timeout,
1789 idle_session_timeout,
1790 statement_timeout,
1791 )
1792 .await
1793 .unwrap();
1794 for _ in 0..3 {
1795 let rows = leader_pg_election
1796 .pg_client
1797 .read()
1798 .await
1799 .query(&leader_pg_election.sql_set.campaign, &[])
1800 .await
1801 .unwrap();
1802 assert!(rows[0].get::<_, bool>(0));
1803 }
1804 leader_pg_election.is_leader.store(true, Ordering::Relaxed);
1805 leader_pg_election.reset_campaign().await;
1806 assert!(!leader_pg_election.is_leader());
1807 tokio::time::timeout(Duration::from_secs(5), async {
1809 loop {
1810 let rows = follower_client
1811 .query(&leader_pg_election.sql_set.campaign, &[])
1812 .await
1813 .unwrap();
1814 if rows[0].get::<_, bool>(0) {
1815 break;
1816 }
1817 tokio::time::sleep(Duration::from_millis(10)).await;
1818 }
1819 })
1820 .await
1821 .unwrap();
1822 follower_client
1823 .query(&leader_pg_election.sql_set.step_down, &[])
1824 .await
1825 .unwrap();
1826 drop_table(&leader_pg_election, table_name).await;
1827 }
1828
1829 #[tokio::test]
1830 async fn test_idle_session_timeout() {
1831 maybe_skip_postgres_integration_test!();
1832 common_telemetry::init_default_ut_logging();
1833 let execution_timeout = Duration::from_secs(10);
1834 let statement_timeout = Duration::from_secs(10);
1835 let idle_session_timeout = Duration::from_secs(1);
1836 let mut client = create_postgres_client(
1837 None,
1838 execution_timeout,
1839 idle_session_timeout,
1840 statement_timeout,
1841 )
1842 .await
1843 .unwrap();
1844 tokio::time::sleep(Duration::from_millis(1100)).await;
1845 let err = client.query("SELECT 1", &[]).await.unwrap_err();
1847 assert_matches!(err, error::Error::PostgresExecution { .. });
1848 let error::Error::PostgresExecution { error, .. } = err else {
1849 panic!("Expected PostgresExecution error");
1850 };
1851 assert!(error.is_closed());
1852 client.reset_client().await.unwrap();
1854 let _ = client.query("SELECT 1", &[]).await.unwrap();
1855 }
1856
1857 #[test]
1858 fn test_election_sql_with_schema() {
1859 let f = ElectionSqlFactory::new(42, Some("test_schema"), "greptime_metakv");
1860 let s = f.build();
1861 assert!(s.campaign.contains("pg_try_advisory_lock"));
1862 assert!(
1863 s.put_value_with_lease
1864 .contains("\"test_schema\".\"greptime_metakv\"")
1865 );
1866 assert!(
1867 s.update_value_with_lease
1868 .contains("\"test_schema\".\"greptime_metakv\"")
1869 );
1870 assert!(
1871 s.get_value_with_lease
1872 .contains("\"test_schema\".\"greptime_metakv\"")
1873 );
1874 assert!(
1875 s.get_value_with_lease_by_prefix
1876 .contains("\"test_schema\".\"greptime_metakv\"")
1877 );
1878 assert!(
1879 s.delete_value
1880 .contains("\"test_schema\".\"greptime_metakv\"")
1881 );
1882 }
1883}