]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/carp.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / carp.cc
index 4bcf8a9276caa01cb67e2b5cd028d7e9a8008cfc..65bec9db0551bb3737cf4fad9673f5ef5d3651a3 100644 (file)
@@ -1,31 +1,33 @@
+
 /*
- * $Id: carp.cc,v 1.5 1998/08/13 21:14:39 wessels Exp $
+ * $Id$
  *
  * DEBUG: section 39    Cache Array Routing Protocol
- * AUTHOR: Eric Stern
+ * AUTHOR: Henrik Nordstrom
+ * BASED ON: carp.c by Eric Stern and draft-vinod-carp-v1-03.txt
  *
- * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
  *
- *  Squid is the result of efforts by numerous individuals from the
- *  Internet community.  Development is led by Duane Wessels of the
- *  National Laboratory for Applied Network Research and funded by the
- *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
- *  Duane Wessels and the University of California San Diego.  Please
- *  see the COPYRIGHT file for full details.  Squid incorporates
- *  software developed and/or copyrighted by other sources.  Please see
- *  the CREDITS file for full details.
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
- *  
+ *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *  
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  */
 
 #include "squid.h"
+#include "CacheManager.h"
+#include "Store.h"
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+static int n_carp_peers = 0;
+static peer **carp_peers = NULL;
+static OBJH carpCachemgr;
+
+static int
+peerSortWeight(const void *a, const void *b)
+{
+    const peer *const *p1 = (const peer *const *)a;
+    const peer *const *p2 = (const peer *const *)b;
+    return (*p1)->weight - (*p2)->weight;
+}
 
-#if USE_CARP
+static void
+carpRegisterWithCacheManager(void)
+{
+    CacheManager::GetInstance()->
+    registerAction("carp", "CARP information", carpCachemgr, 0, 1);
+}
 
 void
 carpInit(void)
 {
-    /* calculate load factors */
-    int K = 0;
-    float a = 0.0;
-    float X;
-    float Xn;
-    float n;
+    int W = 0;
+    int K;
     int k;
+    double P_last, X_last, Xn;
     peer *p;
+    peer **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;
+
+    /* 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) {
-       a += p->carp.load_factor;
-       K++;
+        if (!p->options.carp)
+            continue;
+
+        assert(p->type == PEER_PARENT);
+
+        if (p->weight == 0)
+            continue;
+
+        n_carp_peers++;
+
+        W += p->weight;
+    }
+
+    if (n_carp_peers == 0)
+        return;
+
+    carp_peers = (peer **)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 this peers hash */
+        p->carp.hash = 0;
+
+        for (t = p->name; *t != 0; t++)
+            p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *t;
+
+        p->carp.hash += p->carp.hash * 0x62531965;
+
+        p->carp.hash = ROTATE_LEFT(p->carp.hash, 21);
+
+        /* and load factor */
+        p->carp.load_factor = ((double) p->weight) / (double) W;
+
+        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);
     }
-    if (a == 0.0)
-       /* CARP load factors not configured */
-       return;
-    /*
-     * sum of carp-load-factor's for all cache_peer's in squid.conf
-     * must equal 1.0
+
+    /* Sort our list on weight */
+    qsort(carp_peers, n_carp_peers, sizeof(*carp_peers), peerSortWeight);
+
+    /* Calculate the load factor multipliers X_k
+     *
+     * X_1 = pow ((K*p_1), (1/K))
+     * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
+     * X_k += pow ((X_{k-1}, {K-k+1})
+     * X_k = pow (X_k, {1/(K-k+1)})
+     * simplified to have X_1 part of the loop
      */
