]> git.proxmox.com Git - proxmox.git/commitdiff
RateLimitedStream: allow periodic limiter updates
authorDietmar Maurer <dietmar@proxmox.com>
Thu, 4 Nov 2021 09:36:41 +0000 (10:36 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Wed, 10 Nov 2021 08:51:08 +0000 (09:51 +0100)
proxmox-http/src/client/rate_limited_stream.rs

index 00ba0664484861867010ec989f182928ee9eb3c5..ea993832f7006a219edd39f448a96f25cd6b890f 100644 (file)
@@ -19,6 +19,8 @@ pub struct RateLimitedStream<S> {
     read_delay: Option<Pin<Box<Sleep>>>,
     write_limiter: Option<Arc<Mutex<RateLimiter>>>,
     write_delay: Option<Pin<Box<Sleep>>>,
+    update_limiter_cb: Option<Box<dyn Fn() -> (Option<Arc<Mutex<RateLimiter>>>, Option<Arc<Mutex<RateLimiter>>>) + Send>>,
+    last_limiter_update: Instant,
     stream: S,
 }
 
@@ -43,9 +45,44 @@ impl <S> RateLimitedStream<S> {
             read_delay: None,
             write_limiter,
             write_delay: None,
+            update_limiter_cb: None,
+            last_limiter_update: Instant::now(),
             stream,
         }
     }
+
+    /// Creates a new instance with limiter update callback.
+    ///
+    /// The fuction is called every minute to update/change the used limiters.
+    ///
+    /// Note: This function is called within an async context, so it
+    /// should be fast and must not block.
+    pub fn with_limiter_update_cb<F: Fn() -> (Option<Arc<Mutex<RateLimiter>>>, Option<Arc<Mutex<RateLimiter>>>) + Send + 'static>(
+        stream: S,
+        update_limiter_cb: F,
+    ) -> Self {
+        let (read_limiter, write_limiter) = update_limiter_cb();
+        Self {
+            read_limiter,
+            read_delay: None,
+            write_limiter,
+            write_delay: None,
+            update_limiter_cb: Some(Box::new(update_limiter_cb)),
+            last_limiter_update: Instant::now(),
+            stream,
+        }
+    }
+
+    fn update_limiters(&mut self) {
+        if let Some(ref update_limiter_cb) = self.update_limiter_cb {
+            if self.last_limiter_update.elapsed().as_secs() >= 5 {
+                self.last_limiter_update = Instant::now();
+                let (read_limiter, write_limiter) = update_limiter_cb();
+                self.read_limiter = read_limiter;
+                self.write_limiter = write_limiter;
+            }
+        }
+    }
 }
 
 fn register_traffic(
@@ -90,6 +127,8 @@ impl <S: AsyncWrite + Unpin> AsyncWrite for RateLimitedStream<S> {
 
         this.write_delay = None;
 
+        this.update_limiters();
+
         let result = Pin::new(&mut this.stream).poll_write(ctx, buf);
 
         if let Some(ref limiter) = this.write_limiter {
@@ -118,6 +157,8 @@ impl <S: AsyncWrite + Unpin> AsyncWrite for RateLimitedStream<S> {
 
         this.write_delay = None;
 
+        this.update_limiters();
+
         let result = Pin::new(&mut this.stream).poll_write_vectored(ctx, bufs);
 
         if let Some(ref limiter) = this.write_limiter {
@@ -161,6 +202,8 @@ impl <S: AsyncRead + Unpin> AsyncRead for RateLimitedStream<S> {
 
         this.read_delay = None;
 
+        this.update_limiters();
+
         let filled_len = buf.filled().len();
         let result = Pin::new(&mut this.stream).poll_read(ctx, buf);