stas 2003/03/02 19:39:07
Modified: xs/Apache/RequestIO Apache__RequestIO.h xs/Apache/SubRequest Apache__SubRequest.h src/modules/perl mod_perl.c modperl_filter.c modperl_filter.h xs/tables/current/ModPerl FunctionTable.pm t/filter out_bbs_ctx.t out_str_ctx.t t/filter/TestFilter out_bbs_ctx.pm out_str_ctx.pm . Changes Log: revamp the code handling output flushing and flush bucket sending. Namelly modperl_wbucket_flush and modperl_wbucket_pass now can be told to send a flush bucket by themselves, attaching it to the data bb they are already sending. This halfs the number of output filter invocations when the response handler flushes output via $| or rflush. adjust tests, which were counting the number of invocations. Revision Changes Path 1.36 +3 -4 modperl-2.0/xs/Apache/RequestIO/Apache__RequestIO.h Index: Apache__RequestIO.h =================================================================== RCS file: /home/cvs/modperl-2.0/xs/Apache/RequestIO/Apache__RequestIO.h,v retrieving revision 1.35 retrieving revision 1.36 diff -u -r1.35 -r1.36 --- Apache__RequestIO.h 2 Mar 2003 13:32:26 -0000 1.35 +++ Apache__RequestIO.h 3 Mar 2003 03:39:06 -0000 1.36 @@ -23,8 +23,7 @@ #define mpxs_output_flush(r, rcfg) \ /* if ($|) */ \ if (IoFLUSH(PL_defoutgv)) { \ - MP_FAILURE_CROAK(modperl_wbucket_flush(rcfg->wbucket)); \ - ap_rflush(r); \ + MP_FAILURE_CROAK(modperl_wbucket_flush(rcfg->wbucket, TRUE)); \ } static MP_INLINE apr_size_t mpxs_ap_rvputs(pTHX_ I32 items, @@ -145,9 +144,9 @@ rcfg = modperl_config_req_get(r); - MP_FAILURE_CROAK(modperl_wbucket_flush(rcfg->wbucket)); + MP_FAILURE_CROAK(modperl_wbucket_flush(rcfg->wbucket, TRUE)); - return ap_rflush(r); + return APR_SUCCESS; } static MP_INLINE long mpxs_ap_get_client_block(pTHX_ request_rec *r, 1.3 +1 -1 modperl-2.0/xs/Apache/SubRequest/Apache__SubRequest.h Index: Apache__SubRequest.h =================================================================== RCS file: /home/cvs/modperl-2.0/xs/Apache/SubRequest/Apache__SubRequest.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Apache__SubRequest.h 23 Jan 2003 00:31:28 -0000 1.2 +++ Apache__SubRequest.h 3 Mar 2003 03:39:06 -0000 1.3 @@ -7,7 +7,7 @@ if (r->main) { modperl_config_req_t *rcfg = modperl_config_req_get(r->main); - MP_FAILURE_CROAK(modperl_wbucket_flush(rcfg->wbucket)); + MP_FAILURE_CROAK(modperl_wbucket_flush(rcfg->wbucket, FALSE)); } return ap_run_sub_req(r); 1.154 +1 -1 modperl-2.0/src/modules/perl/mod_perl.c Index: mod_perl.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/mod_perl.c,v retrieving revision 1.153 retrieving revision 1.154 diff -u -r1.153 -r1.154 --- mod_perl.c 2 Mar 2003 13:26:25 -0000 1.153 +++ mod_perl.c 3 Mar 2003 03:39:06 -0000 1.154 @@ -742,7 +742,7 @@ MP_dRCFG; /* flush output buffer */ - return modperl_wbucket_flush(rcfg->wbucket); + return modperl_wbucket_flush(rcfg->wbucket, FALSE); } static int modperl_response_handler_run(request_rec *r, int finish) 1.54 +81 -55 modperl-2.0/src/modules/perl/modperl_filter.c Index: modperl_filter.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_filter.c,v retrieving revision 1.53 retrieving revision 1.54 diff -u -r1.53 -r1.54 --- modperl_filter.c 2 Mar 2003 10:30:56 -0000 1.53 +++ modperl_filter.c 3 Mar 2003 03:39:06 -0000 1.54 @@ -1,9 +1,54 @@ #include "mod_perl.h" +/* helper funcs */ + +#define MP_FILTER_POOL(f) f->r ? f->r->pool : f->c->pool + +MP_INLINE static apr_status_t send_input_eos(modperl_filter_t *filter) +{ + apr_bucket_alloc_t *ba = filter->f->c->bucket_alloc; + apr_bucket *b = apr_bucket_eos_create(ba); + APR_BRIGADE_INSERT_TAIL(filter->bb_out, b); + ((modperl_filter_ctx_t *)filter->f->ctx)->sent_eos = 1; + return APR_SUCCESS; +} + +MP_INLINE static apr_status_t send_input_flush(modperl_filter_t *filter) +{ + apr_bucket_alloc_t *ba = filter->f->c->bucket_alloc; + apr_bucket *b = apr_bucket_flush_create(ba); + APR_BRIGADE_INSERT_TAIL(filter->bb_out, b); + return APR_SUCCESS; +} + +MP_INLINE static apr_status_t send_output_eos(ap_filter_t *f) +{ + apr_bucket_alloc_t *ba = f->c->bucket_alloc; + apr_bucket_brigade *bb = apr_brigade_create(MP_FILTER_POOL(f), + ba); + apr_bucket *b = apr_bucket_eos_create(ba); + APR_BRIGADE_INSERT_TAIL(bb, b); + ((modperl_filter_ctx_t *)f->ctx)->sent_eos = 1; + MP_TRACE_f(MP_FUNC, "sending EOS bucket in separate bb\n"); + return ap_pass_brigade(f, bb); +} + +MP_INLINE static apr_status_t send_output_flush(ap_filter_t *f) +{ + apr_bucket_alloc_t *ba = f->c->bucket_alloc; + apr_bucket_brigade *bb = apr_brigade_create(MP_FILTER_POOL(f), + ba); + apr_bucket *b = apr_bucket_flush_create(ba); + APR_BRIGADE_INSERT_TAIL(bb, b); + MP_TRACE_f(MP_FUNC, "sending FLUSH bucket in separate bb\n"); + return ap_pass_brigade(f, bb); +} + /* simple buffer api */ MP_INLINE apr_status_t modperl_wbucket_pass(modperl_wbucket_t *wb, - const char *buf, apr_size_t len) + const char *buf, apr_size_t len, + int add_flush_bucket) { apr_bucket_alloc_t *ba = (*wb->filters)->c->bucket_alloc; apr_bucket_brigade *bb; @@ -56,20 +101,39 @@ bucket = apr_bucket_transient_create(work_buf, len, ba); APR_BRIGADE_INSERT_TAIL(bb, bucket); + if (add_flush_bucket) { + /* append the flush bucket rather then calling ap_rflush, to + * prevent a creation of yet another bb, which will cause an + * extra call for each filter in the chain */ + apr_bucket *bucket = apr_bucket_flush_create(ba); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + } + MP_TRACE_f(MP_FUNC, "buffer length=%d\n", len); return ap_pass_brigade(*(wb->filters), bb); } -MP_INLINE apr_status_t modperl_wbucket_flush(modperl_wbucket_t *wb) +/* if add_flush_bucket is TRUE + * and there is data to flush, + * a flush bucket is added to the tail of bb with data + * otherwise + * a flush bucket is sent in its own bb + */ +MP_INLINE apr_status_t modperl_wbucket_flush(modperl_wbucket_t *wb, + int add_flush_bucket) { apr_status_t rv = APR_SUCCESS; if (wb->outcnt) { - rv = modperl_wbucket_pass(wb, wb->outbuf, wb->outcnt); + rv = modperl_wbucket_pass(wb, wb->outbuf, wb->outcnt, + add_flush_bucket); wb->outcnt = 0; } - + else if (add_flush_bucket) { + rv = send_output_flush(*(wb->filters)); + } + return rv; } @@ -87,14 +151,14 @@ if ((len + wb->outcnt) > sizeof(wb->outbuf)) { apr_status_t rv; - if ((rv = modperl_wbucket_flush(wb)) != APR_SUCCESS) { + if ((rv = modperl_wbucket_flush(wb, FALSE)) != APR_SUCCESS) { return rv; } } if (len >= sizeof(wb->outbuf)) { *wlen = len; - return modperl_wbucket_pass(wb, buf, len); + return modperl_wbucket_pass(wb, buf, len, FALSE); } else { memcpy(&wb->outbuf[wb->outcnt], buf, len); @@ -106,8 +170,6 @@ /* generic filter routines */ -#define MP_FILTER_POOL(f) f->r ? f->r->pool : f->c->pool - modperl_filter_t *modperl_filter_new(ap_filter_t *f, apr_bucket_brigade *bb, modperl_filter_mode_e mode, @@ -223,46 +285,6 @@ return status; } -/* output filters */ - -MP_INLINE static apr_status_t send_input_eos(modperl_filter_t *filter) -{ - apr_bucket_alloc_t *ba = filter->f->c->bucket_alloc; - apr_bucket *b = apr_bucket_eos_create(ba); - APR_BRIGADE_INSERT_TAIL(filter->bb_out, b); - ((modperl_filter_ctx_t *)filter->f->ctx)->sent_eos = 1; - return APR_SUCCESS; - -} - -MP_INLINE static apr_status_t send_input_flush(modperl_filter_t *filter) -{ - apr_bucket_alloc_t *ba = filter->f->c->bucket_alloc; - apr_bucket *b = apr_bucket_flush_create(ba); - APR_BRIGADE_INSERT_TAIL(filter->bb_out, b); - return APR_SUCCESS; -} - -MP_INLINE static apr_status_t send_output_eos(ap_filter_t *f) -{ - apr_bucket_alloc_t *ba = f->c->bucket_alloc; - apr_bucket_brigade *bb = apr_brigade_create(MP_FILTER_POOL(f), - ba); - apr_bucket *b = apr_bucket_eos_create(ba); - APR_BRIGADE_INSERT_TAIL(bb, b); - ((modperl_filter_ctx_t *)f->ctx)->sent_eos = 1; - return ap_pass_brigade(f->next, bb); -} - -MP_INLINE static apr_status_t send_output_flush(ap_filter_t *f) -{ - apr_bucket_alloc_t *ba = f->c->bucket_alloc; - apr_bucket_brigade *bb = apr_brigade_create(MP_FILTER_POOL(f), - ba); - apr_bucket *b = apr_bucket_flush_create(ba); - APR_BRIGADE_INSERT_TAIL(bb, b); - return ap_pass_brigade(f->next, bb); -} /* unrolled APR_BRIGADE_FOREACH loop */ @@ -501,26 +523,30 @@ MP_INLINE apr_status_t modperl_output_filter_flush(modperl_filter_t *filter) { + int add_flush_bucket = FALSE; + if (((modperl_filter_ctx_t *)filter->f->ctx)->sent_eos) { /* no data should be sent after EOS has been sent */ return filter->rc; } - filter->rc = modperl_wbucket_flush(&filter->wbucket); + if (filter->flush) { + add_flush_bucket = TRUE; + filter->flush = 0; + } + + filter->rc = modperl_wbucket_flush(&filter->wbucket, add_flush_bucket); if (filter->rc != APR_SUCCESS) { return filter->rc; } - if (filter->eos || filter->flush) { - MP_TRACE_f(MP_FUNC, "sending %s bucket\n", - filter->eos ? "EOS" : "FLUSH"); - filter->rc = filter->eos ? - send_output_eos(filter->f) : send_output_flush(filter->f); + if (filter->eos) { + filter->rc = send_output_eos(filter->f->next); if (filter->bb_in) { apr_brigade_destroy(filter->bb_in); filter->bb_in = NULL; } - filter->flush = filter->eos = 0; + filter->eos = 0; } return filter->rc; 1.21 +4 -2 modperl-2.0/src/modules/perl/modperl_filter.h Index: modperl_filter.h =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_filter.h,v retrieving revision 1.20 retrieving revision 1.21 diff -u -r1.20 -r1.21 --- modperl_filter.h 25 Jan 2003 03:08:04 -0000 1.20 +++ modperl_filter.h 3 Mar 2003 03:39:06 -0000 1.21 @@ -16,9 +16,11 @@ /* simple buffer api */ MP_INLINE apr_status_t modperl_wbucket_pass(modperl_wbucket_t *b, - const char *buf, apr_size_t len); + const char *buf, apr_size_t len, + int add_flush_bucket); -MP_INLINE apr_status_t modperl_wbucket_flush(modperl_wbucket_t *b); +MP_INLINE apr_status_t modperl_wbucket_flush(modperl_wbucket_t *b, + int add_flush_bucket); MP_INLINE apr_status_t modperl_wbucket_write(pTHX_ modperl_wbucket_t *b, 1.107 +8 -0 modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm Index: FunctionTable.pm =================================================================== RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v retrieving revision 1.106 retrieving revision 1.107 diff -u -r1.106 -r1.107 --- FunctionTable.pm 2 Mar 2003 13:28:13 -0000 1.106 +++ FunctionTable.pm 3 Mar 2003 03:39:06 -0000 1.107 @@ -4577,6 +4577,10 @@ { 'type' => 'modperl_wbucket_t *', 'name' => 'b' + }, + { + 'type' => 'int', + 'name' => 'add_flush_bucket' } ] }, @@ -4598,6 +4602,10 @@ { 'type' => 'apr_size_t', 'name' => 'len' + }, + { + 'type' => 'int', + 'name' => 'add_flush_bucket' } ] }, 1.2 +2 -1 modperl-2.0/t/filter/out_bbs_ctx.t Index: out_bbs_ctx.t =================================================================== RCS file: /home/cvs/modperl-2.0/t/filter/out_bbs_ctx.t,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- out_bbs_ctx.t 15 Jan 2003 06:47:15 -0000 1.1 +++ out_bbs_ctx.t 3 Mar 2003 03:39:06 -0000 1.2 @@ -8,7 +8,8 @@ plan tests => 1; my $blocks = 33; -my $invoked = 100; +my $invoked = 34; # 33 bb made of data and 1 flush bucket (unbuffered print) + # 1 bb with EOS bucket my $sig = join "\n", "received $blocks complete blocks", "filter invoked $invoked times\n"; my $data = "#" x $blocks . "x" x $blocks; 1.2 +3 -1 modperl-2.0/t/filter/out_str_ctx.t Index: out_str_ctx.t =================================================================== RCS file: /home/cvs/modperl-2.0/t/filter/out_str_ctx.t,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- out_str_ctx.t 15 Jan 2003 06:47:15 -0000 1.1 +++ out_str_ctx.t 3 Mar 2003 03:39:06 -0000 1.2 @@ -8,7 +8,9 @@ plan tests => 1; my $blocks = 33; -my $invoked = 100; +my $invoked = 67; # 33 bb made of data and 1 flush bucket (unbuffered print) + # 33 bb made of 1 flush bucket (rflush) + # 1 bb with EOS bucket my $sig = join "\n", "received $blocks complete blocks", "filter invoked $invoked times\n"; my $data = "#" x $blocks . "x" x $blocks; 1.3 +5 -1 modperl-2.0/t/filter/TestFilter/out_bbs_ctx.pm Index: out_bbs_ctx.pm =================================================================== RCS file: /home/cvs/modperl-2.0/t/filter/TestFilter/out_bbs_ctx.pm,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- out_bbs_ctx.pm 2 Mar 2003 11:36:15 -0000 1.2 +++ out_bbs_ctx.pm 3 Mar 2003 03:39:06 -0000 1.3 @@ -78,7 +78,11 @@ $r->content_type('text/plain'); - # make sure that + # just to make sure that print() won't flush, or we would get the + # count wrong + local $| = 0; + + # make sure that: # - we send big enough data so it won't fit into one buffer # - use chunk size which doesn't nicely fit into a buffer size, so # we have something to store in the context between filter calls 1.2 +4 -0 modperl-2.0/t/filter/TestFilter/out_str_ctx.pm Index: out_str_ctx.pm =================================================================== RCS file: /home/cvs/modperl-2.0/t/filter/TestFilter/out_str_ctx.pm,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- out_str_ctx.pm 15 Jan 2003 06:47:15 -0000 1.1 +++ out_str_ctx.pm 3 Mar 2003 03:39:06 -0000 1.2 @@ -65,6 +65,10 @@ $r->content_type('text/plain'); + # just to make sure that print() flushes, or we would get the + # count wrong + local $| = 1; + # make sure that # - we send big enough data so it won't fit into one buffer # - use chunk size which doesn't nicely fit into a buffer size, so 1.141 +8 -0 modperl-2.0/Changes Index: Changes =================================================================== RCS file: /home/cvs/modperl-2.0/Changes,v retrieving revision 1.140 retrieving revision 1.141 diff -u -r1.140 -r1.141 --- Changes 2 Mar 2003 22:47:19 -0000 1.140 +++ Changes 3 Mar 2003 03:39:07 -0000 1.141 @@ -10,6 +10,14 @@ =item 1.99_09-dev +revamp the code handling output flushing and flush bucket +sending. Namelly modperl_wbucket_flush and modperl_wbucket_pass now +can be told to send a flush bucket by themselves, attaching it to the +data bb they are already sending. This halfs the number of output +filter invocations when the response handler flushes output via $| or +rflush. adjust tests, which were counting the number of invocations. +[Stas] + move ModPerl::RegistryCooker to use a hash as object (similar to mp1), to make it easier to subclass. [Nathan Byrd <[EMAIL PROTECTED]>]