4 * $Id: refresh.cc,v 1.34 1998/08/21 04:03:48 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 */
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
;
62 #define REFRESH_DEFAULT_MIN (time_t)0
63 #define REFRESH_DEFAULT_PCT 0.20
64 #define REFRESH_DEFAULT_MAX (time_t)259200
66 static const refresh_t
*refreshLimits(const char *);
67 static const refresh_t
*refreshUncompiledPattern(const char *);
68 static OBJH refreshStats
;
70 static const refresh_t
*
71 refreshLimits(const char *url
)
74 for (R
= Config
.Refresh
; R
; R
= R
->next
) {
75 if (!regexec(&(R
->compiled_pattern
), url
, 0, 0, 0))
81 static const refresh_t
*
82 refreshUncompiledPattern(const char *pat
)
85 for (R
= Config
.Refresh
; R
; R
= R
->next
) {
86 if (0 == strcmp(R
->pattern
, pat
))
94 * return 1 if its time to revalidate this entry, 0 otherwise
97 refreshCheck(const StoreEntry
* entry
, request_t
* request
, time_t delta
)
101 time_t min
= REFRESH_DEFAULT_MIN
;
102 double pct
= REFRESH_DEFAULT_PCT
;
103 time_t max
= REFRESH_DEFAULT_MAX
;
105 int override_expire
= 0;
106 int override_lastmod
= 0;
107 int reload_into_ims
= 0;
108 int ignore_reload
= 0;
110 const char *pattern
= ".";
113 time_t check_time
= squid_curtime
+ delta
;
115 uri
= entry
->mem_obj
->url
;
117 uri
= urlCanonical(request
);
118 debug(22, 3) ("refreshCheck: '%s'\n", uri
);
119 refreshCounts
.total
++;
120 if (EBIT_TEST(entry
->flag
, ENTRY_REVALIDATE
)) {
121 debug(22, 3) ("refreshCheck: YES: Required Authorization\n");
122 refreshCounts
.revalidate_stale
++;
125 if ((R
= refreshLimits(uri
))) {
129 pattern
= R
->pattern
;
131 override_expire
= R
->flags
.override_expire
;
132 override_lastmod
= R
->flags
.override_lastmod
;
133 reload_into_ims
= R
->flags
.reload_into_ims
;
134 ignore_reload
= R
->flags
.ignore_reload
;
138 if (!reload_into_ims
)
139 reload_into_ims
= Config
.onoff
.reload_into_ims
;
141 debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n",
142 pattern
, (int) min
, (int) (100.0 * pct
), (int) max
);
143 age
= check_time
- entry
->timestamp
;
144 debug(22, 3) ("refreshCheck: age = %d\n", (int) age
);
145 debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time
));
146 debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry
->timestamp
));
148 if (request
->flags
.nocache_hack
) {
150 /* The clients no-cache header is ignored */
151 debug(22, 3) ("refreshCheck: MAYBE: ignore-reload\n");
152 } else if (reload_into_ims
) {
153 /* The clients no-cache header is changed into a IMS query */
154 debug(22, 3) ("refreshCheck: YES: reload-into-ims\n");
157 /* The clients no-cache header is not overridden on this request */
158 debug(22, 3) ("refreshCheck: YES: client reload\n");
159 request
->flags
.nocache
= 1;
164 if (request
->max_age
> -1) {
165 if (age
> request
->max_age
) {
166 debug(22, 3) ("refreshCheck: YES: age > client-max-age\n");
167 refreshCounts
.request_max_age_stale
++;
172 if (override_expire
&& age
<= min
) {
173 debug(22, 3) ("refreshCheck: NO: age < min && override_expire\n");
177 if (entry
->expires
> -1) {
178 if (entry
->expires
<= check_time
) {
179 debug(22, 3) ("refreshCheck: YES: expires <= curtime\n");
180 refreshCounts
.response_expires_stale
++;
183 debug(22, 3) ("refreshCheck: NO: expires > curtime\n");
184 refreshCounts
.response_expires_fresh
++;
189 debug(22, 3) ("refreshCheck: YES: age > max\n");
190 refreshCounts
.conf_max_age_stale
++;
194 if (override_lastmod
&& age
<= min
) {
195 debug(22, 3) ("refreshCheck: NO: age < min && override_lastmod\n");
199 if (entry
->lastmod
> -1 && entry
->timestamp
> entry
->lastmod
) {
200 factor
= (double) age
/ (double) (entry
->timestamp
- entry
->lastmod
);
201 debug(22, 3) ("refreshCheck: factor = %f\n", factor
);
203 debug(22, 3) ("refreshCheck: NO: factor < pct\n");
204 refreshCounts
.last_modified_factor_fresh
++;
207 debug(22, 3) ("refreshCheck: YES: factor >= pct\n");
208 refreshCounts
.last_modified_factor_stale
++;
213 debug(22, 3) ("refreshCheck: NO: age < min\n");
214 refreshCounts
.conf_min_age_fresh
++;
217 debug(22, 3) ("refreshCheck: YES: default stale\n");
218 refreshCounts
.default_stale
++;
222 /* returns an approximate time when refreshCheck() may return true */
224 refreshWhen(const StoreEntry
* entry
)
227 time_t refresh_time
= squid_curtime
;
228 time_t min
= REFRESH_DEFAULT_MIN
;
229 time_t max
= REFRESH_DEFAULT_MAX
;
230 double pct
= REFRESH_DEFAULT_PCT
;
231 const char *pattern
= ".";
232 if (entry
->mem_obj
) {
233 assert(entry
->mem_obj
->url
);
234 debug(22, 3) ("refreshWhen: key '%s'\n", storeKeyText(entry
->key
));
235 debug(22, 3) ("refreshWhen: url '%s'\n", entry
->mem_obj
->url
);
236 if (EBIT_TEST(entry
->flag
, ENTRY_REVALIDATE
)) {
237 debug(22, 3) ("refreshWhen: NOW: Required Authorization\n");
240 debug(22, 3) ("refreshWhen: entry: exp: %d, tstamp: %d, lmt: %d\n",
241 entry
->expires
, entry
->timestamp
, entry
->lastmod
);
242 R
= refreshLimits(entry
->mem_obj
->url
);
244 R
= refreshUncompiledPattern(".");
250 pattern
= R
->pattern
;
252 debug(22, 3) ("refreshWhen: Matched '%s %d %d%% %d'\n",
253 pattern
, (int) min
, (int) (100.0 * pct
), (int) max
);
254 /* convert to absolute numbers */
255 min
+= entry
->timestamp
;
256 max
+= entry
->timestamp
;
257 if (-1 < entry
->expires
) {
258 debug(22, 3) ("refreshWhen: expires set\n");
259 refresh_time
= entry
->expires
;
260 } else if (entry
->timestamp
<= entry
->lastmod
) {
261 debug(22, 3) ("refreshWhen: lastvalid <= lastmod\n");
262 refresh_time
= squid_curtime
;
264 refresh_time
= (entry
->timestamp
- entry
->lastmod
) * pct
+ entry
->timestamp
;
265 debug(22, 3) ("refreshWhen: using refresh pct\n");
267 /* take min/max into account, max takes priority over min */
268 if (refresh_time
< min
)
270 if (refresh_time
> max
)
272 debug(22, 3) ("refreshWhen: answer: %d (in %d secs)\n",
273 refresh_time
, (int) (refresh_time
- squid_curtime
));
278 getMaxAge(const char *url
)
281 debug(22, 3) ("getMaxAge: '%s'\n", url
);
282 if ((R
= refreshLimits(url
)))
285 return REFRESH_DEFAULT_MAX
;
289 refreshStats(StoreEntry
* sentry
)
291 storeAppendPrintf(sentry
, "refreshCounts.total\t%d\n",
292 refreshCounts
.total
);
293 storeAppendPrintf(sentry
, "refreshCounts.revalidate_stale\t%d\n",
294 refreshCounts
.revalidate_stale
);
295 storeAppendPrintf(sentry
, "refreshCounts.request_max_age_stale\t%d\n",
296 refreshCounts
.request_max_age_stale
);
297 storeAppendPrintf(sentry
, "refreshCounts.response_expires_stale\t%d\n",
298 refreshCounts
.response_expires_stale
);
299 storeAppendPrintf(sentry
, "refreshCounts.response_expires_fresh\t%d\n",
300 refreshCounts
.response_expires_fresh
);
301 storeAppendPrintf(sentry
, "refreshCounts.conf_max_age_stale\t%d\n",
302 refreshCounts
.conf_max_age_stale
);
303 storeAppendPrintf(sentry
, "refreshCounts.last_modified_factor_fresh\t%d\n",
304 refreshCounts
.last_modified_factor_fresh
);
305 storeAppendPrintf(sentry
, "refreshCounts.last_modified_factor_stale\t%d\n",
306 refreshCounts
.last_modified_factor_stale
);
307 storeAppendPrintf(sentry
, "refreshCounts.conf_min_age_fresh\t%d\n",
308 refreshCounts
.conf_min_age_fresh
);
309 storeAppendPrintf(sentry
, "refreshCounts.default_stale\t%d\n",
310 refreshCounts
.default_stale
);
316 cachemgrRegister("refresh",
317 "Refresh Algorithm Statistics",