Welcome! Log In Create A New Profile

Advanced

[PATCH 1 of 2] Buffers reuse in chunked filter

Maxim Dounin
September 09, 2011 07:10AM
# HG changeset patch
# User Maxim Dounin <mdounin@mdounin.ru>
# Date 1315564269 -14400
# Node ID b667ed67c0b9046b94291fa6f52e850006011718
# Parent 014764a85840606c90317e9f44f2b9fa139cbc8b
Buffers reuse in chunked filter.

There were 2 buffers allocated on each buffer chain sent through chunked
filter (one buffer for chunk size, another one for trailing CRLF, about
120 bytes in total on 32-bit platforms). This resulted in large memory
consumption with long-lived requests sending many buffer chains. Usual
example of problematic scenario is streaming though proxy with
proxy_buffering set to off.

Introduced buffers reuse reduces memory consumption in the above problematic
scenario.

See here for initial report:
http://mailman.nginx.org/pipermail/nginx/2010-April/019814.html

diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c
--- a/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -9,6 +9,12 @@
#include <ngx_http.h>


+typedef struct {
+ ngx_chain_t *free;
+ ngx_chain_t *busy;
+} ngx_http_chunked_filter_ctx_t;
+
+
static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf);


@@ -50,7 +56,8 @@ static ngx_http_output_body_filter_pt
static ngx_int_t
ngx_http_chunked_header_filter(ngx_http_request_t *r)
{
- ngx_http_core_loc_conf_t *clcf;
+ ngx_http_core_loc_conf_t *clcf;
+ ngx_http_chunked_filter_ctx_t *ctx;

if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
|| r->headers_out.status == NGX_HTTP_NO_CONTENT
@@ -70,6 +77,14 @@ ngx_http_chunked_header_filter(ngx_http_
if (clcf->chunked_transfer_encoding) {
r->chunked = 1;

+ ctx = ngx_pcalloc(r->pool,
+ sizeof(ngx_http_chunked_filter_ctx_t));
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);
+
} else {
r->keepalive = 0;
}
@@ -83,17 +98,21 @@ ngx_http_chunked_header_filter(ngx_http_
static ngx_int_t
ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
- u_char *chunk;
- off_t size;
- ngx_buf_t *b;
- ngx_chain_t out, tail, *cl, *tl, **ll;
+ u_char *chunk;
+ off_t size;
+ ngx_int_t rc;
+ ngx_buf_t *b;
+ ngx_chain_t *out, *cl, *tl, **ll;
+ ngx_http_chunked_filter_ctx_t *ctx;

if (in == NULL || !r->chunked || r->header_only) {
return ngx_http_next_body_filter(r, in);
}

- out.buf = NULL;
- ll = &out.next;
+ ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);
+
+ out = NULL;
+ ll = &out;

size = 0;
cl = in;
@@ -127,31 +146,46 @@ ngx_http_chunked_body_filter(ngx_http_re
}

if (size) {
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
+ tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (tl == NULL) {
return NGX_ERROR;
}

- /* the "0000000000000000" is 64-bit hexadimal string */
+ b = tl->buf;
+ chunk = b->start;

- chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
if (chunk == NULL) {
- return NGX_ERROR;
+ /* the "0000000000000000" is 64-bit hexadecimal string */
+
+ chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
+ if (chunk == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->start = chunk;
+ b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
}

+ b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
+ b->memory = 0;
b->temporary = 1;
b->pos = chunk;
b->last = ngx_sprintf(chunk, "%xO" CRLF, size);

- out.buf = b;
+ tl->next = out;
+ out = tl;
}

if (cl->buf->last_buf) {
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
+ tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (tl == NULL) {
return NGX_ERROR;
}
+
+ b = tl->buf;

+ b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
+ b->temporary = 0;
b->memory = 1;
b->last_buf = 1;
b->pos = (u_char *) CRLF "0" CRLF CRLF;
@@ -159,35 +193,38 @@ ngx_http_chunked_body_filter(ngx_http_re

cl->buf->last_buf = 0;

+ *ll = tl;
+
if (size == 0) {
b->pos += 2;
- out.buf = b;
- out.next = NULL;
-
- return ngx_http_next_body_filter(r, &out);
}

- } else {
- if (size == 0) {
- *ll = NULL;
- return ngx_http_next_body_filter(r, out.next);
- }
-
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
+ } else if (size > 0) {
+ tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (tl == NULL) {
return NGX_ERROR;
}

+ b = tl->buf;
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
+ b->temporary = 0;
b->memory = 1;
b->pos = (u_char *) CRLF;
b->last = b->pos + 2;
+
+ *ll = tl;
+
+ } else {
+ *ll = NULL;
}

- tail.buf = b;
- tail.next = NULL;
- *ll = &tail;
+ rc = ngx_http_next_body_filter(r, out);

- return ngx_http_next_body_filter(r, &out);
+ ngx_chain_update_chains(&ctx->free, &ctx->busy, &out,
+ (ngx_buf_tag_t) &ngx_http_chunked_filter_module);
+
+ return rc;
}



_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH 0 of 2] reduce memory footprint for long-lived requests

Maxim Dounin 1856 September 09, 2011 07:10AM

[PATCH 1 of 2] Buffers reuse in chunked filter

Maxim Dounin 724 September 09, 2011 07:10AM

Re: [PATCH 1 of 2] Buffers reuse in chunked filter

splitice 958 September 09, 2011 08:02AM

Re: [PATCH 1 of 2] Buffers reuse in chunked filter

Kornél Schadl 728 September 09, 2011 08:38AM

Re: [PATCH 1 of 2] Buffers reuse in chunked filter

Maxim Dounin 908 September 09, 2011 08:44AM

[PATCH 2 of 2] API change: ngx_chain_update_chains() now requires pool

Maxim Dounin 765 September 09, 2011 07:10AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 140
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready