]> git.ipfire.org Git - thirdparty/squid.git/blame - src/refresh.cc
2.1 branch merge
[thirdparty/squid.git] / src / refresh.cc
CommitLineData
e4e6a8db 1
cbe3a719 2
e4e6a8db 3/*
c68e9c6b 4 * $Id: refresh.cc,v 1.44 1998/11/12 06:28:23 wessels Exp $
e4e6a8db 5 *
6 * DEBUG: section 22 Refresh Calculation
7 * AUTHOR: Harvest Derived
8 *
42c04c16 9 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 10 * ----------------------------------------------------------
e4e6a8db 11 *
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
e25c139f 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.
e4e6a8db 20 *
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.
25 *
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.
30 *
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
cbdec147 33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 34 *
e4e6a8db 35 */
36
37#ifndef USE_POSIX_REGEX
38#define USE_POSIX_REGEX /* put before includes; always use POSIX */
39#endif
40
41#include "squid.h"
42
7d47d8e6 43typedef enum {
44 rcHTTP, rcICP, rcCDigest, rcCount
45} refreshCountsEnum;
829a9357 46
47static struct RefreshCounts {
48 const char *proto;
1c3e77cd 49 int total;
50 int revalidate_stale;
51 int request_max_age_stale;
cc7cfa8e 52 int request_reload2ims_stale;
53 int request_reload_stale;
54 int min_age_override_exp_fresh;
55 int min_age_override_lmt_fresh;
1c3e77cd 56 int response_expires_stale;
57 int response_expires_fresh;
58 int conf_max_age_stale;
59 int last_modified_factor_fresh;
60 int last_modified_factor_stale;
e76b47f2 61 int response_lmt_now_stale;
1c3e77cd 62 int conf_min_age_fresh;
63 int default_stale;
8e1fb1a1 64 /* maybe-counters -- intermediate decisions that may affect the result */
65 int request_reload_ignore_maybe;
66 int response_lmt_future_maybe;
829a9357 67} refreshCounts[rcCount];
1c3e77cd 68
e4e6a8db 69/*
70 * Defaults:
71 * MIN NONE
72 * PCT 20%
73 * MAX 3 days
74 */
48f44632 75#define REFRESH_DEFAULT_MIN (time_t)0
c3f6d204 76#define REFRESH_DEFAULT_PCT 0.20
48f44632 77#define REFRESH_DEFAULT_MAX (time_t)259200
e4e6a8db 78
0cdcddb9 79static const refresh_t *refreshLimits(const char *);
2b5133db 80static const refresh_t *refreshUncompiledPattern(const char *);
1c3e77cd 81static OBJH refreshStats;
2b5133db 82
6018f0de 83static const refresh_t *
84refreshLimits(const char *url)
85{
86 const refresh_t *R;
87 for (R = Config.Refresh; R; R = R->next) {
88 if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
89 return R;
90 }
91 return NULL;
92}
93
2b5133db 94static const refresh_t *
95refreshUncompiledPattern(const char *pat)
96{
97 const refresh_t *R;
98 for (R = Config.Refresh; R; R = R->next) {
99 if (0 == strcmp(R->pattern, pat))
100 return R;
101 }
102 return NULL;
103}
104
829a9357 105/* return 1 if the entry must be revalidated within delta seconds
106 * 0 otherwise
107 *
108 * note: request maybe null (e.g. for cache digests build)
e4e6a8db 109 */
829a9357 110static int
111refreshCheck(const StoreEntry * entry, request_t * request, time_t delta, struct RefreshCounts *rc)
e4e6a8db 112{
6018f0de 113 const refresh_t *R;
829a9357 114 const char *uri = NULL;
e4e6a8db 115 time_t min = REFRESH_DEFAULT_MIN;
c3f6d204 116 double pct = REFRESH_DEFAULT_PCT;
e4e6a8db 117 time_t max = REFRESH_DEFAULT_MAX;
9f60cfdf 118#if HTTP_VIOLATIONS
1dfa1d81 119 int override_expire = 0;
120 int override_lastmod = 0;
cbe3a719 121 int reload_into_ims = 0;
122 int ignore_reload = 0;
9f60cfdf 123#endif
829a9357 124 const char *pattern = "<none>";
e4e6a8db 125 time_t age;
c3f6d204 126 double factor;
a207429f 127 time_t check_time = squid_curtime + delta;
9b5d1d21 128 if (entry->mem_obj)
129 uri = entry->mem_obj->url;
7d47d8e6 130 else if (request)
9b5d1d21 131 uri = urlCanonical(request);
7d47d8e6 132
829a9357 133 debug(22, 3) ("refreshCheck(%s): '%s'\n", rc->proto, uri ? uri : "<none>");
134 rc->total++;
d46a87a8 135 if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE)) {
a47b9029 136 debug(22, 3) ("refreshCheck: YES: Required Authorization\n");
829a9357 137 rc->revalidate_stale++;
c54e9052 138 return 1;
139 }
829a9357 140 if ((R = uri ? refreshLimits(uri) : refreshUncompiledPattern("."))) {
e4e6a8db 141 min = R->min;
142 pct = R->pct;
143 max = R->max;
144 pattern = R->pattern;
9f60cfdf 145#if HTTP_VIOLATIONS
1dfa1d81 146 override_expire = R->flags.override_expire;
147 override_lastmod = R->flags.override_lastmod;
cbe3a719 148 reload_into_ims = R->flags.reload_into_ims;
149 ignore_reload = R->flags.ignore_reload;
9f60cfdf 150#endif
e4e6a8db 151 }
9f60cfdf 152#if HTTP_VIOLATIONS
cbe3a719 153 if (!reload_into_ims)
154 reload_into_ims = Config.onoff.reload_into_ims;
9f60cfdf 155#endif
a3d5953d 156 debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n",
c3f6d204 157 pattern, (int) min, (int) (100.0 * pct), (int) max);
a207429f 158 age = check_time - entry->timestamp;
a3d5953d 159 debug(22, 3) ("refreshCheck: age = %d\n", (int) age);
49d3fcb0 160 debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time));
161 debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry->timestamp));
829a9357 162 /* request-specific checks */
163 if (request) {
9f60cfdf 164#if HTTP_VIOLATIONS
829a9357 165 if (request->flags.nocache_hack) {
166 if (ignore_reload) {
167 /* The clients no-cache header is ignored */
168 debug(22, 3) ("refreshCheck: MAYBE: ignore-reload\n");
8e1fb1a1 169 rc->request_reload_ignore_maybe++;
829a9357 170 } else if (reload_into_ims) {
171 /* The clients no-cache header is changed into a IMS query */
172 debug(22, 3) ("refreshCheck: YES: reload-into-ims\n");
cc7cfa8e 173 rc->request_reload2ims_stale++;
829a9357 174 return 1;
175 } else {
176 /* The clients no-cache header is not overridden on this request */
177 debug(22, 3) ("refreshCheck: YES: client reload\n");
178 request->flags.nocache = 1;
cc7cfa8e 179 rc->request_reload_stale++;
829a9357 180 return 1;
181 }
cbe3a719 182 }
9f60cfdf 183#endif
829a9357 184 if (request->max_age > -1) {
185 if (age > request->max_age) {
186 debug(22, 3) ("refreshCheck: YES: age > client-max-age\n");
187 rc->request_max_age_stale++;
188 return 1;
189 }
48f44632 190 }
191 }
9f60cfdf 192#if HTTP_VIOLATIONS
1dfa1d81 193 if (override_expire && age <= min) {
194 debug(22, 3) ("refreshCheck: NO: age < min && override_expire\n");
cc7cfa8e 195 rc->min_age_override_exp_fresh++;
1dfa1d81 196 return 0;
197 }
9f60cfdf 198#endif
1c3e77cd 199 if (entry->expires > -1) {
a207429f 200 if (entry->expires <= check_time) {
a3d5953d 201 debug(22, 3) ("refreshCheck: YES: expires <= curtime\n");
829a9357 202 rc->response_expires_stale++;
34308e0f 203 return 1;
204 } else {
a3d5953d 205 debug(22, 3) ("refreshCheck: NO: expires > curtime\n");
829a9357 206 rc->response_expires_fresh++;
34308e0f 207 return 0;
208 }
e4e6a8db 209 }
210 if (age > max) {
a3d5953d 211 debug(22, 3) ("refreshCheck: YES: age > max\n");
829a9357 212 rc->conf_max_age_stale++;
e4e6a8db 213 return 1;
214 }
9f60cfdf 215#if HTTP_VIOLATIONS
1dfa1d81 216 if (override_lastmod && age <= min) {
217 debug(22, 3) ("refreshCheck: NO: age < min && override_lastmod\n");
cc7cfa8e 218 rc->min_age_override_lmt_fresh++;
1dfa1d81 219 return 0;
220 }
9f60cfdf 221#endif
1c3e77cd 222 if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
223 factor = (double) age / (double) (entry->timestamp - entry->lastmod);
224 debug(22, 3) ("refreshCheck: factor = %f\n", factor);
225 if (factor < pct) {
226 debug(22, 3) ("refreshCheck: NO: factor < pct\n");
829a9357 227 rc->last_modified_factor_fresh++;
0d508d5b 228 return 0;
1c3e77cd 229 } else {
230 debug(22, 3) ("refreshCheck: YES: factor >= pct\n");
829a9357 231 rc->last_modified_factor_stale++;
1c3e77cd 232 return 1;
0d508d5b 233 }
e76b47f2 234 } else if (entry->lastmod > -1 && entry->timestamp == entry->lastmod) {
235 debug(22, 3) ("refreshCheck: YES: last-modified 'now'\n");
236 rc->response_lmt_now_stale++;
237 return 1;
238 } else if (entry->lastmod > -1 && entry->timestamp < entry->lastmod) {
239 debug(22, 3) ("refreshCheck: MAYBE: last-modified in the future\n");
8e1fb1a1 240 rc->response_lmt_future_maybe++;
e4e6a8db 241 }
1c3e77cd 242 if (age <= min) {
cc7cfa8e 243 debug(22, 3) ("refreshCheck: NO: age <= min\n");
829a9357 244 rc->conf_min_age_fresh++;
0d508d5b 245 return 0;
e4e6a8db 246 }
5c1c8975 247 debug(22, 3) ("refreshCheck: YES: default stale\n");
829a9357 248 rc->default_stale++;
0d508d5b 249 return 1;
e4e6a8db 250}
48f44632 251
829a9357 252/* refreshCheck... functions below are protocol-specific wrappers around
253 * refreshCheck() function above */
254
255int
7d47d8e6 256refreshCheckHTTP(const StoreEntry * entry, request_t * request)
257{
42125db6 258 return refreshCheck(entry, request, 0, &refreshCounts[rcHTTP]);
829a9357 259}
260
261int
7d47d8e6 262refreshCheckICP(const StoreEntry * entry, request_t * request)
263{
42125db6 264 return refreshCheck(entry, request, 30, &refreshCounts[rcICP]);
829a9357 265}
266
267int
7d47d8e6 268refreshCheckDigest(const StoreEntry * entry, time_t delta)
269{
c68e9c6b 270 return refreshCheck(entry,
271 entry->mem_obj ? entry->mem_obj->request : NULL,
272 delta,
273 &refreshCounts[rcCDigest]);
6018f0de 274}
275
48f44632 276time_t
277getMaxAge(const char *url)
278{
6018f0de 279 const refresh_t *R;
a3d5953d 280 debug(22, 3) ("getMaxAge: '%s'\n", url);
6018f0de 281 if ((R = refreshLimits(url)))
282 return R->max;
283 else
284 return REFRESH_DEFAULT_MAX;
48f44632 285}
1c3e77cd 286
829a9357 287static void
288refreshCountsStats(StoreEntry * sentry, struct RefreshCounts *rc)
289{
cc7cfa8e 290 int sum = 0;
291 int tot = rc->total;
292
829a9357 293 storeAppendPrintf(sentry, "\n\n%s histogram:\n", rc->proto);
294 storeAppendPrintf(sentry, "Category\tCount\t%%Total\n");
295
cc7cfa8e 296#define refreshCountsStatsEntry(name) { \
297 if (rc->name || !strcmp(#name, "total")) \
298 storeAppendPrintf(sentry, "%s\t%6d\t%6.2f\n", \
299 #name, rc->name, xpercent(rc->name, tot)); \
300 sum += rc->name; \
301}
302 refreshCountsStatsEntry(revalidate_stale);
303 refreshCountsStatsEntry(request_reload2ims_stale);
304 refreshCountsStatsEntry(request_reload_stale);
305 refreshCountsStatsEntry(request_max_age_stale);
306 refreshCountsStatsEntry(min_age_override_exp_fresh);
307 refreshCountsStatsEntry(response_expires_stale);
308 refreshCountsStatsEntry(response_expires_fresh);
309 refreshCountsStatsEntry(conf_max_age_stale);
310 refreshCountsStatsEntry(min_age_override_lmt_fresh);
311 refreshCountsStatsEntry(last_modified_factor_fresh);
312 refreshCountsStatsEntry(last_modified_factor_stale);
e76b47f2 313 refreshCountsStatsEntry(response_lmt_now_stale);
cc7cfa8e 314 refreshCountsStatsEntry(conf_min_age_fresh);
315 refreshCountsStatsEntry(default_stale);
7d47d8e6 316 tot = sum; /* paranoid: "total" line shows 100% if we forgot nothing */
cc7cfa8e 317 refreshCountsStatsEntry(total);
8e1fb1a1 318 /* maybe counters */
319 refreshCountsStatsEntry(request_reload_ignore_maybe);
320 refreshCountsStatsEntry(response_lmt_future_maybe);
829a9357 321}
322
1c3e77cd 323static void
324refreshStats(StoreEntry * sentry)
325{
829a9357 326 int i;
327 int total = 0;
328
329 /* get total usage count */
330 for (i = 0; i < rcCount; ++i)
331 total += refreshCounts[i].total;
332
333 /* protocol usage histogram */
334 storeAppendPrintf(sentry, "\nRefreshCheck calls per protocol\n\n");
335 storeAppendPrintf(sentry, "Protocol\t#Calls\t%%Calls\n");
336 for (i = 0; i < rcCount; ++i)
337 storeAppendPrintf(sentry, "%10s\t%6d\t%6.2f\n",
338 refreshCounts[i].proto,
7d47d8e6 339 refreshCounts[i].total,
829a9357 340 xpercent(refreshCounts[i].total, total));
341
342 /* per protocol histograms */
343 storeAppendPrintf(sentry, "\n\nRefreshCheck histograms for various protocols\n");
344 for (i = 0; i < rcCount; ++i)
42125db6 345 refreshCountsStats(sentry, &refreshCounts[i]);
1c3e77cd 346}
347
348void
829a9357 349refreshInit()
1c3e77cd 350{
829a9357 351 memset(refreshCounts, 0, sizeof(refreshCounts));
352 refreshCounts[rcHTTP].proto = "HTTP";
353 refreshCounts[rcICP].proto = "ICP";
354 refreshCounts[rcCDigest].proto = "Cache Digests";
355
1c3e77cd 356 cachemgrRegister("refresh",
357 "Refresh Algorithm Statistics",
358 refreshStats,
359 0,
360 1);
361}