Skip to main content

rocketmq_protocol/protocol/route/
route_data_view.rs

1// Copyright 2023 The RocketMQ Rust Authors
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::cmp::Ordering;
16use std::collections::HashMap;
17
18use crate::common::wire_constants::MASTER_ID;
19use cheetah_string::CheetahString;
20use serde::Deserialize;
21use serde::Serialize;
22
23#[derive(Debug, Clone, Serialize, Deserialize, Default)]
24pub struct BrokerData {
25    cluster: CheetahString,
26    #[serde(rename = "brokerName")]
27    broker_name: CheetahString,
28    #[serde(rename = "brokerAddrs")]
29    broker_addrs: HashMap<u64 /* broker id */, CheetahString /* broker ip */>,
30    #[serde(rename = "zoneName")]
31    zone_name: Option<CheetahString>,
32    #[serde(rename = "enableActingMaster")]
33    enable_acting_master: bool,
34}
35
36impl PartialEq for BrokerData {
37    fn eq(&self, other: &Self) -> bool {
38        self.broker_name == other.broker_name && self.broker_addrs == other.broker_addrs
39    }
40}
41
42impl Eq for BrokerData {}
43
44impl PartialOrd for BrokerData {
45    #[inline]
46    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
47        Some(self.cmp(other))
48    }
49}
50
51impl Ord for BrokerData {
52    #[inline]
53    fn cmp(&self, other: &Self) -> Ordering {
54        self.broker_name.cmp(&other.broker_name)
55    }
56}
57
58impl BrokerData {
59    pub fn new(
60        cluster: CheetahString,
61        broker_name: CheetahString,
62        broker_addrs: HashMap<u64, CheetahString>,
63        zone_name: Option<CheetahString>,
64    ) -> BrokerData {
65        BrokerData {
66            cluster,
67            broker_name,
68            broker_addrs,
69            zone_name,
70            enable_acting_master: false,
71        }
72    }
73
74    #[inline]
75    pub fn set_cluster(&mut self, cluster: CheetahString) {
76        self.cluster = cluster;
77    }
78
79    #[inline]
80    pub fn set_broker_name(&mut self, broker_name: CheetahString) {
81        self.broker_name = broker_name;
82    }
83
84    #[inline]
85    pub fn set_broker_addrs(&mut self, broker_addrs: HashMap<u64, CheetahString>) {
86        self.broker_addrs = broker_addrs;
87    }
88
89    #[inline]
90    pub fn set_zone_name(&mut self, zone_name: Option<CheetahString>) {
91        self.zone_name = zone_name;
92    }
93
94    #[inline]
95    pub fn set_enable_acting_master(&mut self, enable_acting_master: bool) {
96        self.enable_acting_master = enable_acting_master;
97    }
98
99    #[inline]
100    pub fn cluster(&self) -> &str {
101        &self.cluster
102    }
103
104    #[inline]
105    pub fn broker_name(&self) -> &CheetahString {
106        &self.broker_name
107    }
108
109    #[inline]
110    pub fn broker_addrs(&self) -> &HashMap<u64, CheetahString> {
111        &self.broker_addrs
112    }
113
114    #[inline]
115    pub fn broker_addrs_mut(&mut self) -> &mut HashMap<u64, CheetahString> {
116        &mut self.broker_addrs
117    }
118
119    #[inline]
120    pub fn remove_broker_by_addr(&mut self, broker_id: u64, broker_addr: &CheetahString) {
121        self.broker_addrs
122            .retain(|key, value| value != broker_addr || *key == broker_id);
123    }
124
125    #[inline]
126    pub fn zone_name(&self) -> Option<&CheetahString> {
127        self.zone_name.as_ref()
128    }
129
130    #[inline]
131    pub fn enable_acting_master(&self) -> bool {
132        self.enable_acting_master
133    }
134
135    pub fn select_broker_addr_with_index(&self, index: usize) -> Option<CheetahString> {
136        if let Some(master_address) = self.broker_addrs.get(&MASTER_ID) {
137            return Some(master_address.clone());
138        }
139        let mut slaves = self.broker_addrs.iter().collect::<Vec<_>>();
140        slaves.sort_unstable_by_key(|(id, _)| **id);
141        if slaves.is_empty() {
142            return None;
143        }
144        slaves.get(index % slaves.len()).map(|(_, value)| (*value).clone())
145    }
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Default)]
149pub struct QueueData {
150    #[serde(rename = "brokerName")]
151    pub broker_name: CheetahString,
152    #[serde(rename = "readQueueNums")]
153    pub read_queue_nums: u32,
154    #[serde(rename = "writeQueueNums")]
155    pub write_queue_nums: u32,
156    pub perm: u32,
157    #[serde(rename = "topicSysFlag")]
158    pub topic_sys_flag: u32,
159}
160
161impl QueueData {
162    pub fn new(
163        broker_name: CheetahString,
164        read_queue_nums: u32,
165        write_queue_nums: u32,
166        perm: u32,
167        topic_sys_flag: u32,
168    ) -> Self {
169        Self {
170            broker_name,
171            read_queue_nums,
172            write_queue_nums,
173            perm,
174            topic_sys_flag,
175        }
176    }
177
178    #[inline]
179    pub fn broker_name(&self) -> &CheetahString {
180        &self.broker_name
181    }
182
183    #[inline]
184    pub fn read_queue_nums(&self) -> u32 {
185        self.read_queue_nums
186    }
187
188    #[inline]
189    pub fn write_queue_nums(&self) -> u32 {
190        self.write_queue_nums
191    }
192
193    #[inline]
194    pub fn perm(&self) -> u32 {
195        self.perm
196    }
197
198    #[inline]
199    pub fn topic_sys_flag(&self) -> u32 {
200        self.topic_sys_flag
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use std::collections::HashMap;
207
208    use super::*;
209
210    #[test]
211    fn broker_data_methods_preserve_route_fields() {
212        let mut broker_data = BrokerData::new(
213            CheetahString::from("cluster1"),
214            CheetahString::from("broker1"),
215            HashMap::new(),
216            None,
217        );
218        assert_eq!(broker_data.cluster(), "cluster1");
219        assert_eq!(broker_data.broker_name(), "broker1");
220        assert!(broker_data.broker_addrs().is_empty());
221        assert_eq!(broker_data.zone_name(), None);
222        assert!(!broker_data.enable_acting_master());
223
224        broker_data.set_cluster(CheetahString::from("cluster2"));
225        broker_data.set_broker_name(CheetahString::from("broker2"));
226        broker_data.set_broker_addrs(HashMap::from([(1, CheetahString::from("127.0.0.1"))]));
227        broker_data
228            .broker_addrs_mut()
229            .insert(2, CheetahString::from("127.0.0.2"));
230        broker_data.set_zone_name(Some(CheetahString::from("zone1")));
231        broker_data.set_enable_acting_master(true);
232
233        assert_eq!(broker_data.cluster(), "cluster2");
234        assert_eq!(broker_data.broker_name(), "broker2");
235        assert_eq!(
236            broker_data.broker_addrs(),
237            &HashMap::from([
238                (1, CheetahString::from("127.0.0.1")),
239                (2, CheetahString::from("127.0.0.2")),
240            ])
241        );
242        assert_eq!(broker_data.zone_name(), Some(&CheetahString::from("zone1")));
243        assert!(broker_data.enable_acting_master());
244    }
245
246    #[test]
247    fn remove_broker_by_addr_keeps_the_current_id_only() {
248        let mut broker_data = BrokerData::new(
249            CheetahString::from("cluster1"),
250            CheetahString::from("broker1"),
251            HashMap::from([
252                (1, CheetahString::from("127.0.0.1")),
253                (2, CheetahString::from("127.0.0.1")),
254                (3, CheetahString::from("127.0.0.3")),
255            ]),
256            None,
257        );
258
259        broker_data.remove_broker_by_addr(1, &"127.0.0.1".into());
260        assert_eq!(
261            broker_data.broker_addrs(),
262            &HashMap::from([
263                (1, CheetahString::from("127.0.0.1")),
264                (3, CheetahString::from("127.0.0.3")),
265            ])
266        );
267    }
268
269    #[test]
270    fn select_broker_addr_prefers_master_and_indexes_slaves() {
271        let mut broker_data = BrokerData::new(
272            CheetahString::from("cluster1"),
273            CheetahString::from("broker1"),
274            HashMap::new(),
275            None,
276        );
277        assert_eq!(broker_data.select_broker_addr_with_index(0), None);
278
279        broker_data.set_broker_addrs(HashMap::from([
280            (4, CheetahString::from("127.0.0.4")),
281            (2, CheetahString::from("127.0.0.2")),
282        ]));
283        assert_eq!(
284            broker_data.select_broker_addr_with_index(0),
285            Some(CheetahString::from("127.0.0.2"))
286        );
287        assert_eq!(
288            broker_data.select_broker_addr_with_index(1),
289            Some(CheetahString::from("127.0.0.4"))
290        );
291        assert_eq!(
292            broker_data.select_broker_addr_with_index(2),
293            Some(CheetahString::from("127.0.0.2"))
294        );
295
296        broker_data
297            .broker_addrs_mut()
298            .insert(MASTER_ID, CheetahString::from("127.0.0.1"));
299        assert_eq!(
300            broker_data.select_broker_addr_with_index(1),
301            Some(CheetahString::from("127.0.0.1"))
302        );
303    }
304
305    #[test]
306    fn queue_data_methods_preserve_route_fields() {
307        let queue_data = QueueData::new(CheetahString::from("broker1"), 4, 4, 6, 0);
308
309        assert_eq!(queue_data.broker_name(), "broker1");
310        assert_eq!(queue_data.read_queue_nums(), 4);
311        assert_eq!(queue_data.write_queue_nums(), 4);
312        assert_eq!(queue_data.perm(), 6);
313        assert_eq!(queue_data.topic_sys_flag(), 0);
314    }
315}