/*
- * $Id: refresh.cc,v 1.76 2007/05/24 01:45:03 hno Exp $
- *
* DEBUG: section 22 Refresh Calculation
* AUTHOR: Harvest Derived
*
#endif
#include "squid.h"
-#include "CacheManager.h"
-#include "Store.h"
-#include "MemObject.h"
+#include "mgr/Registration.h"
+#include "HttpHdrCc.h"
#include "HttpRequest.h"
#include "HttpReply.h"
+#include "MemObject.h"
+#include "RefreshPattern.h"
#include "SquidTime.h"
+#include "SquidConfig.h"
+#include "Store.h"
+#include "URL.h"
typedef enum {
rcHTTP,
STALE_EXPIRES,
STALE_MAX_RULE,
STALE_LMFACTOR_RULE,
+ STALE_MAX_STALE,
STALE_DEFAULT = 299
};
#define REFRESH_DEFAULT_PCT 0.20
#define REFRESH_DEFAULT_MAX (time_t)259200
-static const refresh_t *refreshUncompiledPattern(const char *);
+static const RefreshPattern *refreshUncompiledPattern(const char *);
static OBJH refreshStats;
-static int refreshStaleness(const StoreEntry *, time_t, time_t, const refresh_t *, stale_flags *);
+static int refreshStaleness(const StoreEntry * entry, time_t check_time, const time_t age, const RefreshPattern * R, stale_flags * sf);
-static refresh_t DefaultRefresh;
+static RefreshPattern DefaultRefresh;
-const refresh_t *
+const RefreshPattern *
refreshLimits(const char *url)
{
- const refresh_t *R;
+ const RefreshPattern *R;
for (R = Config.Refresh; R; R = R->next) {
if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
return NULL;
}
-static const refresh_t *
+static const RefreshPattern *
refreshUncompiledPattern(const char *pat)
{
- const refresh_t *R;
+ const RefreshPattern *R;
for (R = Config.Refresh; R; R = R->next) {
if (0 == strcmp(R->pattern, pat))
* times.
*/
static int
-refreshStaleness(const StoreEntry * entry, time_t check_time, time_t age, const refresh_t * R, stale_flags * sf)
+refreshStaleness(const StoreEntry * entry, time_t check_time, const time_t age, const RefreshPattern * R, stale_flags * sf)
{
/** \par
* Check for an explicit expiration time (Expires: header).
*/
-
if (entry->expires > -1) {
sf->expires = true;
}
}
- assert(age >= 0);
/** \par
* Use local heuristics to determine staleness. Start with the
* max age from the refresh_pattern rule.
*/
-
if (age > R->max) {
debugs(22, 3, "STALE: age " << age << " > max " << R->max << " ");
sf->max = true;
static int
refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
{
- const refresh_t *R;
+ const RefreshPattern *R;
const char *uri = NULL;
time_t age = 0;
time_t check_time = squid_curtime + delta;
debugs(22, 3, "refreshCheck: '" << (uri ? uri : "<none>") << "'");
- assert(age >= 0);
if (check_time > entry->timestamp)
age = check_time - entry->timestamp;
+ // FIXME: what to do when age < 0 or counter overflow?
assert(age >= 0);
+
R = uri ? refreshLimits(uri) : refreshUncompiledPattern(".");
if (NULL == R)
R = &DefaultRefresh;
- memset(&sf, '\0', sizeof(sf));
-
- assert(age >= 0);
- staleness = refreshStaleness(entry, check_time, age, R, &sf);
-
- debugs(22, 3, "Staleness = " << staleness);
-
debugs(22, 3, "refreshCheck: Matched '" << R->pattern << " " <<
(int) R->min << " " << (int) (100.0 * R->pct) << "%% " <<
(int) R->max << "'");
-
- debugs(22, 3, "refreshCheck: age = " << age);
+ debugs(22, 3, "\tage:\t" << age);
debugs(22, 3, "\tcheck_time:\t" << mkrfc1123(check_time));
debugs(22, 3, "\tentry->timestamp:\t" << mkrfc1123(entry->timestamp));
- if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1) {
+ if (request && !request->flags.ignore_cc) {
+ const HttpHdrCc *const cc = request->cache_control;
+ if (cc && cc->hasMinFresh()) {
+ const int32_t minFresh=cc->minFresh();
+ debugs(22, 3, "\tage + min-fresh:\t" << age << " + " <<
+ minFresh << " = " << age + minFresh);
+ debugs(22, 3, "\tcheck_time + min-fresh:\t" << check_time << " + "
+ << minFresh << " = " <<
+ mkrfc1123(check_time + minFresh));
+ age += minFresh;
+ check_time += minFresh;
+ }
+ }
+
+ memset(&sf, '\0', sizeof(sf));
+
+ staleness = refreshStaleness(entry, check_time, age, R, &sf);
+
+ debugs(22, 3, "Staleness = " << staleness);
+
+ // stale-if-error requires any failure be passed thru when its period is over.
+ if (request && entry->mem_obj && entry->mem_obj->getReply() && entry->mem_obj->getReply()->cache_control &&
+ entry->mem_obj->getReply()->cache_control->hasStaleIfError() &&
+ entry->mem_obj->getReply()->cache_control->staleIfError() < staleness) {
+
+ debugs(22, 3, "refreshCheck: stale-if-error period expired.");
+ request->flags.fail_on_validation_err = 1;
+ }
+
+ if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1
+#if USE_HTTP_VIOLATIONS
+ && !R->flags.ignore_must_revalidate
+#endif
+ ) {
debugs(22, 3, "refreshCheck: YES: Must revalidate stale response");
+ if (request)
+ request->flags.fail_on_validation_err = 1;
return STALE_MUST_REVALIDATE;
}
/* request-specific checks */
- if (request) {
+ if (request && !request->flags.ignore_cc) {
HttpHdrCc *cc = request->cache_control;
if (request->flags.ims && (R->flags.refresh_ims || Config.onoff.refresh_all_ims)) {
return STALE_FORCED_RELOAD;
}
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
if (!request->flags.nocache_hack) {
(void) 0;
#endif
if (NULL != cc) {
- if (cc->max_age > -1) {
-#if HTTP_VIOLATIONS
- if (R->flags.ignore_reload && cc->max_age == 0) {} else
+ if (cc->hasMaxAge()) {
+#if USE_HTTP_VIOLATIONS
+ if (R->flags.ignore_reload && cc->maxAge() == 0) {
+ debugs(22, 3, "refreshCheck: MAYBE: client-max-age = 0 and ignore-reload");
+ } else
#endif
{
-#if 0
-
- if (cc->max_age == 0) {
+ if (cc->maxAge() == 0) {
debugs(22, 3, "refreshCheck: YES: client-max-age = 0");
return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
}
-#endif
- if (age > cc->max_age) {
+ if (age > cc->maxAge()) {
debugs(22, 3, "refreshCheck: YES: age > client-max-age");
return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
}
}
}
- if (EBIT_TEST(cc->mask, CC_MAX_STALE) && staleness > -1) {
- if (cc->max_stale < 0) {
+ if (cc->hasMaxStale() && staleness > -1) {
+ if (cc->maxStale()==HttpHdrCc::MAX_STALE_ANY) {
/* max-stale directive without a value */
debugs(22, 3, "refreshCheck: NO: max-stale wildcard");
return FRESH_REQUEST_MAX_STALE_ALL;
- } else if (staleness < cc->max_stale) {
+ } else if (staleness < cc->maxStale()) {
debugs(22, 3, "refreshCheck: NO: staleness < max-stale");
return FRESH_REQUEST_MAX_STALE_VALUE;
}
/*
* At this point the response is stale, unless one of
* the override options kicks in.
+ * NOTE: max-stale config blocks the overrides.
*/
+ int max_stale = (R->max_stale >= 0 ? R->max_stale : Config.maxStale);
+ if ( max_stale >= 0 && staleness > max_stale) {
+ debugs(22, 3, "refreshCheck: YES: max-stale limit");
+ if (request)
+ request->flags.fail_on_validation_err = 1;
+ return STALE_MAX_STALE;
+ }
+
if (sf.expires) {
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
if (R->flags.override_expire && age < R->min) {
debugs(22, 3, "refreshCheck: NO: age < min && override-expire");
return STALE_MAX_RULE;
if (sf.lmfactor) {
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
if (R->flags.override_lastmod && age < R->min) {
debugs(22, 3, "refreshCheck: NO: age < min && override-lastmod");
* be refreshed.
*/
int reason = refreshCheck(entry, NULL, Config.minimum_expiry_time);
- refreshCounts[rcStore].total++;
- refreshCounts[rcStore].status[reason]++;
+ ++ refreshCounts[rcStore].total;
+ ++ refreshCounts[rcStore].status[reason];
if (reason < STALE_MUST_REVALIDATE)
/* Does not need refresh. This is certainly cachable */
return 1;
}
+/// whether reply is stale if it is a hit
+static bool
+refreshIsStaleIfHit(const int reason)
+{
+ switch (reason) {
+ case FRESH_MIN_RULE:
+ case FRESH_LMFACTOR_RULE:
+ case FRESH_EXPIRES:
+ return false;
+ default:
+ return true;
+ }
+}
+
/* refreshCheck... functions below are protocol-specific wrappers around
* refreshCheck() function above */
refreshCheckHTTP(const StoreEntry * entry, HttpRequest * request)
{
int reason = refreshCheck(entry, request, 0);
- refreshCounts[rcHTTP].total++;
- refreshCounts[rcHTTP].status[reason]++;
- return (reason < 200) ? 0 : 1;
+ ++ refreshCounts[rcHTTP].total;
+ ++ refreshCounts[rcHTTP].status[reason];
+ request->flags.stale_if_hit = refreshIsStaleIfHit(reason);
+ return (Config.onoff.offline || reason < 200) ? 0 : 1;
}
int
refreshCheckICP(const StoreEntry * entry, HttpRequest * request)
{
int reason = refreshCheck(entry, request, 30);
- refreshCounts[rcICP].total++;
- refreshCounts[rcICP].status[reason]++;
+ ++ refreshCounts[rcICP].total;
+ ++ refreshCounts[rcICP].status[reason];
return (reason < 200) ? 0 : 1;
}
refreshCheckHTCP(const StoreEntry * entry, HttpRequest * request)
{
int reason = refreshCheck(entry, request, 10);
- refreshCounts[rcHTCP].total++;
- refreshCounts[rcHTCP].status[reason]++;
+ ++ refreshCounts[rcHTCP].total;
+ ++ refreshCounts[rcHTCP].status[reason];
return (reason < 200) ? 0 : 1;
}
int reason = refreshCheck(entry,
entry->mem_obj ? entry->mem_obj->request : NULL,
delta);
- refreshCounts[rcCDigest].total++;
- refreshCounts[rcCDigest].status[reason]++;
+ ++ refreshCounts[rcCDigest].total;
+ ++ refreshCounts[rcCDigest].status[reason];
return (reason < 200) ? 0 : 1;
}
time_t
getMaxAge(const char *url)
{
- const refresh_t *R;
+ const RefreshPattern *R;
debugs(22, 3, "getMaxAge: '" << url << "'");
if ((R = refreshLimits(url)))
static void
refreshRegisterWithCacheManager(void)
{
- CacheManager::GetInstance()->
- registerAction("refresh", "Refresh Algorithm Statistics", refreshStats, 0, 1);
+ Mgr::RegisterAction("refresh", "Refresh Algorithm Statistics", refreshStats, 0, 1);
}
void