]> git.ipfire.org Git - thirdparty/squid.git/blob - src/refresh.cc
2.1 merge
[thirdparty/squid.git] / src / refresh.cc
1
2
3 /*
4 * $Id: refresh.cc,v 1.45 1998/11/13 20:50:56 wessels Exp $
5 *
6 * DEBUG: section 22 Refresh Calculation
7 * AUTHOR: Harvest Derived
8 *
9 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
10 * ----------------------------------------------------------
11 *
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.
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
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 *
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
43 typedef enum {
44 rcHTTP, rcICP, rcCDigest, rcCount
45 } refreshCountsEnum;
46
47 static struct RefreshCounts {
48 const char *proto;
49 int total;
50 int revalidate_stale;
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;
64 int default_stale;
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];
69
70 /*
71 * Defaults:
72 * MIN NONE
73 * PCT 20%
74 * MAX 3 days
75 */
76 #define REFRESH_DEFAULT_MIN (time_t)0
77 #define REFRESH_DEFAULT_PCT 0.20
78 #define REFRESH_DEFAULT_MAX (time_t)259200
79
80 static const refresh_t *refreshLimits(const char *);
81 static const refresh_t *refreshUncompiledPattern(const char *);
82 static OBJH refreshStats;
83
84 static const refresh_t *
85 refreshLimits(const char *url)
86 {
87 const refresh_t *R;
88 for (R = Config.Refresh; R; R = R->next) {
89 if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
90 return R;
91 }
92 return NULL;
93 }
94
95 static const refresh_t *
96 refreshUncompiledPattern(const char *pat)
97 {
98 const refresh_t *R;
99 for (R = Config.Refresh; R; R = R->next) {
100 if (0 == strcmp(R->pattern, pat))
101 return R;
102 }
103 return NULL;
104 }
105
106 /* return 1 if the entry must be revalidated within delta seconds
107 * 0 otherwise
108 *
109 * note: request maybe null (e.g. for cache digests build)
110 */
111 static int
112 refreshCheck(const StoreEntry * entry, request_t * request, time_t delta, struct RefreshCounts *rc)
113 {
114 const refresh_t *R;
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;
119 #if HTTP_VIOLATIONS
120 int override_expire = 0;
121 int override_lastmod = 0;
122 int reload_into_ims = 0;
123 int ignore_reload = 0;
124 #endif
125 const char *pattern = "<none>";
126 time_t age;
127 double factor;
128 time_t check_time = squid_curtime + delta;
129 if (entry->mem_obj)
130 uri = entry->mem_obj->url;
131 else if (request)
132 uri = urlCanonical(request);
133
134 debug(22, 3) ("refreshCheck(%s): '%s'\n", rc->proto, uri ? uri : "<none>");
135 rc->total++;
136 if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE)) {
137 debug(22, 3) ("refreshCheck: YES: Required Authorization\n");
138 rc->revalidate_stale++;
139 return 1;
140 }
141 if ((R = uri ? refreshLimits(uri) : refreshUncompiledPattern("."))) {
142 min = R->min;
143 pct = R->pct;
144 max = R->max;
145 pattern = R->pattern;
146 #if HTTP_VIOLATIONS
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;
151 #endif
152 }
153 #if HTTP_VIOLATIONS
154 if (!reload_into_ims)
155 reload_into_ims = Config.onoff.reload_into_ims;
156 #endif
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 */
164 if (request) {
165 #if HTTP_VIOLATIONS
166 if (request->flags.nocache_hack) {
167 if (ignore_reload) {
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++;
175 return 1;
176 } else {
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++;
181 return 1;
182 }
183 }
184 #endif
185 if (age < 0) {
186 debug(22, 3) ("refreshCheck: YES: age < 0\n");
187 rc->negative_age_stale++;
188 return 1;
189 }
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++;
194 return 1;
195 }
196 }
197 }
198 #if HTTP_VIOLATIONS
199 if (override_expire && age <= min) {
200 debug(22, 3) ("refreshCheck: NO: age < min && override_expire\n");
201 rc->min_age_override_exp_fresh++;
202 return 0;
203 }
204 #endif
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++;
209 return 1;
210 } else {
211 debug(22, 3) ("refreshCheck: NO: expires > curtime\n");
212 rc->response_expires_fresh++;
213 return 0;
214 }
215 }
216 if (age > max) {
217 debug(22, 3) ("refreshCheck: YES: age > max\n");
218 rc->conf_max_age_stale++;
219 return 1;
220 }
221 #if HTTP_VIOLATIONS
222 if (override_lastmod && age <= min) {
223 debug(22, 3) ("refreshCheck: NO: age < min && override_lastmod\n");
224 rc->min_age_override_lmt_fresh++;
225 return 0;
226 }
227 #endif
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);
231 if (factor < pct) {
232 debug(22, 3) ("refreshCheck: NO: factor < pct\n");
233 rc->last_modified_factor_fresh++;
234 return 0;
235 } else {
236 debug(22, 3) ("refreshCheck: YES: factor >= pct\n");
237 rc->last_modified_factor_stale++;
238 return 1;
239 }
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++;
243 return 1;
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++;
247 }
248 if (age <= min) {
249 debug(22, 3) ("refreshCheck: NO: age <= min\n");
250 rc->conf_min_age_fresh++;
251 return 0;
252 }
253 debug(22, 3) ("refreshCheck: YES: default stale\n");
254 rc->default_stale++;
255 return 1;
256 }
257
258 /* refreshCheck... functions below are protocol-specific wrappers around
259 * refreshCheck() function above */
260
261 int
262 refreshCheckHTTP(const StoreEntry * entry, request_t * request)
263 {
264 return refreshCheck(entry, request, 0, &refreshCounts[rcHTTP]);
265 }
266
267 int
268 refreshCheckICP(const StoreEntry * entry, request_t * request)
269 {
270 return refreshCheck(entry, request, 30, &refreshCounts[rcICP]);
271 }
272
273 int
274 refreshCheckDigest(const StoreEntry * entry, time_t delta)
275 {
276 return refreshCheck(entry,
277 entry->mem_obj ? entry->mem_obj->request : NULL,
278 delta,
279 &refreshCounts[rcCDigest]);
280 }
281
282 time_t
283 getMaxAge(const char *url)
284 {
285 const refresh_t *R;
286 debug(22, 3) ("getMaxAge: '%s'\n", url);
287 if ((R = refreshLimits(url)))
288 return R->max;
289 else
290 return REFRESH_DEFAULT_MAX;
291 }
292
293 static void
294 refreshCountsStats(StoreEntry * sentry, struct RefreshCounts *rc)
295 {
296 int sum = 0;
297 int tot = rc->total;
298
299 storeAppendPrintf(sentry, "\n\n%s histogram:\n", rc->proto);
300 storeAppendPrintf(sentry, "Category\tCount\t%%Total\n");
301
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)); \
306 sum += rc->name; \
307 }
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);
324 /* maybe counters */
325 refreshCountsStatsEntry(request_reload_ignore_maybe);
326 refreshCountsStatsEntry(response_lmt_future_maybe);
327 }
328
329 static void
330 refreshStats(StoreEntry * sentry)
331 {
332 int i;
333 int total = 0;
334
335 /* get total usage count */
336 for (i = 0; i < rcCount; ++i)
337 total += refreshCounts[i].total;
338
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));
347
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]);
352 }
353
354 void
355 refreshInit()
356 {
357 memset(refreshCounts, 0, sizeof(refreshCounts));
358 refreshCounts[rcHTTP].proto = "HTTP";
359 refreshCounts[rcICP].proto = "ICP";
360 refreshCounts[rcCDigest].proto = "Cache Digests";
361
362 cachemgrRegister("refresh",
363 "Refresh Algorithm Statistics",
364 refreshStats,
365 0,
366 1);
367 }