summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorYann Ylavic <ylavic@apache.org>2018-07-16 14:49:55 +0200
committerYann Ylavic <ylavic@apache.org>2018-07-16 14:49:55 +0200
commited8996d9a0e503031ef70915ee0f067a71b20a16 (patch)
treeeadc36ec08c3203cfd6ace32408da59b22410c47 /server
parentRebuild. (diff)
downloadapache2-ed8996d9a0e503031ef70915ee0f067a71b20a16.tar.xz
apache2-ed8996d9a0e503031ef70915ee0f067a71b20a16.zip
core: Add ReadBufferSize, FlushMaxThreshold and FlushMaxPipelined directives.
ReadBufferSize allows to configure the size of read buffers, for now it's mainly used for file buckets reads (apr_bucket_file_set_buf_size), but it could be used to replace AP_IOBUFSIZE in multiple places. FlushMaxThreshold and FlushMaxPipelined allow to configure the hardcoded THRESHOLD_MAX_BUFFER and MAX_REQUESTS_IN_PIPELINE from "util_filter.c". The former sets the maximum size above which pending data are forcibly flushed to the network (blocking eventually), and the latter sets the number of pipelined/pending responses above which they are flushed regardless of whether a pipelined request is immediately available (zero disables pipelining). Larger ReadBufferSize and FlushMaxThreshold can trade memory consumption for performances with the capacity of today's networks. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1836032 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server')
-rw-r--r--server/core.c111
-rw-r--r--server/util_filter.c29
2 files changed, 119 insertions, 21 deletions
diff --git a/server/core.c b/server/core.c
index d928ba2263..d70acc369c 100644
--- a/server/core.c
+++ b/server/core.c
@@ -30,6 +30,11 @@
#include "apr_random.h"
#endif
+#include "apr_version.h"
+#if APR_MAJOR_VERSION < 2
+#include "apu_version.h"
+#endif
+
#define APR_WANT_IOVEC
#define APR_WANT_STRFUNC
#define APR_WANT_MEMFUNC
@@ -91,6 +96,9 @@
#define AP_CONTENT_MD5_ON 1
#define AP_CONTENT_MD5_UNSET 2
+#define AP_FLUSH_MAX_THRESHOLD 65536
+#define AP_FLUSH_MAX_PIPELINED 5
+
APR_HOOK_STRUCT(
APR_HOOK_LINK(get_mgmt_items)
APR_HOOK_LINK(insert_network_bucket)
@@ -406,6 +414,13 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
if (new->enable_sendfile != ENABLE_SENDFILE_UNSET) {
conf->enable_sendfile = new->enable_sendfile;
}
+
+ if (new->read_buf_size) {
+ conf->read_buf_size = new->read_buf_size;
+ }
+ else {
+ conf->read_buf_size = base->read_buf_size;
+ }
if (new->allow_encoded_slashes_set) {
conf->allow_encoded_slashes = new->allow_encoded_slashes;
@@ -482,14 +497,13 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
apr_table_setn(conf->accf_map, "http", "data");
apr_table_setn(conf->accf_map, "https", "data");
#endif
+
+ conf->flush_max_threshold = AP_FLUSH_MAX_THRESHOLD;
+ conf->flush_max_pipelined = AP_FLUSH_MAX_PIPELINED;
}
- /* pcalloc'ed - we have NULL's/0's
- else ** is_virtual ** {
- conf->ap_document_root = NULL;
- conf->access_name = NULL;
- conf->accf_map = NULL;
+ else {
+ conf->flush_max_pipelined = -1;
}
- */
/* initialization, no special case for global context */
@@ -593,11 +607,19 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
conf->protocols_honor_order = ((virt->protocols_honor_order < 0) ?
base->protocols_honor_order :
virt->protocols_honor_order);
+
conf->async_filter = ((virt->async_filter_set) ?
virt->async_filter :
base->async_filter);
conf->async_filter_set = base->async_filter_set || virt->async_filter_set;
+ conf->flush_max_threshold = (virt->flush_max_threshold)
+ ? virt->flush_max_threshold
+ : base->flush_max_threshold;
+ conf->flush_max_pipelined = (virt->flush_max_pipelined >= 0)
+ ? virt->flush_max_pipelined
+ : base->flush_max_pipelined;
+
return conf;
}
@@ -1259,6 +1281,13 @@ AP_DECLARE(apr_off_t) ap_get_limit_req_body(const request_rec *r)
return d->limit_req_body;
}
+AP_DECLARE(apr_size_t) ap_get_read_buf_size(const request_rec *r)
+{
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+
+ return d->read_buf_size ? d->read_buf_size : AP_IOBUFSIZE;
+}
+
/*****************************************************************
*
@@ -2285,6 +2314,65 @@ static const char *set_enable_sendfile(cmd_parms *cmd, void *d_,
return NULL;
}
+static const char *set_read_buf_size(cmd_parms *cmd, void *d_,
+ const char *arg)
+{
+ core_dir_config *d = d_;
+ apr_off_t size;
+ char *end;
+
+ if (apr_strtoff(&size, arg, &end, 10)
+ || size < 0 || size > APR_SIZE_MAX || *end)
+ return apr_pstrcat(cmd->pool,
+ "parameter must be a number between 0 and "
+ APR_STRINGIFY(APR_SIZE_MAX) "): ",
+ arg, NULL);
+
+ d->read_buf_size = (apr_size_t)size;
+
+ return NULL;
+}
+
+static const char *set_flush_max_threshold(cmd_parms *cmd, void *d_,
+ const char *arg)
+{
+ core_server_config *conf =
+ ap_get_core_module_config(cmd->server->module_config);
+ apr_off_t size;
+ char *end;
+
+ if (apr_strtoff(&size, arg, &end, 10)
+ || size <= 0 || size > APR_SIZE_MAX || *end)
+ return apr_pstrcat(cmd->pool,
+ "parameter must be a number between 1 and "
+ APR_STRINGIFY(APR_SIZE_MAX) "): ",
+ arg, NULL);
+
+ conf->flush_max_threshold = (apr_size_t)size;
+
+ return NULL;
+}
+
+static const char *set_flush_max_pipelined(cmd_parms *cmd, void *d_,
+ const char *arg)
+{
+ core_server_config *conf =
+ ap_get_core_module_config(cmd->server->module_config);
+ apr_off_t num;
+ char *end;
+
+ if (apr_strtoff(&num, arg, &end, 10)
+ || num < 0 || num > APR_INT32_MAX || *end)
+ return apr_pstrcat(cmd->pool,
+ "parameter must be a number between 0 and "
+ APR_STRINGIFY(APR_INT32_MAX) ": ",
+ arg, NULL);
+
+ conf->flush_max_pipelined = (apr_int32_t)num;
+
+ return NULL;
+}
+
/*
* Report a missing-'>' syntax error.
@@ -4594,6 +4682,12 @@ AP_INIT_TAKE1("EnableMMAP", set_enable_mmap, NULL, OR_FILEINFO,
"Controls whether memory-mapping may be used to read files"),
AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,
"Controls whether sendfile may be used to transmit files"),
+AP_INIT_TAKE1("ReadBufferSize", set_read_buf_size, NULL, OR_FILEINFO,
+ "Size (in bytes) of the memory buffers used to read data"),
+AP_INIT_TAKE1("FlushMaxThreshold", set_flush_max_threshold, NULL, RSRC_CONF,
+ "Maximum size (in bytes) above which pending data are flushed (blocking) to the network"),
+AP_INIT_TAKE1("FlushMaxPipelined", set_flush_max_pipelined, NULL, RSRC_CONF,
+ "Number of pipelined/pending responses above which they are flushed to the network"),
/* Old server config file commands */
@@ -5044,6 +5138,11 @@ static int default_handler(request_rec *r)
(void)apr_bucket_file_enable_mmap(e, 0);
}
#endif
+#if APR_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 6)
+ if (d->read_buf_size) {
+ apr_bucket_file_set_buf_size(e, d->read_buf_size);
+ }
+#endif
}
e = apr_bucket_eos_create(c->bucket_alloc);
diff --git a/server/util_filter.c b/server/util_filter.c
index 5474c31da1..04c637a8a1 100644
--- a/server/util_filter.c
+++ b/server/util_filter.c
@@ -33,10 +33,6 @@
#define FILTER_POOL apr_hook_global_pool
#include "ap_hooks.h" /* for apr_hook_global_pool */
-/* XXX: Should these be configurable parameters? */
-#define THRESHOLD_MAX_BUFFER 65536
-#define MAX_REQUESTS_IN_PIPELINE 5
-
/*
** This macro returns true/false if a given filter should be inserted BEFORE
** another filter. This will happen when one of: 1) there isn't another
@@ -825,7 +821,8 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f,
apr_size_t bytes_in_brigade, non_file_bytes_in_brigade;
int eor_buckets_in_brigade, morphing_bucket_in_brigade;
int loglevel = ap_get_conn_module_loglevel(f->c, APLOG_MODULE_INDEX);
-
+ core_server_config *conf;
+
if (loglevel >= APLOG_TRACE6) {
ap_log_cerror(
APLOG_MARK, APLOG_TRACE6, 0, f->c,
@@ -845,16 +842,16 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f,
* of everything up that point.
*
* b) The request is in CONN_STATE_HANDLER state, and the brigade
- * contains at least THRESHOLD_MAX_BUFFER bytes in non-file
+ * contains at least flush_max_threshold bytes in non-file
* buckets: Do blocking writes until the amount of data in the
- * buffer is less than THRESHOLD_MAX_BUFFER. (The point of this
+ * buffer is less than flush_max_threshold. (The point of this
* rule is to provide flow control, in case a handler is
* streaming out lots of data faster than the data can be
* sent to the client.)
*
* c) The request is in CONN_STATE_HANDLER state, and the brigade
- * contains at least MAX_REQUESTS_IN_PIPELINE EOR buckets:
- * Do blocking writes until less than MAX_REQUESTS_IN_PIPELINE EOR
+ * contains at least flush_max_pipelined EOR buckets:
+ * Do blocking writes until less than flush_max_pipelined EOR
* buckets are left. (The point of this rule is to prevent too many
* FDs being kept open by pipelined requests, possibly allowing a
* DoS).
@@ -862,7 +859,7 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f,
* d) The request is being served by a connection filter and the
* brigade contains a morphing bucket: If there was no other
* reason to do a blocking write yet, try reading the bucket. If its
- * contents fit into memory before THRESHOLD_MAX_BUFFER is reached,
+ * contents fit into memory before flush_max_threshold is reached,
* everything is fine. Otherwise we need to do a blocking write the
* up to and including the morphing bucket, because ap_save_brigade()
* would read the whole bucket into memory later on.
@@ -875,6 +872,8 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f,
eor_buckets_in_brigade = 0;
morphing_bucket_in_brigade = 0;
+ conf = ap_get_core_module_config(f->c->base_server->module_config);
+
for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb);
bucket = next) {
next = APR_BUCKET_NEXT(bucket);
@@ -899,18 +898,18 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f,
}
if (APR_BUCKET_IS_FLUSH(bucket)
- || non_file_bytes_in_brigade >= THRESHOLD_MAX_BUFFER
+ || non_file_bytes_in_brigade >= conf->flush_max_threshold
|| (!f->r && morphing_bucket_in_brigade)
- || eor_buckets_in_brigade > MAX_REQUESTS_IN_PIPELINE) {
+ || eor_buckets_in_brigade > conf->flush_max_pipelined) {
/* this segment of the brigade MUST be sent before returning. */
if (loglevel >= APLOG_TRACE6) {
char *reason = APR_BUCKET_IS_FLUSH(bucket) ?
"FLUSH bucket" :
- (non_file_bytes_in_brigade >= THRESHOLD_MAX_BUFFER) ?
- "THRESHOLD_MAX_BUFFER" :
+ (non_file_bytes_in_brigade >= conf->flush_max_threshold) ?
+ "max threshold" :
(!f->r && morphing_bucket_in_brigade) ? "morphing bucket" :
- "MAX_REQUESTS_IN_PIPELINE";
+ "max requests in pipeline";
ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, f->c,
"will flush because of %s", reason);
ap_log_cerror(APLOG_MARK, APLOG_TRACE8, 0, f->c,