]> granicus.if.org Git - apache/commitdiff
Allow for initual burst at full speed
authorJim Jagielski <jim@apache.org>
Wed, 23 Nov 2016 12:15:01 +0000 (12:15 +0000)
committerJim Jagielski <jim@apache.org>
Wed, 23 Nov 2016 12:15:01 +0000 (12:15 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1770951 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/log-message-tags/next-number
docs/manual/mod/mod_ratelimit.xml
modules/filters/mod_ratelimit.c

diff --git a/CHANGES b/CHANGES
index bed19108d20e43107cf933223d005f78782506c4..ccb724486f3e984fa61872e9046f520890c1d6bf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_ratelimit: Allow for initial "burst" amount at full speed before
+     throttling: PR 60145 [Andy Valencia <ajv-etradanalhos vsta.org>,
+     Jim Jagielski]
+
   *) event: Allow to use the whole allocated scoreboard (up to ServerLimit
      slots) to avoid scoreboard full errors when some processes are finishing
      gracefully. Also, make gracefully finishing processes close all
index 294337bb646b5b52727165e0b0200589c4f82d4b..98233cb68ed41b80058180738d42456f5d7c8fbe 100644 (file)
@@ -1 +1 @@
-3485
+3486
index affb2daf26e1f0b1e3ab2a258e1a7b37c1992e99..8adfb8acb343f2fdb04502995035aabff1783672 100644 (file)
@@ -37,11 +37,17 @@ the document to validate. -->
 The connection speed to be simulated is specified, in KiB/s, using the environment
 variable <code>rate-limit</code>.</p>
 
+<p>Optionally, an initial amount of burst data, in KiB, may be
+configured to be passed at full speed before throttling to the
+specified rate limit.  This value is optional, and is set using
+the environment variable <code>rate-initial-burst</code>.</p>
+
 <example><title>Example Configuration</title>
 <highlight language="config">
 &lt;Location "/downloads"&gt;
     SetOutputFilter RATE_LIMIT
     SetEnv rate-limit 400
+    SetEnv rate-initial-burst 512
 &lt;/Location&gt;
 </highlight>
 </example>
index a2e9bd0197710ae321edc4e9a51a598601162a39..0f95e80a73e432342c86370e1ee14fe296cf8fa0 100644 (file)
@@ -35,12 +35,13 @@ typedef struct rl_ctx_t
 {
     int speed;
     int chunk_size;
+    int burst;
     rl_state_e state;
     apr_bucket_brigade *tmpbb;
     apr_bucket_brigade *holdingbb;
 } rl_ctx_t;
 
-#if 0
+#if defined(RLFDEBUG)
 static void brigade_dump(request_rec *r, apr_bucket_brigade *bb)
 {
     apr_bucket *e;
@@ -53,7 +54,7 @@ static void brigade_dump(request_rec *r, apr_bucket_brigade *bb)
 
     }
 }
-#endif
+#endif /* RLFDEBUG */
 
 static apr_status_t
 rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
@@ -71,10 +72,12 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
         return APR_ECONNABORTED;
     }
 
+    /* Set up our rl_ctx_t on first use */
     if (ctx == NULL) {
 
         const char *rl = NULL;
         int ratelimit;
+        int burst = 0;
 
         /* no subrequests. */
         if (f->r->main != NULL) {
@@ -82,6 +85,7 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
             return ap_pass_brigade(f->next, bb);
         }
 
+        /* Configuration: rate limit */
         rl = apr_table_get(f->r->subprocess_env, "rate-limit");
 
         if (rl == NULL) {
@@ -97,11 +101,21 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
             return ap_pass_brigade(f->next, bb);
         }
 
-        /* first run, init stuff */
+        /* Configuration: optional initial burst */
+        rl = apr_table_get(f->r->subprocess_env, "rate-initial-burst");
+        if (rl != NULL) {
+            burst = atoi(rl) * 1024;
+            if (burst <= 0) {
+                burst = 0;
+            }
+        }
+
+        /* Set up our context */
         ctx = apr_palloc(f->r->pool, sizeof(rl_ctx_t));
         f->ctx = ctx;
         ctx->state = RATE_LIMIT;
         ctx->speed = ratelimit;
+        ctx->burst = burst;
 
         /* calculate how many bytes / interval we want to send */
         /* speed is bytes / second, so, how many  (speed / 1000 % interval) */
@@ -183,7 +197,15 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
 
                 apr_brigade_length(bb, 1, &len);
 
-                rv = apr_brigade_partition(bb, ctx->chunk_size, &stop_point);
+                /*
+                 * Pull next chunk of data; the initial amount is our
+                 * burst allotment (if any) plus a chunk.  All subsequent
+                 * iterations are just chunks with whatever remaining
+                 * burst amounts we have left (in case not done in the
+                 * first bucket).
+                 */
+                rv = apr_brigade_partition(bb,
+                    ctx->chunk_size + ctx->burst, &stop_point);
                 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
                     ctx->state = RATE_ERROR;
                     ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456)
@@ -207,15 +229,33 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
 
                 APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb);
 
-#if 0
+                /*
+                 * Adjust the burst amount depending on how much
+                 * we've done up to now.
+                 */
+                if (ctx->burst) {
+                    len = ctx->burst;
+                    apr_brigade_length(ctx->tmpbb, 1, &len);
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r,
+                        APLOGNO(03485) "rl: burst %d; len %"APR_OFF_T_FMT, ctx->burst, len);
+                    if (len < ctx->burst) {
+                        ctx->burst -= len;
+                    }
+                    else {
+                        ctx->burst = 0;
+                    }
+                }
+
+#if defined(RLFDEBUG)
                 brigade_dump(f->r, ctx->tmpbb);
                 brigade_dump(f->r, bb);
-#endif
+#endif /* RLFDEBUG */
 
                 rv = ap_pass_brigade(f->next, ctx->tmpbb);
                 apr_brigade_cleanup(ctx->tmpbb);
 
                 if (rv != APR_SUCCESS) {
+                    /* Most often, user disconnects from stream */
                     ctx->state = RATE_ERROR;
                     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457)
                                   "rl: brigade pass failed.");