Re: svn commit: r711886 - /httpd/httpd/branches/2.2.x/STATUS

2008-11-08 Thread Ruediger Pluem


On 11/07/2008 05:33 PM, Joe Orton wrote:
 On Fri, Nov 07, 2008 at 01:29:15PM +0100, Plüm, Rüdiger, VF-Group wrote:
 Would it be possible to substitute the backend (fake) conn_rec's 
 -bucket_alloc pointer with the real r-connection-bucket_alloc, 
 for the duration of the request/response to the backend?  Wouldn't 
 that ensure that all the buckets in question exactly have the 
 correct lifetime?
 I though about this as well, but I suppose this is a risky road to take.
 Keep in mind that mod_ssl and the core network filters below might use this
 bucket allocator and that we keep this backend connection alive while the 
 front
 end connection might have died. So we might still have buckets in this
 backend connection pipe created by the previous request that are dead on the
 new request. This may cause segfaults when we start using the backend
 connection again.
 
 Fair enough.  Transmuting the buckets into TRANSIENTs seems like a 
 reasonable solution, in any case, it's sort of saying lifetime issues, 
 buyer beware in bucket-speak which exactly matches the problem in hand.
 
 In ap_proxy_buckets_lifetime_transform() is there any reason to restrict 
 to:
 
 +if (APR_BUCKET_IS_HEAP(e) || APR_BUCKET_IS_TRANSIENT(e)
 +|| APR_BUCKET_IS_IMMORTAL(e) || APR_BUCKET_IS_POOL(e)) {
 +apr_bucket_read(e, data, bytes, APR_BLOCK_READ);
 
 instead of simply:
 
  if (!APR_BUCKET_IS_METADATA(e)) {
 // ...likewise transmute to a TRANSIENT
 
 ?  You already know that the brigade size is constrained, right, so 
 there is no worry about memory consumption from morphing buckets, and 
 the technique should should work equally well for any data bucket?

This is a valid and good point I have not though about before :-).
Especially that the length of the brigade is limited. And it seems better
in this case to possibly do a sub optimal conversion of a data bucket
(like an MMAP bucket or especially a file bucket) than to not convert it at
all. So I adjusted this part of the code. Thanks for reviewing.

Regards

Rüdiger



Re: svn commit: r711886 - /httpd/httpd/branches/2.2.x/STATUS

2008-11-07 Thread Graham Leggett

Joe Orton wrote:


What is the problem at all?

mod_proxy_http uses a a conn_rec to communicate with the backend. It somehow 
reverses
the meaning of input and output filters and uses them to send the request and 
receive
the response. In order to use persistent SSL connections to the backend it is 
needed
to keep this conn_rec (and thus its bucket allocator) alive and tied to the 
backend
connection. Thus it is no longer destroyed at the end of a client request / 
connection.
So the conn_rec and especially the bucket allocator for the backend have a 
lifecycle
that is disjoint from the one to the client. Especially it can happen that due 
to e.g.
a faulty backend connection the conn_rec to the backend *lives* shorter than
buckets that are still buffered somewhere in the output filter chain to the 
client
(see comments in removed code below). This causes segfaults when these buckets 
are
accessed then or if brigades that contain them get cleaned up later on due to a 
parent
pool cleanup.


Not sure if I've got my head round this correctly, but...

Would it be possible to substitute the backend (fake) conn_rec's 
-bucket_alloc pointer with the real r-connection-bucket_alloc, for 
the duration of the request/response to the backend?  Wouldn't that 
ensure that all the buckets in question exactly have the correct 
lifetime?


What looks broken to me is the fact that there is a link between the 
backend connection_rec and the frontend request_rec at all.


Both of these structures have completely independent and unrelated 
lifecycles, and either structure might outlive the other structure.


Ideally there needs to be a way of passing data that belongs to the 
backend across to the frontend without making any assumption that one 
will outlive the other. If this isn't possible, then we'll just be 
forced to copy the data.


Regards,
Graham
--


smime.p7s
Description: S/MIME Cryptographic Signature


Re: svn commit: r711886 - /httpd/httpd/branches/2.2.x/STATUS

2008-11-07 Thread Joe Orton
On Thu, Nov 06, 2008 at 09:58:52PM +0100, Ruediger Pluem wrote:
 What is the problem at all?
 
 mod_proxy_http uses a a conn_rec to communicate with the backend. It somehow 
 reverses
 the meaning of input and output filters and uses them to send the request and 
 receive
 the response. In order to use persistent SSL connections to the backend it is 
 needed
 to keep this conn_rec (and thus its bucket allocator) alive and tied to the 
 backend
 connection. Thus it is no longer destroyed at the end of a client request / 
 connection.
 So the conn_rec and especially the bucket allocator for the backend have a 
 lifecycle
 that is disjoint from the one to the client. Especially it can happen that 
 due to e.g.
 a faulty backend connection the conn_rec to the backend *lives* shorter than
 buckets that are still buffered somewhere in the output filter chain to the 
 client
 (see comments in removed code below). This causes segfaults when these 
 buckets are
 accessed then or if brigades that contain them get cleaned up later on due to 
 a parent
 pool cleanup.

Not sure if I've got my head round this correctly, but...

Would it be possible to substitute the backend (fake) conn_rec's 
-bucket_alloc pointer with the real r-connection-bucket_alloc, for 
the duration of the request/response to the backend?  Wouldn't that 
ensure that all the buckets in question exactly have the correct 
lifetime?

Regards, Joe


Re: svn commit: r711886 - /httpd/httpd/branches/2.2.x/STATUS

2008-11-07 Thread Joe Orton
On Fri, Nov 07, 2008 at 01:29:15PM +0100, Plüm, Rüdiger, VF-Group wrote:
  Would it be possible to substitute the backend (fake) conn_rec's 
  -bucket_alloc pointer with the real r-connection-bucket_alloc, 
  for the duration of the request/response to the backend?  Wouldn't 
  that ensure that all the buckets in question exactly have the 
  correct lifetime?
 
 I though about this as well, but I suppose this is a risky road to take.
 Keep in mind that mod_ssl and the core network filters below might use this
 bucket allocator and that we keep this backend connection alive while the 
 front
 end connection might have died. So we might still have buckets in this
 backend connection pipe created by the previous request that are dead on the
 new request. This may cause segfaults when we start using the backend
 connection again.

Fair enough.  Transmuting the buckets into TRANSIENTs seems like a 
reasonable solution, in any case, it's sort of saying lifetime issues, 
buyer beware in bucket-speak which exactly matches the problem in hand.

In ap_proxy_buckets_lifetime_transform() is there any reason to restrict 
to:

+if (APR_BUCKET_IS_HEAP(e) || APR_BUCKET_IS_TRANSIENT(e)
+|| APR_BUCKET_IS_IMMORTAL(e) || APR_BUCKET_IS_POOL(e)) {
+apr_bucket_read(e, data, bytes, APR_BLOCK_READ);

instead of simply:

 if (!APR_BUCKET_IS_METADATA(e)) {
// ...likewise transmute to a TRANSIENT

?  You already know that the brigade size is constrained, right, so 
there is no worry about memory consumption from morphing buckets, and 
the technique should should work equally well for any data bucket?

Apologies if you've already thought about this too but it might be worth 
a comment in the code explaining why, if so :)

Regards, Joe


Re: svn commit: r711886 - /httpd/httpd/branches/2.2.x/STATUS

2008-11-07 Thread Plüm, Rüdiger, VF-Group
 

 -Ursprüngliche Nachricht-
 Von: Joe Orton [mailto:[EMAIL PROTECTED] 
 Gesendet: Freitag, 7. November 2008 13:11
 An: dev@httpd.apache.org
 Betreff: Re: svn commit: r711886 - /httpd/httpd/branches/2.2.x/STATUS
 
 On Thu, Nov 06, 2008 at 09:58:52PM +0100, Ruediger Pluem wrote:
  What is the problem at all?
  
  mod_proxy_http uses a a conn_rec to communicate with the 
 backend. It somehow reverses
  the meaning of input and output filters and uses them to 
 send the request and receive
  the response. In order to use persistent SSL connections to 
 the backend it is needed
  to keep this conn_rec (and thus its bucket allocator) alive 
 and tied to the backend
  connection. Thus it is no longer destroyed at the end of a 
 client request / connection.
  So the conn_rec and especially the bucket allocator for the 
 backend have a lifecycle
  that is disjoint from the one to the client. Especially it 
 can happen that due to e.g.
  a faulty backend connection the conn_rec to the backend 
 *lives* shorter than
  buckets that are still buffered somewhere in the output 
 filter chain to the client
  (see comments in removed code below). This causes segfaults 
 when these buckets are
  accessed then or if brigades that contain them get cleaned 
 up later on due to a parent
  pool cleanup.
 
 Not sure if I've got my head round this correctly, but...
 
 Would it be possible to substitute the backend (fake) conn_rec's 
 -bucket_alloc pointer with the real 
 r-connection-bucket_alloc, for 
 the duration of the request/response to the backend?  Wouldn't that 
 ensure that all the buckets in question exactly have the correct 
 lifetime?

I though about this as well, but I suppose this is a risky road to take.
Keep in mind that mod_ssl and the core network filters below might use this
bucket allocator and that we keep this backend connection alive while the front
end connection might have died. So we might still have buckets in this
backend connection pipe created by the previous request that are dead on the
new request. This may cause segfaults when we start using the backend
connection again.

Regards

Rüdiger


Re: svn commit: r711886 - /httpd/httpd/branches/2.2.x/STATUS

2008-11-06 Thread Ruediger Pluem


On 11/06/2008 05:07 PM, [EMAIL PROTECTED] wrote:
 Author: jim
 Date: Thu Nov  6 08:06:54 2008
 New Revision: 711886
 
 URL: http://svn.apache.org/viewvc?rev=711886view=rev
 Log:
 Hold off until I learn more from Ruediger
 
 Modified:
 httpd/httpd/branches/2.2.x/STATUS
 
 Modified: httpd/httpd/branches/2.2.x/STATUS
 URL: 
 http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/STATUS?rev=711886r1=711885r2=711886view=diff
 ==
 --- httpd/httpd/branches/2.2.x/STATUS (original)
 +++ httpd/httpd/branches/2.2.x/STATUS Thu Nov  6 08:06:54 2008
 @@ -135,7 +135,7 @@
  http://svn.apache.org/viewvc?rev=706921view=rev
   Backport version for 2.2.x of patch:
  Trunk version of patch works
 - +1: jim
 + +1: 
   rpluem: This code still has bad edge cases that lead to segfaults. I 
 have
   a better version in the pipe that currently undergoes testing and will
   be in trunk soon.

After analysing some crashes on one of my systems I came to the conclusion that 
the
current approach to solve the problem still has open edge cases of which some 
IMHO
could not be fixed this way. Furthermore the already complex flushing code 
would become
even more complex and harder to understand. So I chose a new approach to solve 
the problem.

What is the problem at all?

mod_proxy_http uses a a conn_rec to communicate with the backend. It somehow 
reverses
the meaning of input and output filters and uses them to send the request and 
receive
the response. In order to use persistent SSL connections to the backend it is 
needed
to keep this conn_rec (and thus its bucket allocator) alive and tied to the 
backend
connection. Thus it is no longer destroyed at the end of a client request / 
connection.
So the conn_rec and especially the bucket allocator for the backend have a 
lifecycle
that is disjoint from the one to the client. Especially it can happen that due 
to e.g.
a faulty backend connection the conn_rec to the backend *lives* shorter than
buckets that are still buffered somewhere in the output filter chain to the 
client
(see comments in removed code below). This causes segfaults when these buckets 
are
accessed then or if brigades that contain them get cleaned up later on due to a 
parent
pool cleanup.

The new approach to solve the problem is to transform the lifetime of the 
buckets
by shifting them to a different allocator. The basic approach is to iterate over
the brigade fetched from the backend connection and

for metabuckets recreate them
for data buckets read them and put the read data in a transient bucket.

Currently only HEAP, TRANSIENT, POOL and IMMORTAL data buckets are expected 
from the backend.
In this case apr_bucket_read is a trivial operation that only returns a pointer 
to the
data stored in the bucket. Once we pass the buckets down the chain filters are 
responsible
to set the buckets aside if they do not consume them in this filter pass. 
Setting aside
a transient bucket causes the data to be moved into a freshly allocated memory 
area that
is allocated from the bucket allocator, in this case the correct one as it is 
the one from
the connection to the client. This way effort intensive memory copying only 
happens, when
really needed. A big plus of this approach is that it opens the door again for 
returning
the backend connection back to the connection pool as soon as we have received 
all data
from the backend instead of the need to wait until all data is flushed to the 
client.
I guess this will make some people happy here :-).

Well here we go:


Index: modules/proxy/proxy_util.c
===
--- modules/proxy/proxy_util.c  (revision 711224)
+++ modules/proxy/proxy_util.c  (working copy)
@@ -1628,9 +1628,6 @@
 {
 proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
 proxy_worker *worker = conn-worker;
-apr_bucket_brigade *bb;
-conn_rec *c;
-request_rec *r;

 /*
  * If the connection pool is NULL the worker
@@ -1651,112 +1648,6 @@
 }
 #endif

-r = conn-r;
-if (conn-need_flush  r) {
-request_rec *main_request;
-
-/*
- * We need to get to the main request as subrequests do not count any
- * sent bytes.
- */
-main_request = r;
-while (main_request-main) {
-main_request = main_request-main;
-}
-if (main_request-bytes_sent || r-eos_sent) {
-ap_filter_t *flush_filter;
-
-/*
- * We need to ensure that buckets that may have been buffered in 
the
- * network filters get flushed to the network. This is needed since
- * these buckets have been created with the bucket allocator of the
- * backend connection. This allocator either gets destroyed if
- * conn-close is set or the worker address is not reusable which
- * causes the