peer_sourcehash.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 /* DEBUG: section 39 Peer source hash based selection */
10 
11 #include "squid.h"
12 #include "base/RunnersRegistry.h"
13 #include "CachePeer.h"
14 #include "CachePeers.h"
15 #include "HttpRequest.h"
16 #include "mgr/Registration.h"
17 #include "neighbors.h"
18 #include "peer_sourcehash.h"
19 #include "PeerSelectState.h"
20 #include "SquidConfig.h"
21 #include "Store.h"
22 
23 #include <cmath>
24 
25 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
26 
28 static auto &
30 {
31  static const auto hashPeers = new SelectedCachePeers();
32  return *hashPeers;
33 }
34 
37 
38 static int
39 peerSortWeight(const void *a, const void *b)
40 {
41  const CachePeer *const *p1 = (const CachePeer *const *)a;
42  const CachePeer *const *p2 = (const CachePeer *const *)b;
43  return (*p1)->weight - (*p2)->weight;
44 }
45 
46 static void
48 {
49  int W = 0;
50  double P_last, X_last, Xn;
51  char *t;
52  /* Clean up */
53 
54  SourceHashPeers().clear();
55  /* find out which peers we have */
56 
57  RawCachePeers rawSourceHashPeers;
58  for (const auto &p: CurrentCachePeers()) {
59  const auto peer = p.get();
60 
61  if (!p->options.sourcehash)
62  continue;
63 
64  assert(p->type == PEER_PARENT);
65 
66  if (p->weight == 0)
67  continue;
68 
69  rawSourceHashPeers.push_back(peer);
70 
71  W += p->weight;
72  }
73 
75 
76  if (rawSourceHashPeers.empty())
77  return;
78 
79  /* calculate hashes and load factors */
80  for (const auto &p: rawSourceHashPeers) {
81  /* calculate this peers hash */
82  p->sourcehash.hash = 0;
83 
84  for (t = p->name; *t != 0; ++t)
85  p->sourcehash.hash += ROTATE_LEFT(p->sourcehash.hash, 19) + (unsigned int) *t;
86 
87  p->sourcehash.hash += p->sourcehash.hash * 0x62531965;
88 
89  p->sourcehash.hash = ROTATE_LEFT(p->sourcehash.hash, 21);
90 
91  /* and load factor */
92  p->sourcehash.load_factor = ((double) p->weight) / (double) W;
93 
94  if (floor(p->sourcehash.load_factor * 1000.0) == 0.0)
95  p->sourcehash.load_factor = 0.0;
96  }
97 
98  /* Sort our list on weight */
99  qsort(rawSourceHashPeers.data(), rawSourceHashPeers.size(), sizeof(decltype(rawSourceHashPeers)::value_type), peerSortWeight);
100 
101  /* Calculate the load factor multipliers X_k
102  *
103  * X_1 = pow ((K*p_1), (1/K))
104  * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
105  * X_k += pow ((X_{k-1}, {K-k+1})
106  * X_k = pow (X_k, {1/(K-k+1)})
107  * simplified to have X_1 part of the loop
108  */
109  const auto K = rawSourceHashPeers.size();
110 
111  P_last = 0.0; /* Empty P_0 */
112 
113  Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
114 
115  X_last = 0.0; /* Empty X_0, nullifies the first pow statement */
116 
117  for (size_t k = 1; k <= K; ++k) {
118  double Kk1 = (double) (K - k + 1);
119  const auto p = rawSourceHashPeers[k - 1];
120  p->sourcehash.load_multiplier = (Kk1 * (p->sourcehash.load_factor - P_last)) / Xn;
121  p->sourcehash.load_multiplier += pow(X_last, Kk1);
122  p->sourcehash.load_multiplier = pow(p->sourcehash.load_multiplier, 1.0 / Kk1);
123  Xn *= p->sourcehash.load_multiplier;
124  X_last = p->sourcehash.load_multiplier;
125  P_last = p->sourcehash.load_factor;
126  }
127 
128  SourceHashPeers().assign(rawSourceHashPeers.begin(), rawSourceHashPeers.end());
129 }
130 
133 {
134 public:
135  /* RegisteredRunner API */
136  void useConfig() override { peerSourceHashInit(); }
137  void syncConfig() override { peerSourceHashInit(); }
138 };
139 
141 
142 static void
144 {
145  Mgr::RegisterAction("sourcehash", "peer sourcehash information",
146  peerSourceHashCachemgr, 0, 1);
147 }
148 
149 CachePeer *
151 {
152  const char *c;
153  CachePeer *p = nullptr;
154  unsigned int user_hash = 0;
155  unsigned int combined_hash;
156  double score;
157  double high_score = 0;
158  const char *key = nullptr;
159  char ntoabuf[MAX_IPSTRLEN];
160 
161  if (SourceHashPeers().empty())
162  return nullptr;
163 
164  assert(ps);
165  HttpRequest *request = ps->request;
166 
167  key = request->client_addr.toStr(ntoabuf, sizeof(ntoabuf));
168 
169  /* calculate hash key */
170  debugs(39, 2, "peerSourceHashSelectParent: Calculating hash for " << key);
171 
172  for (c = key; *c != 0; ++c)
173  user_hash += ROTATE_LEFT(user_hash, 19) + *c;
174 
175  /* select CachePeer */
176  for (const auto &tp: SourceHashPeers()) {
177  if (!tp)
178  continue; // peer gone
179 
180  combined_hash = (user_hash ^ tp->sourcehash.hash);
181  combined_hash += combined_hash * 0x62531965;
182  combined_hash = ROTATE_LEFT(combined_hash, 21);
183  score = combined_hash * tp->sourcehash.load_multiplier;
184  debugs(39, 3, *tp << " combined_hash " << combined_hash <<
185  " score " << std::setprecision(0) << score);
186 
187  if ((score > high_score) && peerHTTPOkay(tp.get(), ps)) {
188  p = tp.get();
189  high_score = score;
190  }
191  }
192 
193  if (p)
194  debugs(39, 2, "selected " << *p);
195 
196  return p;
197 }
198 
199 static void
201 {
202  int sumfetches = 0;
203  storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
204  "Hostname",
205  "Hash",
206  "Multiplier",
207  "Factor",
208  "Actual");
209 
210  for (const auto &p: SourceHashPeers()) {
211  if (!p)
212  continue;
213  sumfetches += p->stats.fetches;
214  }
215 
216  for (const auto &p: SourceHashPeers()) {
217  if (!p)
218  continue;
219  storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
220  p->name, p->sourcehash.hash,
221  p->sourcehash.load_multiplier,
222  p->sourcehash.load_factor,
223  sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
224  }
225 }
226 
HttpRequest * request
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:855
static void peerSourceHashRegisterWithCacheManager(void)
void useConfig() override
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:812
#define ROTATE_LEFT(x, n)
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
int weight
Definition: CachePeer.h:150
void OBJH(StoreEntry *)
Definition: forward.h:44
@ PEER_PARENT
Definition: enums.h:25
std::vector< CbcPointer< CachePeer >, PoolingAllocator< CbcPointer< CachePeer > > > SelectedCachePeers
Definition: CachePeers.h:63
std::vector< CachePeer *, PoolingAllocator< CachePeer * > > RawCachePeers
Temporary, local storage of raw pointers to zero or more Config.peers.
Definition: CachePeers.h:66
DefineRunnerRegistrator(PeerSourceHashRr)
#define assert(EX)
Definition: assert.h:17
void EVH void double
Definition: stub_event.cc:16
static int peerSortWeight(const void *a, const void *b)
CachePeer * peerSourceHashSelectParent(PeerSelector *ps)
static auto & SourceHashPeers()
sourcehash peers ordered by their sourcehash weight
reacts to RegisteredRunner events relevant to this module
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
Definition: Registration.cc:54
void syncConfig() override
const CachePeers & CurrentCachePeers()
Definition: CachePeers.cc:43
int peerHTTPOkay(const CachePeer *p, PeerSelector *ps)
Definition: neighbors.cc:252
static void peerSourceHashInit(void)
Ip::Address client_addr
Definition: HttpRequest.h:149
static OBJH peerSourceHashCachemgr
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
int unsigned int
Definition: stub_fd.cc:19

 

Introduction

Documentation

Support

Miscellaneous