bryancall commented on code in PR #11271:
URL: https://github.com/apache/trafficserver/pull/11271#discussion_r1575406770


##########
plugins/experimental/rate_limit/limiter.h:
##########
@@ -24,16 +24,129 @@
 #include <string>
 #include <climits>
 #include <mutex>
+#include <thread>
 
 #include "tscore/ink_config.h"
 #include "ts/ts.h"
 #include <yaml-cpp/yaml.h>
 #include "utilities.h"
 
-constexpr auto QUEUE_DELAY_TIME = std::chrono::milliseconds{300}; // Examine 
the queue every 300ms
-using QueueTime                 = 
std::chrono::time_point<std::chrono::system_clock>;
+constexpr auto BUCKET_REFILL_INTERVAL = std::chrono::milliseconds{25};  // 
Increase rate limit buckets every 25ms
+constexpr auto QUEUE_DELAY_TIME       = std::chrono::milliseconds{300}; // 
Examine the queue every 300ms
+using QueueTime                       = 
std::chrono::time_point<std::chrono::system_clock>;
 
-enum { RATE_LIMITER_TYPE_SNI = 0, RATE_LIMITER_TYPE_REMAP, 
RATE_LIMITER_TYPE_MAX };
+int bucket_refill_cont(TSCont cont, TSEvent event, void *edata);
+class BucketManager
+{
+  using self_type = BucketManager;
+
+public:
+  class RateBucket
+  {
+    using self_type = RateBucket;
+
+  public:
+    RateBucket(uint32_t max) : _count(0), _max(max) {}
+    ~RateBucket() = default;
+
+    RateBucket(self_type &&)                = delete;
+    self_type &operator=(const self_type &) = delete;
+    self_type &operator=(self_type &&)      = delete;
+
+    uint32_t
+    count() const
+    {
+      return _count.load(std::memory_order_acquire);
+    }
+
+    bool
+    consume()
+    {
+      uint32_t val = _count.load(std::memory_order_acquire);
+
+      while (val > 0) {
+        if (_count.compare_exchange_weak(val, val - 1, 
std::memory_order_release, std::memory_order_acquire)) {
+          break;
+        }
+      }
+      TSReleaseAssert(val <= _max);
+
+      return val > 0;
+    }
+
+    // This should only be called from the manager, as such no locking is 
needed
+  protected:
+    void
+    refill()
+    {
+      static const uint32_t amount = _max / (1000 / 
BUCKET_REFILL_INTERVAL.count());
+      uint32_t old                 = _count.load(std::memory_order_acquire);
+      uint32_t nval;
+
+      do {
+        nval = old + amount;
+      } while (!_count.compare_exchange_weak(old, std::min(nval, _max), 
std::memory_order_release, std::memory_order_acquire));
+    }
+
+  private:
+    friend class BucketManager;
+
+    std::atomic<uint32_t> _count;
+    uint32_t _max;
+
+  }; // End class RateBucket
+
+  BucketManager() = default;
+  ~BucketManager()
+  {
+    if (_running) {
+      _running = false;
+      _thread.join(); // Wait for the thread to finish
+    }
+  }
+
+  BucketManager(self_type &&)             = delete;
+  self_type &operator=(const self_type &) = delete;
+  self_type &operator=(self_type &&)      = delete;
+
+  void refill_thread();
+
+  std::shared_ptr<RateBucket>
+  add(uint32_t max)
+  {
+    auto bucket = std::make_shared<RateBucket>(max);
+    std::lock_guard<std::mutex> lock(_mutex);
+
+    if (!_running) {
+      _running = true;
+      _thread  = std::thread(&BucketManager::refill_thread, this);
+    }
+
+    _buckets.push_back(bucket);
+
+    return bucket;
+  }
+
+  void
+  remove(std::shared_ptr<RateBucket> bucket)
+  {
+    std::lock_guard<std::mutex> lock(_mutex);
+    auto it = std::find(_buckets.begin(), _buckets.end(), bucket);
+
+    if (it != _buckets.end()) {
+      _buckets.erase(it);
+    }
+  }
+
+private:
+  std::vector<std::shared_ptr<RateBucket>> _buckets;
+  std::mutex _mutex;     // Protect the bucket list
+  bool _running = false; // Is the Bucket manager thread running already ?
+  std::thread _thread;   // The thread refilling the buckets
+
+}; // End class BucketManager
+
+extern BucketManager gBucketMngr;
 
 // order must align with the above
 static const char *types[] = {

Review Comment:
   Seeing this on the CI builds:
   ```
   ../plugins/experimental/rate_limit/limiter.h:168:20: error: 'suffixes' 
defined but not used [-Werror=unused-variable]
     168 | static const char *suffixes[] = {
         |                    ^~~~~~~~
   ../plugins/experimental/rate_limit/limiter.h:152:20: error: 'types' defined 
but not used [-Werror=unused-variable]
     152 | static const char *types[] = {
         |                    ^~~~~
   cc1plus: note: unrecognized command-line option '-Wno-vla-extension' may 
have been intended to silence earlier diagnostics
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to