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) => State::Leader(LeaderState { ..leader.clone() }),
102 State::Follower(follower) => State::Leader(LeaderState {
103 server_addr: follower.server_addr.clone(),
104 enable_leader_cache,
105 }),
106 }
107}
108
109pub fn become_follower() -> impl FnOnce(&State) -> State {
110 move |prev| match prev {
111 State::Leader(leader) => State::Follower(FollowerState {
112 server_addr: leader.server_addr.clone(),
113 }),
114 State::Follower(follower) => State::Follower(FollowerState { ..follower.clone() }),
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use std::assert_matches::assert_matches;
121
122 use crate::state::{FollowerState, LeaderState, State, become_follower, become_leader};
123
124 #[tokio::test]
125 async fn test_next_state() {
126 let mut state = State::follower("test".to_string());
127
128 state.next_state(become_leader(false));
129
130 assert_matches!(
131 state,
132 State::Leader(LeaderState {
133 enable_leader_cache: false,
134 ..
135 })
136 );
137
138 state.next_state(become_leader(false));
139
140 assert_matches!(
141 state,
142 State::Leader(LeaderState {
143 enable_leader_cache: false,
144 ..
145 })
146 );
147
148 state.next_state(become_follower());
149
150 assert_matches!(state, State::Follower(FollowerState { .. }));
151
152 state.next_state(become_follower());
153
154 assert_matches!(state, State::Follower(FollowerState { .. }));
155 }
156}