> -----Original Message-----
> From: Graham Leggett
> Sent: Dienstag, 29. Oktober 2013 00:47
> To: [email protected]
> Subject: [Patch] mod_ssl write completion
>
> Hi all,
>
> I was on the wrong track with regards mod_ssl and the flush-on-eos, the
> patch below to mod_ssl echoes a similar strategy the core output filter
> uses to enter write completion mode.
>
> The idea is that if the brigade to be written contains an EOS bucket but
> not a flush bucket, we can safely set aside the buckets and when event is
> present enter write completion. As soon as we do see a flush bucket, or if
> we have previously set aside we write as normal. Because we only trigger
> this behaviour when we see an EOS bucket we only set aside once per
> request, which should keep RAM use bounded, and leave generators that
> stream unbounded data unaffected.
>
> This should in theory make most mod_ssl requests behave similarly to
> normal requests with respect to async behaviour. A typical response
> contains a file bucket and eos, which will be immediately set aside and
> enter write completion. Proxied responses should enter write completion
> when the last bucket is produced, which could be the whole response if
> ProxyIOBufferSize is set large enough. Cached responses also contain just
> a (file or heap) bucket and eos, so should also benefit. Any content
> generator that sends the EOS bucket separately from the data won't
> benefit, but we can fix any of those separately.
>
> All the SSL tests pass with this patch, but more eyes welcome.
>
> Index: modules/ssl/ssl_engine_io.c
> ===================================================================
> --- modules/ssl/ssl_engine_io.c (revision 1536348)
> +++ modules/ssl/ssl_engine_io.c (working copy)
> typedef struct {
> @@ -1675,6 +1677,62 @@
> return ssl_io_filter_error(f, bb, status);
> }
>
> + /* We now try and take advantage of write completion in async mpms.
> + * If our brigade contains an EOS bucket and no flush buckets, set
> + * aside the whole brigade and leave early. We will get called again
> + * during write completion, at which point we'll do the actual write.
> + */
> + if (f->c->cs) {
> +
> + if (!filter_ctx->bb) {
> + filter_ctx->bb = apr_brigade_create(f->c->pool, f->c-
> >bucket_alloc);
> + }
> +
> + if (!APR_BRIGADE_EMPTY(filter_ctx->bb)) {
> +
> + APR_BRIGADE_PREPEND(bb, filter_ctx->bb);
> +
> + f->c->data_in_output_filters--;
> + ap_assert(f->c->data_in_output_filters >= 0);
> +
> + }
> + else {
> + apr_bucket *bucket;
> + int found = 0;
> +
> + if (filter_ctx->deferred_write_pool) {
> + apr_pool_clear(filter_ctx->deferred_write_pool);
> + }
> +
> + /* EOS, but no flush */
> + for (bucket = APR_BRIGADE_FIRST(bb);
> + bucket != APR_BRIGADE_SENTINEL(bb); bucket =
> + APR_BUCKET_NEXT(bucket)) {
> + if (APR_BUCKET_IS_EOS(bucket)) {
> + found = 1;
> + }
> + if (APR_BUCKET_IS_FLUSH(bucket)) {
> + found = 0;
> + break;
> + }
> + }
> +
> + /* leave early */
> + if (found) {
> + if (!filter_ctx->deferred_write_pool) {
> + apr_pool_create(&filter_ctx->deferred_write_pool,
> + f->c->pool);
> + apr_pool_tag(filter_ctx->deferred_write_pool,
> + "ssl_deferred_write");
> + }
> + status = ap_save_brigade(f, &(filter_ctx->bb), &bb,
> + filter_ctx->deferred_write_pool);
When will this saved brigade handed over to the core output filter?
How will it be triggered? IMHO the WRITE_COMPLETION only calls the core output
filter.
> + f->c->data_in_output_filters++;
> + return APR_SUCCESS;
> + }
> + }
> + }
> +
> while (!APR_BRIGADE_EMPTY(bb)) {
> apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
>
> Index: server/core_filters.c
> ===================================================================
> --- server/core_filters.c (revision 1536348)
> +++ server/core_filters.c (working copy)
> @@ -413,7 +413,8 @@
> else {
> bb = ctx->buffered_bb;
> }
> - c->data_in_output_filters = 0;
> + c->data_in_output_filters--;
Why do you switch from a boolean flag to a counter?
Regards
Rüdiger