refresh.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:12k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: refresh.c,v 1.47 1999/01/19 23:18:01 wessels Exp $
  3.  *
  4.  * DEBUG: section 22    Refresh Calculation
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #ifndef USE_POSIX_REGEX
  35. #define USE_POSIX_REGEX /* put before includes; always use POSIX */
  36. #endif
  37. #include "squid.h"
  38. typedef enum {
  39.     rcHTTP, rcICP, rcCDigest, rcStore, rcCount
  40. } refreshCountsEnum;
  41. static struct RefreshCounts {
  42.     const char *proto;
  43.     int total;
  44.     int revalidate_stale;
  45.     int request_max_age_stale;
  46.     int request_reload2ims_stale;
  47.     int request_reload_stale;
  48.     int negative_age_stale;
  49.     int min_age_override_exp_fresh;
  50.     int min_age_override_lmt_fresh;
  51.     int response_expires_stale;
  52.     int response_expires_fresh;
  53.     int conf_max_age_stale;
  54.     int last_modified_factor_fresh;
  55.     int last_modified_factor_stale;
  56.     int response_lmt_now_stale;
  57.     int conf_min_age_fresh;
  58.     int default_stale;
  59.     /* maybe-counters -- intermediate decisions that may affect the result */
  60.     int request_reload_ignore_maybe;
  61.     int response_lmt_future_maybe;
  62. } refreshCounts[rcCount];
  63. /*
  64.  * Defaults:
  65.  *      MIN     NONE
  66.  *      PCT     20%
  67.  *      MAX     3 days
  68.  */
  69. #define REFRESH_DEFAULT_MIN (time_t)0
  70. #define REFRESH_DEFAULT_PCT 0.20
  71. #define REFRESH_DEFAULT_MAX (time_t)259200
  72. static const refresh_t *refreshLimits(const char *);
  73. static const refresh_t *refreshUncompiledPattern(const char *);
  74. static OBJH refreshStats;
  75. static const refresh_t *
  76. refreshLimits(const char *url)
  77. {
  78.     const refresh_t *R;
  79.     for (R = Config.Refresh; R; R = R->next) {
  80. if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
  81.     return R;
  82.     }
  83.     return NULL;
  84. }
  85. static const refresh_t *
  86. refreshUncompiledPattern(const char *pat)
  87. {
  88.     const refresh_t *R;
  89.     for (R = Config.Refresh; R; R = R->next) {
  90. if (0 == strcmp(R->pattern, pat))
  91.     return R;
  92.     }
  93.     return NULL;
  94. }
  95. /*  return 1 if the entry must be revalidated within delta seconds
  96.  *         0 otherwise
  97.  *
  98.  *  note: request maybe null (e.g. for cache digests build)
  99.  */
  100. static int
  101. refreshCheck(const StoreEntry * entry, request_t * request, time_t delta, struct RefreshCounts *rc)
  102. {
  103.     const refresh_t *R;
  104.     const char *uri = NULL;
  105.     time_t min = REFRESH_DEFAULT_MIN;
  106.     double pct = REFRESH_DEFAULT_PCT;
  107.     time_t max = REFRESH_DEFAULT_MAX;
  108. #if HTTP_VIOLATIONS
  109.     int override_expire = 0;
  110.     int override_lastmod = 0;
  111.     int reload_into_ims = 0;
  112.     int ignore_reload = 0;
  113. #endif
  114.     const char *pattern = "<none>";
  115.     time_t age;
  116.     double factor;
  117.     time_t check_time = squid_curtime + delta;
  118.     if (entry->mem_obj)
  119. uri = entry->mem_obj->url;
  120.     else if (request)
  121. uri = urlCanonical(request);
  122.     debug(22, 3) ("refreshCheck(%s): '%s'n", rc->proto, uri ? uri : "<none>");
  123.     rc->total++;
  124.     if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE)) {
  125. debug(22, 3) ("refreshCheck: YES: Required Authorizationn");
  126. rc->revalidate_stale++;
  127. return 1;
  128.     }
  129.     if ((R = uri ? refreshLimits(uri) : refreshUncompiledPattern("."))) {
  130. min = R->min;
  131. pct = R->pct;
  132. max = R->max;
  133. pattern = R->pattern;
  134. #if HTTP_VIOLATIONS
  135. override_expire = R->flags.override_expire;
  136. override_lastmod = R->flags.override_lastmod;
  137. reload_into_ims = R->flags.reload_into_ims;
  138. ignore_reload = R->flags.ignore_reload;
  139. #endif
  140.     }
  141. #if HTTP_VIOLATIONS
  142.     if (!reload_into_ims)
  143. reload_into_ims = Config.onoff.reload_into_ims;
  144. #endif
  145.     debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'n",
  146. pattern, (int) min, (int) (100.0 * pct), (int) max);
  147.     age = check_time - entry->timestamp;
  148.     debug(22, 3) ("refreshCheck: age = %dn", (int) age);
  149.     debug(22, 3) ("tcheck_time:t%sn", mkrfc1123(check_time));
  150.     debug(22, 3) ("tentry->timestamp:t%sn", mkrfc1123(entry->timestamp));
  151.     /* request-specific checks */
  152.     if (request) {
  153. #if HTTP_VIOLATIONS
  154. if (request->flags.nocache_hack) {
  155.     if (ignore_reload) {
  156. /* The clients no-cache header is ignored */
  157. debug(22, 3) ("refreshCheck: MAYBE: ignore-reloadn");
  158. rc->request_reload_ignore_maybe++;
  159.     } else if (reload_into_ims) {
  160. /* The clients no-cache header is changed into a IMS query */
  161. debug(22, 3) ("refreshCheck: YES: reload-into-imsn");
  162. rc->request_reload2ims_stale++;
  163. return 1;
  164.     } else {
  165. /* The clients no-cache header is not overridden on this request */
  166. debug(22, 3) ("refreshCheck: YES: client reloadn");
  167. request->flags.nocache = 1;
  168. rc->request_reload_stale++;
  169. return 1;
  170.     }
  171. }
  172. #endif
  173. if (age < 0) {
  174.     debug(22, 3) ("refreshCheck: YES: age < 0n");
  175.     rc->negative_age_stale++;
  176.     return 1;
  177. }
  178. if (request->cache_control && request->cache_control->max_age > -1) {
  179.     if (age > request->cache_control->max_age) {
  180. debug(22, 3) ("refreshCheck: YES: age > client-max-agen");
  181. rc->request_max_age_stale++;
  182. return 1;
  183.     }
  184. }
  185.     }
  186. #if HTTP_VIOLATIONS
  187.     if (override_expire && age <= min) {
  188. debug(22, 3) ("refreshCheck: NO: age < min && override_expiren");
  189. rc->min_age_override_exp_fresh++;
  190. return 0;
  191.     }
  192. #endif
  193.     if (entry->expires > -1) {
  194. if (entry->expires <= check_time) {
  195.     debug(22, 3) ("refreshCheck: YES: expires <= curtimen");
  196.     rc->response_expires_stale++;
  197.     return 1;
  198. } else {
  199.     debug(22, 3) ("refreshCheck: NO: expires > curtimen");
  200.     rc->response_expires_fresh++;
  201.     return 0;
  202. }
  203.     }
  204.     if (age > max) {
  205. debug(22, 3) ("refreshCheck: YES: age > maxn");
  206. rc->conf_max_age_stale++;
  207. return 1;
  208.     }
  209. #if HTTP_VIOLATIONS
  210.     if (override_lastmod && age <= min) {
  211. debug(22, 3) ("refreshCheck: NO: age < min && override_lastmodn");
  212. rc->min_age_override_lmt_fresh++;
  213. return 0;
  214.     }
  215. #endif
  216.     if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
  217. factor = (double) age / (double) (entry->timestamp - entry->lastmod);
  218. debug(22, 3) ("refreshCheck: factor = %fn", factor);
  219. if (factor < pct) {
  220.     debug(22, 3) ("refreshCheck: NO: factor < pctn");
  221.     rc->last_modified_factor_fresh++;
  222.     return 0;
  223. } else {
  224.     debug(22, 3) ("refreshCheck: YES: factor >= pctn");
  225.     rc->last_modified_factor_stale++;
  226.     return 1;
  227. }
  228.     } else if (entry->lastmod > -1 && entry->timestamp == entry->lastmod) {
  229. debug(22, 3) ("refreshCheck: YES: last-modified 'now'n");
  230. rc->response_lmt_now_stale++;
  231. return 1;
  232.     } else if (entry->lastmod > -1 && entry->timestamp < entry->lastmod) {
  233. debug(22, 3) ("refreshCheck: MAYBE: last-modified in the futuren");
  234. rc->response_lmt_future_maybe++;
  235.     }
  236.     if (age <= min) {
  237. debug(22, 3) ("refreshCheck: NO: age <= minn");
  238. rc->conf_min_age_fresh++;
  239. return 0;
  240.     }
  241.     debug(22, 3) ("refreshCheck: YES: default stalen");
  242.     rc->default_stale++;
  243.     return 1;
  244. }
  245. int
  246. refreshIsCachable(const StoreEntry * entry)
  247. {
  248.     /*
  249.      * Don't look at the request to avoid no-cache and other nuisances.
  250.      * the object should have a mem_obj so the URL will be found there.
  251.      * 60 seconds delta, to avoid objects which expire almost
  252.      * immediately, and which can't be refreshed.
  253.      */
  254.     if (!refreshCheck(entry, NULL, 60, &refreshCounts[rcStore]))
  255. /* Does not need refresh. This is certainly cachable */
  256. return 1;
  257.     if (entry->lastmod < 0)
  258. /* Last modified is needed to do a refresh */
  259. return 0;
  260.     if (entry->mem_obj == NULL)
  261. /* no mem_obj? */
  262. return 1;
  263.     if (entry->mem_obj->reply)
  264. /* no reply? */
  265. return 1;
  266.     if (entry->mem_obj->reply->content_length == 0)
  267. /* No use refreshing (caching?) 0 byte objects */
  268. return 0;
  269.     /* This seems to be refreshable. Cache it */
  270.     return 1;
  271. }
  272. /* refreshCheck... functions below are protocol-specific wrappers around
  273.  * refreshCheck() function above */
  274. int
  275. refreshCheckHTTP(const StoreEntry * entry, request_t * request)
  276. {
  277.     return refreshCheck(entry, request, 0, &refreshCounts[rcHTTP]);
  278. }
  279. int
  280. refreshCheckICP(const StoreEntry * entry, request_t * request)
  281. {
  282.     return refreshCheck(entry, request, 30, &refreshCounts[rcICP]);
  283. }
  284. int
  285. refreshCheckDigest(const StoreEntry * entry, time_t delta)
  286. {
  287.     return refreshCheck(entry,
  288. entry->mem_obj ? entry->mem_obj->request : NULL,
  289. delta,
  290. &refreshCounts[rcCDigest]);
  291. }
  292. time_t
  293. getMaxAge(const char *url)
  294. {
  295.     const refresh_t *R;
  296.     debug(22, 3) ("getMaxAge: '%s'n", url);
  297.     if ((R = refreshLimits(url)))
  298. return R->max;
  299.     else
  300. return REFRESH_DEFAULT_MAX;
  301. }
  302. static void
  303. refreshCountsStats(StoreEntry * sentry, struct RefreshCounts *rc)
  304. {
  305.     int sum = 0;
  306.     int tot = rc->total;
  307.     storeAppendPrintf(sentry, "nn%s histogram:n", rc->proto);
  308.     storeAppendPrintf(sentry, "CategorytCountt%%Totaln");
  309. #define refreshCountsStatsEntry(name) { 
  310.     if (rc->name || !strcmp(#name, "total")) 
  311. storeAppendPrintf(sentry, "%st%6dt%6.2fn", 
  312.     #name, rc->name, xpercent(rc->name, tot)); 
  313.     sum += rc->name; 
  314. }
  315.     refreshCountsStatsEntry(revalidate_stale);
  316.     refreshCountsStatsEntry(request_reload2ims_stale);
  317.     refreshCountsStatsEntry(request_reload_stale);
  318.     refreshCountsStatsEntry(request_max_age_stale);
  319.     refreshCountsStatsEntry(min_age_override_exp_fresh);
  320.     refreshCountsStatsEntry(response_expires_stale);
  321.     refreshCountsStatsEntry(response_expires_fresh);
  322.     refreshCountsStatsEntry(conf_max_age_stale);
  323.     refreshCountsStatsEntry(min_age_override_lmt_fresh);
  324.     refreshCountsStatsEntry(last_modified_factor_fresh);
  325.     refreshCountsStatsEntry(last_modified_factor_stale);
  326.     refreshCountsStatsEntry(response_lmt_now_stale);
  327.     refreshCountsStatsEntry(conf_min_age_fresh);
  328.     refreshCountsStatsEntry(default_stale);
  329.     tot = sum; /* paranoid: "total" line shows 100% if we forgot nothing */
  330.     refreshCountsStatsEntry(total);
  331.     /* maybe counters */
  332.     refreshCountsStatsEntry(request_reload_ignore_maybe);
  333.     refreshCountsStatsEntry(response_lmt_future_maybe);
  334. }
  335. static void
  336. refreshStats(StoreEntry * sentry)
  337. {
  338.     int i;
  339.     int total = 0;
  340.     /* get total usage count */
  341.     for (i = 0; i < rcCount; ++i)
  342. total += refreshCounts[i].total;
  343.     /* protocol usage histogram */
  344.     storeAppendPrintf(sentry, "nRefreshCheck calls per protocolnn");
  345.     storeAppendPrintf(sentry, "Protocolt#Callst%%Callsn");
  346.     for (i = 0; i < rcCount; ++i)
  347. storeAppendPrintf(sentry, "%10st%6dt%6.2fn",
  348.     refreshCounts[i].proto,
  349.     refreshCounts[i].total,
  350.     xpercent(refreshCounts[i].total, total));
  351.     /* per protocol histograms */
  352.     storeAppendPrintf(sentry, "nnRefreshCheck histograms for various protocolsn");
  353.     for (i = 0; i < rcCount; ++i)
  354. refreshCountsStats(sentry, &refreshCounts[i]);
  355. }
  356. void
  357. refreshInit()
  358. {
  359.     memset(refreshCounts, 0, sizeof(refreshCounts));
  360.     refreshCounts[rcHTTP].proto = "HTTP";
  361.     refreshCounts[rcICP].proto = "ICP";
  362.     refreshCounts[rcStore].proto = "On Store";
  363.     refreshCounts[rcCDigest].proto = "Cache Digests";
  364.     cachemgrRegister("refresh",
  365. "Refresh Algorithm Statistics",
  366. refreshStats,
  367. 0,
  368. 1);
  369. }