Squid Web Cache master
Loading...
Searching...
No Matches
ResolvedPeers.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
10#include "CachePeer.h"
11#include "comm/Connection.h"
12#include "comm/ConnOpener.h"
13#include "ResolvedPeers.h"
14#include "SquidConfig.h"
15
16#include <algorithm>
17
23
24void
26{
27 debugs(17, 4, path);
28 assert(path);
29
30 const auto pos = path.position_;
31 assert(pos < paths_.size());
32
33 assert(!paths_[pos].available);
34 paths_[pos].available = true;
36
37 // if we restored availability of a path that we used to skip, update
38 const auto pathsToTheLeft = pos;
39 if (pathsToTheLeft < pathsToSkip) {
40 pathsToSkip = pathsToTheLeft;
41 } else {
42 // *found was unavailable so pathsToSkip could not end at it
43 Must(pathsToTheLeft != pathsToSkip);
44 }
45}
46
47void
49{
50 paths_.emplace_back(path);
51 Must(paths_.back().available); // no pathsToSkip updates are needed
53}
54
56ResolvedPeers::Paths::iterator
58{
59 Must(pathsToSkip <= paths_.size());
60 return paths_.begin() + pathsToSkip; // may return end()
61}
62
65ResolvedPeers::makeFinding(const Paths::iterator &path, bool foundOther)
66{
67 return std::make_pair((foundOther ? paths_.end() : path), foundOther);
68}
69
73{
74 const auto path = start();
75 const auto foundNextOrSpare = path != paths_.end() &&
76 (currentPeer.getPeer() != path->connection->getPeer() || // next peer
77 ConnectionFamily(currentPeer) != ConnectionFamily(*path->connection));
78 return makeFinding(path, foundNextOrSpare);
79}
80
84{
85 const auto primeFamily = ConnectionFamily(currentPeer);
86 const auto primePeer = currentPeer.getPeer();
87 const auto path = std::find_if(start(), paths_.end(),
88 [primeFamily, primePeer](const ResolvedPeerPath &candidate) {
89 if (!candidate.available)
90 return false;
91 if (primePeer != candidate.connection->getPeer())
92 return true; // found next peer
93 if (primeFamily != ConnectionFamily(*candidate.connection))
94 return true; // found spare
95 return false;
96 });
97 const auto foundNext = path != paths_.end() &&
98 primePeer != path->connection->getPeer();
99 return makeFinding(path, foundNext);
100}
101
105{
106 const auto path = start();
107 const auto foundNext = path != paths_.end() &&
108 currentPeer.getPeer() != path->connection->getPeer();
109 return makeFinding(path, foundNext);
110}
111
114{
115 Must(!empty());
116 return extractFound("first: ", start());
117}
118
121{
122 const auto found = findPrime(currentPeer).first;
123 if (found != paths_.end())
124 return extractFound("same-peer same-family match: ", found);
125
126 debugs(17, 7, "no same-peer same-family paths");
127 return nullptr;
128}
129
132{
133 const auto found = findSpare(currentPeer).first;
134 if (found != paths_.end())
135 return extractFound("same-peer different-family match: ", found);
136
137 debugs(17, 7, "no same-peer different-family paths");
138 return nullptr;
139}
140
143ResolvedPeers::extractFound(const char *description, const Paths::iterator &found)
144{
145 auto &path = *found;
146 debugs(17, 7, description << path.connection);
147 assert(path.available);
148 path.available = false;
150
151 // if we extracted the left-most available path, find the next one
152 if (static_cast<size_type>(found - paths_.begin()) == pathsToSkip) {
153 while (++pathsToSkip < paths_.size() && !paths_[pathsToSkip].available) {}
154 }
155
156 const auto cleanPath = path.connection->cloneProfile();
157 return PeerConnectionPointer(cleanPath, found - paths_.begin());
158}
159
160bool
162{
163 return findSpare(currentPeer).first != paths_.end();
164}
165
168bool
169ResolvedPeers::doneWith(const Finding &findings) const
170{
171 if (findings.first != paths_.end())
172 return false; // not done because the caller found a viable path X
173
174 // The caller did not find any path X. If the caller found any "other"
175 // paths, then we are done with paths X. If there are no "other" paths,
176 // then destinationsFinalized is the answer.
177 return findings.second ? true : destinationsFinalized;
178}
179
180bool
182{
183 return doneWith(findSpare(currentPeer));
184}
185
186bool
188{
189 return doneWith(findPrime(currentPeer));
190}
191
192bool
194{
195 return doneWith(findPeer(currentPeer));
196}
197
198int
200{
201 return conn.remote.isIPv4() ? AF_INET : AF_INET6;
202}
203
205void
211
213void
219
220std::ostream &
221operator <<(std::ostream &os, const ResolvedPeers &peers)
222{
223 if (peers.empty())
224 return os << "[no paths]";
225 return os << peers.size() << (peers.destinationsFinalized ? "" : "+") << " paths";
226}
227
228/* PeerConnectionPointer */
229
230void
231PeerConnectionPointer::print(std::ostream &os) const
232{
233 // We should see no combinations of a nil connection and a set position
234 // because assigning nullptr (to our smart pointer) naturally erases both
235 // fields. We report such unexpected combinations for debugging sake, but do
236 // not complicate this code to report them beautifully.
237
238 if (connection_)
239 os << connection_;
240
241 if (position_ != npos)
242 os << " @" << position_;
243}
244
std::ostream & operator<<(std::ostream &os, const ResolvedPeers &peers)
summarized ResolvedPeers (for debugging)
class SquidConfig Config
#define Must(condition)
#define assert(EX)
Definition assert.h:17
CachePeer * getPeer() const
Ip::Address remote
Definition Connection.h:152
bool isIPv4() const
Definition Address.cc:178
Comm::ConnectionPointer connection_
half-baked, open, failed, or closed Comm::Connection (or nil)
void print(std::ostream &) const
debugging dump
static constexpr auto npos
non-existent position for nil connection
size_type position_
ResolvedPeers-maintained membership index (or npos)
Finding makeFinding(const Paths::iterator &found, bool foundOther)
finalizes the iterator part of the given preliminary find*() result
Paths paths_
resolved addresses in (peer, family) order
PeerConnectionPointer extractFront()
extracts and returns the first queued address
bool doneWith(const Finding &findings) const
size_type pathsToSkip
bool haveSpare(const Comm::Connection &currentPeer)
whether extractSpare() would return a non-nil path right now
Finding findPrime(const Comm::Connection &currentPeer)
void increaseAvailability()
increments the number of available paths
Finding findSpare(const Comm::Connection &currentPeer)
Paths::iterator start()
size_type availablePaths
the total number of currently available elements in paths_
static int ConnectionFamily(const Comm::Connection &conn)
The protocol family of the given path, AF_INET or AF_INET6.
bool doneWithPrimes(const Comm::Connection &currentPeer)
whether extractPrime() returns and will continue to return nil
std::pair< Paths::iterator, bool > Finding
bool doneWithPeer(const Comm::Connection &currentPeer)
whether doneWithPrimes() and doneWithSpares() are true for currentPeer
void reinstatePath(const PeerConnectionPointer &)
size_type size() const
the current number of candidate paths
PeerConnectionPointer extractFound(const char *description, const Paths::iterator &found)
convenience method to finish a successful extract*() call
Paths::size_type size_type
PeerConnectionPointer extractSpare(const Comm::Connection &currentPeer)
void decreaseAvailability()
decrements the number of available paths
bool empty() const
whether we lack any known candidate paths
bool destinationsFinalized
whether all of the available candidate paths received from DNS
void addPath(const Comm::ConnectionPointer &)
add a candidate path to try after all the existing paths
Finding findPeer(const Comm::Connection &currentPeer)
PeerConnectionPointer extractPrime(const Comm::Connection &currentPeer)
bool doneWithSpares(const Comm::Connection &currentPeer)
whether extractSpare() returns and will continue to return nil
int forward_max_tries
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192