]> git.ipfire.org Git - thirdparty/squid.git/blame - src/refresh.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / refresh.cc
CommitLineData
e4e6a8db 1
2/*
e4e6a8db 3 * DEBUG: section 22 Refresh Calculation
4 * AUTHOR: Harvest Derived
5 *
2b6662ba 6 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 7 * ----------------------------------------------------------
e4e6a8db 8 *
2b6662ba 9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
e4e6a8db 17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
26ac0430 22 *
e4e6a8db 23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
26ac0430 27 *
e4e6a8db 28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
cbdec147 30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 31 *
e4e6a8db 32 */
33
34#ifndef USE_POSIX_REGEX
35#define USE_POSIX_REGEX /* put before includes; always use POSIX */
36#endif
37
582c2af2 38#include "squid.h"
582c2af2 39#include "HttpHdrCc.h"
924f73bc 40#include "HttpReply.h"
602d9612 41#include "HttpRequest.h"
582c2af2 42#include "MemObject.h"
602d9612 43#include "mgr/Registration.h"
8d9a8184 44#include "RefreshPattern.h"
4d5904f7 45#include "SquidConfig.h"
602d9612 46#include "SquidTime.h"
582c2af2 47#include "Store.h"
b1bd952a 48#include "URL.h"
e4e6a8db 49
7d47d8e6 50typedef enum {
65fa5c61 51 rcHTTP,
52 rcICP,
53#if USE_HTCP
54 rcHTCP,
55#endif
56#if USE_CACHE_DIGESTS
57 rcCDigest,
58#endif
59 rcStore,
60 rcCount
7d47d8e6 61} refreshCountsEnum;
829a9357 62
26ac0430 63typedef struct {
1f848b2c 64 bool expires;
65 bool min;
66 bool lmfactor;
67 bool max;
2fadd50d 68} stale_flags;
65fa5c61 69
70/*
71 * This enumerated list assigns specific values, ala HTTP/FTP status
72 * codes. All Fresh codes are in the range 100-199 and all stale
73 * codes are 200-299. We might want to use these codes in logging,
74 * so best to keep them consistent over time.
75 */
76enum {
77 FRESH_REQUEST_MAX_STALE_ALL = 100,
78 FRESH_REQUEST_MAX_STALE_VALUE,
79 FRESH_EXPIRES,
80 FRESH_LMFACTOR_RULE,
81 FRESH_MIN_RULE,
82 FRESH_OVERRIDE_EXPIRES,
83 FRESH_OVERRIDE_LASTMOD,
84 STALE_MUST_REVALIDATE = 200,
85 STALE_RELOAD_INTO_IMS,
86 STALE_FORCED_RELOAD,
87 STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE,
88 STALE_EXPIRES,
89 STALE_MAX_RULE,
90 STALE_LMFACTOR_RULE,
570d3f75 91 STALE_MAX_STALE,
65fa5c61 92 STALE_DEFAULT = 299
93};
94
26ac0430 95static struct RefreshCounts {
829a9357 96 const char *proto;
1c3e77cd 97 int total;
65fa5c61 98 int status[STALE_DEFAULT + 1];
62e76326 99}
100
101refreshCounts[rcCount];
1c3e77cd 102
e4e6a8db 103/*
104 * Defaults:
105 * MIN NONE
106 * PCT 20%
107 * MAX 3 days
108 */
48f44632 109#define REFRESH_DEFAULT_MIN (time_t)0
c3f6d204 110#define REFRESH_DEFAULT_PCT 0.20
48f44632 111#define REFRESH_DEFAULT_MAX (time_t)259200
e4e6a8db 112
8d9a8184 113static const RefreshPattern *refreshUncompiledPattern(const char *);
1c3e77cd 114static OBJH refreshStats;
8d9a8184 115static int refreshStaleness(const StoreEntry * entry, time_t check_time, const time_t age, const RefreshPattern * R, stale_flags * sf);
65fa5c61 116
8d9a8184 117static RefreshPattern DefaultRefresh;
2b5133db 118
8d9a8184 119const RefreshPattern *
6018f0de 120refreshLimits(const char *url)
121{
8d9a8184 122 const RefreshPattern *R;
62e76326 123
6018f0de 124 for (R = Config.Refresh; R; R = R->next) {
62e76326 125 if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
126 return R;
6018f0de 127 }
62e76326 128
6018f0de 129 return NULL;
130}
131
8d9a8184 132static const RefreshPattern *
2b5133db 133refreshUncompiledPattern(const char *pat)
134{
8d9a8184 135 const RefreshPattern *R;
62e76326 136
2b5133db 137 for (R = Config.Refresh; R; R = R->next) {
62e76326 138 if (0 == strcmp(R->pattern, pat))
139 return R;
2b5133db 140 }
62e76326 141
2b5133db 142 return NULL;
143}
144
b2f01ec3 145/**
65fa5c61 146 * Calculate how stale the response is (or will be at the check_time).
147 * Staleness calculation is based on the following: (1) response
148 * expiration time, (2) age greater than configured maximum, (3)
149 * last-modified factor, and (4) age less than configured minimum.
150 *
b2f01ec3
AJ
151 * \retval -1 If the response is fresh.
152 * \retval >0 Otherwise return it's staleness.
153 * \retval 0 NOTE return value of 0 means the response is stale.
65fa5c61 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 */
160static int
8d9a8184 161refreshStaleness(const StoreEntry * entry, time_t check_time, const time_t age, const RefreshPattern * R, stale_flags * sf)
65fa5c61 162{
b2f01ec3
AJ
163 /** \par
164 * Check for an explicit expiration time (Expires: header).
65fa5c61 165 */
166 if (entry->expires > -1) {
1f848b2c 167 sf->expires = true;
62e76326 168
169 if (entry->expires > check_time) {
4a7a3d56 170 debugs(22, 3, "FRESH: expires " << entry->expires <<
171 " >= check_time " << check_time << " ");
bf8fe701 172
62e76326 173 return -1;
174 } else {
4a7a3d56 175 debugs(22, 3, "STALE: expires " << entry->expires <<
176 " < check_time " << check_time << " ");
bf8fe701 177
62e76326 178 return (check_time - entry->expires);
179 }
65fa5c61 180 }
62e76326 181
b2f01ec3 182 /** \par
65fa5c61 183 * Use local heuristics to determine staleness. Start with the
184 * max age from the refresh_pattern rule.
185 */
186 if (age > R->max) {
4a7a3d56 187 debugs(22, 3, "STALE: age " << age << " > max " << R->max << " ");
1f848b2c 188 sf->max = true;
62e76326 189 return (age - R->max);
65fa5c61 190 }
62e76326 191
b2f01ec3
AJ
192 /** \par
193 * Try the last-modified factor algorithm: refresh_pattern n% percentage of Last-Modified: age.
65fa5c61 194 */
195 if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
62e76326 196 /*
197 * stale_age is the Age of the response when it became/becomes
198 * stale according to the last-modified factor algorithm.
199 */
200 time_t stale_age = static_cast<time_t>((entry->timestamp - entry->lastmod) * R->pct);
1f848b2c 201 sf->lmfactor = true;
62e76326 202
203 if (age >= stale_age) {
4a7a3d56 204 debugs(22, 3, "STALE: age " << age << " > stale_age " << stale_age);
62e76326 205 return (age - stale_age);
206 } else {
4a7a3d56 207 debugs(22, 3, "FRESH: age " << age << " <= stale_age " << stale_age);
62e76326 208 return -1;
209 }
65fa5c61 210 }
62e76326 211
b2f01ec3
AJ
212 /** \par
213 * Finally, if all else fails; staleness is determined by the refresh_pattern
65fa5c61 214 * configured minimum age.
215 */
9e4b5932 216 if (age < R->min) {
217 debugs(22, 3, "FRESH: age " << age << " < min " << R->min);
1f848b2c 218 sf->min = true;
62e76326 219 return -1;
65fa5c61 220 }
62e76326 221
9e4b5932 222 debugs(22, 3, "STALE: age " << age << " >= min " << R->min);
65fa5c61 223 return (age - R->min);
224}
225
b2f01ec3
AJ
226/**
227 * \retval 1 if the entry must be revalidated within delta seconds
228 * \retval 0 otherwise
829a9357 229 *
230 * note: request maybe null (e.g. for cache digests build)
e4e6a8db 231 */
829a9357 232static int
190154cf 233refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
e4e6a8db 234{
8d9a8184 235 const RefreshPattern *R;
829a9357 236 const char *uri = NULL;
65fa5c61 237 time_t age = 0;
a207429f 238 time_t check_time = squid_curtime + delta;
65fa5c61 239 int staleness;
240 stale_flags sf;
62e76326 241
9b5d1d21 242 if (entry->mem_obj)
62e76326 243 uri = entry->mem_obj->url;
7d47d8e6 244 else if (request)
62e76326 245 uri = urlCanonical(request);
7d47d8e6 246
bf8fe701 247 debugs(22, 3, "refreshCheck: '" << (uri ? uri : "<none>") << "'");
65fa5c61 248
249 if (check_time > entry->timestamp)
62e76326 250 age = check_time - entry->timestamp;
251
efd62b86 252 // FIXME: what to do when age < 0 or counter overflow?
b2f01ec3 253 assert(age >= 0);
efd62b86 254
65fa5c61 255 R = uri ? refreshLimits(uri) : refreshUncompiledPattern(".");
62e76326 256
65fa5c61 257 if (NULL == R)
62e76326 258 R = &DefaultRefresh;
259
bf8fe701 260 debugs(22, 3, "refreshCheck: Matched '" << R->pattern << " " <<
261 (int) R->min << " " << (int) (100.0 * R->pct) << "%% " <<
262 (int) R->max << "'");
65fa5c61 263
64f8c2cb 264 debugs(22, 3, "\tage:\t" << age);
62e76326 265
bf8fe701 266 debugs(22, 3, "\tcheck_time:\t" << mkrfc1123(check_time));
62e76326 267
bf8fe701 268 debugs(22, 3, "\tentry->timestamp:\t" << mkrfc1123(entry->timestamp));
65fa5c61 269
450fe1cb 270 if (request && !request->flags.ignoreCc) {
64f8c2cb 271 const HttpHdrCc *const cc = request->cache_control;
d74ad83f 272 if (cc && cc->hasMinFresh()) {
4ce6e3b5 273 const int32_t minFresh=cc->minFresh();
64f8c2cb 274 debugs(22, 3, "\tage + min-fresh:\t" << age << " + " <<
77da1817 275 minFresh << " = " << age + minFresh);
64f8c2cb 276 debugs(22, 3, "\tcheck_time + min-fresh:\t" << check_time << " + "
422acb7f
FC
277 << minFresh << " = " <<
278 mkrfc1123(check_time + minFresh));
279 age += minFresh;
280 check_time += minFresh;
64f8c2cb
AR
281 }
282 }
283
284 memset(&sf, '\0', sizeof(sf));
285
286 staleness = refreshStaleness(entry, check_time, age, R, &sf);
287
288 debugs(22, 3, "Staleness = " << staleness);
289
65fd3895
AJ
290 // stale-if-error requires any failure be passed thru when its period is over.
291 if (request && entry->mem_obj && entry->mem_obj->getReply() && entry->mem_obj->getReply()->cache_control &&
77da1817 292 entry->mem_obj->getReply()->cache_control->hasStaleIfError() &&
4ce6e3b5 293 entry->mem_obj->getReply()->cache_control->staleIfError() < staleness) {
65fd3895
AJ
294
295 debugs(22, 3, "refreshCheck: stale-if-error period expired.");
e857372a 296 request->flags.failOnValidationError = true;
65fd3895
AJ
297 }
298
4ca08219 299 if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1
626096be 300#if USE_HTTP_VIOLATIONS
04f7fd38 301 && !R->flags.ignore_must_revalidate
4ca08219 302#endif
04f7fd38 303 ) {
bf8fe701 304 debugs(22, 3, "refreshCheck: YES: Must revalidate stale response");
5b1d04af 305 if (request)
e857372a 306 request->flags.failOnValidationError = true;
62e76326 307 return STALE_MUST_REVALIDATE;
65fa5c61 308 }
62e76326 309
829a9357 310 /* request-specific checks */
450fe1cb 311 if (request && !request->flags.ignoreCc) {
62e76326 312 HttpHdrCc *cc = request->cache_control;
4c3ef9b2 313
45e5102d 314 if (request->flags.ims && (R->flags.refresh_ims || Config.onoff.refresh_all_ims)) {
4c3ef9b2 315 /* The clients no-cache header is changed into a IMS query */
bf8fe701 316 debugs(22, 3, "refreshCheck: YES: refresh-ims");
4c3ef9b2 317 return STALE_FORCED_RELOAD;
318 }
319
626096be 320#if USE_HTTP_VIOLATIONS
62e76326 321
450fe1cb 322 if (!request->flags.noCacheHack()) {
62e76326 323 (void) 0;
324 } else if (R->flags.ignore_reload) {
325 /* The clients no-cache header is ignored */
bf8fe701 326 debugs(22, 3, "refreshCheck: MAYBE: ignore-reload");
62e76326 327 } else if (R->flags.reload_into_ims || Config.onoff.reload_into_ims) {
328 /* The clients no-cache header is changed into a IMS query */
bf8fe701 329 debugs(22, 3, "refreshCheck: YES: reload-into-ims");
62e76326 330 return STALE_RELOAD_INTO_IMS;
331 } else {
332 /* The clients no-cache header is not overridden on this request */
bf8fe701 333 debugs(22, 3, "refreshCheck: YES: client reload");
e857372a 334 request->flags.noCache = true;
62e76326 335 return STALE_FORCED_RELOAD;
336 }
337
9f60cfdf 338#endif
62e76326 339 if (NULL != cc) {
d74ad83f 340 if (cc->hasMaxAge()) {
626096be 341#if USE_HTTP_VIOLATIONS
cf7c2e94 342 if (R->flags.ignore_reload && cc->maxAge() == 0) {
7792a5ae
AR
343 debugs(22, 3, "refreshCheck: MAYBE: client-max-age = 0 and ignore-reload");
344 } else
528b2c61 345#endif
62e76326 346 {
cf7c2e94 347 if (cc->maxAge() == 0) {
bf8fe701 348 debugs(22, 3, "refreshCheck: YES: client-max-age = 0");
62e76326 349 return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
350 }
351
cf7c2e94 352 if (age > cc->maxAge()) {
bf8fe701 353 debugs(22, 3, "refreshCheck: YES: age > client-max-age");
62e76326 354 return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
355 }
356 }
357 }
358
d74ad83f
FC
359 if (cc->hasMaxStale() && staleness > -1) {
360 if (cc->maxStale()==HttpHdrCc::MAX_STALE_ANY) {
62e76326 361 /* max-stale directive without a value */
bf8fe701 362 debugs(22, 3, "refreshCheck: NO: max-stale wildcard");
62e76326 363 return FRESH_REQUEST_MAX_STALE_ALL;
4ce6e3b5 364 } else if (staleness < cc->maxStale()) {
bf8fe701 365 debugs(22, 3, "refreshCheck: NO: staleness < max-stale");
62e76326 366 return FRESH_REQUEST_MAX_STALE_VALUE;
367 }
368 }
369 }
48f44632 370 }
62e76326 371
65fa5c61 372 if (-1 == staleness) {
bf8fe701 373 debugs(22, 3, "refreshCheck: object isn't stale..");
ed1de692 374 if (sf.expires) {
bf8fe701 375 debugs(22, 3, "refreshCheck: returning FRESH_EXPIRES");
62e76326 376 return FRESH_EXPIRES;
26ac0430 377 }
62e76326 378
379 assert(!sf.max);
380
ed1de692 381 if (sf.lmfactor) {
bf8fe701 382 debugs(22, 3, "refreshCheck: returning FRESH_LMFACTOR_RULE");
62e76326 383 return FRESH_LMFACTOR_RULE;
26ac0430 384 }
62e76326 385
386 assert(sf.min);
387
bf8fe701 388 debugs(22, 3, "refreshCheck: returning FRESH_MIN_RULE");
62e76326 389 return FRESH_MIN_RULE;
1dfa1d81 390 }
62e76326 391
65fa5c61 392 /*
393 * At this point the response is stale, unless one of
542c4d60 394 * the override options kicks in.
570d3f75 395 * NOTE: max-stale config blocks the overrides.
65fa5c61 396 */
570d3f75 397 int max_stale = (R->max_stale >= 0 ? R->max_stale : Config.maxStale);
60c3d5b7 398 if ( max_stale >= 0 && staleness > max_stale) {
570d3f75
AJ
399 debugs(22, 3, "refreshCheck: YES: max-stale limit");
400 if (request)
e857372a 401 request->flags.failOnValidationError = true;
570d3f75
AJ
402 return STALE_MAX_STALE;
403 }
404
65fa5c61 405 if (sf.expires) {
626096be 406#if USE_HTTP_VIOLATIONS
62e76326 407
408 if (R->flags.override_expire && age < R->min) {
bf8fe701 409 debugs(22, 3, "refreshCheck: NO: age < min && override-expire");
62e76326 410 return FRESH_OVERRIDE_EXPIRES;
411 }
412
65fa5c61 413#endif
62e76326 414 return STALE_EXPIRES;
e4e6a8db 415 }
62e76326 416
65fa5c61 417 if (sf.max)
62e76326 418 return STALE_MAX_RULE;
419
65fa5c61 420 if (sf.lmfactor) {
626096be 421#if USE_HTTP_VIOLATIONS
62e76326 422
423 if (R->flags.override_lastmod && age < R->min) {
bf8fe701 424 debugs(22, 3, "refreshCheck: NO: age < min && override-lastmod");
62e76326 425 return FRESH_OVERRIDE_LASTMOD;
426 }
427
65fa5c61 428#endif
62e76326 429 return STALE_LMFACTOR_RULE;
e4e6a8db 430 }
62e76326 431
bf8fe701 432 debugs(22, 3, "refreshCheck: returning STALE_DEFAULT");
65fa5c61 433 return STALE_DEFAULT;
e4e6a8db 434}
48f44632 435
cfa9f1cb 436int
437refreshIsCachable(const StoreEntry * entry)
438{
439 /*
440 * Don't look at the request to avoid no-cache and other nuisances.
441 * the object should have a mem_obj so the URL will be found there.
26ac0430
AJ
442 * minimum_expiry_time seconds delta (defaults to 60 seconds), to
443 * avoid objects which expire almost immediately, and which can't
6a2f3fcf 444 * be refreshed.
cfa9f1cb 445 */
6a2f3fcf 446 int reason = refreshCheck(entry, NULL, Config.minimum_expiry_time);
5db6bf73
FC
447 ++ refreshCounts[rcStore].total;
448 ++ refreshCounts[rcStore].status[reason];
62e76326 449
451c8350 450 if (reason < STALE_MUST_REVALIDATE)
62e76326 451 /* Does not need refresh. This is certainly cachable */
452 return 1;
453
cfa9f1cb 454 if (entry->lastmod < 0)
62e76326 455 /* Last modified is needed to do a refresh */
456 return 0;
457
cfa9f1cb 458 if (entry->mem_obj == NULL)
62e76326 459 /* no mem_obj? */
460 return 1;
461
528b2c61 462 if (entry->getReply() == NULL)
62e76326 463 /* no reply? */
464 return 1;
465
528b2c61 466 if (entry->getReply()->content_length == 0)
62e76326 467 /* No use refreshing (caching?) 0 byte objects */
468 return 0;
469
cfa9f1cb 470 /* This seems to be refreshable. Cache it */
471 return 1;
472}
473
bcfba8bd
AR
474/// whether reply is stale if it is a hit
475static bool
476refreshIsStaleIfHit(const int reason)
477{
478 switch (reason) {
479 case FRESH_MIN_RULE:
480 case FRESH_LMFACTOR_RULE:
481 case FRESH_EXPIRES:
482 return false;
483 default:
484 return true;
485 }
486}
487
829a9357 488/* refreshCheck... functions below are protocol-specific wrappers around
489 * refreshCheck() function above */
490
491int
190154cf 492refreshCheckHTTP(const StoreEntry * entry, HttpRequest * request)
7d47d8e6 493{
65fa5c61 494 int reason = refreshCheck(entry, request, 0);
5db6bf73
FC
495 ++ refreshCounts[rcHTTP].total;
496 ++ refreshCounts[rcHTTP].status[reason];
450fe1cb 497 request->flags.staleIfHit = refreshIsStaleIfHit(reason);
bcfba8bd 498 return (Config.onoff.offline || reason < 200) ? 0 : 1;
829a9357 499}
500
501int
190154cf 502refreshCheckICP(const StoreEntry * entry, HttpRequest * request)
7d47d8e6 503{
65fa5c61 504 int reason = refreshCheck(entry, request, 30);
5db6bf73
FC
505 ++ refreshCounts[rcICP].total;
506 ++ refreshCounts[rcICP].status[reason];
65fa5c61 507 return (reason < 200) ? 0 : 1;
829a9357 508}
509
65fa5c61 510#if USE_HTCP
32b3cf93 511int
190154cf 512refreshCheckHTCP(const StoreEntry * entry, HttpRequest * request)
32b3cf93 513{
65fa5c61 514 int reason = refreshCheck(entry, request, 10);
5db6bf73
FC
515 ++ refreshCounts[rcHTCP].total;
516 ++ refreshCounts[rcHTCP].status[reason];
65fa5c61 517 return (reason < 200) ? 0 : 1;
32b3cf93 518}
62e76326 519
65fa5c61 520#endif
32b3cf93 521
65fa5c61 522#if USE_CACHE_DIGESTS
829a9357 523int
7d47d8e6 524refreshCheckDigest(const StoreEntry * entry, time_t delta)
525{
65fa5c61 526 int reason = refreshCheck(entry,
62e76326 527 entry->mem_obj ? entry->mem_obj->request : NULL,
528 delta);
5db6bf73
FC
529 ++ refreshCounts[rcCDigest].total;
530 ++ refreshCounts[rcCDigest].status[reason];
65fa5c61 531 return (reason < 200) ? 0 : 1;
6018f0de 532}
62e76326 533
65fa5c61 534#endif
6018f0de 535
48f44632 536time_t
537getMaxAge(const char *url)
538{
8d9a8184 539 const RefreshPattern *R;
bf8fe701 540 debugs(22, 3, "getMaxAge: '" << url << "'");
62e76326 541
6018f0de 542 if ((R = refreshLimits(url)))
62e76326 543 return R->max;
6018f0de 544 else
62e76326 545 return REFRESH_DEFAULT_MAX;
48f44632 546}
1c3e77cd 547
829a9357 548static void
62e76326 549
829a9357 550refreshCountsStats(StoreEntry * sentry, struct RefreshCounts *rc)
551{
cc7cfa8e 552 int sum = 0;
553 int tot = rc->total;
554
829a9357 555 storeAppendPrintf(sentry, "\n\n%s histogram:\n", rc->proto);
65fa5c61 556 storeAppendPrintf(sentry, "Count\t%%Total\tCategory\n");
829a9357 557
65fa5c61 558#define refreshCountsStatsEntry(code,desc) { \
559 storeAppendPrintf(sentry, "%6d\t%6.2f\t%s\n", \
560 rc->status[code], xpercent(rc->status[code], tot), desc); \
561 sum += rc->status[code]; \
cc7cfa8e 562}
65fa5c61 563
564 refreshCountsStatsEntry(FRESH_REQUEST_MAX_STALE_ALL,
62e76326 565 "Fresh: request max-stale wildcard");
65fa5c61 566 refreshCountsStatsEntry(FRESH_REQUEST_MAX_STALE_VALUE,
62e76326 567 "Fresh: request max-stale value");
65fa5c61 568 refreshCountsStatsEntry(FRESH_EXPIRES,
62e76326 569 "Fresh: expires time not reached");
65fa5c61 570 refreshCountsStatsEntry(FRESH_LMFACTOR_RULE,
62e76326 571 "Fresh: refresh_pattern last-mod factor percentage");
65fa5c61 572 refreshCountsStatsEntry(FRESH_MIN_RULE,
62e76326 573 "Fresh: refresh_pattern min value");
65fa5c61 574 refreshCountsStatsEntry(FRESH_OVERRIDE_EXPIRES,
62e76326 575 "Fresh: refresh_pattern override expires");
65fa5c61 576 refreshCountsStatsEntry(FRESH_OVERRIDE_LASTMOD,
62e76326 577 "Fresh: refresh_pattern override lastmod");
65fa5c61 578 refreshCountsStatsEntry(STALE_MUST_REVALIDATE,
62e76326 579 "Stale: response has must-revalidate");
65fa5c61 580 refreshCountsStatsEntry(STALE_RELOAD_INTO_IMS,
62e76326 581 "Stale: changed reload into IMS");
65fa5c61 582 refreshCountsStatsEntry(STALE_FORCED_RELOAD,
62e76326 583 "Stale: request has no-cache directive");
65fa5c61 584 refreshCountsStatsEntry(STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE,
62e76326 585 "Stale: age exceeds request max-age value");
65fa5c61 586 refreshCountsStatsEntry(STALE_EXPIRES,
62e76326 587 "Stale: expires time reached");
65fa5c61 588 refreshCountsStatsEntry(STALE_MAX_RULE,
62e76326 589 "Stale: refresh_pattern max age rule");
65fa5c61 590 refreshCountsStatsEntry(STALE_LMFACTOR_RULE,
62e76326 591 "Stale: refresh_pattern last-mod factor percentage");
65fa5c61 592 refreshCountsStatsEntry(STALE_DEFAULT,
62e76326 593 "Stale: by default");
65fa5c61 594
7d47d8e6 595 tot = sum; /* paranoid: "total" line shows 100% if we forgot nothing */
65fa5c61 596 storeAppendPrintf(sentry, "%6d\t%6.2f\tTOTAL\n",
62e76326 597 rc->total, xpercent(rc->total, tot));
65fa5c61 598 \
62e76326 599 storeAppendPrintf(sentry, "\n");
829a9357 600}
601
1c3e77cd 602static void
603refreshStats(StoreEntry * sentry)
604{
829a9357 605 int i;
606 int total = 0;
607
608 /* get total usage count */
62e76326 609
829a9357 610 for (i = 0; i < rcCount; ++i)
62e76326 611 total += refreshCounts[i].total;
829a9357 612
613 /* protocol usage histogram */
614 storeAppendPrintf(sentry, "\nRefreshCheck calls per protocol\n\n");
62e76326 615
829a9357 616 storeAppendPrintf(sentry, "Protocol\t#Calls\t%%Calls\n");
62e76326 617
829a9357 618 for (i = 0; i < rcCount; ++i)
62e76326 619 storeAppendPrintf(sentry, "%10s\t%6d\t%6.2f\n",
620 refreshCounts[i].proto,
621 refreshCounts[i].total,
622 xpercent(refreshCounts[i].total, total));
829a9357 623
624 /* per protocol histograms */
625 storeAppendPrintf(sentry, "\n\nRefreshCheck histograms for various protocols\n");
62e76326 626
829a9357 627 for (i = 0; i < rcCount; ++i)
62e76326 628 refreshCountsStats(sentry, &refreshCounts[i]);
1c3e77cd 629}
630
5f5e883f
FC
631static void
632refreshRegisterWithCacheManager(void)
633{
8822ebee 634 Mgr::RegisterAction("refresh", "Refresh Algorithm Statistics", refreshStats, 0, 1);
5f5e883f
FC
635}
636
1c3e77cd 637void
9bc73deb 638refreshInit(void)
1c3e77cd 639{
829a9357 640 memset(refreshCounts, 0, sizeof(refreshCounts));
641 refreshCounts[rcHTTP].proto = "HTTP";
642 refreshCounts[rcICP].proto = "ICP";
65fa5c61 643#if USE_HTCP
62e76326 644
32b3cf93 645 refreshCounts[rcHTCP].proto = "HTCP";
65fa5c61 646#endif
62e76326 647
cfa9f1cb 648 refreshCounts[rcStore].proto = "On Store";
65fa5c61 649#if USE_CACHE_DIGESTS
62e76326 650
829a9357 651 refreshCounts[rcCDigest].proto = "Cache Digests";
65fa5c61 652#endif
62e76326 653
65fa5c61 654 memset(&DefaultRefresh, '\0', sizeof(DefaultRefresh));
655 DefaultRefresh.pattern = "<none>";
656 DefaultRefresh.min = REFRESH_DEFAULT_MIN;
657 DefaultRefresh.pct = REFRESH_DEFAULT_PCT;
658 DefaultRefresh.max = REFRESH_DEFAULT_MAX;
d120ed12
FC
659
660 refreshRegisterWithCacheManager();
1c3e77cd 661}