# HG changeset patch # User Igor Sysoev # Date 1229893200 -10800 # Node ID fd759445d8a890a9db4ab645581358fdce277908 # Parent e2c4e8b635a873c8b4ac413a953fade4de5b16b3 nginx 0.7.28 *) Change: in memory allocation in the ngx_http_gzip_filter_module. *) Change: the default "gzip_buffers" directive values have been changed to 32 4k or 16 8k from 4 4k/8k. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +Changes with nginx 0.7.28 22 Dec 2008 + + *) Change: in memory allocation in the ngx_http_gzip_filter_module. + + *) Change: the default "gzip_buffers" directive values have been + changed to 32 4k or 16 8k from 4 4k/8k. + + Changes with nginx 0.7.27 15 Dec 2008 *) Feature: the "try_files" directive. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,12 @@ +Изменения в nginx 0.7.28 22.12.2008 + + *) Изменение: в выделении памяти в модуле ngx_http_gzip_filter_module. + + *) Изменение: значения по умолчанию для директивы gzip_values изменены + с 4 4k/8k на 32 4k или 16 8k. + + Изменения в nginx 0.7.27 15.12.2008 *) Добавление: директива try_files. diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.7.27" +#define NGINX_VERSION "0.7.28" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -201,12 +201,6 @@ ngx_chain_update_chains(ngx_chain_t **fr break; } -#if (NGX_HAVE_WRITE_ZEROCOPY) - if ((*busy)->buf->zerocopy_busy) { - break; - } -#endif - if ((*busy)->buf->tag != tag) { *busy = (*busy)->next; continue; diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -51,8 +51,6 @@ struct ngx_buf_s { unsigned last_shadow:1; unsigned temp_file:1; - unsigned zerocopy_busy:1; - /* STUB */ int num; }; diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h --- a/src/core/ngx_palloc.h +++ b/src/core/ngx_palloc.h @@ -14,7 +14,6 @@ /* * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86. - * On FreeBSD 5.x it allows to use the zero copy sending. * On Windows NT it decreases a number of locked pages in a kernel. */ #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1) diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -541,12 +541,6 @@ ngx_http_charset_body_filter(ngx_http_re break; } -#if (NGX_HAVE_WRITE_ZEROCOPY) - if (b->zerocopy_busy) { - break; - } -#endif - ctx->busy = cl->next; if (b->tag != (ngx_buf_tag_t) &ngx_http_charset_filter_module) { diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -60,12 +60,12 @@ ngx_module_t ngx_http_flv_module = { static ngx_int_t ngx_http_flv_handler(ngx_http_request_t *r) { - u_char *p, *n, *last; + u_char *last; off_t start, len; size_t root; ngx_int_t rc; ngx_uint_t level, i; - ngx_str_t path; + ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out[2]; @@ -167,18 +167,10 @@ ngx_http_flv_handler(ngx_http_request_t i = 1; if (r->args.len) { - p = (u_char *) ngx_strnstr(r->args.data, "start=", r->args.len); - - if (p) { - p += 6; - for (n = p; n < r->args.data + r->args.len; n++) { - if (*n == '&') { - break; - } - } + if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) { - start = ngx_atoof(p, n - p); + start = ngx_atoof(value.data, value.len); if (start == NGX_ERROR || start >= len) { start = 0; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -34,21 +34,27 @@ typedef struct { ngx_chain_t *busy; ngx_chain_t *out; ngx_chain_t **last_out; + + ngx_chain_t *copied; + ngx_chain_t *copy_buf; + ngx_buf_t *in_buf; ngx_buf_t *out_buf; ngx_int_t bufs; - off_t length; - void *preallocated; char *free_mem; ngx_uint_t allocated; + int wbits; + int memlevel; + unsigned flush:4; unsigned redo:1; unsigned done:1; unsigned nomem:1; unsigned gzheader:1; + unsigned buffering:1; size_t zin; size_t zout; @@ -76,6 +82,10 @@ struct gztrailer { #endif +static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, + ngx_http_gzip_ctx_t *ctx); +static ngx_int_t ngx_http_gzip_filter_copy_recycled(ngx_http_gzip_ctx_t *ctx, + ngx_chain_t *in); static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, @@ -92,6 +102,8 @@ static ngx_int_t ngx_http_gzip_filter_de static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size); static void ngx_http_gzip_filter_free(void *opaque, void *address); +static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, + ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r, @@ -245,6 +257,9 @@ ngx_http_gzip_header_filter(ngx_http_req ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); ctx->request = r; + ctx->buffering = 1; + + ngx_http_gzip_filter_memory(r, ctx); h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { @@ -259,8 +274,6 @@ ngx_http_gzip_header_filter(ngx_http_req r->headers_out.content_encoding = h; - ctx->length = r->headers_out.content_length_n; - r->main_filter_need_in_memory = 1; ngx_http_clear_content_length(r); @@ -283,6 +296,30 @@ ngx_http_gzip_body_filter(ngx_http_reque return ngx_http_next_body_filter(r, in); } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http gzip filter"); + + if (ctx->buffering) { + + if (in) { + switch (ngx_http_gzip_filter_copy_recycled(ctx, in)) { + + case NGX_OK: + return NGX_OK; + + case NGX_DONE: + in = NULL; + break; + + default: /* NGX_ERROR */ + goto failed; + } + + } else { + ctx->buffering = 0; + } + } + if (ctx->preallocated == NULL) { if (ngx_http_gzip_filter_deflate_start(r, ctx) != NGX_OK) { goto failed; @@ -356,6 +393,8 @@ ngx_http_gzip_body_filter(ngx_http_reque } if (ctx->out == NULL) { + ngx_http_gzip_filter_free_copy_buf(r, ctx); + return ctx->busy ? NGX_AGAIN : NGX_OK; } @@ -371,6 +410,8 @@ ngx_http_gzip_body_filter(ngx_http_reque goto failed; } + ngx_http_gzip_filter_free_copy_buf(r, ctx); + ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out, (ngx_buf_tag_t) &ngx_http_gzip_filter_module); ctx->last_out = &ctx->out; @@ -394,15 +435,16 @@ failed: ngx_pfree(r->pool, ctx->preallocated); } + ngx_http_gzip_filter_free_copy_buf(r, ctx); + return NGX_ERROR; } -static ngx_int_t -ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, - ngx_http_gzip_ctx_t *ctx) +static void +ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - int rc, wbits, memlevel; + int wbits, memlevel; ngx_http_gzip_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); @@ -410,16 +452,19 @@ ngx_http_gzip_filter_deflate_start(ngx_h wbits = conf->wbits; memlevel = conf->memlevel; - if (ctx->length > 0) { + if (r->headers_out.content_length_n > 0) { /* the actual zlib window size is smaller by 262 bytes */ - while (ctx->length < ((1 << (wbits - 1)) - 262)) { + while (r->headers_out.content_length_n < ((1 << (wbits - 1)) - 262)) { wbits--; memlevel--; } } + ctx->wbits = wbits; + ctx->memlevel = memlevel; + /* * We preallocate a memory for zlib in one buffer (200K-400K), this * decreases a number of malloc() and free() calls and also probably @@ -433,6 +478,96 @@ ngx_http_gzip_filter_deflate_start(ngx_h */ ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); +} + + +static ngx_int_t +ngx_http_gzip_filter_copy_recycled(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in) +{ + size_t size, buffered; + ngx_buf_t *b, *buf; + ngx_chain_t *cl, **ll; + ngx_http_request_t *r; + + r = ctx->request; + + r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; + + buffered = 0; + ll = &ctx->in; + + for (cl = ctx->in; cl; cl = cl->next) { + buffered += cl->buf->last - cl->buf->pos; + ll = &cl->next; + } + + while (in) { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + b = in->buf; + + size = b->last - b->pos; + buffered += size; + + if (b->flush || b->last_buf) { + ctx->buffering = 0; + + } else if (buffered > ctx->allocated / 2) { + + /* + * With default memory settings zlib starts to output gzipped data + * only after it has got about 90K, so it makes sense to allocate + * zlib memory (200-400K) only after we have enough data + * to compress. Although we copy recycled buffers, nevertheless + * for responses up to 120K this allows to allocate zlib memory, + * to compress and to output the response in one step + * using hot CPU cache. + */ + + ctx->buffering = 0; + } + + if (ctx->buffering && size && b->recycled) { + + buf = ngx_create_temp_buf(r->pool, size); + if (buf == NULL) { + return NGX_ERROR; + } + + buf->last = ngx_cpymem(buf->pos, b->pos, size); + b->pos = b->last; + + buf->last_buf = b->last_buf; + buf->tag = (ngx_buf_tag_t) &ngx_http_gzip_filter_module; + + cl->buf = buf; + + } else { + cl->buf = b; + } + + *ll = cl; + ll = &cl->next; + in = in->next; + } + + *ll = NULL; + + return ctx->buffering ? NGX_OK : NGX_DONE; +} + + +static ngx_int_t +ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, + ngx_http_gzip_ctx_t *ctx) +{ + int rc; + ngx_http_gzip_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); ctx->preallocated = ngx_palloc(r->pool, ctx->allocated); if (ctx->preallocated == NULL) { @@ -446,7 +581,7 @@ ngx_http_gzip_filter_deflate_start(ngx_h ctx->zstream.opaque = ctx; rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED, - -wbits, memlevel, Z_DEFAULT_STRATEGY); + - ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY); if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, @@ -454,8 +589,6 @@ ngx_http_gzip_filter_deflate_start(ngx_h return NGX_ERROR; } - r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; - ctx->last_out = &ctx->out; ctx->crc32 = crc32(0L, Z_NULL, 0); ctx->flush = Z_NO_FLUSH; @@ -510,7 +643,24 @@ ngx_http_gzip_filter_add_data(ngx_http_r return NGX_DECLINED; } + if (ctx->copy_buf) { + + /* + * to avoid CPU cache trashing we do not free() just quit buf, + * but postpone free()ing after zlib compressing and data output + */ + + ctx->copy_buf->next = ctx->copied; + ctx->copied = ctx->copy_buf; + ctx->copy_buf = NULL; + } + ctx->in_buf = ctx->in->buf; + + if (ctx->in_buf->tag == (ngx_buf_tag_t) &ngx_http_gzip_filter_module) { + ctx->copy_buf = ctx->in; + } + ctx->in = ctx->in->next; ctx->zstream.next_in = ctx->in_buf->pos; @@ -832,6 +982,20 @@ ngx_http_gzip_filter_free(void *opaque, } +static void +ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r, + ngx_http_gzip_ctx_t *ctx) +{ + ngx_chain_t *cl; + + for (cl = ctx->copied; cl; cl = cl->next) { + ngx_pfree(r->pool, cl->buf->start); + } + + ctx->copied = NULL; +} + + static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf) { @@ -930,7 +1094,8 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, ngx_conf_merge_value(conf->enable, prev->enable, 0); - ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize); + ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, + (128 * 1024) / ngx_pagesize, ngx_pagesize); ngx_conf_merge_value(conf->level, prev->level, 1); ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS); diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -935,12 +935,6 @@ ngx_http_ssi_output(ngx_http_request_t * break; } -#if (NGX_HAVE_WRITE_ZEROCOPY) - if (b->zerocopy_busy) { - break; - } -#endif - if (b->shadow) { b->shadow->pos = b->shadow->last; } diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -465,12 +465,6 @@ ngx_http_sub_output(ngx_http_request_t * break; } -#if (NGX_HAVE_WRITE_ZEROCOPY) - if (b->zerocopy_busy) { - break; - } -#endif - if (b->shadow) { b->shadow->pos = b->shadow->last; } diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.27'; +our $VERSION = '0.7.28'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -76,6 +76,9 @@ ngx_int_t ngx_http_parse_header_line(ngx ngx_uint_t allow_underscores); ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, ngx_str_t *value); +ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, + ngx_str_t *value); + ngx_int_t ngx_http_find_server_conf(ngx_http_request_t *r); void ngx_http_update_location_config(ngx_http_request_t *r); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -1481,3 +1481,45 @@ ngx_http_parse_multi_header_lines(ngx_ar return NGX_DECLINED; } + + +ngx_int_t +ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value) +{ + u_char *p; + + if (r->args.len == 0) { + return NGX_DECLINED; + } + + for (p = r->args.data; *p && *p != ' '; p++) { + + /* + * although r->args.data is not null-terminated by itself, + * however, there is null in the end of request line + */ + + p = ngx_strcasestrn(p, (char *) name, len - 1); + + if (p == NULL) { + return NGX_DECLINED; + } + + if ((p == r->args.data || *(p - 1) == '&') && *(p + len) == '=') { + + value->data = p + len + 1; + + p = (u_char *) ngx_strchr(p, '&'); + + if (p == NULL) { + p = r->args.data + r->args.len; + } + + value->len = p - value->data; + + return NGX_OK; + } + } + + return NGX_DECLINED; +} diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2488,7 +2488,9 @@ ngx_http_upstream_finalize_request(ngx_h ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "finalize http upstream request: %i", rc); - *u->cleanup = NULL; + if (u->cleanup) { + *u->cleanup = NULL; + } if (u->state && u->state->response_sec) { tp = ngx_timeofday(); diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -772,51 +772,23 @@ ngx_http_variable_argument(ngx_http_requ { ngx_str_t *name = (ngx_str_t *) data; - u_char *p, *arg; - size_t len; + u_char *arg; + size_t len; + ngx_str_t value; - if (r->args.len == 0) { + len = name->len - (sizeof("arg_") - 1); + arg = name->data + sizeof("arg_") - 1; + + if (ngx_http_arg(r, arg, len, &value) != NGX_OK) { v->not_found = 1; return NGX_OK; } - len = name->len - 1 - (sizeof("arg_") - 1); - arg = name->data + sizeof("arg_") - 1; - - for (p = r->args.data; *p && *p != ' '; p++) { - - /* - * although r->args.data is not null-terminated by itself, - * however, there is null in the end of request line - */ - - p = ngx_strcasestrn(p, (char *) arg, len); - - if (p == NULL) { - v->not_found = 1; - return NGX_OK; - } - - if ((p == r->args.data || *(p - 1) == '&') && *(p + len + 1) == '=') { - - v->data = p + len + 2; - - p = (u_char *) ngx_strchr(p, '&'); - - if (p == NULL) { - p = r->args.data + r->args.len; - } - - v->len = p - v->data; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - - return NGX_OK; - } - } - - v->not_found = 1; + v->data = value.data; + v->len = value.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; return NGX_OK; } diff --git a/src/os/unix/ngx_freebsd.h b/src/os/unix/ngx_freebsd.h --- a/src/os/unix/ngx_freebsd.h +++ b/src/os/unix/ngx_freebsd.h @@ -14,7 +14,6 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( extern int ngx_freebsd_kern_osreldate; extern int ngx_freebsd_hw_ncpu; extern u_long ngx_freebsd_net_inet_tcp_sendspace; -extern int ngx_freebsd_kern_ipc_zero_copy_send; extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; extern ngx_uint_t ngx_freebsd_use_tcp_nopush; diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -19,9 +19,6 @@ u_long ngx_freebsd_net_inet_tcp_sendspa /* FreeBSD 4.9 */ int ngx_freebsd_machdep_hlt_logical_cpus; -/* FreeBSD 5.0 */ -int ngx_freebsd_kern_ipc_zero_copy_send; - ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; ngx_uint_t ngx_freebsd_use_tcp_nopush; @@ -68,10 +65,6 @@ sysctl_t sysctls[] = { &ngx_freebsd_kern_ipc_somaxconn, sizeof(ngx_freebsd_kern_ipc_somaxconn), 0 }, - { "kern.ipc.zero_copy.send", - &ngx_freebsd_kern_ipc_zero_copy_send, - sizeof(ngx_freebsd_kern_ipc_zero_copy_send), 0 }, - { NULL, NULL, 0, 0 } }; diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -13,7 +13,6 @@ #define NGX_IO_SENDFILE 1 -#define NGX_IO_ZEROCOPY 2 typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size);