2 * DEBUG: section 15 Neighbor Routines
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "acl/FilledChecklist.h"
35 #include "anyp/PortCfg.h"
36 #include "CacheDigest.h"
37 #include "CachePeer.h"
38 #include "CachePeerDomainList.h"
39 #include "comm/Connection.h"
40 #include "comm/ConnOpener.h"
45 #include "HttpRequest.h"
46 #include "icmp/net_db.h"
49 #include "ip/Address.h"
52 #include "MemObject.h"
53 #include "mgr/Registration.h"
54 #include "multicast.h"
55 #include "neighbors.h"
56 #include "NeighborTypeDomainList.h"
57 #include "PeerDigest.h"
58 #include "PeerSelectState.h"
59 #include "RequestFlags.h"
60 #include "SquidConfig.h"
61 #include "SquidMath.h"
62 #include "SquidTime.h"
65 #include "store_key_md5.h"
69 /* count mcast group peers every 15 minutes */
70 #define MCAST_COUNT_RATE 900
72 bool peerAllowedToUse(const CachePeer
*, HttpRequest
*);
73 static int peerWouldBePinged(const CachePeer
*, HttpRequest
*);
74 static void neighborRemove(CachePeer
*);
75 static void neighborAlive(CachePeer
*, const MemObject
*, const icp_common_t
*);
77 static void neighborAliveHtcp(CachePeer
*, const MemObject
*, const HtcpReplyData
*);
79 static void neighborCountIgnored(CachePeer
*);
80 static void peerRefreshDNS(void *);
81 static IPH peerDNSConfigure
;
82 static bool peerProbeConnect(CachePeer
*);
83 static CNCB peerProbeConnectDone
;
84 static void peerCountMcastPeersDone(void *data
);
85 static void peerCountMcastPeersStart(void *data
);
86 static void peerCountMcastPeersSchedule(CachePeer
* p
, time_t when
);
87 static IRCB peerCountHandleIcpReply
;
89 static void neighborIgnoreNonPeer(const Ip::Address
&, icp_opcode
);
90 static OBJH neighborDumpPeers
;
91 static OBJH neighborDumpNonPeers
;
92 static void dump_peers(StoreEntry
* sentry
, CachePeer
* peers
);
94 static unsigned short echo_port
;
96 static int NLateReplies
= 0;
97 static CachePeer
*first_ping
= NULL
;
100 neighborTypeStr(const CachePeer
* p
)
102 if (p
->type
== PEER_NONE
)
105 if (p
->type
== PEER_SIBLING
)
108 if (p
->type
== PEER_MULTICAST
)
109 return "Multicast Group";
115 whichPeer(const Ip::Address
&from
)
120 debugs(15, 3, "whichPeer: from " << from
);
122 for (p
= Config
.peers
; p
; p
= p
->next
) {
123 for (j
= 0; j
< p
->n_addresses
; ++j
) {
124 if (from
== p
->addresses
[j
] && from
.port() == p
->icp
.port
) {
134 neighborType(const CachePeer
* p
, const HttpRequest
* request
)
137 const NeighborTypeDomainList
*d
= NULL
;
139 for (d
= p
->typelist
; d
; d
= d
->next
) {
140 if (0 == matchDomainName(request
->GetHost(), d
->domain
))
141 if (d
->type
!= PEER_NONE
)
144 #if PEER_MULTICAST_SIBLINGS
145 if (p
->type
== PEER_MULTICAST
)
146 if (p
->options
.mcast_siblings
)
154 * \return Whether it is appropriate to fetch REQUEST from PEER.
157 peerAllowedToUse(const CachePeer
* p
, HttpRequest
* request
)
160 const CachePeerDomainList
*d
= NULL
;
161 assert(request
!= NULL
);
163 if (neighborType(p
, request
) == PEER_SIBLING
) {
164 #if PEER_MULTICAST_SIBLINGS
165 if (p
->type
== PEER_MULTICAST
&& p
->options
.mcast_siblings
&&
166 (request
->flags
.noCache
|| request
->flags
.refresh
|| request
->flags
.loopDetected
|| request
->flags
.needValidation
))
167 debugs(15, 2, "peerAllowedToUse(" << p
->name
<< ", " << request
->GetHost() << ") : multicast-siblings optimization match");
169 if (request
->flags
.noCache
)
172 if (request
->flags
.refresh
)
175 if (request
->flags
.loopDetected
)
178 if (request
->flags
.needValidation
)
182 // CONNECT requests are proxy requests. Not to be forwarded to origin servers.
183 // Unless the destination port matches, in which case we MAY perform a 'DIRECT' to this CachePeer.
184 if (p
->options
.originserver
&& request
->method
== Http::METHOD_CONNECT
&& request
->port
!= p
->in_addr
.port())
187 if (p
->peer_domain
== NULL
&& p
->access
== NULL
)
190 bool do_ping
= false;
191 for (d
= p
->peer_domain
; d
; d
= d
->next
) {
192 if (0 == matchDomainName(request
->GetHost(), d
->domain
)) {
193 do_ping
= d
->do_ping
;
197 do_ping
= !d
->do_ping
;
200 if (p
->peer_domain
&& !do_ping
)
203 if (p
->access
== NULL
)
206 ACLFilledChecklist
checklist(p
->access
, request
, NULL
);
208 return (checklist
.fastCheck() == ACCESS_ALLOWED
);
211 /* Return TRUE if it is okay to send an ICP request to this CachePeer. */
213 peerWouldBePinged(const CachePeer
* p
, HttpRequest
* request
)
215 if (p
->icp
.port
== 0)
218 if (p
->options
.no_query
)
221 if (p
->options
.mcast_responder
)
224 if (p
->n_addresses
== 0)
227 if (p
->options
.background_ping
&& (squid_curtime
- p
->stats
.last_query
< Config
.backgroundPingRate
))
230 /* the case below seems strange, but can happen if the
231 * URL host is on the other side of a firewall */
232 if (p
->type
== PEER_SIBLING
)
233 if (!request
->flags
.hierarchical
)
236 if (!peerAllowedToUse(p
, request
))
239 /* Ping dead peers every timeout interval */
240 if (squid_curtime
- p
->stats
.last_query
> Config
.Timeout
.deadPeer
)
249 /* Return TRUE if it is okay to send an HTTP request to this CachePeer. */
251 peerHTTPOkay(const CachePeer
* p
, HttpRequest
* request
)
254 if (p
->stats
.conn_open
>= p
->max_conn
)
257 if (!peerAllowedToUse(p
, request
))
267 neighborsCount(HttpRequest
* request
)
272 for (p
= Config
.peers
; p
; p
= p
->next
)
273 if (peerWouldBePinged(p
, request
))
276 debugs(15, 3, "neighborsCount: " << count
);
282 getFirstUpParent(HttpRequest
* request
)
286 for (p
= Config
.peers
; p
; p
= p
->next
) {
290 if (neighborType(p
, request
) != PEER_PARENT
)
293 if (!peerHTTPOkay(p
, request
))
299 debugs(15, 3, "getFirstUpParent: returning " << (p
? p
->host
: "NULL"));
304 getRoundRobinParent(HttpRequest
* request
)
309 for (p
= Config
.peers
; p
; p
= p
->next
) {
310 if (!p
->options
.roundrobin
)
313 if (neighborType(p
, request
) != PEER_PARENT
)
316 if (!peerHTTPOkay(p
, request
))
323 if (p
->weight
== q
->weight
) {
324 if (q
->rr_count
< p
->rr_count
)
326 } else if ( ((double) q
->rr_count
/ q
->weight
) < ((double) p
->rr_count
/ p
->weight
)) {
337 debugs(15, 3, HERE
<< "returning " << (q
? q
->host
: "NULL"));
343 getWeightedRoundRobinParent(HttpRequest
* request
)
349 for (p
= Config
.peers
; p
; p
= p
->next
) {
350 if (!p
->options
.weighted_roundrobin
)
353 if (neighborType(p
, request
) != PEER_PARENT
)
356 if (!peerHTTPOkay(p
, request
))
359 if (q
&& q
->rr_count
< p
->rr_count
)
365 if (q
&& q
->rr_count
> 1000000)
366 for (p
= Config
.peers
; p
; p
= p
->next
) {
367 if (!p
->options
.weighted_roundrobin
)
370 if (neighborType(p
, request
) != PEER_PARENT
)
377 weighted_rtt
= (q
->stats
.rtt
- q
->basetime
) / q
->weight
;
379 if (weighted_rtt
< 1)
382 q
->rr_count
+= weighted_rtt
;
384 debugs(15, 3, "getWeightedRoundRobinParent: weighted_rtt " << weighted_rtt
);
387 debugs(15, 3, "getWeightedRoundRobinParent: returning " << (q
? q
->host
: "NULL"));
392 * This gets called every 5 minutes to clear the round-robin counter.
393 * The exact timing is an arbitrary default, set on estimate timing of a
394 * large number of requests in a high-performance environment during the
395 * period. The larger the number of requests between cycled resets the
396 * more balanced the operations.
399 \todo Make the reset timing a selectable parameter in squid.conf
402 peerClearRRLoop(void *data
)
405 eventAdd("peerClearRR", peerClearRRLoop
, data
, 5 * 60.0, 0);
409 * This gets called on startup and restart to kick off the CachePeer round-robin
410 * maintenance event. It ensures that no matter how many times its called
411 * no more than one event is scheduled.
414 peerClearRRStart(void)
416 static bool event_added
= false;
418 peerClearRRLoop(NULL
);
424 * Called whenever the round-robin counters need to be reset to a sane state.
425 * So far those times are:
426 * - On startup and reconfigure - to set the counters to sane initial settings.
427 * - When a CachePeer has revived from dead, to prevent the revived CachePeer being
428 * flooded with requests which it has 'missed' during the down period.
434 for (p
= Config
.peers
; p
; p
= p
->next
) {
440 * Perform all actions when a CachePeer is detected revived.
443 peerAlive(CachePeer
*p
)
445 if (p
->stats
.logged_state
== PEER_DEAD
&& p
->tcp_up
) {
446 debugs(15, DBG_IMPORTANT
, "Detected REVIVED " << neighborTypeStr(p
) << ": " << p
->name
);
447 p
->stats
.logged_state
= PEER_ALIVE
;
451 p
->stats
.last_reply
= squid_curtime
;
452 p
->stats
.probe_start
= 0;
456 getDefaultParent(HttpRequest
* request
)
460 for (p
= Config
.peers
; p
; p
= p
->next
) {
461 if (neighborType(p
, request
) != PEER_PARENT
)
464 if (!p
->options
.default_parent
)
467 if (!peerHTTPOkay(p
, request
))
470 debugs(15, 3, "getDefaultParent: returning " << p
->host
);
475 debugs(15, 3, "getDefaultParent: returning NULL");
480 getNextPeer(CachePeer
* p
)
492 neighborRemove(CachePeer
* target
)
495 CachePeer
**P
= NULL
;
514 first_ping
= Config
.peers
;
518 neighborsRegisterWithCacheManager()
520 Mgr::RegisterAction("server_list",
521 "Peer Cache Statistics",
522 neighborDumpPeers
, 0, 1);
524 if (Comm::IsConnOpen(icpIncomingConn
)) {
525 Mgr::RegisterAction("non_peers",
526 "List of Unknown sites sending ICP messages",
527 neighborDumpNonPeers
, 0, 1);
534 struct servent
*sep
= NULL
;
535 const char *me
= getMyHostname();
536 CachePeer
*thisPeer
= NULL
;
537 CachePeer
*next
= NULL
;
539 neighborsRegisterWithCacheManager();
541 if (Comm::IsConnOpen(icpIncomingConn
)) {
543 for (thisPeer
= Config
.peers
; thisPeer
; thisPeer
= next
) {
544 next
= thisPeer
->next
;
546 if (0 != strcmp(thisPeer
->host
, me
))
549 for (AnyP::PortCfg
*s
= Config
.Sockaddr
.http
; s
; s
= s
->next
) {
550 if (thisPeer
->http_port
!= s
->s
.port())
553 debugs(15, DBG_IMPORTANT
, "WARNING: Peer looks like this host");
555 debugs(15, DBG_IMPORTANT
, " Ignoring " <<
556 neighborTypeStr(thisPeer
) << " " << thisPeer
->host
<<
557 "/" << thisPeer
->http_port
<< "/" <<
560 neighborRemove(thisPeer
);
565 peerRefreshDNS((void *) 1);
567 sep
= getservbyname("echo", "udp");
568 echo_port
= sep
? ntohs((unsigned short) sep
->s_port
) : 7;
570 first_ping
= Config
.peers
;
574 neighborsUdpPing(HttpRequest
* request
,
581 const char *url
= entry
->url();
582 MemObject
*mem
= entry
->mem_obj
;
588 int queries_sent
= 0;
589 int peers_pinged
= 0;
590 int parent_timeout
= 0, parent_exprep
= 0;
591 int sibling_timeout
= 0, sibling_exprep
= 0;
592 int mcast_timeout
= 0, mcast_exprep
= 0;
594 if (Config
.peers
== NULL
)
597 assert(entry
->swap_status
== SWAPOUT_NONE
);
599 mem
->start_ping
= current_time
;
601 mem
->ping_reply_callback
= callback
;
603 mem
->ircb_data
= callback_data
;
605 reqnum
= icpSetCacheKey((const cache_key
*)entry
->key
);
607 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
611 debugs(15, 5, "neighborsUdpPing: Peer " << p
->host
);
613 if (!peerWouldBePinged(p
, request
))
614 continue; /* next CachePeer */
618 debugs(15, 4, "neighborsUdpPing: pinging peer " << p
->host
<< " for '" << url
<< "'");
620 debugs(15, 3, "neighborsUdpPing: key = '" << entry
->getMD5Text() << "'");
622 debugs(15, 3, "neighborsUdpPing: reqnum = " << reqnum
);
625 if (p
->options
.htcp
&& !p
->options
.htcp_only_clr
) {
626 if (Config
.Port
.htcp
<= 0) {
627 debugs(15, DBG_CRITICAL
, "HTCP is disabled! Cannot send HTCP request to peer.");
631 debugs(15, 3, "neighborsUdpPing: sending HTCP query");
632 if (htcpQuery(entry
, request
, p
) <= 0)
633 continue; // unable to send.
637 if (Config
.Port
.icp
<= 0 || !Comm::IsConnOpen(icpOutgoingConn
)) {
638 debugs(15, DBG_CRITICAL
, "ICP is disabled! Cannot send ICP request to peer.");
642 if (p
->type
== PEER_MULTICAST
)
643 mcastSetTtl(icpOutgoingConn
->fd
, p
->mcast
.ttl
);
645 if (p
->icp
.port
== echo_port
) {
646 debugs(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping");
647 query
= _icp_common_t::createMessage(ICP_DECHO
, 0, url
, reqnum
, 0);
648 icpUdpSend(icpOutgoingConn
->fd
, p
->in_addr
, query
, LOG_ICP_QUERY
, 0);
652 if (Config
.onoff
.query_icmp
)
653 if (p
->icp
.version
== ICP_VERSION_2
)
654 flags
|= ICP_FLAG_SRC_RTT
;
656 query
= _icp_common_t::createMessage(ICP_QUERY
, flags
, url
, reqnum
, 0);
658 icpUdpSend(icpOutgoingConn
->fd
, p
->in_addr
, query
, LOG_ICP_QUERY
, 0);
665 ++ p
->stats
.pings_sent
;
667 if (p
->type
== PEER_MULTICAST
) {
668 mcast_exprep
+= p
->mcast
.n_replies_expected
;
669 mcast_timeout
+= (p
->stats
.rtt
* p
->mcast
.n_replies_expected
);
670 } else if (neighborUp(p
)) {
671 /* its alive, expect a reply from it */
673 if (neighborType(p
, request
) == PEER_PARENT
) {
675 parent_timeout
+= p
->stats
.rtt
;
678 sibling_timeout
+= p
->stats
.rtt
;
681 /* Neighbor is dead; ping it anyway, but don't expect a reply */
682 /* log it once at the threshold */
684 if (p
->stats
.logged_state
== PEER_ALIVE
) {
685 debugs(15, DBG_IMPORTANT
, "Detected DEAD " << neighborTypeStr(p
) << ": " << p
->name
);
686 p
->stats
.logged_state
= PEER_DEAD
;
690 p
->stats
.last_query
= squid_curtime
;
693 * keep probe_start == 0 for a multicast CachePeer,
694 * so neighborUp() never says this CachePeer is dead.
697 if ((p
->type
!= PEER_MULTICAST
) && (p
->stats
.probe_start
== 0))
698 p
->stats
.probe_start
= squid_curtime
;
701 if ((first_ping
= first_ping
->next
) == NULL
)
702 first_ping
= Config
.peers
;
705 * How many replies to expect?
707 *exprep
= parent_exprep
+ sibling_exprep
+ mcast_exprep
;
710 * If there is a configured timeout, use it
712 if (Config
.Timeout
.icp_query
)
713 *timeout
= Config
.Timeout
.icp_query
;
717 *timeout
= 2 * parent_timeout
/ parent_exprep
;
718 else if (mcast_exprep
)
719 *timeout
= 2 * mcast_timeout
/ mcast_exprep
;
721 *timeout
= 2 * sibling_timeout
/ sibling_exprep
;
723 *timeout
= 2000; /* 2 seconds */
725 if (Config
.Timeout
.icp_query_max
)
726 if (*timeout
> Config
.Timeout
.icp_query_max
)
727 *timeout
= Config
.Timeout
.icp_query_max
;
729 if (*timeout
< Config
.Timeout
.icp_query_min
)
730 *timeout
= Config
.Timeout
.icp_query_min
;
736 /* lookup the digest of a given CachePeer */
738 peerDigestLookup(CachePeer
* p
, HttpRequest
* request
)
740 #if USE_CACHE_DIGESTS
741 const cache_key
*key
= request
? storeKeyPublicByRequest(request
) : NULL
;
744 debugs(15, 5, "peerDigestLookup: peer " << p
->host
);
745 /* does the peeer have a valid digest? */
748 debugs(15, 5, "peerDigestLookup: gone!");
750 } else if (!peerHTTPOkay(p
, request
)) {
751 debugs(15, 5, "peerDigestLookup: !peerHTTPOkay");
753 } else if (!p
->digest
->flags
.needed
) {
754 debugs(15, 5, "peerDigestLookup: note need");
755 peerDigestNeeded(p
->digest
);
757 } else if (!p
->digest
->flags
.usable
) {
758 debugs(15, 5, "peerDigestLookup: !ready && " << (p
->digest
->flags
.requested
? "" : "!") << "requested");
762 debugs(15, 5, "peerDigestLookup: OK to lookup peer " << p
->host
);
763 assert(p
->digest
->cd
);
764 /* does digest predict a hit? */
766 if (!cacheDigestTest(p
->digest
->cd
, key
))
769 debugs(15, 5, "peerDigestLookup: peer " << p
->host
<< " says HIT!");
778 /* select best CachePeer based on cache digests */
780 neighborsDigestSelect(HttpRequest
* request
)
782 CachePeer
*best_p
= NULL
;
783 #if USE_CACHE_DIGESTS
786 int choice_count
= 0;
787 int ichoice_count
= 0;
792 if (!request
->flags
.hierarchical
)
795 storeKeyPublicByRequest(request
);
797 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
806 lookup
= peerDigestLookup(p
, request
);
808 if (lookup
== LOOKUP_NONE
)
813 if (lookup
== LOOKUP_MISS
)
816 p_rtt
= netdbHostRtt(p
->host
);
818 debugs(15, 5, "neighborsDigestSelect: peer " << p
->host
<< " rtt: " << p_rtt
);
820 /* is this CachePeer better than others in terms of rtt ? */
821 if (!best_p
|| (p_rtt
&& p_rtt
< best_rtt
)) {
825 if (p_rtt
) /* informative choice (aka educated guess) */
828 debugs(15, 4, "neighborsDigestSelect: peer " << p
->host
<< " leads with rtt " << best_rtt
);
832 debugs(15, 4, "neighborsDigestSelect: choices: " << choice_count
<< " (" << ichoice_count
<< ")");
833 peerNoteDigestLookup(request
, best_p
,
834 best_p
? LOOKUP_HIT
: (choice_count
? LOOKUP_MISS
: LOOKUP_NONE
));
835 request
->hier
.n_choices
= choice_count
;
836 request
->hier
.n_ichoices
= ichoice_count
;
843 peerNoteDigestLookup(HttpRequest
* request
, CachePeer
* p
, lookup_t lookup
)
845 #if USE_CACHE_DIGESTS
847 strncpy(request
->hier
.cd_host
, p
->host
, sizeof(request
->hier
.cd_host
)-1);
849 *request
->hier
.cd_host
= '\0';
851 request
->hier
.cd_lookup
= lookup
;
852 debugs(15, 4, "peerNoteDigestLookup: peer " << (p
? p
->host
: "<none>") << ", lookup: " << lookup_t_str
[lookup
] );
857 neighborAlive(CachePeer
* p
, const MemObject
* mem
, const icp_common_t
* header
)
860 ++ p
->stats
.pings_acked
;
862 if ((icp_opcode
) header
->opcode
<= ICP_END
)
863 ++ p
->icp
.counts
[header
->opcode
];
865 p
->icp
.version
= (int) header
->version
;
869 neighborUpdateRtt(CachePeer
* p
, MemObject
* mem
)
871 int rtt
, rtt_av_factor
;
876 if (!mem
->start_ping
.tv_sec
)
879 rtt
= tvSubMsec(mem
->start_ping
, current_time
);
881 if (rtt
< 1 || rtt
> 10000)
884 rtt_av_factor
= RTT_AV_FACTOR
;
886 if (p
->options
.weighted_roundrobin
)
887 rtt_av_factor
= RTT_BACKGROUND_AV_FACTOR
;
889 p
->stats
.rtt
= Math::intAverage(p
->stats
.rtt
, rtt
, p
->stats
.pings_acked
, rtt_av_factor
);
894 neighborAliveHtcp(CachePeer
* p
, const MemObject
* mem
, const HtcpReplyData
* htcp
)
897 ++ p
->stats
.pings_acked
;
898 ++ p
->htcp
.counts
[htcp
->hit
? 1 : 0];
899 p
->htcp
.version
= htcp
->version
;
905 neighborCountIgnored(CachePeer
* p
)
910 ++ p
->stats
.ignored_replies
;
915 static CachePeer
*non_peers
= NULL
;
918 neighborIgnoreNonPeer(const Ip::Address
&from
, icp_opcode opcode
)
922 for (np
= non_peers
; np
; np
= np
->next
) {
923 if (np
->in_addr
!= from
)
926 if (np
->in_addr
.port() != from
.port())
933 np
= (CachePeer
*)xcalloc(1, sizeof(CachePeer
));
935 np
->icp
.port
= from
.port();
936 np
->type
= PEER_NONE
;
937 np
->host
= new char[MAX_IPSTRLEN
];
938 from
.toStr(np
->host
,MAX_IPSTRLEN
);
939 np
->next
= non_peers
;
943 ++ np
->icp
.counts
[opcode
];
945 if (isPowTen(++np
->stats
.ignored_replies
))
946 debugs(15, DBG_IMPORTANT
, "WARNING: Ignored " << np
->stats
.ignored_replies
<< " replies from non-peer " << np
->host
);
949 /* ignoreMulticastReply
951 * * We want to ignore replies from multicast peers if the
952 * * cache_host_domain rules would normally prevent the CachePeer
956 ignoreMulticastReply(CachePeer
* p
, MemObject
* mem
)
961 if (!p
->options
.mcast_responder
)
964 if (peerHTTPOkay(p
, mem
->request
))
971 * I should attach these records to the entry. We take the first
972 * hit we get our wait until everyone misses. The timeout handler
973 * call needs to nip this shopping list or call one of the misses.
975 * If a hit process is already started, then sobeit
978 neighborsUdpAck(const cache_key
* key
, icp_common_t
* header
, const Ip::Address
&from
)
982 MemObject
*mem
= NULL
;
983 peer_t ntype
= PEER_NONE
;
984 icp_opcode opcode
= (icp_opcode
) header
->opcode
;
986 debugs(15, 6, "neighborsUdpAck: opcode " << opcode
<< " '" << storeKeyText(key
) << "'");
988 if (NULL
!= (entry
= Store::Root().get(key
)))
989 mem
= entry
->mem_obj
;
991 if ((p
= whichPeer(from
)))
992 neighborAlive(p
, mem
, header
);
994 if (opcode
> ICP_END
)
997 const char *opcode_d
= icp_opcode_str
[opcode
];
1000 neighborUpdateRtt(p
, mem
);
1002 /* Does the entry exist? */
1003 if (NULL
== entry
) {
1004 debugs(12, 3, "neighborsUdpAck: Cache key '" << storeKeyText(key
) << "' not found");
1005 neighborCountIgnored(p
);
1009 /* check if someone is already fetching it */
1010 if (EBIT_TEST(entry
->flags
, ENTRY_DISPATCHED
)) {
1011 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key
) << "' already being fetched.");
1012 neighborCountIgnored(p
);
1017 debugs(15, 2, "Ignoring " << opcode_d
<< " for missing mem_obj: " << storeKeyText(key
));
1018 neighborCountIgnored(p
);
1022 if (entry
->ping_status
!= PING_WAITING
) {
1023 debugs(15, 2, "neighborsUdpAck: Late " << opcode_d
<< " for " << storeKeyText(key
));
1024 neighborCountIgnored(p
);
1028 if (entry
->lock_count
== 0) {
1029 // TODO: many entries are unlocked; why is this reported at level 1?
1030 debugs(12, DBG_IMPORTANT
, "neighborsUdpAck: '" << storeKeyText(key
) << "' has no locks");
1031 neighborCountIgnored(p
);
1035 debugs(15, 3, "neighborsUdpAck: " << opcode_d
<< " for '" << storeKeyText(key
) << "' from " << (p
? p
->host
: "source") << " ");
1038 ntype
= neighborType(p
, mem
->request
);
1041 if (ignoreMulticastReply(p
, mem
)) {
1042 neighborCountIgnored(p
);
1043 } else if (opcode
== ICP_MISS
) {
1045 neighborIgnoreNonPeer(from
, opcode
);
1047 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1049 } else if (opcode
== ICP_HIT
) {
1051 neighborIgnoreNonPeer(from
, opcode
);
1053 header
->opcode
= ICP_HIT
;
1054 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1056 } else if (opcode
== ICP_DECHO
) {
1058 neighborIgnoreNonPeer(from
, opcode
);
1059 } else if (ntype
== PEER_SIBLING
) {
1060 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
1061 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
1063 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1065 } else if (opcode
== ICP_SECHO
) {
1067 debugs(15, DBG_IMPORTANT
, "Ignoring SECHO from neighbor " << p
->host
);
1068 neighborCountIgnored(p
);
1070 debugs(15, DBG_IMPORTANT
, "Unsolicited SECHO from " << from
);
1072 } else if (opcode
== ICP_DENIED
) {
1074 neighborIgnoreNonPeer(from
, opcode
);
1075 } else if (p
->stats
.pings_acked
> 100) {
1076 if (100 * p
->icp
.counts
[ICP_DENIED
] / p
->stats
.pings_acked
> 95) {
1077 debugs(15, DBG_CRITICAL
, "95%% of replies from '" << p
->host
<< "' are UDP_DENIED");
1078 debugs(15, DBG_CRITICAL
, "Disabling '" << p
->host
<< "', please check your configuration.");
1082 neighborCountIgnored(p
);
1085 } else if (opcode
== ICP_MISS_NOFETCH
) {
1086 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_ICP
, header
, mem
->ircb_data
);
1088 debugs(15, DBG_CRITICAL
, "neighborsUdpAck: Unexpected ICP reply: " << opcode_d
);
1093 peerFindByName(const char *name
)
1095 CachePeer
*p
= NULL
;
1097 for (p
= Config
.peers
; p
; p
= p
->next
) {
1098 if (!strcasecmp(name
, p
->name
))
1106 peerFindByNameAndPort(const char *name
, unsigned short port
)
1108 CachePeer
*p
= NULL
;
1110 for (p
= Config
.peers
; p
; p
= p
->next
) {
1111 if (strcasecmp(name
, p
->name
))
1114 if (port
!= p
->http_port
)
1124 neighborUp(const CachePeer
* p
)
1127 if (!peerProbeConnect((CachePeer
*) p
)) {
1128 debugs(15, 8, "neighborUp: DOWN (probed): " << p
->host
<< " (" << p
->in_addr
<< ")");
1134 * The CachePeer can not be UP if we don't have any IP addresses
1137 if (0 == p
->n_addresses
) {
1138 debugs(15, 8, "neighborUp: DOWN (no-ip): " << p
->host
<< " (" << p
->in_addr
<< ")");
1142 if (p
->options
.no_query
) {
1143 debugs(15, 8, "neighborUp: UP (no-query): " << p
->host
<< " (" << p
->in_addr
<< ")");
1147 if (p
->stats
.probe_start
!= 0 &&
1148 squid_curtime
- p
->stats
.probe_start
> Config
.Timeout
.deadPeer
) {
1149 debugs(15, 8, "neighborUp: DOWN (dead): " << p
->host
<< " (" << p
->in_addr
<< ")");
1153 debugs(15, 8, "neighborUp: UP: " << p
->host
<< " (" << p
->in_addr
<< ")");
1158 peerDestroy(void *data
)
1160 CachePeer
*p
= (CachePeer
*)data
;
1165 CachePeerDomainList
*nl
= NULL
;
1167 for (CachePeerDomainList
*l
= p
->peer_domain
; l
; l
= nl
) {
1169 safe_free(l
->domain
);
1175 safe_free(p
->domain
);
1176 #if USE_CACHE_DIGESTS
1178 cbdataReferenceDone(p
->digest
);
1183 peerNoteDigestGone(CachePeer
* p
)
1185 #if USE_CACHE_DIGESTS
1186 cbdataReferenceDone(p
->digest
);
1191 peerDNSConfigure(const ipcache_addrs
*ia
, const DnsLookupDetails
&, void *data
)
1193 CachePeer
*p
= (CachePeer
*)data
;
1197 if (p
->n_addresses
== 0) {
1198 debugs(15, DBG_IMPORTANT
, "Configuring " << neighborTypeStr(p
) << " " << p
->host
<< "/" << p
->http_port
<< "/" << p
->icp
.port
);
1200 if (p
->type
== PEER_MULTICAST
)
1201 debugs(15, DBG_IMPORTANT
, " Multicast TTL = " << p
->mcast
.ttl
);
1207 debugs(0, DBG_CRITICAL
, "WARNING: DNS lookup for '" << p
->host
<< "' failed!");
1211 if ((int) ia
->count
< 1) {
1212 debugs(0, DBG_CRITICAL
, "WARNING: No IP address found for '" << p
->host
<< "'!");
1216 p
->tcp_up
= p
->connect_fail_limit
;
1218 for (j
= 0; j
< (int) ia
->count
&& j
< PEER_MAX_ADDRESSES
; ++j
) {
1219 p
->addresses
[j
] = ia
->in_addrs
[j
];
1220 debugs(15, 2, "--> IP address #" << j
<< ": " << p
->addresses
[j
]);
1224 p
->in_addr
.setEmpty();
1225 p
->in_addr
= p
->addresses
[0];
1226 p
->in_addr
.port(p
->icp
.port
);
1228 if (p
->type
== PEER_MULTICAST
)
1229 peerCountMcastPeersSchedule(p
, 10);
1232 if (p
->type
!= PEER_MULTICAST
)
1233 if (!p
->options
.no_netdb_exchange
)
1234 eventAddIsh("netdbExchangeStart", netdbExchangeStart
, p
, 30.0, 1);
1240 peerRefreshDNS(void *data
)
1242 CachePeer
*p
= NULL
;
1244 if (eventFind(peerRefreshDNS
, NULL
))
1245 eventDelete(peerRefreshDNS
, NULL
);
1247 if (!data
&& 0 == stat5minClientRequests()) {
1248 /* no recent client traffic, wait a bit */
1249 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 180.0, 1);
1253 for (p
= Config
.peers
; p
; p
= p
->next
)
1254 ipcache_nbgethostbyname(p
->host
, peerDNSConfigure
, p
);
1256 /* Reconfigure the peers every hour */
1257 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 3600.0, 1);
1261 peerConnectFailedSilent(CachePeer
* p
)
1263 p
->stats
.last_connect_failure
= squid_curtime
;
1266 debugs(15, 2, "TCP connection to " << p
->host
<< "/" << p
->http_port
<<
1274 debugs(15, DBG_IMPORTANT
, "Detected DEAD " << neighborTypeStr(p
) << ": " << p
->name
);
1275 p
->stats
.logged_state
= PEER_DEAD
;
1280 peerConnectFailed(CachePeer
*p
)
1282 debugs(15, DBG_IMPORTANT
, "TCP connection to " << p
->host
<< "/" << p
->http_port
<< " failed");
1283 peerConnectFailedSilent(p
);
1287 peerConnectSucceded(CachePeer
* p
)
1290 debugs(15, 2, "TCP connection to " << p
->host
<< "/" << p
->http_port
<< " succeded");
1291 p
->tcp_up
= p
->connect_fail_limit
; // NP: so peerAlive(p) works properly.
1293 if (!p
->n_addresses
)
1294 ipcache_nbgethostbyname(p
->host
, peerDNSConfigure
, p
);
1296 p
->tcp_up
= p
->connect_fail_limit
;
1300 * peerProbeConnect will be called on dead peers by neighborUp
1303 peerProbeConnect(CachePeer
* p
)
1305 time_t ctimeout
= p
->connect_timeout
> 0 ? p
->connect_timeout
: Config
.Timeout
.peer_connect
;
1306 bool ret
= (squid_curtime
- p
->stats
.last_connect_failure
) > (ctimeout
* 10);
1308 if (p
->testing_now
> 0)
1309 return ret
;/* probe already running */
1311 if (squid_curtime
- p
->stats
.last_connect_probe
== 0)
1312 return ret
;/* don't probe to often */
1314 /* for each IP address of this CachePeer. find one that we can connect to and probe it. */
1315 for (int i
= 0; i
< p
->n_addresses
; ++i
) {
1316 Comm::ConnectionPointer conn
= new Comm::Connection
;
1317 conn
->remote
= p
->addresses
[i
];
1318 conn
->remote
.port(p
->http_port
);
1320 getOutgoingAddress(NULL
, conn
);
1324 AsyncCall::Pointer call
= commCbCall(15,3, "peerProbeConnectDone", CommConnectCbPtrFun(peerProbeConnectDone
, p
));
1325 Comm::ConnOpener
*cs
= new Comm::ConnOpener(conn
, call
, ctimeout
);
1326 cs
->setHost(p
->host
);
1327 AsyncJob::Start(cs
);
1330 p
->stats
.last_connect_probe
= squid_curtime
;
1336 peerProbeConnectDone(const Comm::ConnectionPointer
&conn
, comm_err_t status
, int xerrno
, void *data
)
1338 CachePeer
*p
= (CachePeer
*)data
;
1340 if (status
== COMM_OK
) {
1341 peerConnectSucceded(p
);
1343 peerConnectFailedSilent(p
);
1348 // TODO: log this traffic.
1352 peerCountMcastPeersSchedule(CachePeer
* p
, time_t when
)
1354 if (p
->mcast
.flags
.count_event_pending
)
1357 eventAdd("peerCountMcastPeersStart",
1358 peerCountMcastPeersStart
,
1362 p
->mcast
.flags
.count_event_pending
= true;
1366 peerCountMcastPeersStart(void *data
)
1368 CachePeer
*p
= (CachePeer
*)data
;
1372 icp_common_t
*query
;
1374 LOCAL_ARRAY(char, url
, MAX_URL
);
1375 assert(p
->type
== PEER_MULTICAST
);
1376 p
->mcast
.flags
.count_event_pending
= false;
1377 snprintf(url
, MAX_URL
, "http://");
1378 p
->in_addr
.toUrl(url
+7, MAX_URL
-8 );
1380 fake
= storeCreateEntry(url
, url
, RequestFlags(), Http::METHOD_GET
);
1381 HttpRequest
*req
= HttpRequest::CreateFromUrl(url
);
1382 psstate
= new ps_state
;
1383 psstate
->request
= req
;
1384 HTTPMSGLOCK(psstate
->request
);
1385 psstate
->entry
= fake
;
1386 psstate
->callback
= NULL
;
1387 psstate
->callback_data
= cbdataReference(p
);
1388 psstate
->ping
.start
= current_time
;
1389 mem
= fake
->mem_obj
;
1390 mem
->request
= psstate
->request
;
1391 HTTPMSGLOCK(mem
->request
);
1392 mem
->start_ping
= current_time
;
1393 mem
->ping_reply_callback
= peerCountHandleIcpReply
;
1394 mem
->ircb_data
= psstate
;
1395 mcastSetTtl(icpOutgoingConn
->fd
, p
->mcast
.ttl
);
1396 p
->mcast
.id
= mem
->id
;
1397 reqnum
= icpSetCacheKey((const cache_key
*)fake
->key
);
1398 query
= _icp_common_t::createMessage(ICP_QUERY
, 0, url
, reqnum
, 0);
1399 icpUdpSend(icpOutgoingConn
->fd
, p
->in_addr
, query
, LOG_ICP_QUERY
, 0);
1400 fake
->ping_status
= PING_WAITING
;
1401 eventAdd("peerCountMcastPeersDone",
1402 peerCountMcastPeersDone
,
1404 Config
.Timeout
.mcast_icp_query
/ 1000.0, 1);
1405 p
->mcast
.flags
.counting
= true;
1406 peerCountMcastPeersSchedule(p
, MCAST_COUNT_RATE
);
1410 peerCountMcastPeersDone(void *data
)
1412 ps_state
*psstate
= (ps_state
*)data
;
1413 StoreEntry
*fake
= psstate
->entry
;
1415 if (cbdataReferenceValid(psstate
->callback_data
)) {
1416 CachePeer
*p
= (CachePeer
*)psstate
->callback_data
;
1417 p
->mcast
.flags
.counting
= false;
1418 p
->mcast
.avg_n_members
= Math::doubleAverage(p
->mcast
.avg_n_members
, (double) psstate
->ping
.n_recv
, ++p
->mcast
.n_times_counted
, 10);
1419 debugs(15, DBG_IMPORTANT
, "Group " << p
->host
<< ": " << psstate
->ping
.n_recv
<<
1420 " replies, "<< std::setw(4)<< std::setprecision(2) <<
1421 p
->mcast
.avg_n_members
<<" average, RTT " << p
->stats
.rtt
);
1422 p
->mcast
.n_replies_expected
= (int) p
->mcast
.avg_n_members
;
1425 cbdataReferenceDone(psstate
->callback_data
);
1427 fake
->abort(); // sets ENTRY_ABORTED and initiates releated cleanup
1428 HTTPMSGUNLOCK(fake
->mem_obj
->request
);
1430 HTTPMSGUNLOCK(psstate
->request
);
1431 cbdataFree(psstate
);
1435 peerCountHandleIcpReply(CachePeer
* p
, peer_t type
, AnyP::ProtocolType proto
, void *hdrnotused
, void *data
)
1439 ps_state
*psstate
= (ps_state
*)data
;
1440 StoreEntry
*fake
= psstate
->entry
;
1441 MemObject
*mem
= fake
->mem_obj
;
1442 int rtt
= tvSubMsec(mem
->start_ping
, current_time
);
1443 assert(proto
== AnyP::PROTO_ICP
);
1446 ++ psstate
->ping
.n_recv
;
1447 rtt_av_factor
= RTT_AV_FACTOR
;
1449 if (p
->options
.weighted_roundrobin
)
1450 rtt_av_factor
= RTT_BACKGROUND_AV_FACTOR
;
1452 p
->stats
.rtt
= Math::intAverage(p
->stats
.rtt
, rtt
, psstate
->ping
.n_recv
, rtt_av_factor
);
1456 neighborDumpPeers(StoreEntry
* sentry
)
1458 dump_peers(sentry
, Config
.peers
);
1462 neighborDumpNonPeers(StoreEntry
* sentry
)
1464 dump_peers(sentry
, non_peers
);
1468 dump_peer_options(StoreEntry
* sentry
, CachePeer
* p
)
1470 if (p
->options
.proxy_only
)
1471 storeAppendPrintf(sentry
, " proxy-only");
1473 if (p
->options
.no_query
)
1474 storeAppendPrintf(sentry
, " no-query");
1476 if (p
->options
.background_ping
)
1477 storeAppendPrintf(sentry
, " background-ping");
1479 if (p
->options
.no_digest
)
1480 storeAppendPrintf(sentry
, " no-digest");
1482 if (p
->options
.default_parent
)
1483 storeAppendPrintf(sentry
, " default");
1485 if (p
->options
.roundrobin
)
1486 storeAppendPrintf(sentry
, " round-robin");
1488 if (p
->options
.carp
)
1489 storeAppendPrintf(sentry
, " carp");
1492 if (p
->options
.userhash
)
1493 storeAppendPrintf(sentry
, " userhash");
1496 if (p
->options
.sourcehash
)
1497 storeAppendPrintf(sentry
, " sourcehash");
1499 if (p
->options
.weighted_roundrobin
)
1500 storeAppendPrintf(sentry
, " weighted-round-robin");
1502 if (p
->options
.mcast_responder
)
1503 storeAppendPrintf(sentry
, " multicast-responder");
1505 #if PEER_MULTICAST_SIBLINGS
1506 if (p
->options
.mcast_siblings
)
1507 storeAppendPrintf(sentry
, " multicast-siblings");
1511 storeAppendPrintf(sentry
, " weight=%d", p
->weight
);
1513 if (p
->options
.closest_only
)
1514 storeAppendPrintf(sentry
, " closest-only");
1517 if (p
->options
.htcp
) {
1518 storeAppendPrintf(sentry
, " htcp");
1519 if (p
->options
.htcp_oldsquid
|| p
->options
.htcp_no_clr
|| p
->options
.htcp_no_purge_clr
|| p
->options
.htcp_only_clr
) {
1521 if (p
->options
.htcp_oldsquid
)
1522 storeAppendPrintf(sentry
, "%soldsquid",(doneopts
++>0?",":"="));
1523 if (p
->options
.htcp_no_clr
)
1524 storeAppendPrintf(sentry
, "%sno-clr",(doneopts
++>0?",":"="));
1525 if (p
->options
.htcp_no_purge_clr
)
1526 storeAppendPrintf(sentry
, "%sno-purge-clr",(doneopts
++>0?",":"="));
1527 if (p
->options
.htcp_only_clr
)
1528 storeAppendPrintf(sentry
, "%sonly-clr",(doneopts
++>0?",":"="));
1533 if (p
->options
.no_netdb_exchange
)
1534 storeAppendPrintf(sentry
, " no-netdb-exchange");
1537 if (p
->options
.no_delay
)
1538 storeAppendPrintf(sentry
, " no-delay");
1542 storeAppendPrintf(sentry
, " login=%s", p
->login
);
1544 if (p
->mcast
.ttl
> 0)
1545 storeAppendPrintf(sentry
, " ttl=%d", p
->mcast
.ttl
);
1547 if (p
->connect_timeout
> 0)
1548 storeAppendPrintf(sentry
, " connect-timeout=%d", (int) p
->connect_timeout
);
1550 if (p
->connect_fail_limit
!= PEER_TCP_MAGIC_COUNT
)
1551 storeAppendPrintf(sentry
, " connect-fail-limit=%d", p
->connect_fail_limit
);
1553 #if USE_CACHE_DIGESTS
1556 storeAppendPrintf(sentry
, " digest-url=%s", p
->digest_url
);
1560 if (p
->options
.allow_miss
)
1561 storeAppendPrintf(sentry
, " allow-miss");
1563 if (p
->options
.no_tproxy
)
1564 storeAppendPrintf(sentry
, " no-tproxy");
1566 if (p
->max_conn
> 0)
1567 storeAppendPrintf(sentry
, " max-conn=%d", p
->max_conn
);
1569 if (p
->options
.originserver
)
1570 storeAppendPrintf(sentry
, " originserver");
1573 storeAppendPrintf(sentry
, " forceddomain=%s", p
->domain
);
1575 if (p
->connection_auth
== 0)
1576 storeAppendPrintf(sentry
, " connection-auth=off");
1577 else if (p
->connection_auth
== 1)
1578 storeAppendPrintf(sentry
, " connection-auth=on");
1579 else if (p
->connection_auth
== 2)
1580 storeAppendPrintf(sentry
, " connection-auth=auto");
1582 storeAppendPrintf(sentry
, "\n");
1586 dump_peers(StoreEntry
* sentry
, CachePeer
* peers
)
1588 CachePeer
*e
= NULL
;
1589 char ntoabuf
[MAX_IPSTRLEN
];
1590 CachePeerDomainList
*d
= NULL
;
1595 storeAppendPrintf(sentry
, "There are no neighbors installed.\n");
1597 for (e
= peers
; e
; e
= e
->next
) {
1598 assert(e
->host
!= NULL
);
1599 storeAppendPrintf(sentry
, "\n%-11.11s: %s\n",
1602 storeAppendPrintf(sentry
, "Host : %s/%d/%d\n",
1606 storeAppendPrintf(sentry
, "Flags :");
1607 dump_peer_options(sentry
, e
);
1609 for (i
= 0; i
< e
->n_addresses
; ++i
) {
1610 storeAppendPrintf(sentry
, "Address[%d] : %s\n", i
,
1611 e
->addresses
[i
].toStr(ntoabuf
,MAX_IPSTRLEN
) );
1614 storeAppendPrintf(sentry
, "Status : %s\n",
1615 neighborUp(e
) ? "Up" : "Down");
1616 storeAppendPrintf(sentry
, "FETCHES : %d\n", e
->stats
.fetches
);
1617 storeAppendPrintf(sentry
, "OPEN CONNS : %d\n", e
->stats
.conn_open
);
1618 storeAppendPrintf(sentry
, "AVG RTT : %d msec\n", e
->stats
.rtt
);
1620 if (!e
->options
.no_query
) {
1621 storeAppendPrintf(sentry
, "LAST QUERY : %8d seconds ago\n",
1622 (int) (squid_curtime
- e
->stats
.last_query
));
1624 if (e
->stats
.last_reply
> 0)
1625 storeAppendPrintf(sentry
, "LAST REPLY : %8d seconds ago\n",
1626 (int) (squid_curtime
- e
->stats
.last_reply
));
1628 storeAppendPrintf(sentry
, "LAST REPLY : none received\n");
1630 storeAppendPrintf(sentry
, "PINGS SENT : %8d\n", e
->stats
.pings_sent
);
1632 storeAppendPrintf(sentry
, "PINGS ACKED: %8d %3d%%\n",
1633 e
->stats
.pings_acked
,
1634 Math::intPercent(e
->stats
.pings_acked
, e
->stats
.pings_sent
));
1637 storeAppendPrintf(sentry
, "IGNORED : %8d %3d%%\n", e
->stats
.ignored_replies
, Math::intPercent(e
->stats
.ignored_replies
, e
->stats
.pings_acked
));
1639 if (!e
->options
.no_query
) {
1640 storeAppendPrintf(sentry
, "Histogram of PINGS ACKED:\n");
1643 if (e
->options
.htcp
) {
1644 storeAppendPrintf(sentry
, "\tMisses\t%8d %3d%%\n",
1646 Math::intPercent(e
->htcp
.counts
[0], e
->stats
.pings_acked
));
1647 storeAppendPrintf(sentry
, "\tHits\t%8d %3d%%\n",
1649 Math::intPercent(e
->htcp
.counts
[1], e
->stats
.pings_acked
));
1653 for (op
= ICP_INVALID
; op
< ICP_END
; ++op
) {
1654 if (e
->icp
.counts
[op
] == 0)
1657 storeAppendPrintf(sentry
, " %12.12s : %8d %3d%%\n",
1660 Math::intPercent(e
->icp
.counts
[op
], e
->stats
.pings_acked
));
1671 if (e
->stats
.last_connect_failure
) {
1672 storeAppendPrintf(sentry
, "Last failed connect() at: %s\n",
1673 Time::FormatHttpd(e
->stats
.last_connect_failure
));
1676 if (e
->peer_domain
!= NULL
) {
1677 storeAppendPrintf(sentry
, "DOMAIN LIST: ");
1679 for (d
= e
->peer_domain
; d
; d
= d
->next
) {
1680 storeAppendPrintf(sentry
, "%s%s ",
1681 d
->do_ping
? null_string
: "!", d
->domain
);
1684 storeAppendPrintf(sentry
, "\n");
1687 storeAppendPrintf(sentry
, "keep-alive ratio: %d%%\n", Math::intPercent(e
->stats
.n_keepalives_recv
, e
->stats
.n_keepalives_sent
));
1693 neighborsHtcpReply(const cache_key
* key
, HtcpReplyData
* htcp
, const Ip::Address
&from
)
1695 StoreEntry
*e
= Store::Root().get(key
);
1696 MemObject
*mem
= NULL
;
1698 peer_t ntype
= PEER_NONE
;
1699 debugs(15, 6, "neighborsHtcpReply: " <<
1700 (htcp
->hit
? "HIT" : "MISS") << " " <<
1701 storeKeyText(key
) );
1706 if ((p
= whichPeer(from
)))
1707 neighborAliveHtcp(p
, mem
, htcp
);
1709 /* Does the entry exist? */
1711 debugs(12, 3, "neighyborsHtcpReply: Cache key '" << storeKeyText(key
) << "' not found");
1712 neighborCountIgnored(p
);
1716 /* check if someone is already fetching it */
1717 if (EBIT_TEST(e
->flags
, ENTRY_DISPATCHED
)) {
1718 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key
) << "' already being fetched.");
1719 neighborCountIgnored(p
);
1724 debugs(15, 2, "Ignoring reply for missing mem_obj: " << storeKeyText(key
));
1725 neighborCountIgnored(p
);
1729 if (e
->ping_status
!= PING_WAITING
) {
1730 debugs(15, 2, "neighborsUdpAck: Entry " << storeKeyText(key
) << " is not PING_WAITING");
1731 neighborCountIgnored(p
);
1735 if (e
->lock_count
== 0) {
1736 // TODO: many entries are unlocked; why is this reported at level 1?
1737 debugs(12, DBG_IMPORTANT
, "neighborsUdpAck: '" << storeKeyText(key
) << "' has no locks");
1738 neighborCountIgnored(p
);
1743 ntype
= neighborType(p
, mem
->request
);
1744 neighborUpdateRtt(p
, mem
);
1747 if (ignoreMulticastReply(p
, mem
)) {
1748 neighborCountIgnored(p
);
1752 debugs(15, 3, "neighborsHtcpReply: e = " << e
);
1753 mem
->ping_reply_callback(p
, ntype
, AnyP::PROTO_HTCP
, htcp
, mem
->ircb_data
);
1757 * Send HTCP CLR messages to all peers configured to receive them.
1760 neighborsHtcpClear(StoreEntry
* e
, const char *uri
, HttpRequest
* req
, const HttpRequestMethod
&method
, htcp_clr_reason reason
)
1765 for (p
= Config
.peers
; p
; p
= p
->next
) {
1766 if (!p
->options
.htcp
) {
1769 if (p
->options
.htcp_no_clr
) {
1772 if (p
->options
.htcp_no_purge_clr
&& reason
== HTCP_CLR_PURGE
) {
1775 debugs(15, 3, "neighborsHtcpClear: sending CLR to " << p
->in_addr
.toUrl(buf
, 128));
1776 htcpClear(e
, uri
, req
, method
, p
, reason
);