@@ -21,13 +21,15 @@ use std::hash::Hash;
2121use std:: sync:: { Arc , RwLock } ;
2222
2323use futures:: { Stream , StreamExt } ;
24+ use tokio:: sync:: watch;
2425
2526use 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.
2930pub struct Pool < K , V > {
3031 pool : Arc < RwLock < HashMap < K , V > > > ,
32+ generation_tx : watch:: Sender < u64 > ,
3133}
3234
3335impl < 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>
5255where 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}
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