]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Add support for using custom keys in CARP parents
authorFrancesco Chemolli <kinkie@squid-cache.org>
Tue, 2 Aug 2011 05:15:45 +0000 (07:15 +0200)
committerFrancesco Chemolli <kinkie@squid-cache.org>
Tue, 2 Aug 2011 05:15:45 +0000 (07:15 +0200)
Add a new carp-key option to CARP parents, specifying what parts of an URL
to use in the parent selection algorithm.

src/cache_cf.cc
src/carp.cc
src/cf.data.pre
src/structs.h

index 130c2f188d764f0014d5f0404b556983a94402d0..ad87dff450f52b4a4468cfa404e5596f54c89948 100644 (file)
@@ -2244,6 +2244,28 @@ parse_peer(peer ** head)
                 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
 
             p->options.carp = 1;
+        } else if (!strncasecmp(token, "carp-key=", 9)) {
+            if (p->options.carp != 1)
+                fatalf("parse_peer: carp-key specified on non-carp peer %s/%d\n", p->host, p->http_port);
+            p->options.carp_key.set=1;
+            char *nextkey=token+strlen("carp-key="), *key=nextkey;
+            for (; key; key = nextkey) {
+               nextkey=strchr(key,',');
+               if (nextkey) ++nextkey; // skip the comma, any
+               if (0==strncasecmp(key,"scheme",6)) {
+                       p->options.carp_key.scheme=1;
+               } else if (0==strncasecmp(key,"host",4)) {
+                       p->options.carp_key.host=1;
+               } else if (0==strncasecmp(key,"port",4)) {
+                       p->options.carp_key.port=1;
+               } else if (0==strncasecmp(key,"path",4)) {
+                       p->options.carp_key.path=1;
+               } else if (0==strncasecmp(key,"params",6)) {
+                       p->options.carp_key.params=1;
+               } else {
+                       fatalf("invalid carp-key '%s'",key);
+               }
+            }
         } else if (!strcasecmp(token, "userhash")) {
 #if USE_AUTH
             if (p->type != PEER_PARENT)
index f5f6f3624a2e532c18fdb45d2ae46bf0c11c906c..de5ee22b782129145e16ea0349a603eb8c39cd1e 100644 (file)
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 #include "mgr/Registration.h"
 #include "Store.h"
+#include "URLScheme.h"
 
 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
 
@@ -164,35 +166,69 @@ peer *
 carpSelectParent(HttpRequest * request)
 {
     int k;
-    const char *c;
     peer *p = NULL;
     peer *tp;
     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;
+    debugs(39, 2, "carpSelectParent: Calculating hash for " << urlCanonical(request));
 
     /* select peer */
     for (k = 0; k < n_carp_peers; k++) {
+       String key;
         tp = carp_peers[k];
+        if (tp->options.carp_key.set) {
+            //this code follows urlCanonical's pattern.
+            //   corner cases should use the canonical URL
+            if (tp->options.carp_key.scheme) {
+                // temporary, until bug 1961 URL handling is fixed.
+                const URLScheme sch = request->protocol;
+                key.append(sch.const_str());
+                if (key.size()) //if the scheme is not empty
+                    key.append("://");
+            }
+            if (tp->options.carp_key.host) {
+                key.append(request->GetHost());
+            }
+            if (tp->options.carp_key.port) {
+                static char portbuf[7];
+                snprintf(portbuf,7,":%d", request->port);
+                key.append(portbuf);
+            }
+            if (tp->options.carp_key.path) {
+                String::size_type pos;
+                if ((pos=request->urlpath.find('?'))!=String::npos)
+                    key.append(request->urlpath.substr(0,pos));
+                else
+                    key.append(request->urlpath);
+            }
+            if (tp->options.carp_key.params) {
+                String::size_type pos;
+                if ((pos=request->urlpath.find('?'))!=String::npos)
+                    key.append(request->urlpath.substr(pos,request->urlpath.size()));
+            }
+       }
+        // if the url-based key is empty, e.g. because the user is
+        // asking to balance on the path but the request doesn't supply any,
+        // then fall back to canonical URL
+
+        if (key.size()==0)
+            key=urlCanonical(request);
+
+        for (const char *c = key.rawBuf(), *e=key.rawBuf()+key.size(); c < e; c++)
+            user_hash += ROTATE_LEFT(user_hash, 19) + *c;
         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);
+        debugs(39, 3, "carpSelectParent: key=" << key << " name=" << tp->name << " combined_hash=" << combined_hash  <<
+               " score=" << std::setprecision(0) << score);
 
         if ((score > high_score) && peerHTTPOkay(tp, request)) {
             p = tp;
index 7b550331379be7f9bf1ccc542ad381f8491c5cde..84e44a4052ccad2fe20c8dcf1bf14481f1df6954 100644 (file)
@@ -2168,6 +2168,14 @@ DOC_START
                        than the Squid default location.
        
        
+       ==== CARP OPTIONS ====
+       
+       carp-key=key-specification
+                       use a different key than the full URL to hash against the peer.
+                       the key-specification is a comma-separated list of the keywords                 
+                       scheme, host, port, path, params
+                       Order is not important.
+       
        ==== ACCELERATOR / REVERSE-PROXY OPTIONS ====
        
        originserver    Causes this parent to be contacted as an origin server.
index 4d1710c5e3b25288116e382eb205a762a89c9e5d..fe6c7ea01b57075d2a8f261d3b70f2e3f2705547 100644 (file)
@@ -855,6 +855,14 @@ struct peer {
 #endif
         unsigned int allow_miss:1;
         unsigned int carp:1;
+        struct {
+               unsigned int set:1; //If false, whole url is to be used. Overrides others
+               unsigned int scheme:1;
+               unsigned int host:1;
+               unsigned int port:1;
+               unsigned int path:1;
+               unsigned int params:1;
+        } carp_key;
 #if USE_AUTH
         unsigned int userhash:1;
 #endif