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]>]