1use serde::{Deserialize, Serialize};
11
12use crate::{DatabaseId, Lsn};
13
14#[derive(
19 Debug,
20 Clone,
21 PartialEq,
22 Eq,
23 Serialize,
24 Deserialize,
25 zerompk::ToMessagePack,
26 zerompk::FromMessagePack,
27)]
28#[msgpack(map)]
29pub struct MirrorOrigin {
30 pub source_cluster: String,
32 pub source_database: DatabaseId,
34 pub mode: MirrorMode,
36 pub last_applied: Lsn,
38 pub status: MirrorStatus,
40}
41
42#[derive(
47 Debug,
48 Clone,
49 Copy,
50 PartialEq,
51 Eq,
52 Serialize,
53 Deserialize,
54 zerompk::ToMessagePack,
55 zerompk::FromMessagePack,
56)]
57pub enum MirrorMode {
58 Sync,
61 Async,
63}
64
65#[derive(
70 Debug,
71 Clone,
72 PartialEq,
73 Eq,
74 Serialize,
75 Deserialize,
76 zerompk::ToMessagePack,
77 zerompk::FromMessagePack,
78)]
79pub enum MirrorStatus {
80 Bootstrapping {
82 bytes_done: u64,
84 bytes_total: u64,
86 },
87 Following,
89 Degraded {
91 lag_ms: u64,
93 },
94 Disconnected,
96 Promoted,
99}
100
101#[derive(
106 Debug,
107 Clone,
108 PartialEq,
109 Eq,
110 Serialize,
111 Deserialize,
112 zerompk::ToMessagePack,
113 zerompk::FromMessagePack,
114)]
115#[msgpack(map)]
116pub struct MirrorLagRecord {
117 pub last_applied_lsn: Lsn,
119 pub last_apply_ms: u64,
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 fn round_trip_msgpack<T>(val: &T) -> T
128 where
129 T: zerompk::ToMessagePack + for<'a> zerompk::FromMessagePack<'a>,
130 {
131 let bytes = zerompk::to_msgpack_vec(val).expect("serialize");
132 zerompk::from_msgpack(&bytes).expect("deserialize")
133 }
134
135 fn round_trip_serde<T>(val: &T) -> T
136 where
137 T: Serialize + for<'de> Deserialize<'de>,
138 {
139 let json = sonic_rs::to_string(val).expect("serde serialize");
140 sonic_rs::from_str(&json).expect("serde deserialize")
141 }
142
143 fn sample_origin() -> MirrorOrigin {
144 MirrorOrigin {
145 source_cluster: "prod-us".to_string(),
146 source_database: DatabaseId::DEFAULT,
147 mode: MirrorMode::Async,
148 last_applied: Lsn::new(12_345),
149 status: MirrorStatus::Following,
150 }
151 }
152
153 #[test]
154 fn mirror_mode_msgpack_roundtrip() {
155 assert_eq!(round_trip_msgpack(&MirrorMode::Sync), MirrorMode::Sync);
156 assert_eq!(round_trip_msgpack(&MirrorMode::Async), MirrorMode::Async);
157 }
158
159 #[test]
160 fn mirror_mode_serde_roundtrip() {
161 assert_eq!(round_trip_serde(&MirrorMode::Sync), MirrorMode::Sync);
162 assert_eq!(round_trip_serde(&MirrorMode::Async), MirrorMode::Async);
163 }
164
165 #[test]
166 fn mirror_status_following_msgpack() {
167 let s = MirrorStatus::Following;
168 assert_eq!(round_trip_msgpack(&s), s);
169 }
170
171 #[test]
172 fn mirror_status_bootstrapping_msgpack() {
173 let s = MirrorStatus::Bootstrapping {
174 bytes_done: 1024,
175 bytes_total: 4096,
176 };
177 assert_eq!(round_trip_msgpack(&s), s);
178 }
179
180 #[test]
181 fn mirror_status_degraded_msgpack() {
182 let s = MirrorStatus::Degraded { lag_ms: 7500 };
183 assert_eq!(round_trip_msgpack(&s), s);
184 }
185
186 #[test]
187 fn mirror_status_disconnected_msgpack() {
188 let s = MirrorStatus::Disconnected;
189 assert_eq!(round_trip_msgpack(&s), s);
190 }
191
192 #[test]
193 fn mirror_status_promoted_msgpack() {
194 let s = MirrorStatus::Promoted;
195 assert_eq!(round_trip_msgpack(&s), s);
196 }
197
198 #[test]
199 fn mirror_status_serde_roundtrip() {
200 for s in [
201 MirrorStatus::Following,
202 MirrorStatus::Bootstrapping {
203 bytes_done: 0,
204 bytes_total: 0,
205 },
206 MirrorStatus::Degraded { lag_ms: 5001 },
207 MirrorStatus::Disconnected,
208 MirrorStatus::Promoted,
209 ] {
210 assert_eq!(round_trip_serde(&s), s);
211 }
212 }
213
214 #[test]
215 fn mirror_origin_msgpack_roundtrip() {
216 let o = sample_origin();
217 assert_eq!(round_trip_msgpack(&o), o);
218 }
219
220 #[test]
221 fn mirror_origin_serde_roundtrip() {
222 let o = sample_origin();
223 assert_eq!(round_trip_serde(&o), o);
224 }
225}