PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/carp.cc

https://github.com/dkurochkin/squid
C++ | 267 lines | 164 code | 45 blank | 58 comment | 36 complexity | d7777374d1d9597115213a41a68730cc MD5 | raw file
  1. /*
  2. * $Id$
  3. *
  4. * DEBUG: section 39 Cache Array Routing Protocol
  5. * AUTHOR: Henrik Nordstrom
  6. * BASED ON: carp.c by Eric Stern and draft-vinod-carp-v1-03.txt
  7. *
  8. * SQUID Web Proxy Cache http://www.squid-cache.org/
  9. * ----------------------------------------------------------
  10. *
  11. * Squid is the result of efforts by numerous individuals from
  12. * the Internet community; see the CONTRIBUTORS file for full
  13. * details. Many organizations have provided support for Squid's
  14. * development; see the SPONSORS file for full details. Squid is
  15. * Copyrighted (C) 2001 by the Regents of the University of
  16. * California; see the COPYRIGHT file for full details. Squid
  17. * incorporates software developed and/or copyrighted by other
  18. * sources; see the CREDITS file for full details.
  19. *
  20. * This program is free software; you can redistribute it and/or modify
  21. * it under the terms of the GNU General Public License as published by
  22. * the Free Software Foundation; either version 2 of the License, or
  23. * (at your option) any later version.
  24. *
  25. * This program is distributed in the hope that it will be useful,
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28. * GNU General Public License for more details.
  29. *
  30. * You should have received a copy of the GNU General Public License
  31. * along with this program; if not, write to the Free Software
  32. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  33. *
  34. */
  35. #include "squid.h"
  36. #include "HttpRequest.h"
  37. #include "mgr/Registration.h"
  38. #include "Store.h"
  39. #include "URLScheme.h"
  40. #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
  41. static int n_carp_peers = 0;
  42. static peer **carp_peers = NULL;
  43. static OBJH carpCachemgr;
  44. static int
  45. peerSortWeight(const void *a, const void *b)
  46. {
  47. const peer *const *p1 = (const peer *const *)a;
  48. const peer *const *p2 = (const peer *const *)b;
  49. return (*p1)->weight - (*p2)->weight;
  50. }
  51. static void
  52. carpRegisterWithCacheManager(void)
  53. {
  54. Mgr::RegisterAction("carp", "CARP information", carpCachemgr, 0, 1);
  55. }
  56. void
  57. carpInit(void)
  58. {
  59. int W = 0;
  60. int K;
  61. int k;
  62. double P_last, X_last, Xn;
  63. peer *p;
  64. peer **P;
  65. char *t;
  66. /* Clean up */
  67. for (k = 0; k < n_carp_peers; k++) {
  68. cbdataReferenceDone(carp_peers[k]);
  69. }
  70. safe_free(carp_peers);
  71. n_carp_peers = 0;
  72. /* initialize cache manager before we have a chance to leave the execution path */
  73. carpRegisterWithCacheManager();
  74. /* find out which peers we have */
  75. for (p = Config.peers; p; p = p->next) {
  76. if (!p->options.carp)
  77. continue;
  78. assert(p->type == PEER_PARENT);
  79. if (p->weight == 0)
  80. continue;
  81. n_carp_peers++;
  82. W += p->weight;
  83. }
  84. if (n_carp_peers == 0)
  85. return;
  86. carp_peers = (peer **)xcalloc(n_carp_peers, sizeof(*carp_peers));
  87. /* Build a list of the found peers and calculate hashes and load factors */
  88. for (P = carp_peers, p = Config.peers; p; p = p->next) {
  89. if (!p->options.carp)
  90. continue;
  91. if (p->weight == 0)
  92. continue;
  93. /* calculate this peers hash */
  94. p->carp.hash = 0;
  95. for (t = p->name; *t != 0; t++)
  96. p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t;
  97. p->carp.hash += p->carp.hash * 0x62531965;
  98. p->carp.hash = ROTATE_LEFT(p->carp.hash, 21);
  99. /* and load factor */
  100. p->carp.load_factor = ((double) p->weight) / (double) W;
  101. if (floor(p->carp.load_factor * 1000.0) == 0.0)
  102. p->carp.load_factor = 0.0;
  103. /* add it to our list of peers */
  104. *P++ = cbdataReference(p);
  105. }
  106. /* Sort our list on weight */
  107. qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight);
  108. /* Calculate the load factor multipliers X_k
  109. *
  110. * X_1 = pow ((K*p_1), (1/K))
  111. * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
  112. * X_k += pow ((X_{k-1}, {K-k+1})
  113. * X_k = pow (X_k, {1/(K-k+1)})
  114. * simplified to have X_1 part of the loop
  115. */
  116. K = n_carp_peers;
  117. P_last = 0.0; /* Empty P_0 */
  118. Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
  119. X_last = 0.0; /* Empty X_0, nullifies the first pow statement */
  120. for (k = 1; k <= K; k++) {
  121. double Kk1 = (double) (K - k + 1);
  122. p = carp_peers[k - 1];
  123. p->carp.load_multiplier = (Kk1 * (p->carp.load_factor - P_last)) / Xn;
  124. p->carp.load_multiplier += pow(X_last, Kk1);
  125. p->carp.load_multiplier = pow(p->carp.load_multiplier, 1.0 / Kk1);
  126. Xn *= p->carp.load_multiplier;
  127. X_last = p->carp.load_multiplier;
  128. P_last = p->carp.load_factor;
  129. }
  130. }
  131. peer *
  132. carpSelectParent(HttpRequest * request)
  133. {
  134. int k;
  135. peer *p = NULL;
  136. peer *tp;
  137. unsigned int user_hash = 0;
  138. unsigned int combined_hash;
  139. double score;
  140. double high_score = 0;
  141. if (n_carp_peers == 0)
  142. return NULL;
  143. /* calculate hash key */
  144. debugs(39, 2, "carpSelectParent: Calculating hash for " << urlCanonical(request));
  145. /* select peer */
  146. for (k = 0; k < n_carp_peers; k++) {
  147. String key;
  148. tp = carp_peers[k];
  149. if (tp->options.carp_key.set) {
  150. //this code follows urlCanonical's pattern.
  151. // corner cases should use the canonical URL
  152. if (tp->options.carp_key.scheme) {
  153. // temporary, until bug 1961 URL handling is fixed.
  154. const URLScheme sch = request->protocol;
  155. key.append(sch.const_str());
  156. if (key.size()) //if the scheme is not empty
  157. key.append("://");
  158. }
  159. if (tp->options.carp_key.host) {
  160. key.append(request->GetHost());
  161. }
  162. if (tp->options.carp_key.port) {
  163. static char portbuf[7];
  164. snprintf(portbuf,7,":%d", request->port);
  165. key.append(portbuf);
  166. }
  167. if (tp->options.carp_key.path) {
  168. String::size_type pos;
  169. if ((pos=request->urlpath.find('?'))!=String::npos)
  170. key.append(request->urlpath.substr(0,pos));
  171. else
  172. key.append(request->urlpath);
  173. }
  174. if (tp->options.carp_key.params) {
  175. String::size_type pos;
  176. if ((pos=request->urlpath.find('?'))!=String::npos)
  177. key.append(request->urlpath.substr(pos,request->urlpath.size()));
  178. }
  179. }
  180. // if the url-based key is empty, e.g. because the user is
  181. // asking to balance on the path but the request doesn't supply any,
  182. // then fall back to canonical URL
  183. if (key.size()==0)
  184. key=urlCanonical(request);
  185. for (const char *c = key.rawBuf(), *e=key.rawBuf()+key.size(); c < e; c++)
  186. user_hash += ROTATE_LEFT(user_hash, 19) + *c;
  187. combined_hash = (user_hash ^ tp->carp.hash);
  188. combined_hash += combined_hash * 0x62531965;
  189. combined_hash = ROTATE_LEFT(combined_hash, 21);
  190. score = combined_hash * tp->carp.load_multiplier;
  191. debugs(39, 3, "carpSelectParent: key=" << key << " name=" << tp->name << " combined_hash=" << combined_hash <<
  192. " score=" << std::setprecision(0) << score);
  193. if ((score > high_score) && peerHTTPOkay(tp, request)) {
  194. p = tp;
  195. high_score = score;
  196. }
  197. }
  198. if (p)
  199. debugs(39, 2, "carpSelectParent: selected " << p->name);
  200. return p;
  201. }
  202. static void
  203. carpCachemgr(StoreEntry * sentry)
  204. {
  205. peer *p;
  206. int sumfetches = 0;
  207. storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
  208. "Hostname",
  209. "Hash",
  210. "Multiplier",
  211. "Factor",
  212. "Actual");
  213. for (p = Config.peers; p; p = p->next)
  214. sumfetches += p->stats.fetches;
  215. for (p = Config.peers; p; p = p->next) {
  216. storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
  217. p->name, p->carp.hash,
  218. p->carp.load_multiplier,
  219. p->carp.load_factor,
  220. sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
  221. }
  222. }