On Mar 17, 2010, at 11:27 AM, Torsten Förtsch wrote:

> On Wednesday 17 March 2010 12:15:15 Torsten Förtsch wrote:
>> On Tuesday 16 March 2010 21:09:33 Pavel Georgiev wrote:
>>> for (<some condition>) {
>>>    $request->print("--$this->{boundary}\n");
>>>    $request->print("Content-type: text/html; charset=utf-8;\n\n");
>>>    $request->print("$data\n\n");
>>>    $request->rflush;
>>> }
>>> 
>>> And the result is endless memory growth in the apache process. Is that
>>> what you had in mind?
>>> 
>> 
>> I can confirm this. I have tried this little handler:
>> 
>> sub {
>>  my $r=shift;
>> 
>>  until( -e "/tmp/stop" ) {
>>    $r->print(("x"x70)."\n");
>>    $r->rflush;
>>  }
>> 
>>  return Apache2::Const::OK;
>> }
>> 
>> The httpd process grows slowly but unlimited. Without the rflush() it
>> grows  slower but still does.
>> 
> Here is a bit more stuff on the bug. It is the pool that grows.
> 
> To show it I use a handler that prints an empty document. I think an empty 
> file shipped by the default handler will do as well.
> 
> Then I add the following filter to the request:
> 
> $r->add_output_filter(sub {
>  my ($f, $bb)=...@_;
> 
>  unless( $f->ctx ) {
>    $f->r->headers_out->unset('Content-Length');
>    $f->ctx(1);
>  }
> 
>  my $eos=0;
>  while( my $b=$bb->first ) {
>    $eos++ if( $b->is_eos );
>    $b->delete;
>  }
>  return 0 unless $eos;
> 
>  my $ba=$f->c->bucket_alloc;
>  until( -e '/tmp/stop' ) {
>    my $bb2=APR::Brigade->new($f->c->pool, $ba);
>    $bb2->insert_tail(APR::Bucket->new($ba, ("x"x70)."\n"));
>    $bb2->insert_tail(APR::Bucket::flush_create $ba);
>    $f->next->pass_brigade($bb2);
>  }
> 
>  my $bb2=APR::Brigade->new($f->c->pool, $ba);
>  $bb2->insert_tail(APR::Bucket::eos_create $ba);
>  $f->next->pass_brigade($bb2);
> 
>  return 0;
> });
> 
> The filter drops the empty document and emulates our infinite output. With 
> this filter the httpd process still grows. Now I add a subpool to the loop:
> 
> [...]
>  until( -e '/tmp/stop' ) {
>    my $pool=$f->c->pool->new;                       # create a subpool
>    my $bb2=APR::Brigade->new($pool, $ba);           # use the subpool
>    $bb2->insert_tail(APR::Bucket->new($ba, ("x"x70)."\n"));
>    $bb2->insert_tail(APR::Bucket::flush_create $ba);
>    $f->next->pass_brigade($bb2);
>    $pool->destroy;                                  # and destroy it
>  }
> [...]
> 
> Now it does not grow.
> 
> Torsten Förtsch
> 
> -- 
> Need professional modperl support? Hire me! (http://foertsch.name)
> 
> Like fantasy? http://kabatinte.net


How would that logic (adding subpools and using them) be applied to my 
simplified example:

for (;;) {
   $request->print("--$this->{boundary}\n");
   $request->print("Content-type: text/html; charset=utf-8;\n\n");
   $request->print("$data\n\n");
   $request->rflush;
}

Do I need to add an output filter?

Reply via email to