@@ -21,13 +21,18 @@ 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+ /// Publishes the pool generation after each mutation.
33+ pub generation_tx : watch:: Sender < u64 > ,
34+ /// Receives pool generation changes.
35+ pub generation_rx : watch:: Receiver < u64 > ,
3136}
3237
3338impl < K , V > fmt:: Debug for Pool < K , V >
@@ -44,16 +49,22 @@ impl<K, V> Clone for Pool<K, V> {
4449 fn clone ( & self ) -> Self {
4550 Self {
4651 pool : self . pool . clone ( ) ,
52+ generation_tx : self . generation_tx . clone ( ) ,
53+ generation_rx : self . generation_rx . clone ( ) ,
4754 }
4855 }
4956}
5057
5158impl < K , V > Default for Pool < K , V >
52- where K : Eq + PartialEq + Hash
59+ where
60+ K : Eq + PartialEq + Hash ,
5361{
5462 fn default ( ) -> Self {
63+ let ( generation_tx, generation_rx) = watch:: channel ( 1 ) ;
5564 Self {
5665 pool : Arc :: new ( RwLock :: new ( HashMap :: default ( ) ) ) ,
66+ generation_tx,
67+ generation_rx,
5768 }
5869 }
5970}
8697 tokio:: spawn ( future) ;
8798 }
8899
100+ /// Returns the current pool generation.
101+ pub fn generation ( & self ) -> u64 {
102+ * self . generation_rx . borrow ( )
103+ }
104+
105+ fn increment_generation ( & self ) {
106+ self . generation_tx . send_modify ( |generation| {
107+ * generation = generation
108+ . checked_add ( 1 )
109+ . expect ( "pool generation should not overflow" )
110+ } ) ;
111+ }
112+
89113 /// Returns whether the pool is empty.
90114 pub fn is_empty ( & self ) -> bool {
91115 self . pool
@@ -165,12 +189,12 @@ where
165189 }
166190
167191 /// Finds a key in the pool that satisfies the given predicate.
168- pub fn find ( & self , func : impl Fn ( & K , & V ) -> bool ) -> Option < ( K , V ) > {
192+ pub fn find ( & self , predicate_fn : impl Fn ( & K , & V ) -> bool ) -> Option < ( K , V ) > {
169193 self . pool
170194 . read ( )
171195 . expect ( "lock should not be poisoned" )
172196 . iter ( )
173- . find ( |( key, value) | func ( key, value) )
197+ . find ( |( key, value) | predicate_fn ( key, value) )
174198 . map ( |( key, value) | ( key. clone ( ) , value. clone ( ) ) )
175199 }
176200
@@ -180,24 +204,35 @@ where
180204 . write ( )
181205 . expect ( "lock should not be poisoned" )
182206 . insert ( key, service) ;
207+ self . increment_generation ( ) ;
183208 }
184209
185210 /// Removes a value from the pool.
186211 fn remove ( & self , key : & K ) {
187- self . pool
212+ let removed = self
213+ . pool
188214 . write ( )
189215 . expect ( "lock should not be poisoned" )
190216 . remove ( key) ;
217+ if removed. is_some ( ) {
218+ self . increment_generation ( ) ;
219+ }
191220 }
192221}
193222
194223impl < K , V > FromIterator < ( K , V ) > for Pool < K , V >
195- where K : Eq + PartialEq + Hash
224+ where
225+ K : Eq + PartialEq + Hash ,
196226{
197227 fn from_iter < I > ( iter : I ) -> Self
198- where I : IntoIterator < Item = ( K , V ) > {
228+ where
229+ I : IntoIterator < Item = ( K , V ) > ,
230+ {
231+ let ( generation_tx, generation_rx) = watch:: channel ( 0 ) ;
199232 Self {
200233 pool : Arc :: new ( RwLock :: new ( HashMap :: from_iter ( iter) ) ) ,
234+ generation_tx,
235+ generation_rx,
201236 }
202237 }
203238}
@@ -210,6 +245,32 @@ mod tests {
210245
211246 use super :: * ;
212247
248+ #[ tokio:: test]
249+ async fn test_pool_generation ( ) {
250+ let pool = Pool :: default ( ) ;
251+ let mut generation_rx = pool. generation_rx . clone ( ) ;
252+
253+ assert_eq ! ( pool. generation( ) , 0 ) ;
254+
255+ pool. insert ( 1 , 11 ) ;
256+ generation_rx. changed ( ) . await . unwrap ( ) ;
257+ assert_eq ! ( * generation_rx. borrow_and_update( ) , 1 ) ;
258+ assert_eq ! ( pool. get( & 1 ) , Some ( 11 ) ) ;
259+
260+ pool. insert ( 1 , 12 ) ;
261+ generation_rx. changed ( ) . await . unwrap ( ) ;
262+ assert_eq ! ( * generation_rx. borrow_and_update( ) , 2 ) ;
263+ assert_eq ! ( pool. get( & 1 ) , Some ( 12 ) ) ;
264+
265+ pool. remove ( & 2 ) ;
266+ assert_eq ! ( pool. generation( ) , 2 ) ;
267+
268+ pool. remove ( & 1 ) ;
269+ generation_rx. changed ( ) . await . unwrap ( ) ;
270+ assert_eq ! ( * generation_rx. borrow_and_update( ) , 3 ) ;
271+ assert ! ( !pool. contains_key( & 1 ) ) ;
272+ }
273+
213274 #[ tokio:: test]
214275 async fn test_pool ( ) {
215276 let ( change_stream_tx, change_stream_rx) = tokio:: sync:: mpsc:: channel ( 10 ) ;
0 commit comments