4 * $Id: refresh.cc,v 1.45 1998/11/13 20:50:56 wessels Exp $
6 * DEBUG: section 22 Refresh Calculation
7 * AUTHOR: Harvest Derived
9 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
10 * ----------------------------------------------------------
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
14 * National Laboratory for Applied Network Research and funded by the
15 * National Science Foundation. Squid is Copyrighted (C) 1998 by
16 * Duane Wessels and the University of California San Diego. Please
17 * see the COPYRIGHT file for full details. Squid incorporates
18 * software developed and/or copyrighted by other sources. Please see
19 * the CREDITS file for full details.
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 #ifndef USE_POSIX_REGEX
38 #define USE_POSIX_REGEX /* put before includes; always use POSIX */
44 rcHTTP
, rcICP
, rcCDigest
, rcCount
47 static struct RefreshCounts
{
51 int request_max_age_stale
;
52 int request_reload2ims_stale
;
53 int request_reload_stale
;
54 int negative_age_stale
;
55 int min_age_override_exp_fresh
;
56 int min_age_override_lmt_fresh
;
57 int response_expires_stale
;
58 int response_expires_fresh
;
59 int conf_max_age_stale
;
60 int last_modified_factor_fresh
;
61 int last_modified_factor_stale
;
62 int response_lmt_now_stale
;
63 int conf_min_age_fresh
;
65 /* maybe-counters -- intermediate decisions that may affect the result */
66 int request_reload_ignore_maybe
;
67 int response_lmt_future_maybe
;
68 } refreshCounts
[rcCount
];
76 #define REFRESH_DEFAULT_MIN (time_t)0
77 #define REFRESH_DEFAULT_PCT 0.20
78 #define REFRESH_DEFAULT_MAX (time_t)259200
80 static const refresh_t
*refreshLimits(const char *);
81 static const refresh_t
*refreshUncompiledPattern(const char *);
82 static OBJH refreshStats
;
84 static const refresh_t
*
85 refreshLimits(const char *url
)
88 for (R
= Config
.Refresh
; R
; R
= R
->next
) {
89 if (!regexec(&(R
->compiled_pattern
), url
, 0, 0, 0))
95 static const refresh_t
*
96 refreshUncompiledPattern(const char *pat
)
99 for (R
= Config
.Refresh
; R
; R
= R
->next
) {
100 if (0 == strcmp(R
->pattern
, pat
))
106 /* return 1 if the entry must be revalidated within delta seconds
109 * note: request maybe null (e.g. for cache digests build)
112 refreshCheck(const StoreEntry
* entry
, request_t
* request
, time_t delta
, struct RefreshCounts
*rc
)
115 const char *uri
= NULL
;
116 time_t min
= REFRESH_DEFAULT_MIN
;
117 double pct
= REFRESH_DEFAULT_PCT
;
118 time_t max
= REFRESH_DEFAULT_MAX
;
120 int override_expire
= 0;
121 int override_lastmod
= 0;
122 int reload_into_ims
= 0;
123 int ignore_reload
= 0;
125 const char *pattern
= "<none>";
128 time_t check_time
= squid_curtime
+ delta
;
130 uri
= entry
->mem_obj
->url
;
132 uri
= urlCanonical(request
);
134 debug(22, 3) ("refreshCheck(%s): '%s'\n", rc
->proto
, uri
? uri
: "<none>");
136 if (EBIT_TEST(entry
->flags
, ENTRY_REVALIDATE
)) {
137 debug(22, 3) ("refreshCheck: YES: Required Authorization\n");
138 rc
->revalidate_stale
++;
141 if ((R
= uri
? refreshLimits(uri
) : refreshUncompiledPattern("."))) {
145 pattern
= R
->pattern
;
147 override_expire
= R
->flags
.override_expire
;
148 override_lastmod
= R
->flags
.override_lastmod
;
149 reload_into_ims
= R
->flags
.reload_into_ims
;
150 ignore_reload
= R
->flags
.ignore_reload
;
154 if (!reload_into_ims
)
155 reload_into_ims
= Config
.onoff
.reload_into_ims
;
157 debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n",
158 pattern
, (int) min
, (int) (100.0 * pct
), (int) max
);
159 age
= check_time
- entry
->timestamp
;
160 debug(22, 3) ("refreshCheck: age = %d\n", (int) age
);
161 debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time
));
162 debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry
->timestamp
));
163 /* request-specific checks */
166 if (request
->flags
.nocache_hack
) {
168 /* The clients no-cache header is ignored */
169 debug(22, 3) ("refreshCheck: MAYBE: ignore-reload\n");
170 rc
->request_reload_ignore_maybe
++;
171 } else if (reload_into_ims
) {
172 /* The clients no-cache header is changed into a IMS query */
173 debug(22, 3) ("refreshCheck: YES: reload-into-ims\n");
174 rc
->request_reload2ims_stale
++;
177 /* The clients no-cache header is not overridden on this request */
178 debug(22, 3) ("refreshCheck: YES: client reload\n");
179 request
->flags
.nocache
= 1;
180 rc
->request_reload_stale
++;
186 debug(22, 3) ("refreshCheck: YES: age < 0\n");
187 rc
->negative_age_stale
++;
190 if (request
->max_age
> -1) {
191 if (age
> request
->max_age
) {
192 debug(22, 3) ("refreshCheck: YES: age > client-max-age\n");
193 rc
->request_max_age_stale
++;
199 if (override_expire
&& age
<= min
) {
200 debug(22, 3) ("refreshCheck: NO: age < min && override_expire\n");
201 rc
->min_age_override_exp_fresh
++;
205 if (entry
->expires
> -1) {
206 if (entry
->expires
<= check_time
) {
207 debug(22, 3) ("refreshCheck: YES: expires <= curtime\n");
208 rc
->response_expires_stale
++;
211 debug(22, 3) ("refreshCheck: NO: expires > curtime\n");
212 rc
->response_expires_fresh
++;
217 debug(22, 3) ("refreshCheck: YES: age > max\n");
218 rc
->conf_max_age_stale
++;
222 if (override_lastmod
&& age
<= min
) {
223 debug(22, 3) ("refreshCheck: NO: age < min && override_lastmod\n");
224 rc
->min_age_override_lmt_fresh
++;
228 if (entry
->lastmod
> -1 && entry
->timestamp
> entry
->lastmod
) {
229 factor
= (double) age
/ (double) (entry
->timestamp
- entry
->lastmod
);
230 debug(22, 3) ("refreshCheck: factor = %f\n", factor
);
232 debug(22, 3) ("refreshCheck: NO: factor < pct\n");
233 rc
->last_modified_factor_fresh
++;
236 debug(22, 3) ("refreshCheck: YES: factor >= pct\n");
237 rc
->last_modified_factor_stale
++;
240 } else if (entry
->lastmod
> -1 && entry
->timestamp
== entry
->lastmod
) {
241 debug(22, 3) ("refreshCheck: YES: last-modified 'now'\n");
242 rc
->response_lmt_now_stale
++;
244 } else if (entry
->lastmod
> -1 && entry
->timestamp
< entry
->lastmod
) {
245 debug(22, 3) ("refreshCheck: MAYBE: last-modified in the future\n");
246 rc
->response_lmt_future_maybe
++;
249 debug(22, 3) ("refreshCheck: NO: age <= min\n");
250 rc
->conf_min_age_fresh
++;
253 debug(22, 3) ("refreshCheck: YES: default stale\n");
258 /* refreshCheck... functions below are protocol-specific wrappers around
259 * refreshCheck() function above */
262 refreshCheckHTTP(const StoreEntry
* entry
, request_t
* request
)
264 return refreshCheck(entry
, request
, 0, &refreshCounts
[rcHTTP
]);
268 refreshCheckICP(const StoreEntry
* entry
, request_t
* request
)
270 return refreshCheck(entry
, request
, 30, &refreshCounts
[rcICP
]);
274 refreshCheckDigest(const StoreEntry
* entry
, time_t delta
)
276 return refreshCheck(entry
,
277 entry
->mem_obj
? entry
->mem_obj
->request
: NULL
,
279 &refreshCounts
[rcCDigest
]);
283 getMaxAge(const char *url
)
286 debug(22, 3) ("getMaxAge: '%s'\n", url
);
287 if ((R
= refreshLimits(url
)))
290 return REFRESH_DEFAULT_MAX
;
294 refreshCountsStats(StoreEntry
* sentry
, struct RefreshCounts
*rc
)
299 storeAppendPrintf(sentry
, "\n\n%s histogram:\n", rc
->proto
);
300 storeAppendPrintf(sentry
, "Category\tCount\t%%Total\n");
302 #define refreshCountsStatsEntry(name) { \
303 if (rc->name || !strcmp(#name, "total")) \
304 storeAppendPrintf(sentry, "%s\t%6d\t%6.2f\n", \
305 #name, rc->name, xpercent(rc->name, tot)); \
308 refreshCountsStatsEntry(revalidate_stale
);
309 refreshCountsStatsEntry(request_reload2ims_stale
);
310 refreshCountsStatsEntry(request_reload_stale
);
311 refreshCountsStatsEntry(request_max_age_stale
);
312 refreshCountsStatsEntry(min_age_override_exp_fresh
);
313 refreshCountsStatsEntry(response_expires_stale
);
314 refreshCountsStatsEntry(response_expires_fresh
);
315 refreshCountsStatsEntry(conf_max_age_stale
);
316 refreshCountsStatsEntry(min_age_override_lmt_fresh
);
317 refreshCountsStatsEntry(last_modified_factor_fresh
);
318 refreshCountsStatsEntry(last_modified_factor_stale
);
319 refreshCountsStatsEntry(response_lmt_now_stale
);
320 refreshCountsStatsEntry(conf_min_age_fresh
);
321 refreshCountsStatsEntry(default_stale
);
322 tot
= sum
; /* paranoid: "total" line shows 100% if we forgot nothing */
323 refreshCountsStatsEntry(total
);
325 refreshCountsStatsEntry(request_reload_ignore_maybe
);
326 refreshCountsStatsEntry(response_lmt_future_maybe
);
330 refreshStats(StoreEntry
* sentry
)
335 /* get total usage count */
336 for (i
= 0; i
< rcCount
; ++i
)
337 total
+= refreshCounts
[i
].total
;
339 /* protocol usage histogram */
340 storeAppendPrintf(sentry
, "\nRefreshCheck calls per protocol\n\n");
341 storeAppendPrintf(sentry
, "Protocol\t#Calls\t%%Calls\n");
342 for (i
= 0; i
< rcCount
; ++i
)
343 storeAppendPrintf(sentry
, "%10s\t%6d\t%6.2f\n",
344 refreshCounts
[i
].proto
,
345 refreshCounts
[i
].total
,
346 xpercent(refreshCounts
[i
].total
, total
));
348 /* per protocol histograms */
349 storeAppendPrintf(sentry
, "\n\nRefreshCheck histograms for various protocols\n");
350 for (i
= 0; i
< rcCount
; ++i
)
351 refreshCountsStats(sentry
, &refreshCounts
[i
]);
357 memset(refreshCounts
, 0, sizeof(refreshCounts
));
358 refreshCounts
[rcHTTP
].proto
= "HTTP";
359 refreshCounts
[rcICP
].proto
= "ICP";
360 refreshCounts
[rcCDigest
].proto
= "Cache Digests";
362 cachemgrRegister("refresh",
363 "Refresh Algorithm Statistics",