~ubuntu-branches/ubuntu/jaunty/squid3/jaunty

« back to all changes in this revision

Viewing changes to src/peer_sourcehash.cc

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2008-07-21 09:20:31 UTC
  • mfrom: (1.1.7 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080721092031-bj8vog645lw6487u
Tags: 3.0.STABLE8-1
* Urgency high to meet freeze deadline

* New upstream release

* debian/patches/10-mgr_active_requests
  - Added upstream patch fixing delay_pool reporting in cachemgr.cgi

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * $Id: carp.cc,v 1.27 2008/01/14 12:13:49 hno Exp $
 
4
 *
 
5
 * DEBUG: section 39    Peer source hash based selection
 
6
 * AUTHOR: Henrik Nordstrom
 
7
 * BASED ON: carp.cc
 
8
 *
 
9
 * SQUID Web Proxy Cache          http://www.squid-cache.org/
 
10
 * ----------------------------------------------------------
 
11
 *
 
12
 *  Squid is the result of efforts by numerous individuals from
 
13
 *  the Internet community; see the CONTRIBUTORS file for full
 
14
 *  details.   Many organizations have provided support for Squid's
 
15
 *  development; see the SPONSORS file for full details.  Squid is
 
16
 *  Copyrighted (C) 2001 by the Regents of the University of
 
17
 *  California; see the COPYRIGHT file for full details.  Squid
 
18
 *  incorporates software developed and/or copyrighted by other
 
19
 *  sources; see the CREDITS file for full details.
 
20
 *
 
21
 *  This program is free software; you can redistribute it and/or modify
 
22
 *  it under the terms of the GNU General Public License as published by
 
23
 *  the Free Software Foundation; either version 2 of the License, or
 
24
 *  (at your option) any later version.
 
25
 *  
 
26
 *  This program is distributed in the hope that it will be useful,
 
27
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
28
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
29
 *  GNU General Public License for more details.
 
30
 *  
 
31
 *  You should have received a copy of the GNU General Public License
 
32
 *  along with this program; if not, write to the Free Software
 
33
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 
34
 *
 
35
 */
 
36
 
 
37
#include "squid.h"
 
38
#include "CacheManager.h"
 
39
#include "Store.h"
 
40
#include "HttpRequest.h"
 
41
 
 
42
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
 
43
 
 
44
static int n_sourcehash_peers = 0;
 
45
static peer **sourcehash_peers = NULL;
 
46
static OBJH peerSourceHashCachemgr;
 
47
 
 
48
static int
 
49
peerSortWeight(const void *a, const void *b)
 
50
{
 
51
    const peer *const *p1 = (const peer *const *)a;
 
52
    const peer *const *p2 = (const peer *const *)b;
 
53
    return (*p1)->weight - (*p2)->weight;
 
54
}
 
55
 
 
56
void
 
57
peerSourceHashInit(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
 
 
68
    for (k = 0; k < n_sourcehash_peers; k++) {
 
69
        cbdataReferenceDone(sourcehash_peers[k]);
 
70
    }
 
71
 
 
72
    safe_free(sourcehash_peers);
 
73
    n_sourcehash_peers = 0;
 
74
    /* find out which peers we have */
 
75
 
 
76
    for (p = Config.peers; p; p = p->next) {
 
77
        if (!p->options.sourcehash)
 
78
            continue;
 
79
 
 
80
        assert(p->type == PEER_PARENT);
 
81
 
 
82
        if (p->weight == 0)
 
83
            continue;
 
84
 
 
85
        n_sourcehash_peers++;
 
86
 
 
87
        W += p->weight;
 
88
    }
 
89
 
 
90
    if (n_sourcehash_peers == 0)
 
91
        return;
 
92
 
 
93
    sourcehash_peers = (peer **)xcalloc(n_sourcehash_peers, sizeof(*sourcehash_peers));
 
94
 
 
95
    /* Build a list of the found peers and calculate hashes and load factors */
 
96
    for (P = sourcehash_peers, p = Config.peers; p; p = p->next) {
 
97
        if (!p->options.sourcehash)
 
98
            continue;
 
99
 
 
100
        if (p->weight == 0)
 
101
            continue;
 
102
 
 
103
        /* calculate this peers hash */
 
104
        p->sourcehash.hash = 0;
 
105
 
 
106
        for (t = p->name; *t != 0; t++)
 
107
            p->sourcehash.hash += ROTATE_LEFT(p->sourcehash.hash, 19) + (unsigned int) *t;
 
108
 
 
109
        p->sourcehash.hash += p->sourcehash.hash * 0x62531965;
 
110
 
 
111
        p->sourcehash.hash = ROTATE_LEFT(p->sourcehash.hash, 21);
 
112
 
 
113
        /* and load factor */
 
114
        p->sourcehash.load_factor = ((double) p->weight) / (double) W;
 
115
 
 
116
        if (floor(p->sourcehash.load_factor * 1000.0) == 0.0)
 
117
            p->sourcehash.load_factor = 0.0;
 
118
 
 
119
        /* add it to our list of peers */
 
120
        *P++ = cbdataReference(p);
 
121
    }
 
122
 
 
123
    /* Sort our list on weight */
 
124
    qsort(sourcehash_peers, n_sourcehash_peers, sizeof(*sourcehash_peers), peerSortWeight);
 
125
 
 
126
    /* Calculate the load factor multipliers X_k
 
127
     *
 
128
     * X_1 = pow ((K*p_1), (1/K))
 
129
     * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1})
 
130
     * X_k += pow ((X_{k-1}, {K-k+1})
 
131
     * X_k = pow (X_k, {1/(K-k+1)})
 
132
     * simplified to have X_1 part of the loop
 
133
     */
 
134
    K = n_sourcehash_peers;
 
135
 
 
136
    P_last = 0.0;               /* Empty P_0 */
 
137
 
 
138
    Xn = 1.0;                   /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */
 
139
 
 
140
    X_last = 0.0;               /* Empty X_0, nullifies the first pow statement */
 
141
 
 
142
    for (k = 1; k <= K; k++) {
 
143
        double Kk1 = (double) (K - k + 1);
 
144
        p = sourcehash_peers[k - 1];
 
145
        p->sourcehash.load_multiplier = (Kk1 * (p->sourcehash.load_factor - P_last)) / Xn;
 
146
        p->sourcehash.load_multiplier += pow(X_last, Kk1);
 
147
        p->sourcehash.load_multiplier = pow(p->sourcehash.load_multiplier, 1.0 / Kk1);
 
148
        Xn *= p->sourcehash.load_multiplier;
 
149
        X_last = p->sourcehash.load_multiplier;
 
150
        P_last = p->sourcehash.load_factor;
 
151
    }
 
152
}
 
153
 
 
154
void
 
155
peerSourceHashRegisterWithCacheManager(CacheManager & manager)
 
156
{
 
157
    manager.registerAction("sourcehash", "peer sourcehash information", peerSourceHashCachemgr, 0, 1);
 
158
}
 
159
 
 
160
peer *
 
161
peerSourceHashSelectParent(HttpRequest * request)
 
162
{
 
163
    int k;
 
164
    const char *c;
 
165
    peer *p = NULL;
 
166
    peer *tp;
 
167
    unsigned int user_hash = 0;
 
168
    unsigned int combined_hash;
 
169
    double score;
 
170
    double high_score = 0;
 
171
    const char *key = NULL;
 
172
 
 
173
    if (n_sourcehash_peers == 0)
 
174
        return NULL;
 
175
 
 
176
    key = inet_ntoa(request->client_addr);
 
177
 
 
178
    /* calculate hash key */
 
179
    debugs(39, 2, "peerSourceHashSelectParent: Calculating hash for " << key);
 
180
 
 
181
    for (c = key; *c != 0; c++)
 
182
        user_hash += ROTATE_LEFT(user_hash, 19) + *c;
 
183
 
 
184
    /* select peer */
 
185
    for (k = 0; k < n_sourcehash_peers; k++) {
 
186
        tp = sourcehash_peers[k];
 
187
        combined_hash = (user_hash ^ tp->sourcehash.hash);
 
188
        combined_hash += combined_hash * 0x62531965;
 
189
        combined_hash = ROTATE_LEFT(combined_hash, 21);
 
190
        score = combined_hash * tp->sourcehash.load_multiplier;
 
191
        debugs(39, 3, "peerSourceHashSelectParent: " << tp->name << " combined_hash " << combined_hash  << 
 
192
               " score " << std::setprecision(0) << score);
 
193
 
 
194
        if ((score > high_score) && peerHTTPOkay(tp, request)) {
 
195
            p = tp;
 
196
            high_score = score;
 
197
        }
 
198
    }
 
199
 
 
200
    if (p)
 
201
        debugs(39, 2, "peerSourceHashSelectParent: selected " << p->name);
 
202
 
 
203
    return p;
 
204
}
 
205
 
 
206
static void
 
207
peerSourceHashCachemgr(StoreEntry * sentry)
 
208
{
 
209
    peer *p;
 
210
    int sumfetches = 0;
 
211
    storeAppendPrintf(sentry, "%24s %10s %10s %10s %10s\n",
 
212
                      "Hostname",
 
213
                      "Hash",
 
214
                      "Multiplier",
 
215
                      "Factor",
 
216
                      "Actual");
 
217
 
 
218
    for (p = Config.peers; p; p = p->next)
 
219
        sumfetches += p->stats.fetches;
 
220
 
 
221
    for (p = Config.peers; p; p = p->next) {
 
222
        storeAppendPrintf(sentry, "%24s %10x %10f %10f %10f\n",
 
223
                          p->name, p->sourcehash.hash,
 
224
                          p->sourcehash.load_multiplier,
 
225
                          p->sourcehash.load_factor,
 
226
                          sumfetches ? (double) p->stats.fetches / sumfetches : -1.0);
 
227
    }
 
228
}