This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 93c0819a4297a6f3cc4be3d9aefe99d9b536b7ad
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Mar 7 13:51:00 2025 +0000

    Refactor RateLimiter FastRateLimiter for extension
    
    Preparation for #794
---
 java/org/apache/catalina/util/FastRateLimiter.java |  76 +----------
 java/org/apache/catalina/util/RateLimiter.java     |   7 +-
 java/org/apache/catalina/util/RateLimiterBase.java | 145 +++++++++++++++++++++
 3 files changed, 154 insertions(+), 74 deletions(-)

diff --git a/java/org/apache/catalina/util/FastRateLimiter.java 
b/java/org/apache/catalina/util/FastRateLimiter.java
index 486a133a64..17544c5d28 100644
--- a/java/org/apache/catalina/util/FastRateLimiter.java
+++ b/java/org/apache/catalina/util/FastRateLimiter.java
@@ -14,92 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.catalina.util;
 
 import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import jakarta.servlet.FilterConfig;
-
-import org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor;
 
 /**
  * A RateLimiter that compromises accuracy for speed in order to provide 
maximum throughput.
  */
-public class FastRateLimiter implements RateLimiter {
-
-    private static AtomicInteger index = new AtomicInteger();
-
-    TimeBucketCounter bucketCounter;
-
-    int duration;
-
-    int requests;
-
-    int actualRequests;
-
-    int actualDuration;
-
-    // Initial policy name can be rewritten by setPolicyName()
-    private String policyName = "fast-" + index.incrementAndGet();
-
-    @Override
-    public String getPolicyName() {
-        return policyName;
-    }
-
-    @Override
-    public void setPolicyName(String name) {
-        this.policyName = name;
-    }
+public class FastRateLimiter extends RateLimiterBase {
 
     @Override
-    public int getDuration() {
-        return actualDuration;
+    protected String getDefaultPolicyName() {
+        return "fast";
     }
 
-    @Override
-    public void setDuration(int duration) {
-        this.duration = duration;
-    }
-
-    @Override
-    public int getRequests() {
-        return actualRequests;
-    }
-
-    @Override
-    public void setRequests(int requests) {
-        this.requests = requests;
-    }
 
     @Override
-    public int increment(String ipAddress) {
-        return bucketCounter.increment(ipAddress);
+    protected TimeBucketCounterBase newCounterInstance(int duration, 
ScheduledExecutorService executorService) {
+        return new TimeBucketCounter(duration, executorService);
     }
 
-    @Override
-    public void destroy() {
-        bucketCounter.destroy();
-    }
-
-    @Override
-    public void setFilterConfig(FilterConfig filterConfig) {
-
-        ScheduledExecutorService executorService = (ScheduledExecutorService) 
filterConfig.getServletContext()
-                .getAttribute(ScheduledThreadPoolExecutor.class.getName());
-
-        if (executorService == null) {
-            executorService = new 
java.util.concurrent.ScheduledThreadPoolExecutor(1);
-        }
-
-        bucketCounter = new TimeBucketCounter(duration, executorService);
-        actualRequests = (int) Math.round(bucketCounter.getRatio() * requests);
-        actualDuration = bucketCounter.getActualDuration() / 1000;
-    }
 
     public TimeBucketCounter getBucketCounter() {
-        return bucketCounter;
+        return (TimeBucketCounter) bucketCounter;
     }
 }
diff --git a/java/org/apache/catalina/util/RateLimiter.java 
b/java/org/apache/catalina/util/RateLimiter.java
index bdd8b27736..72effc8498 100644
--- a/java/org/apache/catalina/util/RateLimiter.java
+++ b/java/org/apache/catalina/util/RateLimiter.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.catalina.util;
 
 import jakarta.servlet.FilterConfig;
@@ -46,13 +45,13 @@ public interface RateLimiter {
     void setRequests(int requests);
 
     /**
-     * Increments the number of requests by the given ipAddress in the current 
time window.
+     * Increments the number of requests by the given identifier in the 
current time window.
      *
-     * @param ipAddress the ip address
+     * @param identifier the identifier for which the number of associated 
requests should be incremented
      *
      * @return the new value after incrementing
      */
-    int increment(String ipAddress);
+    int increment(String identifier);
 
     /**
      * Cleanup no longer needed resources.
diff --git a/java/org/apache/catalina/util/RateLimiterBase.java 
b/java/org/apache/catalina/util/RateLimiterBase.java
new file mode 100644
index 0000000000..1f4c699462
--- /dev/null
+++ b/java/org/apache/catalina/util/RateLimiterBase.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.util;
+
+import java.util.Objects;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import jakarta.servlet.FilterConfig;
+
+/**
+ * Base implementation of {@link RateLimiter}, provides runtime data 
maintenance mechanism monitor.
+ */
+public abstract class RateLimiterBase implements RateLimiter {
+
+    private static final AtomicInteger index = new AtomicInteger();
+
+    TimeBucketCounterBase bucketCounter;
+
+    int requests;
+    int actualRequests;
+
+    int duration;
+    int actualDuration;
+
+    // Initial policy name can be rewritten by setPolicyName()
+    private String policyName = null;
+
+    /*
+     * The self-owned utility executor, will be instantiated only when 
ScheduledThreadPoolExecutor is absent during
+     * filter configure phase.
+     */
+    private ScheduledThreadPoolExecutor internalExecutorService = null;
+
+    /**
+     * If policy name has not been specified, the first call of {@link 
#getPolicyName()} returns a auto-generated policy
+     * name using the default policy name as prefix and followed by 
auto-increase index.
+     *
+     * @return default policy name, as a prefix of auto-generated policy name.
+     */
+    protected abstract String getDefaultPolicyName();
+
+
+    @Override
+    public String getPolicyName() {
+        if (policyName == null) {
+            policyName = getDefaultPolicyName() + "-" + 
index.incrementAndGet();
+        }
+        return policyName;
+    }
+
+
+    @Override
+    public void setPolicyName(String name) {
+        Objects.requireNonNull(name);
+        this.policyName = name;
+    }
+
+
+    @Override
+    public int getDuration() {
+        return actualDuration;
+    }
+
+
+    @Override
+    public void setDuration(int duration) {
+        this.duration = duration;
+    }
+
+
+    @Override
+    public int getRequests() {
+        return actualRequests;
+    }
+
+
+    @Override
+    public void setRequests(int requests) {
+        this.requests = requests;
+    }
+
+
+    @Override
+    public int increment(String identifier) {
+        return bucketCounter.increment(identifier);
+    }
+
+
+    @Override
+    public void destroy() {
+        bucketCounter.destroy();
+        if (internalExecutorService != null) {
+            try {
+                internalExecutorService.shutdown();
+            } catch (SecurityException e) {
+                // ignore
+            }
+        }
+    }
+
+
+    /**
+     * Instantiate an instance of {@link TimeBucketCounterBase} for specific 
time bucket size. Concrete classes
+     * determine its counter policy by returning different implementation 
instances.
+     *
+     * @param duration        size of each time bucket in seconds
+     * @param utilityExecutor the executor
+     *
+     * @return counter instance of {@link TimeBucketCounterBase}
+     */
+    protected abstract TimeBucketCounterBase newCounterInstance(int duration, 
ScheduledExecutorService utilityExecutor);
+
+
+    @Override
+    public void setFilterConfig(FilterConfig filterConfig) {
+
+        ScheduledExecutorService executorService = (ScheduledExecutorService) 
filterConfig.getServletContext()
+                .getAttribute(ScheduledThreadPoolExecutor.class.getName());
+
+        if (executorService == null) {
+            internalExecutorService = new 
java.util.concurrent.ScheduledThreadPoolExecutor(1);
+            executorService = internalExecutorService;
+        }
+
+        bucketCounter = newCounterInstance(duration, executorService);
+        actualDuration = bucketCounter.getBucketDuration();
+        actualRequests = (int) Math.round(bucketCounter.getRatio() * requests);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to