---------------------
PatchSet 10857 
Date: 2007/06/19 21:08:33
Author: rousskov
Branch: HEAD
Tag: (none) 
Log:
Ignore comm_write notifications if the newly added
ICAPXaction::ignoreLastWrite member is set. This allows kids to more safely
work around comm inability to cancel a pending write request.

When connect() times out, throw an exception instead of calling mustStop()
because we can bypass the former and not the latter. We cannot bypass mustStop
because the code may use it for legitimate stopping conditions. Eventually,
we may want to have two kinds of exceptions: bypassable and fatal.

Support icap_connect_timeout and icap_io_timeout squid.conf options.

Count I/O timeout as a service failure. This helps suspend broken services
faster and avoid HTTP processing delays when the service is optional.

Eventually, we will probably count all (or most) exceptions as service
failures.

Removed ICAPXaction members that were copied to AsyncJob some time ago.

Polished debugging.

Merged from the squid3-icap branch.

Members: 
	src/ICAP/ICAPXaction.cc:1.19->1.20 
	src/ICAP/ICAPXaction.h:1.11->1.12 

Index: squid3/src/ICAP/ICAPXaction.cc
===================================================================
RCS file: /cvsroot/squid/squid3/src/ICAP/ICAPXaction.cc,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- squid3/src/ICAP/ICAPXaction.cc	29 May 2007 13:31:44 -0000	1.19
+++ squid3/src/ICAP/ICAPXaction.cc	19 Jun 2007 21:08:33 -0000	1.20
@@ -68,6 +68,7 @@
         commEof(false),
         reuseConnection(true),
         isRetriable(true),
+        ignoreLastWrite(false),
         connector(NULL), reader(NULL), writer(NULL), closer(NULL)
 {
     debugs(93,3, typeName << " constructed, this=" << this <<
@@ -81,7 +82,7 @@
 }
 
 void ICAPXaction::disableRetries() {
-    debugs(93,5, typeName << (isRetriable ? "becomes" : "remains") <<
+    debugs(93,5, typeName << (isRetriable ? " becomes" : " remains") <<
         " final" << status());
     isRetriable = false;
 }
@@ -130,7 +131,8 @@
 
     debugs(93,3, typeName << " opens connection to " << s.host.buf() << ":" << s.port);
 
-    commSetTimeout(connection, Config.Timeout.connect,
+    // TODO: service bypass status may differ from that of a transaction
+    commSetTimeout(connection, TheICAPConfig.connect_timeout(service().bypass),
                    &ICAPXaction_noteCommTimedout, this);
 
     closer = &ICAPXaction_noteCommClosed;
@@ -225,12 +227,16 @@
 
     Must(writer);
     writer = NULL;
-
-    Must(commStatus == COMM_OK);
-
-    updateTimeout();
-
-    handleCommWrote(size);
+    
+    if (ignoreLastWrite) {
+        // a hack due to comm inability to cancel a pending write
+        ignoreLastWrite = false; 
+        debugs(93, 7, HERE << "ignoring last write; status: " << commStatus);
+    } else {
+        Must(commStatus == COMM_OK);
+        updateTimeout();
+        handleCommWrote(size);
+    }
 
     ICAPXaction_Exit();
 }
@@ -247,16 +253,14 @@
 
 void ICAPXaction::handleCommTimedout()
 {
-    debugs(93, 0, HERE << "ICAP FD " << connection << " timeout to " << theService->methodStr() << " " << theService->uri.buf());
+    debugs(93, 2, HERE << typeName << " timeout with " <<
+        theService->methodStr() << " " << theService->uri.buf() << status());
     reuseConnection = false;
-    MemBuf mb;
-    mb.init();
-
-    if (fillVirginHttpHeader(mb)) {
-        debugs(93, 0, HERE << "\tfor " << mb.content());
-    }
+    service().noteFailure();
 
-    mustStop("connection with ICAP service timed out");
+    throw TexcHere(connector ?
+        "timed out while connecting to the ICAP service" :
+        "timed out while talking to the ICAP service");
 }
 
 // unexpected connection close while talking to the ICAP service
@@ -293,7 +297,8 @@
     if (reader || writer) {
         // restart the timeout before each I/O
         // XXX: why does Config.Timeout lacks a write timeout?
-        commSetTimeout(connection, Config.Timeout.read,
+        // TODO: service bypass status may differ from that of a transaction
+        commSetTimeout(connection, TheICAPConfig.io_timeout(service().bypass),
             &ICAPXaction_noteCommTimedout, this);
     } else {
         // clear timeout when there is no I/O
Index: squid3/src/ICAP/ICAPXaction.h
===================================================================
RCS file: /cvsroot/squid/squid3/src/ICAP/ICAPXaction.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- squid3/src/ICAP/ICAPXaction.h	8 May 2007 16:32:12 -0000	1.11
+++ squid3/src/ICAP/ICAPXaction.h	19 Jun 2007 21:08:33 -0000	1.12
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ICAPXaction.h,v 1.11 2007/05/08 16:32:12 rousskov Exp $
+ * $Id: ICAPXaction.h,v 1.12 2007/06/19 21:08:33 rousskov Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -132,6 +132,7 @@
     bool commEof;
     bool reuseConnection;
     bool isRetriable;
+    bool ignoreLastWrite;
 
     const char *stopReason;
 
@@ -141,13 +142,9 @@
     IOCB *writer;
     PF *closer;
 
-    const char *typeName; // the type of the final class (child), for debugging
-
 private:
     static int TheLastId;
 
-    const char *inCall; // name of the asynchronous call being executed, if any
-
     static void reusedConnection(void *data);
 
     //CBDATA_CLASS2(ICAPXaction);
