2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 22 Refresh Calculation */
11 #ifndef USE_POSIX_REGEX
12 #define USE_POSIX_REGEX /* put before includes; always use POSIX */
16 #include "base/PackableStream.h"
17 #include "HttpHdrCc.h"
18 #include "HttpReply.h"
19 #include "HttpRequest.h"
20 #include "MemObject.h"
21 #include "mgr/Registration.h"
23 #include "RefreshPattern.h"
24 #include "SquidConfig.h"
42 * Flags indicating which staleness algorithm has been applied.
45 bool expires
; ///< Expires: header absolute timestamp limit
46 bool min
; ///< Heuristic minimum age limited
47 bool lmfactor
; ///< Last-Modified with heuristic determines limit
48 bool max
; ///< Configured maximum age limit
52 * This enumerated list assigns specific values, ala HTTP/FTP status
53 * codes. All Fresh codes are in the range 100-199 and all stale
54 * codes are 200-299. We might want to use these codes in logging,
55 * so best to keep them consistent over time.
58 FRESH_REQUEST_MAX_STALE_ALL
= 100,
59 FRESH_REQUEST_MAX_STALE_VALUE
,
63 FRESH_OVERRIDE_EXPIRES
,
64 FRESH_OVERRIDE_LASTMOD
,
65 STALE_MUST_REVALIDATE
= 200,
66 STALE_RELOAD_INTO_IMS
,
68 STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE
,
76 static struct RefreshCounts
{
79 int status
[STALE_DEFAULT
+ 1];
80 } refreshCounts
[rcCount
];
82 static OBJH refreshStats
;
83 static int refreshStaleness(const StoreEntry
* entry
, time_t check_time
, const time_t age
, const RefreshPattern
* R
, stale_flags
* sf
);
85 static RefreshPattern
DefaultRefresh(nullptr);
87 /** Locate the first refresh_pattern rule that matches the given URL by regex.
89 * \return A pointer to the refresh_pattern parameters to use, or nullptr if there is no match.
91 const RefreshPattern
*
92 refreshLimits(const char *url
)
94 for (auto R
= Config
.Refresh
; R
; R
= R
->next
) {
95 ++(R
->stats
.matchTests
);
96 if (R
->regex().match(url
)) {
97 ++(R
->stats
.matchCount
);
105 /// the first explicit refresh_pattern rule that uses a "." regex (or nil)
106 static const RefreshPattern
*
107 refreshFirstDotRule()
109 for (auto R
= Config
.Refresh
; R
; R
= R
->next
) {
110 if (R
->regex().isDot())
118 * Calculate how stale the response is (or will be at the check_time).
120 * We try the following ways until one gives a result:
122 * 1. response expiration time, if one was set
123 * 2. age greater than configured maximum
124 * 3. last-modified factor algorithm
125 * 4. age less than configured minimum
128 * \param entry the StoreEntry being examined
129 * \param check_time the time (maybe future) at which we want to know whether $
130 * \param age the age of the entry at check_time
131 * \param R the refresh_pattern rule that matched this entry
132 * \param sf small struct to indicate reason for stale/fresh decision
134 * \retval -1 If the response is fresh.
135 * \retval >0 The amount of staleness.
136 * \retval 0 NOTE return value of 0 means the response is stale.
139 refreshStaleness(const StoreEntry
* entry
, time_t check_time
, const time_t age
, const RefreshPattern
* R
, stale_flags
* sf
)
141 // 1. If the cached object has an explicit expiration time, then we rely on this and
142 // completely ignore the Min, Percent and Max values in the refresh_pattern.
143 if (entry
->expires
> -1) {
146 if (entry
->expires
> check_time
) {
147 debugs(22, 3, "FRESH: expires " << entry
->expires
<< " > check_time " << check_time
);
150 debugs(22, 3, "STALE: expires " << entry
->expires
<< " <= check_time " << check_time
);
151 return (check_time
- entry
->expires
);
155 debugs(22, 3, "No explicit expiry given, using heuristics to determine freshness");
157 // 2. If the entry is older than the maximum age in the refresh_pattern, it is STALE.
159 debugs(22, 3, "STALE: age " << age
<< " > max " << R
->max
);
161 return (age
- R
->max
);
164 // 3. If there is a Last-Modified header, try the last-modified factor algorithm.
165 const time_t lastmod_delta
= entry
->timestamp
- entry
->lastModified();
166 if (lastmod_delta
> 0) {
167 /* stale_age is the age of the response when it became/becomes stale according to
168 * the last-modified factor algorithm. It's how long we can consider the response
169 * fresh from the time we cached it.
171 time_t stale_age
= static_cast<time_t>(lastmod_delta
* R
->pct
);
173 debugs(22,3, "Last modified " << lastmod_delta
<< " sec before we cached it, L-M factor " <<
174 (100.0 * R
->pct
) << "% = " << stale_age
<< " sec freshness lifetime");
177 if (age
>= stale_age
) {
178 debugs(22, 3, "STALE: age " << age
<< " > stale_age " << stale_age
);
179 return (age
- stale_age
);
181 debugs(22, 3, "FRESH: age " << age
<< " <= stale_age " << stale_age
);
186 // 4. If the entry is not as old as the minimum age in the refresh_pattern, it is FRESH.
188 debugs(22, 3, "FRESH: age (" << age
<< " sec) is less than configured minimum (" << R
->min
<< " sec)");
193 // 5. default is stale, by the amount we missed the minimum by
194 debugs(22, 3, "STALE: No explicit expiry, no last modified, and older than configured minimum.");
195 return (age
- R
->min
);
198 /** Checks whether a store entry is fresh or stale, and why.
200 * This is where all aspects of request, response and squid configuration
201 * meet to decide whether a response is cacheable or not:
203 * 1. Client request headers that affect cacheability, e.g.
204 * - Cache-Control: no-cache
205 * - Cache-Control: max-age=N
206 * - Cache-Control: max-stale[=N]
209 * 2. Server response headers that affect cacheability, e.g.
211 * - Cache-Control: proxy-revalidate
212 * - Cache-Control: must-revalidate
213 * - Cache-Control: no-cache
214 * - Cache-Control: max-age=N
215 * - Cache-Control: s-maxage=N
220 * 3. Configuration options, e.g.
221 * - reload-into-ims (refresh_pattern)
222 * - ignore-reload (refresh_pattern)
223 * - refresh-ims (refresh_pattern)
224 * - override-lastmod (refresh_pattern)
225 * - override-expire (refresh_pattern)
226 * - reload_into_ims (global option)
227 * - refresh_all_ims (global option)
229 * \returns a status code (from enum above):
230 * - FRESH_REQUEST_MAX_STALE_ALL
231 * - FRESH_REQUEST_MAX_STALE_VALUE
233 * - FRESH_LMFACTOR_RULE
235 * - FRESH_OVERRIDE_EXPIRES
236 * - FRESH_OVERRIDE_LASTMOD
237 * - STALE_MUST_REVALIDATE
238 * - STALE_RELOAD_INTO_IMS
239 * - STALE_FORCED_RELOAD
240 * - STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE
243 * - STALE_LMFACTOR_RULE
247 * \note request may be NULL (e.g. for cache digests build)
249 * \note the store entry being examined is not necessarily cached (e.g. if
250 * this response is being evaluated for the first time)
253 refreshCheck(const StoreEntry
* entry
, HttpRequest
* request
, time_t delta
)
256 time_t check_time
= squid_curtime
+ delta
;
260 // get the URL of this entry, if there is one
261 static const SBuf
nilUri("<none>");
264 uri
= entry
->mem_obj
->storeId();
266 uri
= request
->effectiveRequestUri();
268 debugs(22, 3, "checking freshness of " << *entry
<< " with URI: " << uri
);
270 // age is not necessarily the age now, but the age at the given check_time
271 if (check_time
> entry
->timestamp
)
272 age
= check_time
- entry
->timestamp
;
274 // XXX: what to do when age < 0 or counter overflow?
277 /* We need a refresh rule. In order of preference:
279 * 1. the rule that matches this URI by regex
280 * 2. the "." rule from the config file
281 * 3. the default "." rule
283 // XXX: performance regression. c_str() reallocates
284 const RefreshPattern
*R
= (uri
!= nilUri
) ? refreshLimits(uri
.c_str()) : refreshFirstDotRule();
288 debugs(22, 3, "Matched '" << *R
<< '\'');
290 debugs(22, 3, "\tage:\t" << age
);
292 debugs(22, 3, "\tcheck_time:\t" << Time::FormatRfc1123(check_time
));
294 debugs(22, 3, "\tentry->timestamp:\t" << Time::FormatRfc1123(entry
->timestamp
));
296 if (request
&& !request
->flags
.ignoreCc
) {
297 const HttpHdrCc
*const cc
= request
->cache_control
;
299 if (cc
&& cc
->hasMinFresh(&minFresh
)) {
300 debugs(22, 3, "\tage + min-fresh:\t" << age
<< " + " <<
301 minFresh
<< " = " << age
+ minFresh
);
302 debugs(22, 3, "\tcheck_time + min-fresh:\t" << check_time
<< " + "
303 << minFresh
<< " = " <<
304 Time::FormatRfc1123(check_time
+ minFresh
));
306 check_time
+= minFresh
;
310 memset(&sf
, '\0', sizeof(sf
));
312 staleness
= refreshStaleness(entry
, check_time
, age
, R
, &sf
);
314 debugs(22, 3, "Staleness = " << staleness
);
316 const auto reply
= entry
->hasFreshestReply(); // may be nil
318 // stale-if-error requires any failure be passed thru when its period is over.
319 int staleIfError
= -1;
320 if (request
&& reply
&& reply
->cache_control
&&
321 reply
->cache_control
->hasStaleIfError(&staleIfError
) &&
322 staleIfError
< staleness
) {
324 debugs(22, 3, "stale-if-error period expired. Will produce error if validation fails.");
325 request
->flags
.failOnValidationError
= true;
328 /* If the origin server specified either of:
329 * Cache-Control: must-revalidate
330 * Cache-Control: proxy-revalidate
331 * the spec says the response must always be revalidated if stale.
333 const bool revalidateAlways
= EBIT_TEST(entry
->flags
, ENTRY_REVALIDATE_ALWAYS
);
334 if (revalidateAlways
|| (staleness
> -1 &&
335 EBIT_TEST(entry
->flags
, ENTRY_REVALIDATE_STALE
))) {
336 debugs(22, 3, "YES: Must revalidate stale object (origin set " <<
337 (revalidateAlways
? "no-cache or private" :
338 "must-revalidate, proxy-revalidate or s-maxage") << ")");
340 request
->flags
.failOnValidationError
= true;
341 return STALE_MUST_REVALIDATE
;
344 /* request-specific checks */
345 if (request
&& !request
->flags
.ignoreCc
) {
346 HttpHdrCc
*cc
= request
->cache_control
;
348 /* If the request is an IMS request, and squid is configured NOT to service this from cache
349 * (either by 'refresh-ims' in the refresh pattern or 'refresh_all_ims on' globally)
350 * then force a reload from the origin.
352 if (request
->flags
.ims
&& (R
->flags
.refresh_ims
|| Config
.onoff
.refresh_all_ims
)) {
353 // The client's no-cache header is changed into a IMS query
354 debugs(22, 3, "YES: Client IMS request forcing revalidation of object (refresh-ims option)");
355 return STALE_FORCED_RELOAD
;
358 #if USE_HTTP_VIOLATIONS
359 /* Normally a client reload request ("Cache-Control: no-cache" or "Pragma: no-cache")
360 * means we must treat this response as STALE and fetch a new one.
362 * However, some options exist to override this behaviour. For example, we might just
363 * revalidate our existing response, or even just serve it up without revalidating it.
365 * ---- Note on the meaning of nocache_hack -----
367 * The nocache_hack flag has a very specific and complex meaning:
369 * (a) this is a reload request ("Cache-Control: no-cache" or "Pragma: no-cache" header)
370 * and (b) the configuration file either has at least one refresh_pattern with
371 * ignore-reload or reload-into-ims (not necessarily the rule matching this request) or
372 * the global reload_into_ims is set to on
374 * In other words: this is a client reload, and we might need to override
375 * the default behaviour (but we might not).
377 * "nocache_hack" is a pretty deceptive name for such a complicated meaning.
379 if (request
->flags
.noCacheHack()) {
381 if (R
->flags
.ignore_reload
) {
382 /* The client's no-cache header is ignored completely - we'll try to serve
383 * what we have (assuming it's still fresh, etc.)
385 debugs(22, 3, "MAYBE: Ignoring client reload request - trying to serve from cache (ignore-reload option)");
386 } else if (R
->flags
.reload_into_ims
|| Config
.onoff
.reload_into_ims
) {
387 /* The client's no-cache header is not honoured completely - we'll just try
388 * to revalidate our cached copy (IMS to origin) instead of fetching a new
389 * copy with an unconditional GET.
391 debugs(22, 3, "YES: Client reload request - cheating, only revalidating with origin (reload-into-ims option)");
392 return STALE_RELOAD_INTO_IMS
;
394 /* The client's no-cache header is honoured - we fetch a new copy from origin */
395 debugs(22, 3, "YES: Client reload request - fetching new copy from origin");
396 request
->flags
.noCache
= true;
397 return STALE_FORCED_RELOAD
;
402 // Check the Cache-Control client request header
407 if (cc
->hasMaxAge(&maxAge
)) {
409 // RFC 8246: reply contains CC:immutable then ignore client CC:max-age=N
410 if (reply
&& reply
->cache_control
&& reply
->cache_control
->hasImmutable()) {
411 debugs(22, 3, "MAYBE: Ignoring client CC:max-age=" << maxAge
<< " request - 'Cache-Control: immutable'");
413 #if USE_HTTP_VIOLATIONS
414 // Ignore of client "Cache-Control: max-age=0" header
415 } else if (R
->flags
.ignore_reload
&& maxAge
== 0) {
416 debugs(22, 3, "MAYBE: Ignoring client reload request - trying to serve from cache (ignore-reload option)");
419 // Honour client "Cache-Control: max-age=x" header
420 } else if (age
> maxAge
|| maxAge
== 0) {
421 debugs(22, 3, "YES: Revalidating object - client 'Cache-Control: max-age=" << maxAge
<< "'");
422 return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE
;
426 // max-stale directive
428 if (cc
->hasMaxStale(&maxStale
) && staleness
> -1) {
429 if (maxStale
==HttpHdrCc::MAX_STALE_ANY
) {
430 debugs(22, 3, "NO: Client accepts a stale response of any age - 'Cache-Control: max-stale'");
431 return FRESH_REQUEST_MAX_STALE_ALL
;
432 } else if (staleness
< maxStale
) {
433 debugs(22, 3, "NO: Client accepts a stale response - 'Cache-Control: max-stale=" << maxStale
<< "'");
434 return FRESH_REQUEST_MAX_STALE_VALUE
;
440 // If the object is fresh, return the right FRESH_ code
441 if (-1 == staleness
) {
442 debugs(22, 3, "Object isn't stale..");
444 debugs(22, 3, "returning FRESH_EXPIRES");
445 return FRESH_EXPIRES
;
451 debugs(22, 3, "returning FRESH_LMFACTOR_RULE");
452 return FRESH_LMFACTOR_RULE
;
457 debugs(22, 3, "returning FRESH_MIN_RULE");
458 return FRESH_MIN_RULE
;
462 * At this point the response is stale, unless one of
463 * the override options kicks in.
464 * NOTE: max-stale config blocks the overrides.
466 int max_stale
= (R
->max_stale
>= 0 ? R
->max_stale
: Config
.maxStale
);
467 if ( max_stale
>= 0 && staleness
> max_stale
) {
468 debugs(22, 3, "YES: refresh_pattern max-stale=N limit from squid.conf");
470 request
->flags
.failOnValidationError
= true;
471 return STALE_MAX_STALE
;
475 #if USE_HTTP_VIOLATIONS
477 if (R
->flags
.override_expire
&& age
< R
->min
) {
478 debugs(22, 3, "NO: Serving from cache - even though explicit expiry has passed, we enforce Min value (override-expire option)");
479 return FRESH_OVERRIDE_EXPIRES
;
483 debugs(22, 3, "returning STALE_EXPIRES");
484 return STALE_EXPIRES
;
488 debugs(22, 3, "returning STALE_MAX_RULE");
489 return STALE_MAX_RULE
;
493 #if USE_HTTP_VIOLATIONS
494 if (R
->flags
.override_lastmod
&& age
< R
->min
) {
495 debugs(22, 3, "NO: Serving from cache - even though L-M factor says the object is stale, we enforce Min value (override-lastmod option)");
496 return FRESH_OVERRIDE_LASTMOD
;
499 debugs(22, 3, "YES: L-M factor says the object is stale'");
500 return STALE_LMFACTOR_RULE
;
503 debugs(22, 3, "returning STALE_DEFAULT");
504 return STALE_DEFAULT
;
508 * This is called by http.cc once it has received and parsed the origin server's
509 * response headers. It uses the result as part of its algorithm to decide whether a
510 * response should be cached.
512 * \retval true if the entry is cacheable, regardless of whether FRESH or STALE
513 * \retval false if the entry is not cacheable
515 * TODO: this algorithm seems a bit odd and might not be quite right. Verify against HTTPbis.
518 refreshIsCachable(const StoreEntry
* entry
)
521 * Don't look at the request to avoid no-cache and other nuisances.
522 * the object should have a mem_obj so the URL will be found there.
523 * minimum_expiry_time seconds delta (defaults to 60 seconds), to
524 * avoid objects which expire almost immediately, and which can't
527 * No hittingRequiresCollapsing() or didCollapse concerns here: This
528 * incoming response is fresh now, but we want to check whether it can be
529 * refreshed Config.minimum_expiry_time seconds later.
531 int reason
= refreshCheck(entry
, nullptr, Config
.minimum_expiry_time
);
532 ++ refreshCounts
[rcStore
].total
;
533 ++ refreshCounts
[rcStore
].status
[reason
];
535 if (reason
< STALE_MUST_REVALIDATE
)
536 /* Does not need refresh. This is certainly cachable */
539 if (entry
->lastModified() < 0)
540 /* We should know entry's modification time to do a refresh */
543 if (entry
->mem_obj
== nullptr)
547 if (entry
->mem_obj
->baseReply().content_length
== 0)
548 /* No use refreshing (caching?) 0 byte objects */
551 /* This seems to be refreshable. Cache it */
555 /// whether reply is stale if it is a hit
557 refreshIsStaleIfHit(const int reason
)
561 case FRESH_LMFACTOR_RULE
:
570 * Protocol-specific wrapper around refreshCheck() function.
572 * Note the reason for STALE/FRESH then return true/false respectively.
577 * Do not call this when StoreClient::didCollapse is true. XXX: Callers should
578 * not have to remember to check didCollapse. TODO: Refactor by adding something
579 * like pure virtual StoreClient::refreshCheck() with protocol specializations?
582 refreshCheckHTTP(const StoreEntry
* entry
, HttpRequest
* request
)
584 int reason
= refreshCheck(entry
, request
, 0);
585 ++ refreshCounts
[rcHTTP
].total
;
586 ++ refreshCounts
[rcHTTP
].status
[reason
];
587 request
->flags
.staleIfHit
= refreshIsStaleIfHit(reason
);
588 return (Config
.onoff
.offline
|| reason
< 200) ? 0 : 1;
591 /// \see int refreshCheckHTTP(const StoreEntry * entry, HttpRequest * request)
593 refreshCheckICP(const StoreEntry
* entry
, HttpRequest
* request
)
595 int reason
= refreshCheck(entry
, request
, 30);
596 ++ refreshCounts
[rcICP
].total
;
597 ++ refreshCounts
[rcICP
].status
[reason
];
598 return (reason
< 200) ? 0 : 1;
602 /// \see int refreshCheckHTTP(const StoreEntry * entry, HttpRequest * request)
604 refreshCheckHTCP(const StoreEntry
* entry
, HttpRequest
* request
)
606 int reason
= refreshCheck(entry
, request
, 10);
607 ++ refreshCounts
[rcHTCP
].total
;
608 ++ refreshCounts
[rcHTCP
].status
[reason
];
609 return (reason
< 200) ? 0 : 1;
614 #if USE_CACHE_DIGESTS
615 /// \see int refreshCheckHTTP(const StoreEntry * entry, HttpRequest * request)
617 refreshCheckDigest(const StoreEntry
* entry
, time_t delta
)
619 int reason
= refreshCheck(entry
,
620 entry
->mem_obj
? entry
->mem_obj
->request
.getRaw() : nullptr,
622 ++ refreshCounts
[rcCDigest
].total
;
623 ++ refreshCounts
[rcCDigest
].status
[reason
];
624 return (reason
< 200) ? 0 : 1;
629 * Get the configured maximum caching time for objects with this URL
630 * according to refresh_pattern.
632 * Used by http.cc when generating a upstream requests to ensure that
633 * responses it is given are fresh enough to be worth caching.
635 * \retval pattern-max if there is a refresh_pattern matching the URL configured.
636 * \retval REFRESH_DEFAULT_MAX if there are no explicit limits configured
639 getMaxAge(const char *url
)
641 const RefreshPattern
*R
;
642 debugs(22, 3, "getMaxAge: '" << url
<< "'");
644 if ((R
= refreshLimits(url
)))
647 return REFRESH_DEFAULT_MAX
;
651 refreshCountsStatsEntry(StoreEntry
* sentry
, struct RefreshCounts
&rc
, int code
, const char *desc
)
653 storeAppendPrintf(sentry
, "%6d\t%6.2f\t%s\n", rc
.status
[code
], xpercent(rc
.status
[code
], rc
.total
), desc
);
654 return rc
.status
[code
];
658 refreshCountsStats(StoreEntry
* sentry
, struct RefreshCounts
&rc
)
663 storeAppendPrintf(sentry
, "\n\n%s histogram:\n", rc
.proto
);
664 storeAppendPrintf(sentry
, "Count\t%%Total\tCategory\n");
666 refreshCountsStatsEntry(sentry
, rc
, FRESH_REQUEST_MAX_STALE_ALL
, "Fresh: request max-stale wildcard");
667 refreshCountsStatsEntry(sentry
, rc
, FRESH_REQUEST_MAX_STALE_VALUE
, "Fresh: request max-stale value");
668 refreshCountsStatsEntry(sentry
, rc
, FRESH_EXPIRES
, "Fresh: expires time not reached");
669 refreshCountsStatsEntry(sentry
, rc
, FRESH_LMFACTOR_RULE
, "Fresh: refresh_pattern last-mod factor percentage");
670 refreshCountsStatsEntry(sentry
, rc
, FRESH_MIN_RULE
, "Fresh: refresh_pattern min value");
671 refreshCountsStatsEntry(sentry
, rc
, FRESH_OVERRIDE_EXPIRES
, "Fresh: refresh_pattern override-expires");
672 refreshCountsStatsEntry(sentry
, rc
, FRESH_OVERRIDE_LASTMOD
, "Fresh: refresh_pattern override-lastmod");
673 refreshCountsStatsEntry(sentry
, rc
, STALE_MUST_REVALIDATE
, "Stale: response has must-revalidate");
674 refreshCountsStatsEntry(sentry
, rc
, STALE_RELOAD_INTO_IMS
, "Stale: changed reload into IMS");
675 refreshCountsStatsEntry(sentry
, rc
, STALE_FORCED_RELOAD
, "Stale: request has no-cache directive");
676 refreshCountsStatsEntry(sentry
, rc
, STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE
, "Stale: age exceeds request max-age value");
677 refreshCountsStatsEntry(sentry
, rc
, STALE_EXPIRES
, "Stale: expires time reached");
678 refreshCountsStatsEntry(sentry
, rc
, STALE_MAX_RULE
, "Stale: refresh_pattern max age rule");
679 refreshCountsStatsEntry(sentry
, rc
, STALE_LMFACTOR_RULE
, "Stale: refresh_pattern last-mod factor percentage");
680 refreshCountsStatsEntry(sentry
, rc
, STALE_DEFAULT
, "Stale: by default");
681 storeAppendPrintf(sentry
, "\n");
685 refreshStats(StoreEntry
* sentry
)
687 // display per-rule counts of usage and tests
688 storeAppendPrintf(sentry
, "\nRefresh pattern usage:\n\n");
689 storeAppendPrintf(sentry
, " Used \tChecks \t%% Matches\tPattern\n");
690 for (const RefreshPattern
*R
= Config
.Refresh
; R
; R
= R
->next
) {
691 storeAppendPrintf(sentry
, " %10" PRIu64
"\t%10" PRIu64
"\t%6.2f\t",
694 xpercent(R
->stats
.matchCount
, R
->stats
.matchTests
));
695 PackableStream
os(*sentry
);
703 /* get total usage count */
705 for (i
= 0; i
< rcCount
; ++i
)
706 total
+= refreshCounts
[i
].total
;
708 /* protocol usage histogram */
709 storeAppendPrintf(sentry
, "\nRefreshCheck calls per protocol\n\n");
711 storeAppendPrintf(sentry
, "Protocol\t#Calls\t%%Calls\n");
713 for (i
= 0; i
< rcCount
; ++i
)
714 storeAppendPrintf(sentry
, "%10s\t%6d\t%6.2f\n",
715 refreshCounts
[i
].proto
,
716 refreshCounts
[i
].total
,
717 xpercent(refreshCounts
[i
].total
, total
));
719 /* per protocol histograms */
720 storeAppendPrintf(sentry
, "\n\nRefreshCheck histograms for various protocols\n");
722 for (i
= 0; i
< rcCount
; ++i
)
723 refreshCountsStats(sentry
, refreshCounts
[i
]);
727 RefreshPattern::regex() const
734 RefreshPattern::printPattern(std::ostream
&os
) const
737 regex_
->print(os
, nullptr); // refresh lines do not inherit line flags
743 RefreshPattern::printHead(std::ostream
&os
) const
747 // these adjustments are safe: raw values were configured using integers
748 ' ' << intmax_t(min
/60) << // to minutes
749 ' ' << intmax_t(100.0 * pct
+ 0.5) << '%' << // to percentage points
750 ' ' << intmax_t(max
/60); // to minutes
754 refreshRegisterWithCacheManager(void)
756 Mgr::RegisterAction("refresh", "Refresh Algorithm Statistics", refreshStats
, 0, 1);
762 memset(refreshCounts
, 0, sizeof(refreshCounts
));
763 refreshCounts
[rcHTTP
].proto
= "HTTP";
764 refreshCounts
[rcICP
].proto
= "ICP";
767 refreshCounts
[rcHTCP
].proto
= "HTCP";
770 refreshCounts
[rcStore
].proto
= "On Store";
771 #if USE_CACHE_DIGESTS
773 refreshCounts
[rcCDigest
].proto
= "Cache Digests";
776 refreshRegisterWithCacheManager();