--------------------- PatchSet 3879 Date: 2006/10/25 17:43:52 Author: rousskov Branch: squid3-icap Tag: (none) Log: - Distinguish ICAP services that are down because they have not been contacted yet from services that are down because the last attempt to fetch options failed. The distinction is essential when selecting a service at the ACL level. - Updated service state terminology: A service is "probed" if we tried to get an OPTIONS response from it and succeeded or failed. A down probed service is called "broken". - Report interesting changes in the ICAP service state, some with debugging level one to alert the cache administrator. Members: src/ICAP/ICAPServiceRep.cc:1.1.2.6->1.1.2.7 src/ICAP/ICAPServiceRep.h:1.1.2.5->1.1.2.6 Index: squid3/src/ICAP/ICAPServiceRep.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ICAP/ICAPServiceRep.cc,v retrieving revision 1.1.2.6 retrieving revision 1.1.2.7 diff -u -r1.1.2.6 -r1.1.2.7 --- squid3/src/ICAP/ICAPServiceRep.cc 25 Oct 2006 04:56:34 -0000 1.1.2.6 +++ squid3/src/ICAP/ICAPServiceRep.cc 25 Oct 2006 17:43:52 -0000 1.1.2.7 @@ -159,16 +159,33 @@ void ICAPServiceRep::invalidate() { assert(self != NULL); - self = NULL; // may destroy us and, hence, invalidate cbdata(this) + const bool wasOk = up(); // ignore unprobed service invalidation + + Pointer savedSelf = self; // to prevent destruction when we nullify self + self = NULL; + + announceStatusChange(wasOk, false); + + savedSelf = NULL; // may destroy us and, hence, invalidate cbdata(this) // TODO: it would be nice to invalidate cbdata(this) when not destroyed } +bool ICAPServiceRep::probed() const +{ + return lastUpdate != 0; +} + bool ICAPServiceRep::up() const { return self != NULL && theOptions && theOptions->valid() && theOptions->fresh(); } +bool ICAPServiceRep::broken() const +{ + return probed() && !up(); +} + bool ICAPServiceRep::wantsUrl(const String &urlPath) const { Must(up()); @@ -255,6 +272,7 @@ { Must(cb); Must(self != NULL); + Must(!probed()); // we do not wait for a broken service Client i; i.service = self; @@ -286,9 +304,19 @@ { debugs(93,9, "ICAPService changes options from " << theOptions << " to " << newOptions); + + const bool wasOk = !probed() || up(); + delete theOptions; theOptions = newOptions; + lastUpdate = squid_curtime; + checkOptions(); + announceStatusChange(wasOk, true); +} + +void ICAPServiceRep::checkOptions() +{ if (theOptions == NULL) return; @@ -327,11 +355,22 @@ * Check the ICAP server's date header for clock skew */ int skew = abs((int)(theOptions->timestamp() - squid_curtime)); - if (skew > theOptions->ttl()) debugs(93, 1, host.buf() << "'s clock is skewed by " << skew << " seconds!"); } +void ICAPServiceRep::announceStatusChange(bool wasOk, bool important) const +{ + if (wasOk == up()) // no significant changes to announce + return; + + const int level = important ? 1 : 2; + if (wasOk) + debugs(93,level, "ICAP service is down: " << uri); + else + debugs(93,level, "ICAP service is now up: " << uri); +} + static void ICAPServiceRep_noteNewOptions(ICAPOptXact *x, void *data) { @@ -350,7 +389,6 @@ x->options = NULL; delete x; - lastUpdate = squid_curtime; debugs(93,3, "ICAPService got new options and is now " << status()); scheduleUpdate(); Index: squid3/src/ICAP/ICAPServiceRep.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ICAP/ICAPServiceRep.h,v retrieving revision 1.1.2.5 retrieving revision 1.1.2.6 diff -u -r1.1.2.5 -r1.1.2.6 --- squid3/src/ICAP/ICAPServiceRep.h 25 Oct 2006 04:56:34 -0000 1.1.2.5 +++ squid3/src/ICAP/ICAPServiceRep.h 25 Oct 2006 17:43:52 -0000 1.1.2.6 @@ -1,6 +1,6 @@ /* - * $Id: ICAPServiceRep.h,v 1.1.2.5 2006/10/25 04:56:34 rousskov Exp $ + * $Id: ICAPServiceRep.h,v 1.1.2.6 2006/10/25 17:43:52 rousskov Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -44,17 +44,29 @@ /* The ICAP service representative maintains information about a single ICAP service that Squid communicates with. The representative initiates OPTIONS requests to the service to keep cached options fresh. One ICAP server may - host many ICAP services */ + host many ICAP services. */ /* - * Service is "up" if there is a fresh cached OPTIONS response and is - * "down" otherwise. We do not initiate ICAP transactions with a down - * service, but will wait for a down service to get a fresh OPTIONS - * response (see the callWhenReady method). The callback is called when - * the OPTIONS transaction completes, even if the service is still down - * due to errors. + * A service is "up" if there is a fresh cached OPTIONS response and is + * "down" otherwise. A service is "probed" if we tried to get an OPTIONS + * response from it and succeeded or failed. A probed down service is + * called "broken". + * + * As a bootstrapping mechanism, ICAP transactions wait for an unprobed + * service to get a fresh OPTIONS response (see the callWhenReady method). + * The waiting callback is called when the OPTIONS transaction completes, + * even if the service is now broken. + * + * We do not initiate ICAP transactions with a broken service, but will + * eventually retry to fetch its options in hope to bring the service up. + * + * A service that should no longer be used after Squid reconfiguration is + * treated as if it does not have a fresh cached OPTIONS response. We do + * not try to fetch fresh options for such a service. It should be + * auto-destroyed by refcounting when no longer used. */ + class ICAPServiceRep : public RefCountable { @@ -71,7 +83,9 @@ const char *methodStr() const; const char *vectPointStr() const; - bool up() const; + bool probed() const; // see comments above + bool broken() const; // see comments above + bool up() const; // see comments above typedef void Callback(void *data, Pointer &service); void callWhenReady(Callback *cb, void *data); @@ -127,10 +141,14 @@ bool needNewOptions() const; + void scheduleUpdate(); void scheduleNotification(); - void changeOptions(ICAPOptions *newOptions); + void startGettingOptions(); - void scheduleUpdate(); + void changeOptions(ICAPOptions *newOptions); + void checkOptions(); + + void announceStatusChange(bool wasUp, bool important) const; const char *status() const;