Skip to main content

common_meta/election/rds/
postgres.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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    // SQL to put a value with expire time.
50    //
51    // Parameters for the query:
52    // `$1`: key,
53    // `$2`: value,
54    // `$3`: lease time in seconds
55    //
56    // Returns:
57    // If the key already exists, return the previous value.
58    put_value_with_lease: String,
59    // SQL to update a value with expire time.
60    //
61    // Parameters for the query:
62    // `$1`: key,
63    // `$2`: previous value,
64    // `$3`: updated value,
65    // `$4`: lease time in seconds
66    update_value_with_lease: String,
67    // SQL to get a value with expire time.
68    //
69    // Parameters:
70    // `$1`: key
71    get_value_with_lease: String,
72    // SQL to get all values with expire time with the given key prefix.
73    //
74    // Parameters:
75    // `$1`: key prefix like 'prefix%'
76    //
77    // Returns:
78    // column 0: value,
79    // column 1: current timestamp
80    get_value_with_lease_by_prefix: String,
81    // SQL to delete a value.
82    //
83    // Parameters:
84    // `$1`: key
85    //
86    // Returns:
87    // column 0: key deleted,
88    // column 1: value deleted
89    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        // Campaigning repeatedly acquires the same session-level lock. Release
126        // every acquisition when stepping down, not just the most recent one.
127        "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
183/// PgClient for election.
184///
185/// The session is dedicated to election and candidate registration. It must not
186/// hold unrelated advisory locks, as stepping down releases all session locks.
187pub struct ElectionPgClient {
188    current: Option<deadpool::managed::Object<Manager>>,
189    pool: Pool,
190    /// The client-side timeout for statement execution.
191    ///
192    /// This timeout is enforced by the client application and is independent of any server-side timeouts.
193    /// If a statement takes longer than this duration to execute, the client will abort the operation.
194    execution_timeout: Duration,
195
196    /// The idle session timeout.
197    ///
198    /// This timeout is configured per client session and is enforced by the PostgreSQL server.
199    /// If a session remains idle for longer than this duration, the server will terminate it.
200    idle_session_timeout: Duration,
201
202    /// The statement timeout.
203    ///
204    /// This timeout is configured per client session and is enforced by the PostgreSQL server.
205    /// If a statement takes longer than this duration to execute, the server will abort it.
206    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            // Remove the connection from deadpool and drop it,
242            // forcing TCP close and backend termination.
243            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            // Set idle session timeout and statement timeout.
255            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    /// Returns the result of the query.
265    ///
266    /// # Panics
267    /// if `current` is `None`.
268    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    /// Returns the result of the query.
286    ///
287    /// # Panics
288    /// if `current` is `None`.
289    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
307/// PostgreSql implementation of Election.
308pub 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        // May registered before, just update the lease.
398        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        // Check if the current lease has expired and renew the lease.
405        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            // Safety: origin is Some since we are using `get_value_with_lease` with `true`.
427            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        // Remove expired candidates
436        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    /// Attempts to acquire leadership by executing a campaign. This function continuously checks
449    /// if the current instance can become the leader by acquiring an advisory lock in the PostgreSQL database.
450    ///
451    /// The function operates in a loop, where it:
452    ///
453    /// 1. Waits for a predefined interval before attempting to acquire the lock again.
454    /// 2. Executes the `CAMPAIGN` SQL query to try to acquire the advisory lock.
455    /// 3. Checks the result of the query:
456    ///    - If the lock is successfully acquired (result is true), it calls the `leader_action` method
457    ///      to perform actions as the leader.
458    ///    - If the lock is not acquired (result is false), it calls the `follower_action` method
459    ///      to perform actions as a follower.
460    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    /// Returns value, expire time and current time. If `with_origin` is true, the origin string is also returned.
528    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            // Safety: Checked if res is empty above.
542            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            // Safety: Checked if res is empty above.
551            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    /// Returns all values and expire time with the given key prefix. Also returns the current time.
565    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    /// Returns `true` if the insertion is successful
630    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, &params)
645            .await?;
646        Ok(res.is_empty())
647    }
648
649    /// Returns `true` if the deletion is successful.
650    /// Caution: Should only delete the key if the lease is expired.
651    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    /// Handles the actions of a leader in the election process.
665    ///
666    /// This function performs the following checks and actions:
667    ///
668    /// - **Case 1**: If the current instance believes it is the leader from the previous term,
669    ///   it attempts to renew the lease. It checks if the lease is still valid and either renews it
670    ///   or steps down if it has expired.
671    ///
672    ///   - **Case 1.1**: If the instance is still the leader and the lease is valid, it renews the lease
673    ///     by updating the value associated with the election key.
674    ///   - **Case 1.2**: If the instance is still the leader but the lease has expired, it logs a warning
675    ///     and steps down, initiating a new campaign for leadership.
676    ///   - **Case 1.3**: If the instance is not the leader (which is a rare scenario), it logs a warning
677    ///     indicating that it still holds the lock and steps down to re-initiate the campaign. This may
678    ///     happen if the leader has failed to renew the lease and the session has expired, and recovery
679    ///     after a period of time during which other leaders have been elected and stepped down.
680    ///   - **Case 1.4**: If no lease information is found, it also steps down and re-initiates the campaign.
681    ///
682    /// - **Case 2**: If the current instance is not leader previously, it calls the `elected` method
683    ///   as a newly elected leader.
684    async fn leader_action(&self) -> Result<()> {
685        let key = self.election_key();
686        // Case 1
687        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                        // Case 1.1
695                        (true, true) => {
696                            // Safety: prev is Some since we are using `get_value_with_lease` with `true`.
697                            self.update_value_with_lease(
698                                &key,
699                                &lease.origin,
700                                &self.leader_value,
701                                self.meta_lease_ttl,
702                            )
703                            .await?;
704                        }
705                        // Case 1.2
706                        (true, false) => {
707                            warn!("Leader lease expired, now stepping down.");
708                            self.step_down().await?;
709                        }
710                        // Case 1.3
711                        (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                // Case 1.4
720                None => {
721                    warn!("Leader lease not found, but still hold the lock. Now stepping down.");
722                    self.step_down().await?;
723                }
724            }
725        // Case 2
726        } else {
727            self.elected().await?;
728        }
729        Ok(())
730    }
731
732    /// Handles the actions of a follower in the election process.
733    ///
734    /// This function performs the following checks and actions:
735    ///
736    /// - **Case 1**: If the current instance believes it is the leader from the previous term,
737    ///   it steps down without deleting the key.
738    /// - **Case 2**: If the current instance is not the leader but the lease has expired, it raises an error
739    ///   to re-initiate the campaign. If the leader failed to renew the lease, its session will expire and the lock
740    ///   will be released.
741    /// - **Case 3**: If all checks pass, the function returns without performing any actions.
742    async fn follower_action(&self) -> Result<()> {
743        let key = self.election_key();
744        // Case 1
745        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        // Case 2
753        ensure!(lease.expire_time > lease.current, ElectionNoLeaderSnafu);
754        // Case 3
755        Ok(())
756    }
757
758    /// Step down the leader. The leader should delete the key and notify the leader watcher.
759    ///
760    /// __DO NOT__ check if the deletion is successful, since the key may be deleted by others elected.
761    ///
762    /// ## Caution:
763    /// Should only step down while holding the advisory lock.
764    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    /// Still consider itself as the leader locally but failed to acquire the lock. Step down without deleting the key.
788    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    /// Elected as leader. The leader should put the key and notify the leader watcher.
805    /// Caution: Should only elected while holding the advisory lock.
806    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        // Wait for candidates to register themselves and renew their leases at least once.
1059        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        // Wait for the candidate leases to expire.
1083        tokio::time::sleep(Duration::from_secs(5)).await;
1084        let candidates = pg_election.all_candidates().await.unwrap();
1085        assert!(candidates.is_empty());
1086
1087        // Garbage collection
1088        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        // Step 1: No leader exists, campaign and elected.
1256        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        // Lease timestamps have millisecond precision. Wait for the database
1289        // clock to advance before checking that renewal extends the lease.
1290        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        // Step 2: As a leader, renew the lease.
1307        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        // Step 3: Something wrong, the leader lease expired.
1329        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        // Step 4: Re-campaign and elected.
1361        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        // Step 5: Something wrong, the leader key is deleted by other followers.
1394        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        // Step 6: Re-campaign and elected.
1420        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        // Step 7: Something wrong, the leader key changed by others.
1453        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        // Clean up
1496        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            // Keep both sessions alive so idle timeout cannot hide a leaked lock.
1518            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            // Repeat the same acquisition performed on every campaign iteration.
1550            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            // An unrelated lock in another session must survive the demotion.
1576            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            // Expire the lease explicitly instead of relying on scheduling delays.
1586            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        // Step 1: As a follower, the leader exists and the lease is not expired.
1710        follower_pg_election.follower_action().await.unwrap();
1711
1712        // Step 2: As a follower, the leader exists but the lease expired.
1713        tokio::time::sleep(Duration::from_secs(2)).await;
1714        assert!(follower_pg_election.follower_action().await.is_err());
1715
1716        // Step 3: As a follower, the leader does not exist.
1717        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        // Step 4: Follower thinks it's the leader but failed to acquire the lock.
1724        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        // Clean up
1743        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        // Closing the old session is asynchronous. Wait until its locks are released.
1808        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        // Wait for the idle session timeout.
1846        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        // Reset the client and try again.
1853        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}