]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ResolvedPeers.cc
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
10 #include "CachePeer.h"
11 #include "comm/Connection.h"
12 #include "comm/ConnOpener.h"
13 #include "ResolvedPeers.h"
14 #include "SquidConfig.h"
16 ResolvedPeers::ResolvedPeers()
18 if (Config
.forward_max_tries
> 0)
19 paths_
.reserve(Config
.forward_max_tries
);
23 ResolvedPeers::reinstatePath(const PeerConnectionPointer
&path
)
28 const auto pos
= path
.position_
;
29 assert(pos
< paths_
.size());
31 assert(!paths_
[pos
].available
);
32 paths_
[pos
].available
= true;
33 increaseAvailability();
35 // if we restored availability of a path that we used to skip, update
36 const auto pathsToTheLeft
= pos
;
37 if (pathsToTheLeft
< pathsToSkip
) {
38 pathsToSkip
= pathsToTheLeft
;
40 // *found was unavailable so pathsToSkip could not end at it
41 Must(pathsToTheLeft
!= pathsToSkip
);
46 ResolvedPeers::addPath(const Comm::ConnectionPointer
&path
)
48 paths_
.emplace_back(path
);
49 Must(paths_
.back().available
); // no pathsToSkip updates are needed
50 increaseAvailability();
53 /// \returns the beginning iterator for any available-path search
54 ResolvedPeers::Paths::iterator
55 ResolvedPeers::start()
57 Must(pathsToSkip
<= paths_
.size());
58 return paths_
.begin() + pathsToSkip
; // may return end()
61 /// finalizes the iterator part of the given preliminary find*() result
62 ResolvedPeers::Finding
63 ResolvedPeers::makeFinding(const Paths::iterator
&path
, bool foundOther
)
65 return std::make_pair((foundOther
? paths_
.end() : path
), foundOther
);
68 /// \returns the first available same-peer same-family Finding or <end,...>
69 ResolvedPeers::Finding
70 ResolvedPeers::findPrime(const Comm::Connection
¤tPeer
)
72 const auto path
= start();
73 const auto foundNextOrSpare
= path
!= paths_
.end() &&
74 (currentPeer
.getPeer() != path
->connection
->getPeer() || // next peer
75 ConnectionFamily(currentPeer
) != ConnectionFamily(*path
->connection
));
76 return makeFinding(path
, foundNextOrSpare
);
79 /// \returns the first available same-peer different-family Finding or <end,...>
80 ResolvedPeers::Finding
81 ResolvedPeers::findSpare(const Comm::Connection
¤tPeer
)
83 const auto primeFamily
= ConnectionFamily(currentPeer
);
84 const auto primePeer
= currentPeer
.getPeer();
85 const auto path
= std::find_if(start(), paths_
.end(),
86 [primeFamily
, primePeer
](const ResolvedPeerPath
&candidate
) {
87 if (!candidate
.available
)
89 if (primePeer
!= candidate
.connection
->getPeer())
90 return true; // found next peer
91 if (primeFamily
!= ConnectionFamily(*candidate
.connection
))
92 return true; // found spare
95 const auto foundNext
= path
!= paths_
.end() &&
96 primePeer
!= path
->connection
->getPeer();
97 return makeFinding(path
, foundNext
);
100 /// \returns the first available same-peer Finding or <end,...>
101 ResolvedPeers::Finding
102 ResolvedPeers::findPeer(const Comm::Connection
¤tPeer
)
104 const auto path
= start();
105 const auto foundNext
= path
!= paths_
.end() &&
106 currentPeer
.getPeer() != path
->connection
->getPeer();
107 return makeFinding(path
, foundNext
);
110 PeerConnectionPointer
111 ResolvedPeers::extractFront()
114 return extractFound("first: ", start());
117 PeerConnectionPointer
118 ResolvedPeers::extractPrime(const Comm::Connection
¤tPeer
)
120 const auto found
= findPrime(currentPeer
).first
;
121 if (found
!= paths_
.end())
122 return extractFound("same-peer same-family match: ", found
);
124 debugs(17, 7, "no same-peer same-family paths");
128 PeerConnectionPointer
129 ResolvedPeers::extractSpare(const Comm::Connection
¤tPeer
)
131 const auto found
= findSpare(currentPeer
).first
;
132 if (found
!= paths_
.end())
133 return extractFound("same-peer different-family match: ", found
);
135 debugs(17, 7, "no same-peer different-family paths");
139 /// convenience method to finish a successful extract*() call
140 PeerConnectionPointer
141 ResolvedPeers::extractFound(const char *description
, const Paths::iterator
&found
)
144 debugs(17, 7, description
<< path
.connection
);
145 assert(path
.available
);
146 path
.available
= false;
147 decreaseAvailability();
149 // if we extracted the left-most available path, find the next one
150 if (static_cast<size_type
>(found
- paths_
.begin()) == pathsToSkip
) {
151 while (++pathsToSkip
< paths_
.size() && !paths_
[pathsToSkip
].available
) {}
154 const auto cleanPath
= path
.connection
->cloneProfile();
155 return PeerConnectionPointer(cleanPath
, found
- paths_
.begin());
159 ResolvedPeers::haveSpare(const Comm::Connection
¤tPeer
)
161 return findSpare(currentPeer
).first
!= paths_
.end();
164 /// whether paths_ have no (and will have no) Xs for the current peer based on
165 /// the given findX(current peer) result
167 ResolvedPeers::doneWith(const Finding
&findings
) const
169 if (findings
.first
!= paths_
.end())
170 return false; // not done because the caller found a viable path X
172 // The caller did not find any path X. If the caller found any "other"
173 // paths, then we are done with paths X. If there are no "other" paths,
174 // then destinationsFinalized is the answer.
175 return findings
.second
? true : destinationsFinalized
;
179 ResolvedPeers::doneWithSpares(const Comm::Connection
¤tPeer
)
181 return doneWith(findSpare(currentPeer
));
185 ResolvedPeers::doneWithPrimes(const Comm::Connection
¤tPeer
)
187 return doneWith(findPrime(currentPeer
));
191 ResolvedPeers::doneWithPeer(const Comm::Connection
¤tPeer
)
193 return doneWith(findPeer(currentPeer
));
197 ResolvedPeers::ConnectionFamily(const Comm::Connection
&conn
)
199 return conn
.remote
.isIPv4() ? AF_INET
: AF_INET6
;
202 /// increments the number of available paths
204 ResolvedPeers::increaseAvailability()
207 assert(availablePaths
<= paths_
.size());
210 /// decrements the number of available paths
212 ResolvedPeers::decreaseAvailability()
214 assert(availablePaths
> 0);
219 operator <<(std::ostream
&os
, const ResolvedPeers
&peers
)
222 return os
<< "[no paths]";
223 return os
<< peers
.size() << (peers
.destinationsFinalized
? "" : "+") << " paths";
226 /* PeerConnectionPointer */
229 PeerConnectionPointer::print(std::ostream
&os
) const
231 // We should see no combinations of a nil connection and a set position
232 // because assigning nullptr (to our smart pointer) naturally erases both
233 // fields. We report such unexpected combinations for debugging sake, but do
234 // not complicate this code to report them beautifully.
239 if (position_
!= npos
)
240 os
<< " @" << position_
;