]>
Commit | Line | Data |
---|---|---|
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 | 43 | typedef enum { |
44 | rcHTTP, rcICP, rcCDigest, rcCount | |
45 | } refreshCountsEnum; | |
829a9357 | 46 | |
47 | static 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 | 79 | static const refresh_t *refreshLimits(const char *); |
2b5133db | 80 | static const refresh_t *refreshUncompiledPattern(const char *); |
1c3e77cd | 81 | static OBJH refreshStats; |
2b5133db | 82 | |
6018f0de | 83 | static const refresh_t * |
84 | refreshLimits(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 | 94 | static const refresh_t * |
95 | refreshUncompiledPattern(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 | 110 | static int |
111 | refreshCheck(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 | ||
255 | int | |
7d47d8e6 | 256 | refreshCheckHTTP(const StoreEntry * entry, request_t * request) |
257 | { | |
42125db6 | 258 | return refreshCheck(entry, request, 0, &refreshCounts[rcHTTP]); |
829a9357 | 259 | } |
260 | ||
261 | int | |
7d47d8e6 | 262 | refreshCheckICP(const StoreEntry * entry, request_t * request) |
263 | { | |
42125db6 | 264 | return refreshCheck(entry, request, 30, &refreshCounts[rcICP]); |
829a9357 | 265 | } |
266 | ||
267 | int | |
7d47d8e6 | 268 | refreshCheckDigest(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 | 276 | time_t |
277 | getMaxAge(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 | 287 | static void |
288 | refreshCountsStats(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 | 323 | static void |
324 | refreshStats(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 | ||
348 | void | |
829a9357 | 349 | refreshInit() |
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 | } |