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