cache.c
上传用户:ladybrid91
上传日期:2007-01-04
资源大小:287k
文件大小:7k
源码类别:

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** cache.c
  3. **
  4. ** Copyright (c) 1995 Peter Eriksson <pen@signum.se>
  5. **
  6. ** This program is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2 of the License, or
  9. ** (at your option) any later version.
  10. **
  11. ** This program is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <synch.h>
  23. #include <syslog.h>
  24. #include "phttpd.h"
  25. static unsigned int hash(void *key,
  26.  unsigned keylen,
  27.  unsigned int hashsize)
  28. {
  29.     unsigned char *keyp;
  30.     unsigned int res = 0;
  31.     unsigned int hs = 0;
  32.     keyp = (unsigned char *) key;
  33.     if (keylen == 0)
  34.     {
  35. while (*keyp)
  36. {
  37.     res += (*keyp++) << hs;
  38.     hs = (hs+1)&7;
  39. }
  40.     }
  41.     else
  42.     {
  43. while (keylen-- > 0)
  44. {
  45.     res += (*keyp++) << hs;
  46.     hs = (hs+1)&7;
  47. }
  48.     }
  49.     return res;
  50. }
  51. static int keycmp(void *p1,
  52.    void *p2,
  53.    unsigned int len)
  54. {
  55.     if (len == 0)
  56. return strcmp((char *) p1, (char *) p2);
  57.     else
  58. return memcmp(p1, p2, len);
  59. }
  60. cacheentry_t *cacheentry_alloc(void *key,
  61.        unsigned int keylen,
  62.        void *data,
  63.        void (*release_fcn)(void *data))
  64. {
  65.     cacheentry_t *new;
  66.     new = s_malloc(sizeof(cacheentry_t));
  67.     new->magic = 0x1231246;
  68.     
  69.     mutex_init(&new->lock, USYNC_THREAD, NULL);
  70.     new->use = 1;
  71.     
  72.     new->release_fcn = release_fcn;
  73.     
  74.     new->keylen = keylen;
  75.     if (keylen == 0)
  76. new->key = s_strdup(key);
  77.     else
  78.     {
  79. new->key = s_malloc(keylen);
  80. memcpy(new->key, key, keylen);
  81.     }
  82.     new->data = data;
  83.     return new;
  84. }
  85. static void *garb_thread(void *data)
  86. {
  87.     cache_t *cp = data;
  88.     unsigned int i;
  89.     cacheentry_t *prev, *current;
  90.     time_t current_time;
  91.     
  92.     
  93.   Loop:
  94.     s_sleep(cp->gc_interval);
  95.     time(&current_time);
  96.     if (debug > 1)
  97. fprintf(stderr, "cache:garb_thread(): Startn");
  98.     
  99.     for (i = 0; i < cp->size; i++)
  100.     {
  101. prev = &cp->table[i];
  102. mutex_lock(&prev->lock);
  103. while ((current = prev->next) != NULL)
  104. {
  105.     mutex_lock(&current->lock);
  106.     if (difftime(current_time, current->itime) > cp->ttl)
  107.     {
  108. if (debug > 1)
  109.     fprintf(stderr, "garb_cache: Deleting, key=%sn",
  110.     current->keylen ? "<binary>" : (char *) current->key);
  111. prev->next = current->next;
  112. current->next = NULL;
  113. mutex_unlock(&current->lock);
  114. cache_release(current);
  115.     }
  116.     else
  117.     {
  118. mutex_unlock(&prev->lock);
  119. prev = current;
  120.     }
  121. }
  122. mutex_unlock(&prev->lock);
  123.     }
  124.     
  125.     if (debug > 1)
  126. fprintf(stderr, "cache:garb_thread(): Stopn");
  127.     
  128.     goto Loop;
  129. }
  130. void cache_init(cache_t *cp,
  131. int refresh,
  132. int ttl,
  133. int gc_interval,
  134. unsigned hashsize,
  135. unsigned (*hash_fcn)(void *key,
  136.      unsigned int keylen,
  137.      unsigned int hashsize),
  138. void (*release_fcn)(void *data),
  139. int (*update_fcn)(void *key,
  140.   unsigned int keylen,
  141.   void *data,
  142.   void **new_data,
  143.   void *misc))
  144. {
  145.     unsigned int i;
  146.     
  147.     cp->size = hashsize ? hashsize : 101;
  148.     cp->hash_fcn = hash_fcn ? hash_fcn : hash;
  149.     cp->release_fcn = release_fcn;
  150.     cp->update_fcn = update_fcn;
  151.     cp->refresh = refresh;
  152.     cp->ttl = ttl;
  153.     cp->gc_interval = gc_interval;
  154.     
  155.     cp->table = s_malloc(cp->size * sizeof(cacheentry_t));
  156.     for (i = 0; i < cp->size; i++)
  157. mutex_init(&cp->table[i].lock, USYNC_THREAD, NULL);
  158.     cp->stats.lookups = 0;
  159.     cp->stats.hits = 0;
  160.     if (cp->gc_interval >= 0)
  161.     {
  162. if (thr_create(NULL,
  163.        0,
  164.        (void *(*)(void *)) garb_thread,
  165.        (void *) cp,
  166.        THR_DETACHED+THR_DAEMON,
  167.        NULL))
  168. {
  169.     syslog(LOG_ERR, "thr_create(garb_thread) failed: %m");
  170.     exit(1);
  171. }
  172.     }
  173. }
  174. cacheentry_t *cache_lookup(cache_t *cp,
  175.    void *key,
  176.    unsigned int keylen,
  177.    void *misc,
  178.    unsigned int flags)
  179. {
  180.     unsigned int i;
  181.     cacheentry_t *prev, *current, *new;
  182.     time_t current_time;
  183.     void *new_data;
  184.     
  185.     if (debug > 2)
  186. {
  187. if (keylen == 0)
  188.      fprintf(stderr, "cache_lookup(), key=%sn", (char *) key);
  189. else
  190.      fprintf(stderr, "cache_lookup(), binary keyn");
  191. }
  192.     
  193.     time(&current_time);
  194.     mutex_lock(&cp->stats.lock);
  195.     cp->stats.lookups++;
  196.     mutex_unlock(&cp->stats.lock);
  197.     
  198.     i = cp->hash_fcn(key, keylen, cp->size) % cp->size;
  199.     if (debug > 2)
  200. fprintf(stderr, "thash index=%d, modulo=%d (for %s)n",
  201. i, cp->size, keylen ? "<binary>" : (char *) key);
  202.     
  203.     prev = &cp->table[i];
  204.     mutex_lock(&prev->lock);
  205.     
  206.     while ((current = prev->next) != NULL)
  207.     {
  208. mutex_lock(&current->lock);
  209. if (keylen == current->keylen &&
  210.     keycmp(current->key, key, keylen) == 0)
  211. {
  212.     if ((flags & CF_RELOAD) == 0)
  213.     {
  214. if (difftime(current_time, current->itime) <= cp->refresh)
  215. {
  216.     mutex_lock(&cp->stats.lock);
  217.     cp->stats.hits++;
  218.     mutex_unlock(&cp->stats.lock);
  219.     
  220.     current->use++;
  221.     mutex_unlock(&current->lock);
  222.     mutex_unlock(&prev->lock);
  223.     return current;
  224. }
  225.     }
  226.     
  227.     mutex_lock(&cp->stats.lock);
  228.     cp->stats.updates++;
  229.     mutex_unlock(&cp->stats.lock);
  230.     break;
  231. }
  232. mutex_unlock(&prev->lock);
  233. prev = current;
  234.     }
  235.     if (debug > 2)
  236. fprintf(stderr, "cache_lookup(), updatingn");
  237.     
  238.     if (cp->update_fcn(key, keylen, current ? current->data : NULL,
  239.        &new_data, misc) == 0)
  240.     {
  241. if (current)
  242. {
  243.     current->use++;
  244.     mutex_unlock(&current->lock);
  245.     mutex_unlock(&prev->lock);
  246.     return current;
  247. }
  248. else
  249.     new_data = NULL;
  250.     }
  251.     
  252.     mutex_lock(&cp->stats.lock);
  253.     cp->stats.reloads++;
  254.     mutex_unlock(&cp->stats.lock);
  255.     
  256.     new = cacheentry_alloc(key, keylen, new_data, cp->release_fcn);
  257.     
  258.     /* Data has changed, replace with new info */
  259.     if (debug > 2)
  260. fprintf(stderr, "cache_lookup(), new infon");
  261.     
  262.     time(&new->itime);
  263.     new->use++;
  264.     
  265.     prev->next = new;
  266.     if (current)
  267.     {
  268. new->next = current->next;
  269. current->next = NULL;
  270. mutex_unlock(&current->lock);
  271.     }
  272.     
  273.     mutex_unlock(&prev->lock);
  274.     if (current)
  275. cache_release(current);
  276.     
  277.     return new;
  278. }
  279. void cache_release(cacheentry_t *cep)
  280. {
  281.     if (cep->magic != 0x1231246)
  282. s_abort();
  283.     
  284.     mutex_lock(&cep->lock);
  285.     cep->use--;
  286.     if (debug > 2)
  287. fprintf(stderr, "cache_release(), p-key=%08x, key=%s, use=%dn",
  288. (unsigned int) cep,
  289. cep->keylen ? "<binary>" : (char *) cep->key, cep->use);
  290.     
  291.     if (cep->use > 0)
  292.     {
  293. mutex_unlock(&cep->lock);
  294. return;
  295.     }
  296.     if (cep->release_fcn && cep->data)
  297. cep->release_fcn((void *) cep->data);
  298.     cep->magic = 0x563431;
  299.     
  300.     s_free(cep->key);
  301.     s_free(cep);
  302. }
  303. int cache_getstats(cache_t *ctp,
  304.    cachestat_t *csp)
  305. {
  306.     if (ctp == NULL)
  307. return -1;
  308.     
  309.     mutex_lock(&ctp->stats.lock);
  310.     if (csp)
  311. *csp = ctp->stats;
  312.     mutex_unlock(&ctp->stats.lock);
  313.     return 1;
  314. }