-    assert(a == 1.0);
-    k = 1;
-    n = 0;
-    Xn = 0;
-    for (p = Config.peers; p; p = p->next) {
-       X = pow(K * p->carp.load_factor, 1 / K);
-       if (Xn == 0)
-           Xn = X;
-       else
-           Xn *= X;
-       p->carp.load_multiplier = ((K - k + 1) * (p->carp.load_factor - n)) / Xn
-           ;
-       k++;
-       n = p->carp.load_factor;
+    K = n_carp_peers;
+
+    P_last = 0.0;              /* Empty P_0 */
+
+    Xn = 1.0;                  /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
+
+    X_last = 0.0;              /* Empty X_0, nullifies the first pow statement */
+
+    for (k = 1; k <= K; k++) {
+        double Kk1 = (double) (K - k + 1);
+        p = carp_peers[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);
+        Xn *= p->carp.load_multiplier;
+        X_last = p->carp.load_multiplier;
+        P_last = p->carp.load_factor;
     }
 }
 
 peer *
-carpSelectParent(request_t * request)
+carpSelectParent(HttpRequest * request)
 {
+    int k;
     const char *c;
     peer *p = NULL;
     peer *tp;
-    unsigned long url_hash = 0;
-    unsigned long combined_hash;
-    unsigned long high_score = 0;
-    const char *url = urlCanonical(request);
-    /* calculate url hash */
-    debug(39, 2) ("carpSelectParent: CARP Calculating hash for %s\n", url);
-    for (c = url; *c != 0; c++)
-       url_hash += (url_hash << 19) + *c;
+    unsigned int user_hash = 0;
+    unsigned int combined_hash;
+    double score;
+    double high_score = 0;
+    const char *key = NULL;
+
+    if (n_carp_peers == 0)
+        return NULL;
+
+    key = urlCanonical(request);
+
+    /* calculate hash key */
+    debugs(39, 2, "carpSelectParent: Calculating hash for " << key);
+
+    for (c = key; *c != 0; c++)
+        user_hash += ROTATE_LEFT(user_hash, 19) + *c;
+
     /* select peer */
-    for (tp = Config.peers; tp; tp = tp->next) {
-       if (p->carp.load_factor == 0.0)
-           continue;
-       assert(p->type == PEER_PARENT);
-       combined_hash = (url_hash ^ tp->carp.hash);
-       combined_hash += combined_hash * 0x62531965;
-       combined_hash = combined_hash << 21;
-       combined_hash = combined_hash * tp->carp.load_multiplier;
-       debug(39, 3) ("carpSelectParent: %s combined_hash %d\n",
-           tp->host, combined_hash);
-       if ((combined_hash > high_score) && neighborUp(tp)) {
-           p = tp;
-           high_score = combined_hash;
-       }
+    for (k = 0; k < n_carp_peers; k++) {
+        tp = carp_peers[k];
+        combined_hash = (user_hash ^ tp->carp.hash);
+        combined_hash += combined_hash * 0x62531965;
+        combined_hash = ROTATE_LEFT(combined_hash, 21);
+        score = combined_hash * tp->carp.load_multiplier;
+        debugs(39, 3, "carpSelectParent: " << tp->name << " combined_hash " << combined_hash  <<
+               " score " << std::setprecision(0) << score);
+
+        if ((score > high_score) && peerHTTPOkay(tp, request)) {
+            p = tp;
+            high_score = score;
+        }
     }
+
     if (p)
-       debug(39, 3) ("carpSelectParent: selected CARP %s\n", p->host);
+        debugs(39, 2, "carpSelectParent: selected " << p->name);
+
     return p;
 }
-#endif
+
+static void
+carpCachemgr(StoreEntry * sentry)
+{
+    peer *p;
+    int sumfetches = 0;
+    storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
+                      "Hostname",
+                      "Hash",
+                      "Multiplier",
+                      "Factor",
+                      "Actual");
+
+    for (p = Config.peers; p; p = p->next)
+        sumfetches += p->stats.fetches;
+
+    for (p = Config.peers; p; p = p->next) {
+        storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
+                          p->name, p->carp.hash,
+                          p->carp.load_multiplier,
+                          p->carp.load_factor,
+                          sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
+    }
+}