]>
Commit | Line | Data |
---|---|---|
e4e6a8db | 1 | |
cbe3a719 | 2 | |
e4e6a8db | 3 | /* |
92695e5e | 4 | * $Id: refresh.cc,v 1.33 1998/08/21 03:15: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 | ||
1c3e77cd | 43 | struct { |
44 | int total; | |
45 | int revalidate_stale; | |
46 | int request_max_age_stale; | |
47 | int response_expires_stale; | |
48 | int response_expires_fresh; | |
49 | int conf_max_age_stale; | |
50 | int last_modified_factor_fresh; | |
51 | int last_modified_factor_stale; | |
52 | int conf_min_age_fresh; | |
53 | int default_stale; | |
54 | } refreshCounts; | |
55 | ||
e4e6a8db | 56 | /* |
57 | * Defaults: | |
58 | * MIN NONE | |
59 | * PCT 20% | |
60 | * MAX 3 days | |
61 | */ | |
48f44632 | 62 | #define REFRESH_DEFAULT_MIN (time_t)0 |
c3f6d204 | 63 | #define REFRESH_DEFAULT_PCT 0.20 |
48f44632 | 64 | #define REFRESH_DEFAULT_MAX (time_t)259200 |
e4e6a8db | 65 | |
0cdcddb9 | 66 | static const refresh_t *refreshLimits(const char *); |
2b5133db | 67 | static const refresh_t *refreshUncompiledPattern(const char *); |
1c3e77cd | 68 | static OBJH refreshStats; |
2b5133db | 69 | |
6018f0de | 70 | static const refresh_t * |
71 | refreshLimits(const char *url) | |
72 | { | |
73 | const refresh_t *R; | |
74 | for (R = Config.Refresh; R; R = R->next) { | |
75 | if (!regexec(&(R->compiled_pattern), url, 0, 0, 0)) | |
76 | return R; | |
77 | } | |
78 | return NULL; | |
79 | } | |
80 | ||
2b5133db | 81 | static const refresh_t * |
82 | refreshUncompiledPattern(const char *pat) | |
83 | { | |
84 | const refresh_t *R; | |
85 | for (R = Config.Refresh; R; R = R->next) { | |
86 | if (0 == strcmp(R->pattern, pat)) | |
87 | return R; | |
88 | } | |
89 | return NULL; | |
90 | } | |
91 | ||
e4e6a8db | 92 | /* |
93 | * refreshCheck(): | |
94 | * return 1 if its time to revalidate this entry, 0 otherwise | |
95 | */ | |
96 | int | |
2a24c297 | 97 | refreshCheck(const StoreEntry * entry, request_t * request, time_t delta) |
e4e6a8db | 98 | { |
6018f0de | 99 | const refresh_t *R; |
9b5d1d21 | 100 | const char *uri; |
e4e6a8db | 101 | time_t min = REFRESH_DEFAULT_MIN; |
c3f6d204 | 102 | double pct = REFRESH_DEFAULT_PCT; |
e4e6a8db | 103 | time_t max = REFRESH_DEFAULT_MAX; |
1dfa1d81 | 104 | int override_expire = 0; |
105 | int override_lastmod = 0; | |
cbe3a719 | 106 | int reload_into_ims = 0; |
107 | int ignore_reload = 0; | |
0ee4272b | 108 | const char *pattern = "."; |
e4e6a8db | 109 | time_t age; |
c3f6d204 | 110 | double factor; |
a207429f | 111 | time_t check_time = squid_curtime + delta; |
9b5d1d21 | 112 | if (entry->mem_obj) |
113 | uri = entry->mem_obj->url; | |
114 | else | |
115 | uri = urlCanonical(request); | |
116 | debug(22, 3) ("refreshCheck: '%s'\n", uri); | |
1c3e77cd | 117 | refreshCounts.total++; |
79a15e0a | 118 | if (EBIT_TEST(entry->flag, ENTRY_REVALIDATE)) { |
a47b9029 | 119 | debug(22, 3) ("refreshCheck: YES: Required Authorization\n"); |
1c3e77cd | 120 | refreshCounts.revalidate_stale++; |
c54e9052 | 121 | return 1; |
122 | } | |
9b5d1d21 | 123 | if ((R = refreshLimits(uri))) { |
e4e6a8db | 124 | min = R->min; |
125 | pct = R->pct; | |
126 | max = R->max; | |
127 | pattern = R->pattern; | |
1dfa1d81 | 128 | override_expire = R->flags.override_expire; |
129 | override_lastmod = R->flags.override_lastmod; | |
cbe3a719 | 130 | reload_into_ims = R->flags.reload_into_ims; |
131 | ignore_reload = R->flags.ignore_reload; | |
e4e6a8db | 132 | } |
cbe3a719 | 133 | if (!reload_into_ims) |
134 | reload_into_ims = Config.onoff.reload_into_ims; | |
a3d5953d | 135 | debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n", |
c3f6d204 | 136 | pattern, (int) min, (int) (100.0 * pct), (int) max); |
a207429f | 137 | age = check_time - entry->timestamp; |
a3d5953d | 138 | debug(22, 3) ("refreshCheck: age = %d\n", (int) age); |
49d3fcb0 | 139 | debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time)); |
140 | debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry->timestamp)); | |
92695e5e | 141 | if (request->flags.nocache_hack) { |
cbe3a719 | 142 | if (ignore_reload) { |
143 | /* The clients no-cache header is ignored */ | |
144 | debug(22, 3) ("refreshCheck: MAYBE: ignore-reload\n"); | |
145 | } else if (reload_into_ims) { | |
146 | /* The clients no-cache header is changed into a IMS query */ | |
147 | debug(22, 3) ("refreshCheck: YES: reload-into-ims\n"); | |
148 | return 1; | |
149 | } else { | |
150 | /* The clients no-cache header is not overridden on this request */ | |
151 | debug(22, 3) ("refreshCheck: YES: client reload\n"); | |
92695e5e | 152 | request->flags.nocache = 1; |
cbe3a719 | 153 | return 1; |
154 | } | |
155 | } | |
48f44632 | 156 | if (request->max_age > -1) { |
157 | if (age > request->max_age) { | |
a3d5953d | 158 | debug(22, 3) ("refreshCheck: YES: age > client-max-age\n"); |
1c3e77cd | 159 | refreshCounts.request_max_age_stale++; |
48f44632 | 160 | return 1; |
161 | } | |
162 | } | |
1dfa1d81 | 163 | if (override_expire && age <= min) { |
164 | debug(22, 3) ("refreshCheck: NO: age < min && override_expire\n"); | |
165 | return 0; | |
166 | } | |
1c3e77cd | 167 | if (entry->expires > -1) { |
a207429f | 168 | if (entry->expires <= check_time) { |
a3d5953d | 169 | debug(22, 3) ("refreshCheck: YES: expires <= curtime\n"); |
1c3e77cd | 170 | refreshCounts.response_expires_stale++; |
34308e0f | 171 | return 1; |
172 | } else { | |
a3d5953d | 173 | debug(22, 3) ("refreshCheck: NO: expires > curtime\n"); |
1c3e77cd | 174 | refreshCounts.response_expires_fresh++; |
34308e0f | 175 | return 0; |
176 | } | |
e4e6a8db | 177 | } |
178 | if (age > max) { | |
a3d5953d | 179 | debug(22, 3) ("refreshCheck: YES: age > max\n"); |
1c3e77cd | 180 | refreshCounts.conf_max_age_stale++; |
e4e6a8db | 181 | return 1; |
182 | } | |
1dfa1d81 | 183 | if (override_lastmod && age <= min) { |
184 | debug(22, 3) ("refreshCheck: NO: age < min && override_lastmod\n"); | |
185 | return 0; | |
186 | } | |
1c3e77cd | 187 | if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) { |
188 | factor = (double) age / (double) (entry->timestamp - entry->lastmod); | |
189 | debug(22, 3) ("refreshCheck: factor = %f\n", factor); | |
190 | if (factor < pct) { | |
191 | debug(22, 3) ("refreshCheck: NO: factor < pct\n"); | |
192 | refreshCounts.last_modified_factor_fresh++; | |
0d508d5b | 193 | return 0; |
1c3e77cd | 194 | } else { |
195 | debug(22, 3) ("refreshCheck: YES: factor >= pct\n"); | |
196 | refreshCounts.last_modified_factor_stale++; | |
197 | return 1; | |
0d508d5b | 198 | } |
e4e6a8db | 199 | } |
1c3e77cd | 200 | if (age <= min) { |
201 | debug(22, 3) ("refreshCheck: NO: age < min\n"); | |
202 | refreshCounts.conf_min_age_fresh++; | |
0d508d5b | 203 | return 0; |
e4e6a8db | 204 | } |
5c1c8975 | 205 | debug(22, 3) ("refreshCheck: YES: default stale\n"); |
1c3e77cd | 206 | refreshCounts.default_stale++; |
0d508d5b | 207 | return 1; |
e4e6a8db | 208 | } |
48f44632 | 209 | |
6018f0de | 210 | /* returns an approximate time when refreshCheck() may return true */ |
211 | time_t | |
212 | refreshWhen(const StoreEntry * entry) | |
213 | { | |
214 | const refresh_t *R; | |
215 | time_t refresh_time = squid_curtime; | |
216 | time_t min = REFRESH_DEFAULT_MIN; | |
217 | time_t max = REFRESH_DEFAULT_MAX; | |
c3f6d204 | 218 | double pct = REFRESH_DEFAULT_PCT; |
6018f0de | 219 | const char *pattern = "."; |
2b5133db | 220 | if (entry->mem_obj) { |
221 | assert(entry->mem_obj->url); | |
222 | debug(22, 3) ("refreshWhen: key '%s'\n", storeKeyText(entry->key)); | |
223 | debug(22, 3) ("refreshWhen: url '%s'\n", entry->mem_obj->url); | |
224 | if (EBIT_TEST(entry->flag, ENTRY_REVALIDATE)) { | |
225 | debug(22, 3) ("refreshWhen: NOW: Required Authorization\n"); | |
226 | return refresh_time; | |
227 | } | |
228 | debug(22, 3) ("refreshWhen: entry: exp: %d, tstamp: %d, lmt: %d\n", | |
229 | entry->expires, entry->timestamp, entry->lastmod); | |
230 | R = refreshLimits(entry->mem_obj->url); | |
231 | } else { | |
232 | R = refreshUncompiledPattern("."); | |
6018f0de | 233 | } |
2b5133db | 234 | if (R != NULL) { |
6018f0de | 235 | min = R->min; |
236 | max = R->max; | |
237 | pct = R->pct; | |
238 | pattern = R->pattern; | |
239 | } | |
240 | debug(22, 3) ("refreshWhen: Matched '%s %d %d%% %d'\n", | |
c3f6d204 | 241 | pattern, (int) min, (int) (100.0 * pct), (int) max); |
6018f0de | 242 | /* convert to absolute numbers */ |
243 | min += entry->timestamp; | |
244 | max += entry->timestamp; | |
245 | if (-1 < entry->expires) { | |
246 | debug(22, 3) ("refreshWhen: expires set\n"); | |
247 | refresh_time = entry->expires; | |
4b4cd312 | 248 | } else if (entry->timestamp <= entry->lastmod) { |
6018f0de | 249 | debug(22, 3) ("refreshWhen: lastvalid <= lastmod\n"); |
250 | refresh_time = squid_curtime; | |
251 | } else { | |
c3f6d204 | 252 | refresh_time = (entry->timestamp - entry->lastmod) * pct + entry->timestamp; |
6018f0de | 253 | debug(22, 3) ("refreshWhen: using refresh pct\n"); |
254 | } | |
255 | /* take min/max into account, max takes priority over min */ | |
256 | if (refresh_time < min) | |
257 | refresh_time = min; | |
258 | if (refresh_time > max) | |
259 | refresh_time = max; | |
260 | debug(22, 3) ("refreshWhen: answer: %d (in %d secs)\n", | |
4b4cd312 | 261 | refresh_time, (int) (refresh_time - squid_curtime)); |
6018f0de | 262 | return refresh_time; |
263 | } | |
264 | ||
48f44632 | 265 | time_t |
266 | getMaxAge(const char *url) | |
267 | { | |
6018f0de | 268 | const refresh_t *R; |
a3d5953d | 269 | debug(22, 3) ("getMaxAge: '%s'\n", url); |
6018f0de | 270 | if ((R = refreshLimits(url))) |
271 | return R->max; | |
272 | else | |
273 | return REFRESH_DEFAULT_MAX; | |
48f44632 | 274 | } |
1c3e77cd | 275 | |
276 | static void | |
277 | refreshStats(StoreEntry * sentry) | |
278 | { | |
279 | storeAppendPrintf(sentry, "refreshCounts.total\t%d\n", | |
280 | refreshCounts.total); | |
281 | storeAppendPrintf(sentry, "refreshCounts.revalidate_stale\t%d\n", | |
282 | refreshCounts.revalidate_stale); | |
283 | storeAppendPrintf(sentry, "refreshCounts.request_max_age_stale\t%d\n", | |
284 | refreshCounts.request_max_age_stale); | |
285 | storeAppendPrintf(sentry, "refreshCounts.response_expires_stale\t%d\n", | |
286 | refreshCounts.response_expires_stale); | |
287 | storeAppendPrintf(sentry, "refreshCounts.response_expires_fresh\t%d\n", | |
288 | refreshCounts.response_expires_fresh); | |
289 | storeAppendPrintf(sentry, "refreshCounts.conf_max_age_stale\t%d\n", | |
290 | refreshCounts.conf_max_age_stale); | |
291 | storeAppendPrintf(sentry, "refreshCounts.last_modified_factor_fresh\t%d\n", | |
292 | refreshCounts.last_modified_factor_fresh); | |
293 | storeAppendPrintf(sentry, "refreshCounts.last_modified_factor_stale\t%d\n", | |
294 | refreshCounts.last_modified_factor_stale); | |
295 | storeAppendPrintf(sentry, "refreshCounts.conf_min_age_fresh\t%d\n", | |
296 | refreshCounts.conf_min_age_fresh); | |
297 | storeAppendPrintf(sentry, "refreshCounts.default_stale\t%d\n", | |
298 | refreshCounts.default_stale); | |
299 | } | |
300 | ||
301 | void | |
302 | refreshInit(void) | |
303 | { | |
304 | cachemgrRegister("refresh", | |
305 | "Refresh Algorithm Statistics", | |
306 | refreshStats, | |
307 | 0, | |
308 | 1); | |
309 | } |