Skip to content

Commit 7ccf3d7

Browse files
committed
fix(control-plane): debounce ingester pool rebalances
1 parent 30f075b commit 7ccf3d7

6 files changed

Lines changed: 136 additions & 222 deletions

File tree

quickwit/quickwit-cluster/src/change.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ async fn try_new_node(
328328
#[cfg(any(test, feature = "testsuite"))]
329329
pub mod for_test {
330330
use quickwit_config::GrpcConfig;
331-
use tokio::sync::mpsc;
332331

333332
use super::*;
334333

@@ -337,21 +336,6 @@ pub mod for_test {
337336
ChannelFactory::for_grpc(&GrpcConfig::default())
338337
.expect("plaintext channel factory should build")
339338
}
340-
341-
pub struct ClusterChangeStreamForTest {
342-
pub cluster_change_rx: ClusterChangeStream,
343-
pub cluster_change_tx: mpsc::UnboundedSender<ClusterChange>,
344-
}
345-
346-
impl Default for ClusterChangeStreamForTest {
347-
fn default() -> Self {
348-
let (cluster_change_rx, cluster_change_tx) = ClusterChangeStream::new_unbounded();
349-
Self {
350-
cluster_change_rx,
351-
cluster_change_tx,
352-
}
353-
}
354-
}
355339
}
356340

357341
#[cfg(test)]

quickwit/quickwit-common/src/tower/pool.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ use std::hash::Hash;
2121
use std::sync::{Arc, RwLock};
2222

2323
use futures::{Stream, StreamExt};
24+
use tokio::sync::watch;
2425

2526
use super::Change;
2627

2728
/// A pool of `V` values identified by `K` keys. The pool can be updated manually by calling the
2829
/// `add/remove` methods or by listening to a stream of changes.
2930
pub struct Pool<K, V> {
3031
pool: Arc<RwLock<HashMap<K, V>>>,
32+
generation_tx: watch::Sender<u64>,
3133
}
3234

3335
impl<K, V> fmt::Debug for Pool<K, V>
@@ -44,6 +46,7 @@ impl<K, V> Clone for Pool<K, V> {
4446
fn clone(&self) -> Self {
4547
Self {
4648
pool: self.pool.clone(),
49+
generation_tx: self.generation_tx.clone(),
4750
}
4851
}
4952
}
@@ -52,8 +55,10 @@ impl<K, V> Default for Pool<K, V>
5255
where K: Eq + PartialEq + Hash
5356
{
5457
fn default() -> Self {
58+
let (generation_tx, _generation_rx) = watch::channel(0);
5559
Self {
5660
pool: Arc::new(RwLock::new(HashMap::default())),
61+
generation_tx,
5762
}
5863
}
5964
}
@@ -86,6 +91,24 @@ where
8691
tokio::spawn(future);
8792
}
8893

94+
/// Returns the current pool generation.
95+
pub fn generation(&self) -> u64 {
96+
*self.generation_tx.borrow()
97+
}
98+
99+
/// Subscribes to pool generation changes.
100+
pub fn subscribe(&self) -> watch::Receiver<u64> {
101+
self.generation_tx.subscribe()
102+
}
103+
104+
fn increment_generation(&self) {
105+
self.generation_tx.send_modify(|generation| {
106+
*generation = generation
107+
.checked_add(1)
108+
.expect("pool generation should not overflow")
109+
});
110+
}
111+
89112
/// Returns whether the pool is empty.
90113
pub fn is_empty(&self) -> bool {
91114
self.pool
@@ -180,14 +203,19 @@ where
180203
.write()
181204
.expect("lock should not be poisoned")
182205
.insert(key, service);
206+
self.increment_generation();
183207
}
184208

185209
/// Removes a value from the pool.
186210
fn remove(&self, key: &K) {
187-
self.pool
211+
let removed = self
212+
.pool
188213
.write()
189214
.expect("lock should not be poisoned")
190215
.remove(key);
216+
if removed.is_some() {
217+
self.increment_generation();
218+
}
191219
}
192220
}
193221

@@ -196,8 +224,10 @@ where K: Eq + PartialEq + Hash
196224
{
197225
fn from_iter<I>(iter: I) -> Self
198226
where I: IntoIterator<Item = (K, V)> {
227+
let (generation_tx, _generation_rx) = watch::channel(0);
199228
Self {
200229
pool: Arc::new(RwLock::new(HashMap::from_iter(iter))),
230+
generation_tx,
201231
}
202232
}
203233
}
@@ -210,6 +240,32 @@ mod tests {
210240

211241
use super::*;
212242

243+
#[tokio::test]
244+
async fn test_pool_generation() {
245+
let pool = Pool::default();
246+
let mut generation_rx = pool.subscribe();
247+
248+
assert_eq!(pool.generation(), 0);
249+
250+
pool.insert(1, 11);
251+
generation_rx.changed().await.unwrap();
252+
assert_eq!(*generation_rx.borrow_and_update(), 1);
253+
assert_eq!(pool.get(&1), Some(11));
254+
255+
pool.insert(1, 12);
256+
generation_rx.changed().await.unwrap();
257+
assert_eq!(*generation_rx.borrow_and_update(), 2);
258+
assert_eq!(pool.get(&1), Some(12));
259+
260+
pool.remove(&2);
261+
assert_eq!(pool.generation(), 2);
262+
263+
pool.remove(&1);
264+
generation_rx.changed().await.unwrap();
265+
assert_eq!(*generation_rx.borrow_and_update(), 3);
266+
assert!(!pool.contains_key(&1));
267+
}
268+
213269
#[tokio::test]
214270
async fn test_pool() {
215271
let (change_stream_tx, change_stream_rx) = tokio::sync::mpsc::channel(10);

0 commit comments

Comments
 (0)