Skip to content

Commit c341fbb

Browse files
authored
Fix race condition when selecting server (#273)
* Atomic get and update operation to select the server * Fix syntax error * Using mod * Run fmt * Do not rely on prev index
1 parent 80a848b commit c341fbb

1 file changed

Lines changed: 26 additions & 7 deletions

File tree

lib/src/routing/load_balancing/round_robin_strategy.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ impl RoundRobinStrategy {
3333
if used >= all_servers.len() {
3434
return None; // All servers have been used
3535
}
36-
let _ =
37-
index.compare_exchange(0, all_servers.len(), Ordering::Relaxed, Ordering::Relaxed);
38-
let i = index.fetch_sub(1, Ordering::Relaxed);
39-
if let Some(server) = all_servers.get(i - 1) {
36+
37+
let _ = index.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |i| {
38+
Some((i + all_servers.len() - 1) % all_servers.len())
39+
});
40+
41+
if let Some(server) = all_servers.get(index.load(Ordering::Relaxed)) {
4042
if servers.contains(server) {
4143
return Some(server.clone());
4244
}
@@ -203,17 +205,34 @@ mod tests {
203205
assert_eq!(all_readers.len(), 3);
204206
let strategy = RoundRobinStrategy::new(registry.clone());
205207

206-
// select a reader for db-1
208+
// select some readers for db-1
207209
let reader =
208210
RoundRobinStrategy::select(&all_readers, &servers1, &strategy.reader_index).unwrap();
209211
assert_eq!(reader.address, "server2");
210-
// select a reader for db-2
212+
let reader =
213+
RoundRobinStrategy::select(&all_readers, &servers1, &strategy.reader_index).unwrap();
214+
assert_eq!(reader.address, "server1");
215+
let reader =
216+
RoundRobinStrategy::select(&all_readers, &servers1, &strategy.reader_index).unwrap();
217+
assert_eq!(reader.address, "server2");
218+
219+
// select some readers for db-2
211220
let reader =
212221
RoundRobinStrategy::select(&all_readers, &servers2, &strategy.reader_index).unwrap();
213222
assert_eq!(reader.address, "server1");
214-
// select another reader for db-1
223+
let reader =
224+
RoundRobinStrategy::select(&all_readers, &servers2, &strategy.reader_index).unwrap();
225+
assert_eq!(reader.address, "server3");
226+
let reader =
227+
RoundRobinStrategy::select(&all_readers, &servers2, &strategy.reader_index).unwrap();
228+
assert_eq!(reader.address, "server1");
229+
230+
// select some other readers for db-1
215231
let reader =
216232
RoundRobinStrategy::select(&all_readers, &servers1, &strategy.reader_index).unwrap();
217233
assert_eq!(reader.address, "server2");
234+
let reader =
235+
RoundRobinStrategy::select(&all_readers, &servers1, &strategy.reader_index).unwrap();
236+
assert_eq!(reader.address, "server1");
218237
}
219238
}

0 commit comments

Comments
 (0)