You are viewing a plain text version of this content. The canonical link for it is here.
Posted to apache-bugdb@apache.org by Vasile Gaburici <ga...@ss.pub.ro> on 2000/05/29 11:02:26 UTC
general/6128: AB gives fake failed connections
>Number: 6128
>Category: general
>Synopsis: AB gives fake failed connections
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: apache
>State: open
>Class: sw-bug
>Submitter-Id: apache
>Arrival-Date: Mon May 29 02:10:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator: gaburici@ss.pub.ro
>Release: 2.0a3
>Organization:
apache
>Environment:
Linux 2.2.14-12-s1 i686
>Description:
I was testing some stuff I wrote with ApacheBench 1.3c and found
some bugs in ab. The problem was that ab started more connections than it
was told. That is -n X, started more than X connections. This was a
nuisance because the extra connections were bunk; ab didn't listen on them
and the server got EPIPEs. ab also initiated phony request after it was
through with the real ones. I was opening a connection to the server but
closed it right away. All this trouble translated into fake failed
requests reported by ab.
I fixed all this nastiness by adding proper accounting of
connections started by ab. Now you can be sure -n X will launch exactly X
connections, and ab is going to send proper requests and wait for
responses an all X connections. Please find attached a patch to cure the
problems mentioned herein. The patch is against the ab 1.3c that comes
with Apache 2.0a3. I don't know if it will work or not on the ab that
accompanies Apache 1.3.
If the 5 kb patch didn't make it through this form, I'd be happy to
mail it to one of the developers.
>How-To-Repeat:
>Fix:
--- ab.c.orig Fri Apr 28 21:24:59 2000
+++ ab.c Sun May 28 20:16:34 2000
@@ -83,6 +83,7 @@
** - POST and verbosity by Kurt Sussman <kl...@merlot.com>, August 1998
** - HTML table output added by David N. Welton <da...@prosa.it>, January 1999
** - Added Cookie, Arbitrary header and auth support. <di...@webweaving.org>, April 19
9
+ ** - Accounting of initiated requests. Vasile Gaburici <ga...@cs.pub.ro>, May 2000
**
*/
@@ -98,7 +99,7 @@
* only an issue for loopback usage
*/
-#define VERSION "1.3c"
+#define VERSION "1.3d"
/* -------------------------------------------------------------------- */
@@ -135,7 +136,7 @@
#define STATE_CONNECTING 1
#define STATE_READ 2
-#define CBUFFSIZE 512
+#define CBUFFSIZE 4096 /* allow the bloat that servlet engines send */
struct connection {
ap_socket_t *aprsock;
@@ -158,8 +159,8 @@
int time; /* time in ms for connection */
};
-#define ap_min(a,b) ((a)<(b))?(a):(b)
-#define ap_max(a,b) ((a)>(b))?(a):(b)
+#define ap_min(a,b) (((a)<(b))?(a):(b))
+#define ap_max(a,b) (((a)>(b))?(a):(b))
/* --------------------- GLOBALS ---------------------------- */
@@ -192,6 +193,7 @@
int totalread = 0; /* total number of bytes read */
int totalbread = 0; /* totoal amount of entity body read */
int totalposted = 0; /* total number of bytes posted, inc. headers */
+int started = 0; /* number of requests we have started */
int done = 0; /* number of requests we have done */
int doneka = 0; /* number of keep alive connections done */
int good = 0, bad = 0; /* number of good and bad requests */
@@ -278,6 +280,7 @@
printf("Concurrency Level: %d\n", concurrency);
printf("Time taken for tests: %d.%03d seconds\n",
timetaken / 1000, timetaken % 1000);
+ printf("Requests started: %d\n", started);
printf("Complete requests: %d\n", done);
printf("Failed requests: %d\n", bad);
if (bad)
@@ -482,19 +485,28 @@
if (ap_canonical_error(rv) == APR_EINPROGRESS) {
c->state = STATE_CONNECTING;
ap_add_poll_socket(readbits, c->aprsock, APR_POLLOUT);
+ if (verbosity >= 4) {
+ printf("LOG: Request didn't get through, still trying...\n", started);
+ }
return;
}
else {
ap_remove_poll_socket(readbits, c->aprsock);
ap_close_socket(c->aprsock);
err_conn++;
+ if (verbosity >= 4) {
+ printf("LOG: Request didn't get through, marked bad.\n", started);
+ }
if (bad++ > 10) {
err("\nTest aborted after 10 failures\n\n");
}
start_connect(c);
}
}
-
+ ++started;
+ if (verbosity >= 4) {
+ printf("LOG: Request %d got through\n", started);
+ }
/* connected first time */
write_request(c);
}
@@ -515,6 +527,9 @@
doclen = c->bread;
}
else if (c->bread != doclen) {
+ if (verbosity >= 2) {
+ printf("LOG: Bad length: got %d, expected %d\n", c->bread, doclen);
+ }
bad ++;
err_length++;
}
@@ -529,11 +544,14 @@
}
}
- ap_remove_poll_socket(readbits, c->aprsock);
+ if (APR_NOTFOUND == ap_remove_poll_socket(readbits, c->aprsock)) {
+ printf("FIXME: Error removing socket %p\n", c->aprsock);
+ }
ap_close_socket(c->aprsock);
/* connect again */
- start_connect(c);
+ if(started < requests)
+ start_connect(c);
return;
}
@@ -551,8 +569,10 @@
r = sizeof(buffer);
ap_setsocketopt(c->aprsock, APR_SO_TIMEOUT, aprtimeout);
status = ap_recv(c->aprsock, buffer, &r);
- if (r == 0 || (status != 0 && ap_canonical_error(status) != APR_EAGAIN)) {
+ if (r == 0 || (status != APR_SUCCESS && ap_canonical_error(status) != APR_EAGAIN)) {
good++;
+ if ((status != APR_SUCCESS) && (verbosity >= 2))
+ perror("WARNING: Bad exit status from read");
close_connection(c);
return;
}
@@ -679,6 +699,9 @@
doclen = c->bread;
}
else if (c->bread != doclen) {
+ if (verbosity >= 2) {
+ printf("LOG: Bad length[2]: got %d, expected %d\n", c->bread, doclen);
+ }
bad++;
err_length++;
}
@@ -761,7 +784,7 @@
}
if (verbosity >= 2)
- printf("INFO: POST header == \n---\n%s\n---\n", request);
+ printf("\nINFO: POST header == \n---\n%s\n---\n", request);
reqlen = strlen(request);
@@ -779,6 +802,8 @@
/* ok - lets start */
start = ap_now();
+ concurrency = ap_min(concurrency, requests);
+
/* initialise lots of requests */
for (i = 0; i < concurrency; i++) {
con[i].socknum = i;
@@ -798,7 +823,7 @@
/* Timeout of 30 seconds. */
timeout = 30 * AP_USEC_PER_SEC;
- n = concurrency;
+ /* n need not be set, ap_poll will fill it */
ap_poll(readbits, &n, timeout);
if (!n) {
@@ -808,8 +833,10 @@
err("ap_poll");
for (i = 0; i < concurrency; i++) {
- ap_get_revents(&rv, con[i].aprsock, readbits);
-
+ int status = ap_get_revents(&rv, con[i].aprsock, readbits);
+ /* Not all sockets in con are in readbits */
+ if(APR_EINVALSOCK == status)
+ continue;
/* Note: APR_POLLHUP is set after FIN is received on some
* systems, so treat that like APR_POLLIN so that we try
* to read again.
@@ -820,7 +847,7 @@
start_connect(&con[i]);
continue;
}
- if ((rv & APR_POLLIN) || (rv & APR_POLLPRI) || (rv & APR_POLLHUP))
+ if ((rv & APR_POLLIN) || (rv & APR_POLLPRI) || (rv & APR_POLLHUP))
read_connection(&con[i]);
if (rv & APR_POLLOUT)
write_request(&con[i]);
>Release-Note:
>Audit-Trail:
>Unformatted:
[In order for any reply to be added to the PR database, you need]
[to include <ap...@Apache.Org> in the Cc line and make sure the]
[subject line starts with the report component and number, with ]
[or without any 'Re:' prefixes (such as "general/1098:" or ]
["Re: general/1098:"). If the subject doesn't match this ]
[pattern, your message will be misfiled and ignored. The ]
["apbugs" address is not added to the Cc line of messages from ]
[the database automatically because of the potential for mail ]
[loops. If you do not include this Cc, your reply may be ig- ]
[nored unless you are responding to an explicit request from a ]
[developer. Reply only with text; DO NOT SEND ATTACHMENTS! ]