--- /dev/null
+/*
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_CACHEPEERS_H
+#define SQUID_CACHEPEERS_H
+
+#include "base/forward.h"
+#include "CachePeer.h"
+#include "mem/PoolingAllocator.h"
+
+#include <vector>
+
+/// Weak pointers to zero or more Config.peers.
+/// Users must specify the selection algorithm and the order of entries.
+using SelectedCachePeers = std::vector< CbcPointer<CachePeer>, PoolingAllocator< CbcPointer<CachePeer> > >;
+
+/// Temporary, local storage of raw pointers to zero or more Config.peers.
+using RawCachePeers = std::vector<CachePeer *, PoolingAllocator<CachePeer*> >;
+
+#endif /* SQUID_CACHEPEERS_H */
+
#include "squid.h"
#include "CachePeer.h"
+#include "CachePeers.h"
#include "carp.h"
#include "HttpRequest.h"
#include "mgr/Registration.h"
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-static int n_carp_peers = 0;
-static CachePeer **carp_peers = nullptr;
+/// CARP cache_peers ordered by their CARP weight
+static SelectedCachePeers TheCarpPeers;
+
static OBJH carpCachemgr;
static int
carpInit(void)
{
int W = 0;
- int K;
- int k;
double P_last, X_last, Xn;
- CachePeer *p;
- CachePeer **P;
char *t;
/* Clean up */
- for (k = 0; k < n_carp_peers; ++k) {
- cbdataReferenceDone(carp_peers[k]);
- }
-
- safe_free(carp_peers);
- n_carp_peers = 0;
+ TheCarpPeers.clear();
/* initialize cache manager before we have a chance to leave the execution path */
carpRegisterWithCacheManager();
/* find out which peers we have */
- for (p = Config.peers; p; p = p->next) {
+ RawCachePeers rawCarpPeers;
+ for (auto p = Config.peers; p; p = p->next) {
+ if (!cbdataReferenceValid(p))
+ continue;
+
if (!p->options.carp)
continue;
if (p->weight == 0)
continue;
- ++n_carp_peers;
+ rawCarpPeers.push_back(p);
W += p->weight;
}
- if (n_carp_peers == 0)
+ if (rawCarpPeers.empty())
return;
- carp_peers = (CachePeer **)xcalloc(n_carp_peers, sizeof(*carp_peers));
-
- /* Build a list of the found peers and calculate hashes and load factors */
- for (P = carp_peers, p = Config.peers; p; p = p->next) {
- if (!p->options.carp)
- continue;
-
- if (p->weight == 0)
- continue;
-
+ /* calculate hashes and load factors */
+ for (const auto p: rawCarpPeers) {
/* calculate this peers hash */
p->carp.hash = 0;
if (floor(p->carp.load_factor * 1000.0) == 0.0)
p->carp.load_factor = 0.0;
-
- /* add it to our list of peers */
- *P = cbdataReference(p);
- ++P;
}
/* Sort our list on weight */
- qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight);
+ qsort(rawCarpPeers.data(), rawCarpPeers.size(), sizeof(decltype(rawCarpPeers)::value_type), peerSortWeight);
/* Calculate the load factor multipliers X_k
*
* X_k = pow (X_k, {1/(K-k+1)})
* simplified to have X_1 part of the loop
*/
- K = n_carp_peers;
+ const auto K = rawCarpPeers.size();
P_last = 0.0; /* Empty P_0 */
X_last = 0.0; /* Empty X_0, nullifies the first pow statement */
- for (k = 1; k <= K; ++k) {
+ for (size_t k = 1; k <= K; ++k) {
double Kk1 = (double) (K - k + 1);
- p = carp_peers[k - 1];
+ const auto p = rawCarpPeers[k - 1];
p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn;
p->carp.load_multiplier += pow(X_last, Kk1);
p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1);
X_last = p->carp.load_multiplier;
P_last = p->carp.load_factor;
}
+
+ TheCarpPeers.assign(rawCarpPeers.begin(), rawCarpPeers.end());
}
CachePeer *
assert(ps);
HttpRequest *request = ps->request;
- int k;
CachePeer *p = nullptr;
- CachePeer *tp;
unsigned int user_hash = 0;
unsigned int combined_hash;
double score;
double high_score = 0;
- if (n_carp_peers == 0)
+ if (TheCarpPeers.empty())
return nullptr;
/* calculate hash key */
debugs(39, 2, "carpSelectParent: Calculating hash for " << request->effectiveRequestUri());
/* select CachePeer */
- for (k = 0; k < n_carp_peers; ++k) {
+ for (const auto &tp: TheCarpPeers) {
+ if (!tp)
+ continue; // peer gone
+
SBuf key;
- tp = carp_peers[k];
if (tp->options.carp_key.set) {
// this code follows URI syntax pattern.
// corner cases should use the full effective request URI
debugs(39, 3, *tp << " key=" << key << " combined_hash=" << combined_hash <<
" score=" << std::setprecision(0) << score);
- if ((score > high_score) && peerHTTPOkay(tp, ps)) {
- p = tp;
+ if ((score > high_score) && peerHTTPOkay(tp.get(), ps)) {
+ p = tp.get();
high_score = score;
}
}
static void
carpCachemgr(StoreEntry * sentry)
{
- CachePeer *p;
int sumfetches = 0;
storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
"Hostname",
"Factor",
"Actual");
- for (p = Config.peers; p; p = p->next)
+ for (const auto &p: TheCarpPeers) {
+ if (!p)
+ continue;
sumfetches += p->stats.fetches;
+ }
- for (p = Config.peers; p; p = p->next) {
+ for (const auto &p: TheCarpPeers) {
+ if (!p)
+ continue;
storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
p->name, p->carp.hash,
p->carp.load_multiplier,