/*
- * $Id: client_side.cc,v 1.425 1998/12/09 23:00:58 wessels Exp $
+ * $Id: client_side.cc,v 1.426 1999/01/08 21:12:06 wessels Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
static PF clientReadRequest;
static PF connStateFree;
static PF requestTimeout;
-static int CheckQuickAbort2(const clientHttpRequest *);
static int clientCheckTransferDone(clientHttpRequest *);
static int clientGotNotEnough(clientHttpRequest *);
-static void CheckQuickAbort(clientHttpRequest *);
static void checkFailureRatio(err_type, hier_code);
static void clientProcessMiss(clientHttpRequest *);
static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep);
const http_status status = mem->reply->sline.status;
debug(33, 3) ("clientHandleIMSReply: %s, %d bytes\n", url, (int) size);
if (size < 0 && entry->store_status != STORE_ABORTED)
-#if OLD_CODE
- /*
- * This storeAbort() call causes wrong behaviour in some situations.
- * If there are multiple clients hanging on this entry, the second
- * client will not want the entry to be aborted. This shows up in
- * the stack trace below:
- *
- * #0 0xef5f452c in kill ()
- * #1 0xef5ba620 in abort ()
- * #2 0x7d680 in __eprintf (string=0x82a70 "%s:%u: failed assertion `%s'\n", expression=0x82a90 "client_side.c", line=1111, filename=0x83468 "size > 0")
- * #3 0x2ad7c in clientCacheHit (data=0x31ae318, buf=0x17f1450 "", size=0) at client_side.c:1111
- * #4 0x65cd4 in storeClientCopy2 (e=0x4c48c0, sc=0x2eedd70) at store_client.c:264
- * #5 0x665b0 in InvokeHandlers (e=0x4c48c0) at store_client.c:510
- * #6 0x63c90 in storeAbort (e=0x4c48c0, cbflag=1) at store.c:626
- * #7 0x29190 in clientHandleIMSReply (data=0x31e9518, buf=0x2268810 "", size=-1) at client_side.c:343
- * #8 0x66450 in storeUnregister (e=0x2910c, data=0x31e9518) at store_client.c:467
- * #9 0x29a54 in httpRequestFree (data=0x31e9518) at client_side.c:579
- * #10 0x29eb4 in connStateFree (fd=534528, data=0x314d0d0) at client_side.c:667
- * #11 0x2f27c in commCallCloseHandlers (fd=42) at comm.c:501
- * #12 0x2f410 in comm_close (fd=42) at comm.c:565
- * #13 0x2d054 in clientReadRequest (fd=42, data=0x314d0d0) at client_side.c:2038
- * #14 0x309c8 in comm_poll (msec=434) at comm_select.c:354
- * #15 0x4da64 in main (argc=5, argv=0xeffffd4c) at main.c:587
- */
- storeAbort(entry, 1);
-#endif
- /*
- * Lets just try to return here and see what kind of problems that
- * causes
- */
- return;
+ return;
if (entry->store_status == STORE_ABORTED) {
debug(33, 3) ("clientHandleIMSReply: ABORTED '%s'\n", url);
/* We have an existing entry, but failed to validate it */
debug(33, 3) ("httpRequestFree: %s\n", storeUrl(entry));
if (!clientCheckTransferDone(http)) {
if (entry)
- storeUnregister(entry, http); /* unregister BEFORE abort */
- CheckQuickAbort(http);
+ storeUnregister(entry, http);
entry = http->entry; /* reset, IMS might have changed it */
if (entry && entry->ping_status == PING_WAITING)
storeReleaseRequest(entry);
}
}
-/* return 1 if the request should be aborted */
-static int
-CheckQuickAbort2(const clientHttpRequest * http)
-{
- int curlen;
- int minlen;
- int expectlen;
-
- if (!http->request->flags.cachable)
- return 1;
- if (EBIT_TEST(http->entry->flags, KEY_PRIVATE))
- return 1;
- if (http->entry->mem_obj == NULL)
- return 1;
- expectlen = http->entry->mem_obj->reply->content_length;
- curlen = (int) http->entry->mem_obj->inmem_hi;
- minlen = (int) Config.quickAbort.min << 10;
- if (minlen < 0)
- /* disabled */
- return 0;
- if (curlen > expectlen)
- /* bad content length */
- return 1;
- if ((expectlen - curlen) < minlen)
- /* only little more left */
- return 0;
- if ((expectlen - curlen) > (Config.quickAbort.max << 10))
- /* too much left to go */
- return 1;
- if (expectlen < 100)
- /* avoid FPE */
- return 0;
- if ((curlen / (expectlen / 100)) > Config.quickAbort.pct)
- /* past point of no return */
- return 0;
- return 1;
-}
-
-
-static void
-CheckQuickAbort(clientHttpRequest * http)
-{
- StoreEntry *entry = http->entry;
- /* Note, set entry here because http->entry might get changed (for IMS
- * requests) during the storeAbort() call */
- if (entry == NULL)
- return;
- if (storePendingNClients(entry) > 0)
- return;
- if (entry->store_status != STORE_PENDING)
- return;
- if (CheckQuickAbort2(http) == 0)
- return;
- debug(33, 3) ("CheckQuickAbort: ABORTING %s\n", storeUrl(entry));
- Counter.aborted_requests++;
- storeAbort(entry, 1);
-}
-
#define SENDING_BODY 0
#define SENDING_HDRSONLY 1
static int
/*
- * $Id: comm.cc,v 1.293 1998/12/05 00:54:20 wessels Exp $
+ * $Id: comm.cc,v 1.294 1999/01/08 21:12:08 wessels Exp $
*
* DEBUG: section 5 Socket Functions
* AUTHOR: Harvest Derived
#if USE_ASYNC_IO
int doaioclose = 1;
#endif
+ extern int current_hdl_fd;
debug(5, 5) ("comm_close: FD %d\n", fd);
assert(fd >= 0);
assert(fd < Squid_MaxFD);
return;
if (shutting_down && (!F->open || F->type == FD_FILE))
return;
+ if (fd == current_hdl_fd) {
+ F->flags.delayed_comm_close = 1;
+ return;
+ }
assert(F->open);
assert(F->type != FD_FILE);
#ifdef USE_ASYNC_IO
/*
- * $Id: comm_select.cc,v 1.23 1998/12/04 22:20:15 wessels Exp $
+ * $Id: comm_select.cc,v 1.24 1999/01/08 21:12:09 wessels Exp $
*
* DEBUG: section 5 Socket Functions
*
#define FD_MASK_BYTES sizeof(fd_mask)
#define FD_MASK_BITS (FD_MASK_BYTES*NBBY)
+/* GLOBAL */
+int current_hdl_fd = -1;
/* STATIC */
#if !HAVE_POLL
* more frequently to minimize losses due to the 5 connect
* limit in SunOS */
for (i = 0; i < nfds; i++) {
+ fde *F;
int revents;
if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
continue;
callhttp = 1;
continue;
}
+ F = &fd_table[fd];
if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
debug(5, 6) ("comm_poll: FD %d ready for reading\n", fd);
- if ((hdl = fd_table[fd].read_handler)) {
- fd_table[fd].read_handler = NULL;
- hdl(fd, fd_table[fd].read_data);
+ if ((hdl = F->read_handler)) {
+ F->read_handler = NULL;
+ hdl(current_hdl_fd = fd, F->read_data);
Counter.select_fds++;
}
+ if (F->flags.delayed_comm_close) {
+ current_hdl_fd = -1;
+ comm_close(fd);
+ }
if (commCheckICPIncoming)
comm_poll_icp_incoming();
if (commCheckHTTPIncoming)
}
if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
debug(5, 5) ("comm_poll: FD %d ready for writing\n", fd);
- if ((hdl = fd_table[fd].write_handler)) {
- fd_table[fd].write_handler = NULL;
- hdl(fd, fd_table[fd].write_data);
+ if ((hdl = F->write_handler)) {
+ F->write_handler = NULL;
+ hdl(current_hdl_fd = fd, F->write_data);
Counter.select_fds++;
}
+ if (F->flags.delayed_comm_close) {
+ current_hdl_fd = -1;
+ comm_close(fd);
+ }
if (commCheckICPIncoming)
comm_poll_icp_incoming();
if (commCheckHTTPIncoming)
}
if (revents & POLLNVAL) {
close_handler *ch;
- fde *F = &fd_table[fd];
debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
- debug(5, 0) ("FD %d is a %s\n", fd, fdTypeStr[fd_table[fd].type]);
- debug(5, 0) ("--> %s\n", fd_table[fd].desc);
+ debug(5, 0) ("FD %d is a %s\n", fd, fdTypeStr[F->type]);
+ debug(5, 0) ("--> %s\n", F->desc);
debug(5, 0) ("tmout:%p read:%p write:%p\n",
F->timeout_handler,
F->read_handler,
static time_t last_timeout = 0;
struct timeval poll_time;
double timeout = current_dtime + (msec / 1000.0);
+ fde *F;
do {
#if !ALARM_UPDATES_TIME
getCurrentTime();
callhttp = 1;
continue;
}
+ F = &fd_table[fd];
debug(5, 6) ("comm_select: FD %d ready for reading\n", fd);
- if (fd_table[fd].read_handler) {
- hdl = fd_table[fd].read_handler;
- fd_table[fd].read_handler = NULL;
+ if (F->read_handler) {
+ hdl = F->read_handler;
+ F->read_handler = NULL;
commUpdateReadBits(fd, NULL);
- hdl(fd, fd_table[fd].read_data);
+ hdl(current_hdl_fd = fd, F->read_data);
Counter.select_fds++;
}
+ if (F->flags.delayed_comm_close) {
+ current_hdl_fd = -1;
+ comm_close(fd);
+ }
if (commCheckICPIncoming)
comm_select_icp_incoming();
if (commCheckHTTPIncoming)
callhttp = 1;
continue;
}
+ F = &fd_table[fd];
debug(5, 5) ("comm_select: FD %d ready for writing\n", fd);
- if (fd_table[fd].write_handler) {
- hdl = fd_table[fd].write_handler;
- fd_table[fd].write_handler = NULL;
+ if (F->write_handler) {
+ hdl = F->write_handler;
+ F->write_handler = NULL;
commUpdateWriteBits(fd, NULL);
- hdl(fd, fd_table[fd].write_data);
+ hdl(current_hdl_fd = fd, F->write_data);
Counter.select_fds++;
}
+ if (F->flags.delayed_comm_close) {
+ current_hdl_fd = -1;
+ comm_close(fd);
+ }
if (commCheckICPIncoming)
comm_select_icp_incoming();
if (commCheckHTTPIncoming)
debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
debug(5, 0) ("FD %d is a %s called '%s'\n",
fd,
- fdTypeStr[fd_table[fd].type],
+ fdTypeStr[F->type],
F->desc);
debug(5, 0) ("tmout:%p read:%p write:%p\n",
F->timeout_handler,
/*
- * $Id: forward.cc,v 1.40 1998/12/29 22:51:11 wessels Exp $
+ * $Id: forward.cc,v 1.41 1999/01/08 21:12:10 wessels Exp $
*
* DEBUG: section 17 Request Forwarding
* AUTHOR: Duane Wessels
err->request = requestLink(fwdState->request);
err->xerrno = fwdState->fail.xerrno;
errorAppendEntry(e, err);
- } else {
- storeAbort(e, 0);
}
}
fwdServersFree(&fwdState->servers);
err = errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT);
err->request = requestLink(fwdState->request);
errorAppendEntry(entry, err);
- } else {
- storeAbort(entry, 0);
}
comm_close(fd);
}
e->mem_obj->reply->sline.status);
fwdLogReplyStatus(fwdState->n_tries, e->mem_obj->reply->sline.status);
if (fwdReforward(fwdState)) {
- debug(17, 1) ("fwdComplete: re-forwarding %d %s\n",
+ debug(17, 3) ("fwdComplete: re-forwarding %d %s\n",
e->mem_obj->reply->sline.status,
storeUrl(e));
if (fwdState->server_fd > -1)
/*
- * $Id: ftp.cc,v 1.257 1998/12/05 00:54:25 wessels Exp $
+ * $Id: ftp.cc,v 1.258 1999/01/08 21:12:11 wessels Exp $
*
* DEBUG: section 9 File Transfer Protocol (FTP)
* AUTHOR: Harvest Derived
err = errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT);
err->request = requestLink(ftpState->request);
errorAppendEntry(entry, err);
- } else {
- storeAbort(entry, 0);
}
}
if (ftpState->data.fd > -1) {
Config.Timeout.read);
} else {
assert(mem->inmem_hi > 0);
- storeAbort(entry, 0);
ftpDataTransferDone(ftpState);
}
} else if (len == 0) {
err->request = requestLink(ftpState->request);
errorAppendEntry(entry, err);
}
- if (entry->store_status == STORE_PENDING)
- storeAbort(entry, 0);
comm_close(ftpState->ctrl.fd);
}
}
err->request = requestLink(ftpState->request);
errorAppendEntry(entry, err);
}
- if (entry->store_status == STORE_PENDING)
- storeAbort(entry, 0);
comm_close(ftpState->ctrl.fd);
}
return;
/*
- * $Id: gopher.cc,v 1.141 1998/12/05 00:54:26 wessels Exp $
+ * $Id: gopher.cc,v 1.142 1999/01/08 21:12:13 wessels Exp $
*
* DEBUG: section 10 Gopher
* AUTHOR: Harvest Derived
err = errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT);
err->url = xstrdup(gopherState->request);
errorAppendEntry(entry, err);
- } else {
- storeAbort(entry, 0);
}
comm_close(fd);
}
errorAppendEntry(entry, err);
comm_close(fd);
} else {
- storeAbort(entry, 0);
comm_close(fd);
}
} else if (len == 0 && entry->mem_obj->inmem_hi == 0) {
/*
- * $Id: http.cc,v 1.334 1998/12/11 23:10:47 wessels Exp $
+ * $Id: http.cc,v 1.335 1999/01/08 21:12:14 wessels Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
assert(entry->store_status == STORE_PENDING);
if (entry->mem_obj->inmem_hi == 0) {
fwdFail(httpState->fwd, ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT, 0);
- } else {
- storeAbort(entry, 0);
}
comm_close(fd);
}
fwdFail(httpState->fwd, ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, errno);
comm_close(fd);
} else {
- storeAbort(entry, 0);
comm_close(fd);
}
} else if (len == 0 && entry->mem_obj->inmem_hi == 0) {
/*
- * $Id: store_client.cc,v 1.49 1998/12/05 00:54:44 wessels Exp $
+ * $Id: store_client.cc,v 1.50 1999/01/08 21:12:16 wessels Exp $
*
* DEBUG: section 20 Storage Manager Client-Side Interface
* AUTHOR: Duane Wessels
static void storeClientFileRead(store_client * sc);
static EVH storeClientCopyEvent;
static store_client_t storeClientType(StoreEntry *);
+static int CheckQuickAbort2(StoreEntry * entry);
+static void CheckQuickAbort(StoreEntry * entry);
/* check if there is any client waiting for this object at all */
/* return 1 if there is at least one client */
callback(sc->callback_data, sc->copy_buf, -1);
}
cbdataFree(sc);
+ assert(e->lock_count > 0);
+ if (mem->nclients == 0)
+ CheckQuickAbort(e);
return 1;
}
debug(20, 3) ("storePendingNClients: returning %d\n", npend);
return npend;
}
+
+/* return 1 if the request should be aborted */
+static int
+CheckQuickAbort2(StoreEntry * entry)
+{
+ int curlen;
+ int minlen;
+ int expectlen;
+ MemObject *mem = entry->mem_obj;
+ assert(mem);
+ debug(20, 3) ("CheckQuickAbort2: entry=%p, mem=%p\n", entry, mem);
+ if (!mem->request->flags.cachable) {
+ debug(20, 3) ("CheckQuickAbort2: YES !mem->request->flags.cachable\n");
+ return 1;
+ }
+ if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
+ debug(20, 3) ("CheckQuickAbort2: YES KEY_PRIVATE\n");
+ return 1;
+ }
+ expectlen = mem->reply->content_length;
+ curlen = (int) mem->inmem_hi;
+ minlen = (int) Config.quickAbort.min << 10;
+ if (minlen < 0) {
+ debug(20, 3) ("CheckQuickAbort2: NO disabled\n");
+ return 0;
+ }
+ if (curlen > expectlen) {
+ debug(20, 3) ("CheckQuickAbort2: YES bad content length\n");
+ return 1;
+ }
+ if ((expectlen - curlen) < minlen) {
+ debug(20, 3) ("CheckQuickAbort2: NO only little more left\n");
+ return 0;
+ }
+ if ((expectlen - curlen) > (Config.quickAbort.max << 10)) {
+ debug(20, 3) ("CheckQuickAbort2: YES too much left to go\n");
+ return 1;
+ }
+ if (expectlen < 100) {
+ debug(20, 3) ("CheckQuickAbort2: NO avoid FPE\n");
+ return 0;
+ }
+ if ((curlen / (expectlen / 100)) > Config.quickAbort.pct) {
+ debug(20, 3) ("CheckQuickAbort2: NO past point of no return\n");
+ return 0;
+ }
+ debug(20, 3) ("CheckQuickAbort2: YES default, returning 1\n");
+ return 1;
+}
+
+static void
+CheckQuickAbort(StoreEntry * entry)
+{
+ if (entry == NULL)
+ return;
+ if (storePendingNClients(entry) > 0)
+ return;
+ if (entry->store_status != STORE_PENDING)
+ return;
+ if (CheckQuickAbort2(entry) == 0)
+ return;
+ Counter.aborted_requests++;
+ storeAbort(entry, 1);
+}
/*
- * $Id: store_swapout.cc,v 1.39 1998/12/16 06:34:31 wessels Exp $
+ * $Id: store_swapout.cc,v 1.40 1999/01/08 21:12:17 wessels Exp $
*
* DEBUG: section 20 Storage Manager Swapout Functions
* AUTHOR: Duane Wessels
char *swap_buf;
ssize_t swap_buf_len;
int hdr_len = 0;
- assert(mem != NULL);
+ if (mem == NULL)
+ return;
/* should we swap something out to disk? */
debug(20, 7) ("storeCheckSwapOut: %s\n", storeUrl(e));
debug(20, 7) ("storeCheckSwapOut: store_status = %s\n",
/*
- * $Id: structs.h,v 1.254 1998/12/15 17:33:58 wessels Exp $
+ * $Id: structs.h,v 1.255 1999/01/08 21:12:18 wessels Exp $
*
*
* SQUID Internet Object Cache http://squid.nlanr.net/Squid/
#ifdef OPTIMISTIC_IO
unsigned int calling_io_handler:1;
#endif
+ unsigned int delayed_comm_close:1;
} flags;
int bytes_read;
int bytes_written;
+
/*
- * $Id: whois.cc,v 1.7 1998/12/05 00:54:49 wessels Exp $
+ * $Id: whois.cc,v 1.8 1999/01/08 21:12:19 wessels Exp $
*
* DEBUG: section 75 WHOIS protocol
* AUTHOR: Duane Wessels, Kostas Anagnostakis
fwdFail(p->fwd, ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, errno);
comm_close(fd);
} else {
- storeAbort(entry, 0);
comm_close(fd);
}
} else {