Skip to main content

meta_srv/
state.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, RwLock};
16
17pub type StateRef = Arc<RwLock<State>>;
18
19/// State transition.
20/// ```text
21///                     +------------------------------+
22///                     |                              |
23///                     |                              |
24///                     |                              |
25/// +-------------------v--------------------+         |
26/// | LeaderState{enable_leader_cache:false} |         |
27/// +-------------------+--------------------+         |
28///                     |                              |
29///                     |                              |
30///           +---------v---------+                    |
31///           | Init Leader Cache |                    |
32///           +---------+---------+                    |
33///                     |                              |
34///                     |                              |
35/// +-------------------v-------------------+          |
36/// | LeaderState{enable_leader_cache:true} |          |
37/// +-------------------+-------------------+          |
38///                     |                              |
39///                     |                              |
40///             +-------v-------+                      |
41///             | FollowerState |                      |
42///             +-------+-------+                      |
43///                     |                              |
44///                     |                              |
45///                     +------------------------------+
46///```
47#[derive(Debug, Clone)]
48pub enum State {
49    Leader(LeaderState),
50    Follower(FollowerState),
51}
52
53#[derive(Debug, Clone)]
54pub struct LeaderState {
55    // Disables the leader cache during initiation
56    pub enable_leader_cache: bool,
57
58    pub server_addr: String,
59}
60
61#[derive(Debug, Clone)]
62pub struct FollowerState {
63    pub server_addr: String,
64}
65
66impl State {
67    pub fn follower(server_addr: String) -> State {
68        Self::Follower(FollowerState { server_addr })
69    }
70
71    pub fn leader(server_addr: String, enable_leader_cache: bool) -> State {
72        Self::Leader(LeaderState {
73            enable_leader_cache,
74            server_addr,
75        })
76    }
77
78    /// Returns true if the current state is a leader.
79    pub fn is_leader(&self) -> bool {
80        matches!(self, State::Leader(_))
81    }
82
83    /// Returns true if the leader cache is enabled.
84    pub fn enable_leader_cache(&self) -> bool {
85        match &self {
86            State::Leader(leader) => leader.enable_leader_cache,
87            State::Follower(_) => false,
88        }
89    }
90
91    pub fn next_state<F>(&mut self, f: F)
92    where
93        F: FnOnce(&State) -> State,
94    {
95        *self = f(self);
96    }
97}
98
99pub fn become_leader(enable_leader_cache: bool) -> impl FnOnce(&State) -> State {
100    move |prev| match prev {
101        State::Leader(leader) => {
102            let mut new_leader = leader.clone();
103            new_leader.enable_leader_cache = enable_leader_cache;
104            State::Leader(new_leader)
105        }
106        State::Follower(follower) => State::Leader(LeaderState {
107            server_addr: follower.server_addr.clone(),
108            enable_leader_cache,
109        }),
110    }
111}
112
113pub fn become_follower() -> impl FnOnce(&State) -> State {
114    move |prev| match prev {
115        State::Leader(leader) => State::Follower(FollowerState {
116            server_addr: leader.server_addr.clone(),
117        }),
118        State::Follower(follower) => State::Follower(FollowerState { ..follower.clone() }),
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use std::assert_matches;
125
126    use crate::state::{FollowerState, LeaderState, State, become_follower, become_leader};
127
128    #[tokio::test]
129    async fn test_next_state() {
130        let mut state = State::follower("test".to_string());
131
132        state.next_state(become_leader(false));
133
134        assert_matches!(
135            state,
136            State::Leader(LeaderState {
137                enable_leader_cache: false,
138                ..
139            })
140        );
141
142        state.next_state(become_leader(false));
143
144        assert_matches!(
145            state,
146            State::Leader(LeaderState {
147                enable_leader_cache: false,
148                ..
149            })
150        );
151
152        state.next_state(become_follower());
153
154        assert_matches!(state, State::Follower(FollowerState { .. }));
155
156        state.next_state(become_follower());
157
158        assert_matches!(state, State::Follower(FollowerState { .. }));
159    }
160}