1pub mod common;
16pub mod lease_based;
17pub mod load_based;
18pub mod round_robin;
19#[cfg(test)]
20pub(crate) mod test_utils;
21pub mod weight_compute;
22pub mod weighted_choose;
23use std::collections::HashSet;
24
25use serde::{Deserialize, Serialize};
26use store_api::storage::RegionId;
27use strum::AsRefStr;
28
29use crate::error;
30use crate::error::Result;
31
32#[async_trait::async_trait]
33pub trait Selector: Send + Sync {
34 type Context;
35 type Output;
36
37 async fn select(&self, ctx: &Self::Context, opts: SelectorOptions) -> Result<Self::Output>;
38}
39
40#[async_trait::async_trait]
45pub trait RegionStatAwareSelector: Send + Sync {
46 type Context;
47 type Output;
48
49 async fn select(
50 &self,
51 ctx: &Self::Context,
52 from_peer_id: u64,
53 region_ids: &[RegionId],
54 exclude_peer_ids: HashSet<u64>,
55 ) -> Result<Self::Output>;
56}
57
58#[derive(Debug)]
59pub struct SelectorOptions {
60 pub min_required_items: usize,
62 pub allow_duplication: bool,
64 pub exclude_peer_ids: HashSet<u64>,
66}
67
68impl Default for SelectorOptions {
69 fn default() -> Self {
70 Self {
71 min_required_items: 1,
72 allow_duplication: false,
73 exclude_peer_ids: HashSet::new(),
74 }
75 }
76}
77
78#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default, AsRefStr)]
80#[serde(try_from = "String")]
81pub enum SelectorType {
82 LoadBased,
86 LeaseBased,
89 #[default]
93 RoundRobin,
94}
95
96impl TryFrom<&str> for SelectorType {
97 type Error = error::Error;
98
99 fn try_from(value: &str) -> Result<Self> {
100 match value {
101 "load_based" | "LoadBased" => Ok(SelectorType::LoadBased),
102 "lease_based" | "LeaseBased" => Ok(SelectorType::LeaseBased),
103 "round_robin" | "RoundRobin" => Ok(SelectorType::RoundRobin),
104 other => error::UnsupportedSelectorTypeSnafu {
105 selector_type: other,
106 }
107 .fail(),
108 }
109 }
110}
111
112impl TryFrom<String> for SelectorType {
113 type Error = error::Error;
114
115 fn try_from(value: String) -> Result<Self> {
116 SelectorType::try_from(value.as_str())
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::SelectorType;
123 use crate::error::Result;
124
125 #[test]
126 fn test_default_selector_type() {
127 assert_eq!(SelectorType::RoundRobin, SelectorType::default());
128 }
129
130 #[test]
131 fn test_convert_str_to_selector_type() {
132 let lease_based = "lease_based";
133 let selector_type = lease_based.try_into().unwrap();
134 assert_eq!(SelectorType::LeaseBased, selector_type);
135 let lease_based = "LeaseBased";
136 let selector_type = lease_based.try_into().unwrap();
137 assert_eq!(SelectorType::LeaseBased, selector_type);
138
139 let load_based = "load_based";
140 let selector_type = load_based.try_into().unwrap();
141 assert_eq!(SelectorType::LoadBased, selector_type);
142 let load_based = "LoadBased";
143 let selector_type = load_based.try_into().unwrap();
144 assert_eq!(SelectorType::LoadBased, selector_type);
145
146 let unknown = "unknown";
147 let selector_type: Result<SelectorType> = unknown.try_into();
148 assert!(selector_type.is_err());
149 }
150}