]>
Commit | Line | Data |
---|---|---|
e4e6a8db | 1 | |
2 | /* | |
4a7a3d56 | 3 | * $Id: refresh.cc,v 1.75 2007/04/30 16:56:09 wessels Exp $ |
e4e6a8db | 4 | * |
5 | * DEBUG: section 22 Refresh Calculation | |
6 | * AUTHOR: Harvest Derived | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
e4e6a8db | 10 | * |
2b6662ba | 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. | |
e4e6a8db | 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 | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
e4e6a8db | 34 | */ |
35 | ||
36 | #ifndef USE_POSIX_REGEX | |
37 | #define USE_POSIX_REGEX /* put before includes; always use POSIX */ | |
38 | #endif | |
39 | ||
40 | #include "squid.h" | |
62ee09ca | 41 | #include "CacheManager.h" |
e6ccf245 | 42 | #include "Store.h" |
528b2c61 | 43 | #include "MemObject.h" |
a2ac85d9 | 44 | #include "HttpRequest.h" |
924f73bc | 45 | #include "HttpReply.h" |
985c86bc | 46 | #include "SquidTime.h" |
e4e6a8db | 47 | |
7d47d8e6 | 48 | typedef enum { |
65fa5c61 | 49 | rcHTTP, |
50 | rcICP, | |
51 | #if USE_HTCP | |
52 | rcHTCP, | |
53 | #endif | |
54 | #if USE_CACHE_DIGESTS | |
55 | rcCDigest, | |
56 | #endif | |
57 | rcStore, | |
58 | rcCount | |
7d47d8e6 | 59 | } refreshCountsEnum; |
829a9357 | 60 | |
62e76326 | 61 | typedef struct |
62 | { | |
1f848b2c | 63 | bool expires; |
64 | bool min; | |
65 | bool lmfactor; | |
66 | bool max; | |
62e76326 | 67 | } |
68 | ||
69 | stale_flags; | |
65fa5c61 | 70 | |
71 | /* | |
72 | * This enumerated list assigns specific values, ala HTTP/FTP status | |
73 | * codes. All Fresh codes are in the range 100-199 and all stale | |
74 | * codes are 200-299. We might want to use these codes in logging, | |
75 | * so best to keep them consistent over time. | |
76 | */ | |
77 | enum { | |
78 | FRESH_REQUEST_MAX_STALE_ALL = 100, | |
79 | FRESH_REQUEST_MAX_STALE_VALUE, | |
80 | FRESH_EXPIRES, | |
81 | FRESH_LMFACTOR_RULE, | |
82 | FRESH_MIN_RULE, | |
83 | FRESH_OVERRIDE_EXPIRES, | |
84 | FRESH_OVERRIDE_LASTMOD, | |
85 | STALE_MUST_REVALIDATE = 200, | |
86 | STALE_RELOAD_INTO_IMS, | |
87 | STALE_FORCED_RELOAD, | |
88 | STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE, | |
89 | STALE_EXPIRES, | |
90 | STALE_MAX_RULE, | |
91 | STALE_LMFACTOR_RULE, | |
92 | STALE_DEFAULT = 299 | |
93 | }; | |
94 | ||
62e76326 | 95 | static struct RefreshCounts |
96 | { | |
829a9357 | 97 | const char *proto; |
1c3e77cd | 98 | int total; |
65fa5c61 | 99 | int status[STALE_DEFAULT + 1]; |
62e76326 | 100 | } |
101 | ||
102 | refreshCounts[rcCount]; | |
1c3e77cd | 103 | |
e4e6a8db | 104 | /* |
105 | * Defaults: | |
106 | * MIN NONE | |
107 | * PCT 20% | |
108 | * MAX 3 days | |
109 | */ | |
48f44632 | 110 | #define REFRESH_DEFAULT_MIN (time_t)0 |
c3f6d204 | 111 | #define REFRESH_DEFAULT_PCT 0.20 |
48f44632 | 112 | #define REFRESH_DEFAULT_MAX (time_t)259200 |
e4e6a8db | 113 | |
2b5133db | 114 | static const refresh_t *refreshUncompiledPattern(const char *); |
1c3e77cd | 115 | static OBJH refreshStats; |
65fa5c61 | 116 | static int refreshStaleness(const StoreEntry *, time_t, time_t, const refresh_t *, stale_flags *); |
117 | ||
118 | static refresh_t DefaultRefresh; | |
2b5133db | 119 | |
38f9c547 | 120 | const refresh_t * |
6018f0de | 121 | refreshLimits(const char *url) |
122 | { | |
123 | const refresh_t *R; | |
62e76326 | 124 | |
6018f0de | 125 | for (R = Config.Refresh; R; R = R->next) { |
62e76326 | 126 | if (!regexec(&(R->compiled_pattern), url, 0, 0, 0)) |
127 | return R; | |
6018f0de | 128 | } |
62e76326 | 129 | |
6018f0de | 130 | return NULL; |
131 | } | |
132 | ||
2b5133db | 133 | static const refresh_t * |
134 | refreshUncompiledPattern(const char *pat) | |
135 | { | |
136 | const refresh_t *R; | |
62e76326 | 137 | |
2b5133db | 138 | for (R = Config.Refresh; R; R = R->next) { |
62e76326 | 139 | if (0 == strcmp(R->pattern, pat)) |
140 | return R; | |
2b5133db | 141 | } |
62e76326 | 142 | |
2b5133db | 143 | return NULL; |
144 | } | |
145 | ||
65fa5c61 | 146 | /* |
147 | * Calculate how stale the response is (or will be at the check_time). | |
148 | * Staleness calculation is based on the following: (1) response | |
149 | * expiration time, (2) age greater than configured maximum, (3) | |
150 | * last-modified factor, and (4) age less than configured minimum. | |
151 | * | |
152 | * If the response is fresh, return -1. Otherwise return its | |
153 | * staleness. NOTE return value of 0 means the response is stale. | |
154 | * | |
155 | * The 'stale_flags' structure is used to tell the calling function | |
156 | * _why_ this response is fresh or stale. Its used, for example, | |
157 | * when the admin wants to override expiration and last-modified | |
158 | * times. | |
159 | */ | |
160 | static int | |
161 | refreshStaleness(const StoreEntry * entry, time_t check_time, time_t age, const refresh_t * R, stale_flags * sf) | |
162 | { | |
163 | /* | |
164 | * Check for an explicit expiration time. | |
165 | */ | |
62e76326 | 166 | |
65fa5c61 | 167 | if (entry->expires > -1) { |
1f848b2c | 168 | sf->expires = true; |
62e76326 | 169 | |
170 | if (entry->expires > check_time) { | |
4a7a3d56 | 171 | debugs(22, 3, "FRESH: expires " << entry->expires << |
172 | " >= check_time " << check_time << " "); | |
bf8fe701 | 173 | |
62e76326 | 174 | return -1; |
175 | } else { | |
4a7a3d56 | 176 | debugs(22, 3, "STALE: expires " << entry->expires << |
177 | " < check_time " << check_time << " "); | |
bf8fe701 | 178 | |
62e76326 | 179 | return (check_time - entry->expires); |
180 | } | |
65fa5c61 | 181 | } |
62e76326 | 182 | |
65fa5c61 | 183 | assert(age >= 0); |
184 | /* | |
185 | * Use local heuristics to determine staleness. Start with the | |
186 | * max age from the refresh_pattern rule. | |
187 | */ | |
62e76326 | 188 | |
65fa5c61 | 189 | if (age > R->max) { |
4a7a3d56 | 190 | debugs(22, 3, "STALE: age " << age << " > max " << R->max << " "); |
1f848b2c | 191 | sf->max = true; |
62e76326 | 192 | return (age - R->max); |
65fa5c61 | 193 | } |
62e76326 | 194 | |
65fa5c61 | 195 | /* |
196 | * Try the last-modified factor algorithm. | |
197 | */ | |
198 | if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) { | |
62e76326 | 199 | /* |
200 | * stale_age is the Age of the response when it became/becomes | |
201 | * stale according to the last-modified factor algorithm. | |
202 | */ | |
203 | time_t stale_age = static_cast<time_t>((entry->timestamp - entry->lastmod) * R->pct); | |
1f848b2c | 204 | sf->lmfactor = true; |
62e76326 | 205 | |
206 | if (age >= stale_age) { | |
4a7a3d56 | 207 | debugs(22, 3, "STALE: age " << age << " > stale_age " << stale_age); |
62e76326 | 208 | return (age - stale_age); |
209 | } else { | |
4a7a3d56 | 210 | debugs(22, 3, "FRESH: age " << age << " <= stale_age " << stale_age); |
62e76326 | 211 | return -1; |
212 | } | |
65fa5c61 | 213 | } |
62e76326 | 214 | |
65fa5c61 | 215 | /* |
216 | * If we are here, staleness is determined by the refresh_pattern | |
217 | * configured minimum age. | |
218 | */ | |
219 | if (age <= R->min) { | |
4a7a3d56 | 220 | debugs(22, 3, "FRESH: age " << age << " <= min " << R->min); |
1f848b2c | 221 | sf->min = true; |
62e76326 | 222 | return -1; |
65fa5c61 | 223 | } |
62e76326 | 224 | |
4a7a3d56 | 225 | debugs(22, 3, "STALE: age " << age << " > min " << R->min); |
65fa5c61 | 226 | return (age - R->min); |
227 | } | |
228 | ||
829a9357 | 229 | /* return 1 if the entry must be revalidated within delta seconds |
230 | * 0 otherwise | |
231 | * | |
232 | * note: request maybe null (e.g. for cache digests build) | |
e4e6a8db | 233 | */ |
829a9357 | 234 | static int |
190154cf | 235 | refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta) |
e4e6a8db | 236 | { |
6018f0de | 237 | const refresh_t *R; |
829a9357 | 238 | const char *uri = NULL; |
65fa5c61 | 239 | time_t age = 0; |
a207429f | 240 | time_t check_time = squid_curtime + delta; |
65fa5c61 | 241 | int staleness; |
242 | stale_flags sf; | |
62e76326 | 243 | |
9b5d1d21 | 244 | if (entry->mem_obj) |
62e76326 | 245 | uri = entry->mem_obj->url; |
7d47d8e6 | 246 | else if (request) |
62e76326 | 247 | uri = urlCanonical(request); |
7d47d8e6 | 248 | |
bf8fe701 | 249 | debugs(22, 3, "refreshCheck: '" << (uri ? uri : "<none>") << "'"); |
65fa5c61 | 250 | |
251 | if (check_time > entry->timestamp) | |
62e76326 | 252 | age = check_time - entry->timestamp; |
253 | ||
65fa5c61 | 254 | R = uri ? refreshLimits(uri) : refreshUncompiledPattern("."); |
62e76326 | 255 | |
65fa5c61 | 256 | if (NULL == R) |
62e76326 | 257 | R = &DefaultRefresh; |
258 | ||
65fa5c61 | 259 | memset(&sf, '\0', sizeof(sf)); |
62e76326 | 260 | |
65fa5c61 | 261 | staleness = refreshStaleness(entry, check_time, age, R, &sf); |
62e76326 | 262 | |
bf8fe701 | 263 | debugs(22, 3, "Staleness = " << staleness); |
264 | ||
265 | debugs(22, 3, "refreshCheck: Matched '" << R->pattern << " " << | |
266 | (int) R->min << " " << (int) (100.0 * R->pct) << "%% " << | |
267 | (int) R->max << "'"); | |
65fa5c61 | 268 | |
62e76326 | 269 | |
4a7a3d56 | 270 | debugs(22, 3, "refreshCheck: age = " << age); |
62e76326 | 271 | |
bf8fe701 | 272 | debugs(22, 3, "\tcheck_time:\t" << mkrfc1123(check_time)); |
62e76326 | 273 | |
bf8fe701 | 274 | debugs(22, 3, "\tentry->timestamp:\t" << mkrfc1123(entry->timestamp)); |
65fa5c61 | 275 | |
276 | if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1) { | |
bf8fe701 | 277 | debugs(22, 3, "refreshCheck: YES: Must revalidate stale response"); |
62e76326 | 278 | return STALE_MUST_REVALIDATE; |
65fa5c61 | 279 | } |
62e76326 | 280 | |
829a9357 | 281 | /* request-specific checks */ |
282 | if (request) { | |
62e76326 | 283 | HttpHdrCc *cc = request->cache_control; |
4c3ef9b2 | 284 | |
285 | if (request->flags.ims && (R->flags.refresh_ims || Config.onoff.refresh_all_ims)) { | |
286 | /* The clients no-cache header is changed into a IMS query */ | |
bf8fe701 | 287 | debugs(22, 3, "refreshCheck: YES: refresh-ims"); |
4c3ef9b2 | 288 | return STALE_FORCED_RELOAD; |
289 | } | |
290 | ||
9f60cfdf | 291 | #if HTTP_VIOLATIONS |
62e76326 | 292 | |
293 | if (!request->flags.nocache_hack) { | |
294 | (void) 0; | |
295 | } else if (R->flags.ignore_reload) { | |
296 | /* The clients no-cache header is ignored */ | |
bf8fe701 | 297 | debugs(22, 3, "refreshCheck: MAYBE: ignore-reload"); |
62e76326 | 298 | } else if (R->flags.reload_into_ims || Config.onoff.reload_into_ims) { |
299 | /* The clients no-cache header is changed into a IMS query */ | |
bf8fe701 | 300 | debugs(22, 3, "refreshCheck: YES: reload-into-ims"); |
62e76326 | 301 | return STALE_RELOAD_INTO_IMS; |
302 | } else { | |
303 | /* The clients no-cache header is not overridden on this request */ | |
bf8fe701 | 304 | debugs(22, 3, "refreshCheck: YES: client reload"); |
62e76326 | 305 | request->flags.nocache = 1; |
306 | return STALE_FORCED_RELOAD; | |
307 | } | |
308 | ||
9f60cfdf | 309 | #endif |
62e76326 | 310 | if (NULL != cc) { |
311 | if (cc->max_age > -1) { | |
085008f9 | 312 | #if HTTP_VIOLATIONS |
62e76326 | 313 | if (R->flags.ignore_reload && cc->max_age == 0) {} else |
528b2c61 | 314 | #endif |
62e76326 | 315 | { |
528b2c61 | 316 | #if 0 |
62e76326 | 317 | |
318 | if (cc->max_age == 0) { | |
bf8fe701 | 319 | debugs(22, 3, "refreshCheck: YES: client-max-age = 0"); |
62e76326 | 320 | return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; |
321 | } | |
322 | ||
085008f9 | 323 | #endif |
62e76326 | 324 | if (age > cc->max_age) { |
bf8fe701 | 325 | debugs(22, 3, "refreshCheck: YES: age > client-max-age"); |
62e76326 | 326 | return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; |
327 | } | |
328 | } | |
329 | } | |
330 | ||
331 | if (EBIT_TEST(cc->mask, CC_MAX_STALE) && staleness > -1) { | |
332 | if (cc->max_stale < 0) { | |
333 | /* max-stale directive without a value */ | |
bf8fe701 | 334 | debugs(22, 3, "refreshCheck: NO: max-stale wildcard"); |
62e76326 | 335 | return FRESH_REQUEST_MAX_STALE_ALL; |
336 | } else if (staleness < cc->max_stale) { | |
bf8fe701 | 337 | debugs(22, 3, "refreshCheck: NO: staleness < max-stale"); |
62e76326 | 338 | return FRESH_REQUEST_MAX_STALE_VALUE; |
339 | } | |
340 | } | |
341 | } | |
48f44632 | 342 | } |
62e76326 | 343 | |
65fa5c61 | 344 | if (-1 == staleness) { |
bf8fe701 | 345 | debugs(22, 3, "refreshCheck: object isn't stale.."); |
ed1de692 | 346 | if (sf.expires) { |
bf8fe701 | 347 | debugs(22, 3, "refreshCheck: returning FRESH_EXPIRES"); |
62e76326 | 348 | return FRESH_EXPIRES; |
ed1de692 | 349 | } |
62e76326 | 350 | |
351 | assert(!sf.max); | |
352 | ||
ed1de692 | 353 | if (sf.lmfactor) { |
bf8fe701 | 354 | debugs(22, 3, "refreshCheck: returning FRESH_LMFACTOR_RULE"); |
62e76326 | 355 | return FRESH_LMFACTOR_RULE; |
ed1de692 | 356 | } |
62e76326 | 357 | |
358 | assert(sf.min); | |
359 | ||
bf8fe701 | 360 | debugs(22, 3, "refreshCheck: returning FRESH_MIN_RULE"); |
62e76326 | 361 | return FRESH_MIN_RULE; |
1dfa1d81 | 362 | } |
62e76326 | 363 | |
65fa5c61 | 364 | /* |
365 | * At this point the response is stale, unless one of | |
542c4d60 | 366 | * the override options kicks in. |
65fa5c61 | 367 | */ |
368 | if (sf.expires) { | |
369 | #if HTTP_VIOLATIONS | |
62e76326 | 370 | |
371 | if (R->flags.override_expire && age < R->min) { | |
bf8fe701 | 372 | debugs(22, 3, "refreshCheck: NO: age < min && override-expire"); |
62e76326 | 373 | return FRESH_OVERRIDE_EXPIRES; |
374 | } | |
375 | ||
65fa5c61 | 376 | #endif |
62e76326 | 377 | return STALE_EXPIRES; |
e4e6a8db | 378 | } |
62e76326 | 379 | |
65fa5c61 | 380 | if (sf.max) |
62e76326 | 381 | return STALE_MAX_RULE; |
382 | ||
65fa5c61 | 383 | if (sf.lmfactor) { |
9f60cfdf | 384 | #if HTTP_VIOLATIONS |
62e76326 | 385 | |
386 | if (R->flags.override_lastmod && age < R->min) { | |
bf8fe701 | 387 | debugs(22, 3, "refreshCheck: NO: age < min && override-lastmod"); |
62e76326 | 388 | return FRESH_OVERRIDE_LASTMOD; |
389 | } | |
390 | ||
65fa5c61 | 391 | #endif |
62e76326 | 392 | return STALE_LMFACTOR_RULE; |
e4e6a8db | 393 | } |
62e76326 | 394 | |
bf8fe701 | 395 | debugs(22, 3, "refreshCheck: returning STALE_DEFAULT"); |
65fa5c61 | 396 | return STALE_DEFAULT; |
e4e6a8db | 397 | } |
48f44632 | 398 | |
cfa9f1cb | 399 | int |
400 | refreshIsCachable(const StoreEntry * entry) | |
401 | { | |
402 | /* | |
403 | * Don't look at the request to avoid no-cache and other nuisances. | |
404 | * the object should have a mem_obj so the URL will be found there. | |
6a2f3fcf | 405 | * minimum_expiry_time seconds delta (defaults to 60 seconds), to |
406 | * avoid objects which expire almost immediately, and which can't | |
407 | * be refreshed. | |
cfa9f1cb | 408 | */ |
6a2f3fcf | 409 | int reason = refreshCheck(entry, NULL, Config.minimum_expiry_time); |
65fa5c61 | 410 | refreshCounts[rcStore].total++; |
411 | refreshCounts[rcStore].status[reason]++; | |
62e76326 | 412 | |
451c8350 | 413 | if (reason < STALE_MUST_REVALIDATE) |
62e76326 | 414 | /* Does not need refresh. This is certainly cachable */ |
415 | return 1; | |
416 | ||
cfa9f1cb | 417 | if (entry->lastmod < 0) |
62e76326 | 418 | /* Last modified is needed to do a refresh */ |
419 | return 0; | |
420 | ||
cfa9f1cb | 421 | if (entry->mem_obj == NULL) |
62e76326 | 422 | /* no mem_obj? */ |
423 | return 1; | |
424 | ||
528b2c61 | 425 | if (entry->getReply() == NULL) |
62e76326 | 426 | /* no reply? */ |
427 | return 1; | |
428 | ||
528b2c61 | 429 | if (entry->getReply()->content_length == 0) |
62e76326 | 430 | /* No use refreshing (caching?) 0 byte objects */ |
431 | return 0; | |
432 | ||
cfa9f1cb | 433 | /* This seems to be refreshable. Cache it */ |
434 | return 1; | |
435 | } | |
436 | ||
829a9357 | 437 | /* refreshCheck... functions below are protocol-specific wrappers around |
438 | * refreshCheck() function above */ | |
439 | ||
440 | int | |
190154cf | 441 | refreshCheckHTTP(const StoreEntry * entry, HttpRequest * request) |
7d47d8e6 | 442 | { |
65fa5c61 | 443 | int reason = refreshCheck(entry, request, 0); |
444 | refreshCounts[rcHTTP].total++; | |
445 | refreshCounts[rcHTTP].status[reason]++; | |
446 | return (reason < 200) ? 0 : 1; | |
829a9357 | 447 | } |
448 | ||
449 | int | |
190154cf | 450 | refreshCheckICP(const StoreEntry * entry, HttpRequest * request) |
7d47d8e6 | 451 | { |
65fa5c61 | 452 | int reason = refreshCheck(entry, request, 30); |
453 | refreshCounts[rcICP].total++; | |
454 | refreshCounts[rcICP].status[reason]++; | |
455 | return (reason < 200) ? 0 : 1; | |
829a9357 | 456 | } |
457 | ||
65fa5c61 | 458 | #if USE_HTCP |
32b3cf93 | 459 | int |
190154cf | 460 | refreshCheckHTCP(const StoreEntry * entry, HttpRequest * request) |
32b3cf93 | 461 | { |
65fa5c61 | 462 | int reason = refreshCheck(entry, request, 10); |
463 | refreshCounts[rcHTCP].total++; | |
464 | refreshCounts[rcHTCP].status[reason]++; | |
465 | return (reason < 200) ? 0 : 1; | |
32b3cf93 | 466 | } |
62e76326 | 467 | |
65fa5c61 | 468 | #endif |
32b3cf93 | 469 | |
65fa5c61 | 470 | #if USE_CACHE_DIGESTS |
829a9357 | 471 | int |
7d47d8e6 | 472 | refreshCheckDigest(const StoreEntry * entry, time_t delta) |
473 | { | |
65fa5c61 | 474 | int reason = refreshCheck(entry, |
62e76326 | 475 | entry->mem_obj ? entry->mem_obj->request : NULL, |
476 | delta); | |
65fa5c61 | 477 | refreshCounts[rcCDigest].total++; |
478 | refreshCounts[rcCDigest].status[reason]++; | |
479 | return (reason < 200) ? 0 : 1; | |
6018f0de | 480 | } |
62e76326 | 481 | |
65fa5c61 | 482 | #endif |
6018f0de | 483 | |
48f44632 | 484 | time_t |
485 | getMaxAge(const char *url) | |
486 | { | |
6018f0de | 487 | const refresh_t *R; |
bf8fe701 | 488 | debugs(22, 3, "getMaxAge: '" << url << "'"); |
62e76326 | 489 | |
6018f0de | 490 | if ((R = refreshLimits(url))) |
62e76326 | 491 | return R->max; |
6018f0de | 492 | else |
62e76326 | 493 | return REFRESH_DEFAULT_MAX; |
48f44632 | 494 | } |
1c3e77cd | 495 | |
829a9357 | 496 | static void |
62e76326 | 497 | |
829a9357 | 498 | refreshCountsStats(StoreEntry * sentry, struct RefreshCounts *rc) |
499 | { | |
cc7cfa8e | 500 | int sum = 0; |
501 | int tot = rc->total; | |
502 | ||
829a9357 | 503 | storeAppendPrintf(sentry, "\n\n%s histogram:\n", rc->proto); |
65fa5c61 | 504 | storeAppendPrintf(sentry, "Count\t%%Total\tCategory\n"); |
829a9357 | 505 | |
65fa5c61 | 506 | #define refreshCountsStatsEntry(code,desc) { \ |
507 | storeAppendPrintf(sentry, "%6d\t%6.2f\t%s\n", \ | |
508 | rc->status[code], xpercent(rc->status[code], tot), desc); \ | |
509 | sum += rc->status[code]; \ | |
cc7cfa8e | 510 | } |
65fa5c61 | 511 | |
512 | refreshCountsStatsEntry(FRESH_REQUEST_MAX_STALE_ALL, | |
62e76326 | 513 | "Fresh: request max-stale wildcard"); |
65fa5c61 | 514 | refreshCountsStatsEntry(FRESH_REQUEST_MAX_STALE_VALUE, |
62e76326 | 515 | "Fresh: request max-stale value"); |
65fa5c61 | 516 | refreshCountsStatsEntry(FRESH_EXPIRES, |
62e76326 | 517 | "Fresh: expires time not reached"); |
65fa5c61 | 518 | refreshCountsStatsEntry(FRESH_LMFACTOR_RULE, |
62e76326 | 519 | "Fresh: refresh_pattern last-mod factor percentage"); |
65fa5c61 | 520 | refreshCountsStatsEntry(FRESH_MIN_RULE, |
62e76326 | 521 | "Fresh: refresh_pattern min value"); |
65fa5c61 | 522 | refreshCountsStatsEntry(FRESH_OVERRIDE_EXPIRES, |
62e76326 | 523 | "Fresh: refresh_pattern override expires"); |
65fa5c61 | 524 | refreshCountsStatsEntry(FRESH_OVERRIDE_LASTMOD, |
62e76326 | 525 | "Fresh: refresh_pattern override lastmod"); |
65fa5c61 | 526 | refreshCountsStatsEntry(STALE_MUST_REVALIDATE, |
62e76326 | 527 | "Stale: response has must-revalidate"); |
65fa5c61 | 528 | refreshCountsStatsEntry(STALE_RELOAD_INTO_IMS, |
62e76326 | 529 | "Stale: changed reload into IMS"); |
65fa5c61 | 530 | refreshCountsStatsEntry(STALE_FORCED_RELOAD, |
62e76326 | 531 | "Stale: request has no-cache directive"); |
65fa5c61 | 532 | refreshCountsStatsEntry(STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE, |
62e76326 | 533 | "Stale: age exceeds request max-age value"); |
65fa5c61 | 534 | refreshCountsStatsEntry(STALE_EXPIRES, |
62e76326 | 535 | "Stale: expires time reached"); |
65fa5c61 | 536 | refreshCountsStatsEntry(STALE_MAX_RULE, |
62e76326 | 537 | "Stale: refresh_pattern max age rule"); |
65fa5c61 | 538 | refreshCountsStatsEntry(STALE_LMFACTOR_RULE, |
62e76326 | 539 | "Stale: refresh_pattern last-mod factor percentage"); |
65fa5c61 | 540 | refreshCountsStatsEntry(STALE_DEFAULT, |
62e76326 | 541 | "Stale: by default"); |
65fa5c61 | 542 | |
7d47d8e6 | 543 | tot = sum; /* paranoid: "total" line shows 100% if we forgot nothing */ |
65fa5c61 | 544 | storeAppendPrintf(sentry, "%6d\t%6.2f\tTOTAL\n", |
62e76326 | 545 | rc->total, xpercent(rc->total, tot)); |
65fa5c61 | 546 | \ |
62e76326 | 547 | storeAppendPrintf(sentry, "\n"); |
829a9357 | 548 | } |
549 | ||
1c3e77cd | 550 | static void |
551 | refreshStats(StoreEntry * sentry) | |
552 | { | |
829a9357 | 553 | int i; |
554 | int total = 0; | |
555 | ||
556 | /* get total usage count */ | |
62e76326 | 557 | |
829a9357 | 558 | for (i = 0; i < rcCount; ++i) |
62e76326 | 559 | total += refreshCounts[i].total; |
829a9357 | 560 | |
561 | /* protocol usage histogram */ | |
562 | storeAppendPrintf(sentry, "\nRefreshCheck calls per protocol\n\n"); | |
62e76326 | 563 | |
829a9357 | 564 | storeAppendPrintf(sentry, "Protocol\t#Calls\t%%Calls\n"); |
62e76326 | 565 | |
829a9357 | 566 | for (i = 0; i < rcCount; ++i) |
62e76326 | 567 | storeAppendPrintf(sentry, "%10s\t%6d\t%6.2f\n", |
568 | refreshCounts[i].proto, | |
569 | refreshCounts[i].total, | |
570 | xpercent(refreshCounts[i].total, total)); | |
829a9357 | 571 | |
572 | /* per protocol histograms */ | |
573 | storeAppendPrintf(sentry, "\n\nRefreshCheck histograms for various protocols\n"); | |
62e76326 | 574 | |
829a9357 | 575 | for (i = 0; i < rcCount; ++i) |
62e76326 | 576 | refreshCountsStats(sentry, &refreshCounts[i]); |
1c3e77cd | 577 | } |
578 | ||
579 | void | |
9bc73deb | 580 | refreshInit(void) |
1c3e77cd | 581 | { |
829a9357 | 582 | memset(refreshCounts, 0, sizeof(refreshCounts)); |
583 | refreshCounts[rcHTTP].proto = "HTTP"; | |
584 | refreshCounts[rcICP].proto = "ICP"; | |
65fa5c61 | 585 | #if USE_HTCP |
62e76326 | 586 | |
32b3cf93 | 587 | refreshCounts[rcHTCP].proto = "HTCP"; |
65fa5c61 | 588 | #endif |
62e76326 | 589 | |
cfa9f1cb | 590 | refreshCounts[rcStore].proto = "On Store"; |
65fa5c61 | 591 | #if USE_CACHE_DIGESTS |
62e76326 | 592 | |
829a9357 | 593 | refreshCounts[rcCDigest].proto = "Cache Digests"; |
65fa5c61 | 594 | #endif |
62e76326 | 595 | |
65fa5c61 | 596 | memset(&DefaultRefresh, '\0', sizeof(DefaultRefresh)); |
597 | DefaultRefresh.pattern = "<none>"; | |
598 | DefaultRefresh.min = REFRESH_DEFAULT_MIN; | |
599 | DefaultRefresh.pct = REFRESH_DEFAULT_PCT; | |
600 | DefaultRefresh.max = REFRESH_DEFAULT_MAX; | |
1c3e77cd | 601 | } |
62ee09ca | 602 | |
603 | void | |
604 | refreshRegisterWithCacheManager(CacheManager & manager) | |
605 | { | |
606 | manager.registerAction("refresh", | |
607 | "Refresh Algorithm Statistics", | |
608 | refreshStats, | |
609 | 0, | |
610 | 1); | |
611 | } |