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

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** hashtable.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 "phttpd.h"
  24. static unsigned int hash(const void *key,
  25.  unsigned keylen,
  26.  unsigned int hashsize)
  27. {
  28.     const unsigned char *keyp;
  29.     unsigned int res = 0;
  30.     unsigned int hs = 0;
  31.     keyp = (const unsigned char *) key;
  32.     if (keylen == 0)
  33.     {
  34. while (*keyp)
  35. {
  36.     res += (*keyp++) << hs;
  37.     hs = (hs+1)&7;
  38. }
  39.     }
  40.     else
  41.     {
  42. while (keylen-- > 0)
  43. {
  44.     res += (*keyp++) << hs;
  45.     hs = (hs+1)&7;
  46. }
  47.     }
  48.     return res;
  49. }
  50. static int keycmp(const void *p1,
  51.   unsigned int len1,
  52.   const void *p2,
  53.   unsigned int len2)
  54. {
  55.     if (len1 == 0 && len2 == 0)
  56. return strcmp((char *) p1, (char *) p2);
  57.     else if (len1 == 0 && len2 != 0)
  58. return strncmp(p1, p2, len2);
  59.     else if (len1 == len2)
  60. return memcmp(p1, p2, len2);
  61.     else
  62. return -1;
  63. }
  64. void ht_init(hashtable_t *htp,
  65.      unsigned hashsize,
  66.      unsigned (*hash_fcn)(const void *key,
  67.   unsigned int keylen,
  68.   unsigned int hashsize))
  69. {
  70.     unsigned int i;
  71.     
  72.     htp->size = hashsize ? hashsize : 101;
  73.     htp->hash_fcn = hash_fcn ? hash_fcn : hash;
  74.     htp->table = s_malloc(htp->size * sizeof(hashentry_t));
  75.     for (i = 0; i < htp->size; i++)
  76. mutex_init(&htp->table[i].lock, USYNC_THREAD, NULL);
  77. }
  78. hashentry_t *ht_lookup(hashtable_t *htp,
  79.        const void *key,
  80.        unsigned keylen)
  81. {
  82.     unsigned int i;
  83.     hashentry_t *prev, *current;
  84.     
  85.     if (htp == NULL)
  86. return NULL;
  87.     
  88.     i = htp->hash_fcn(key, keylen, htp->size) % htp->size;
  89.     prev = &htp->table[i];
  90.     mutex_lock(&prev->lock);
  91.     
  92.     while ((current = prev->next) != NULL)
  93.     {
  94. mutex_unlock(&prev->lock);
  95. mutex_lock(&current->lock);
  96. current->use++;
  97. mutex_unlock(&current->lock);
  98. if (keycmp(current->key, current->keylen, key, keylen) == 0)
  99.     return current;
  100. mutex_lock(&current->lock);
  101. current->use--;
  102. prev = current;
  103.     }
  104.     mutex_unlock(&prev->lock);
  105.     return NULL;
  106. }
  107. void ht_release(hashentry_t *hep)
  108. {
  109.     if (hep == NULL)
  110. return;
  111.     
  112.     mutex_lock(&hep->lock);
  113.     hep->use--;
  114.     
  115.     if (debug > 4)
  116. fprintf(stderr, "ht_release(), use=%dn", hep->use);
  117.     
  118.     if (hep->use > 0)
  119.     {
  120. mutex_unlock(&hep->lock);
  121. return;
  122.     }
  123.     
  124.     if (hep->release_fcn)
  125. hep->release_fcn(hep->data);
  126.     s_free(hep->key);
  127.     s_free(hep);
  128. }
  129. hashentry_t *ht_insert(hashtable_t *htp,
  130.        const void *key,
  131.        unsigned int keylen,
  132.        void *data,
  133.        unsigned int flags,
  134.        void (*release_fcn)(void *data))
  135. {
  136.     unsigned int i;
  137.     hashentry_t *prev, *current, *new;
  138.     
  139.     if (htp == NULL)
  140. return NULL;
  141.     
  142.     i = htp->hash_fcn(key, keylen, htp->size) % htp->size;
  143.     
  144.     new = s_malloc(sizeof(hashentry_t));
  145.     mutex_init(&new->lock, USYNC_THREAD, NULL);
  146.     if (keylen)
  147.     {
  148. new->key = s_malloc(keylen);
  149. memcpy(new->key, key, keylen);
  150.     }
  151.     else
  152. new->key = s_strdup(key);
  153.     new->data = data;
  154.     new->use = 1;
  155.     new->release_fcn = release_fcn;
  156.     
  157.     prev = &htp->table[i];
  158.     mutex_lock(&prev->lock);
  159.     
  160.     while ((current = prev->next) != NULL)
  161.     {
  162. mutex_lock(&current->lock);
  163. if (keycmp(current->key, current->keylen, key, keylen) == 0)
  164. {
  165.     /* Already in table */
  166.     
  167.     if (flags & HTF_REPLACE)
  168.     {
  169. if (debug > 2)
  170.     fprintf(stderr, "ht_insert(): Replacing %sn", (char *) key);
  171. prev->next = new;
  172. new->next = current->next;
  173. new->use++;
  174. mutex_unlock(&current->lock);
  175. mutex_unlock(&prev->lock);
  176. ht_release(current);
  177. return new;
  178.     }
  179.     else
  180.     {
  181. mutex_unlock(&current->lock);
  182. mutex_unlock(&prev->lock);
  183. ht_release(new);
  184. return NULL;
  185.     }
  186. }
  187. mutex_unlock(&prev->lock);
  188. prev = current;
  189.     }
  190.     if (flags & HTF_NOINSERT)
  191.     {
  192. /* Only replace already existing data */
  193. mutex_unlock(&prev->lock);
  194. ht_release(new);
  195. return NULL;
  196.     }
  197.     new->use++;
  198.     
  199.     prev->next = new;
  200.     mutex_unlock(&prev->lock);
  201.     
  202.     return new;
  203. }
  204. int ht_delete(hashtable_t *htp,
  205.       hashentry_t *hep)
  206. {
  207.     unsigned int i;
  208.     hashentry_t *prev, *current;
  209.     
  210.     if (htp == NULL)
  211. return -1;
  212.     
  213.     i = htp->hash_fcn(hep->key, hep->keylen, htp->size) % htp->size;
  214.     prev = &htp->table[i];
  215.     mutex_lock(&prev->lock);
  216.     
  217.     while ((current = prev->next) != NULL)
  218.     {
  219. mutex_lock(&current->lock);
  220. if (current == hep)
  221. {
  222.     prev->next = current->next;
  223.     current->next = NULL;
  224.     
  225.     mutex_unlock(&current->lock);
  226.     mutex_unlock(&prev->lock);
  227.     ht_release(current);
  228.     return 0;
  229. }
  230. mutex_unlock(&prev->lock);
  231. prev = current;
  232.     }
  233.     mutex_unlock(&prev->lock);
  234.     return -1;
  235. }
  236. int ht_foreach(hashtable_t *htp,
  237.        int (*foreach_fcn)(hashentry_t *hep, void *misc),
  238.        void *misc)
  239. {
  240.     int retval;
  241.     unsigned int i;
  242.     hashentry_t *prev, *current;
  243.     
  244.     if (htp == NULL)
  245. return -1;
  246.     
  247.     for (i = 0; i < htp->size; i++)
  248.     {
  249. prev = &htp->table[i];
  250. mutex_lock(&prev->lock);
  251. while ((current = prev->next) != NULL)
  252. {
  253.     mutex_unlock(&prev->lock);
  254.     
  255.     mutex_lock(&current->lock);
  256.     current->use++;
  257.     mutex_unlock(&current->lock);
  258.     retval = foreach_fcn(current, misc);
  259.     mutex_lock(&current->lock);
  260.     current->use--;
  261.     
  262.     if (retval < 0)
  263.     {
  264. mutex_unlock(&current->lock);
  265. return retval;
  266.     }
  267.     
  268.     prev = current;
  269. }
  270. mutex_unlock(&prev->lock);
  271.     }
  272.     return 0;
  273. }
  274. void ht_destroy(hashtable_t *htp)
  275. {
  276.     ht_clean(htp);
  277.     s_free(htp->table);
  278. }
  279. int ht_clean(hashtable_t *htp)
  280. {
  281.     unsigned int i;
  282.     hashentry_t *prev, *current;
  283.     
  284.     if (htp == NULL)
  285. return -1;
  286.     
  287.     for (i = 0; i < htp->size; i++)
  288.     {
  289. prev = &htp->table[i];
  290. mutex_lock(&prev->lock);
  291. while ((current = prev->next) != NULL)
  292. {
  293.     mutex_lock(&current->lock);
  294.     prev->next = current->next;
  295.     current->next = NULL;
  296.     mutex_unlock(&current->lock);
  297.     ht_release(current);
  298. }
  299. mutex_unlock(&prev->lock);
  300.     }
  301.     return 0;
  302. }
  303. #ifdef TESTING
  304. int debug = 0;
  305. int print_entry(hashentry_t *hep, void *misc)
  306. {
  307.     if (hep->data)
  308. printf("key=%s, value=%s (use=%d)n", hep->key, hep->data, hep->use);
  309.     else
  310. printf("key=%s, no value (use=%d)n", hep->key, hep->use);
  311.     return 0;
  312. }
  313. main(int argc, char *argv[])
  314. {
  315.     hashtable_t ht;
  316.     hashentry_t *hep;
  317.     int i;
  318.     char *val, *cp;
  319.     
  320.     
  321.     ht_init(&ht, 17, NULL);
  322.     i = 1;
  323.     puts("Inserting:");
  324.     
  325.     /* Insert entries into table */
  326.     for (; i < argc && strcmp(argv[i], "-") != 0; i++)
  327.     {
  328. printf("t%s:n", argv[i]);
  329. val = s_strdup(argv[i]);
  330. cp = strchr(val, ':');
  331. if (cp == NULL)
  332. {
  333.     hep = ht_insert(&ht, val, 0, NULL, 0, NULL);
  334.     if (hep == NULL)
  335. printf("ttFailedn");
  336.     else
  337.     {
  338. ht_release(hep);
  339. printf("ttOKn");
  340.     }
  341. }
  342. else
  343. {
  344.     *cp++ = '';
  345.     hep = ht_insert(&ht, val, 0, cp, 0, NULL);
  346.     if (hep == NULL)
  347. printf("ttFailedn");
  348.     else
  349.     {
  350. ht_release(hep);
  351. printf("ttOKn");
  352.     }
  353. }
  354.     }
  355.     
  356.     puts("Table dump:");
  357.     ht_foreach(&ht, print_entry, NULL);
  358.     
  359.     ++i;
  360.     puts("Deleting:");
  361.     
  362.     /* Delete entries from table */
  363.     for (; i < argc && strcmp(argv[i], "-") != 0; i++)
  364.     {
  365. printf("t%s:n", argv[i]);
  366. hep = ht_lookup(&ht, argv[i], 0);
  367. if (hep)
  368. {
  369.     printf("tt(entry found)n");
  370.     
  371.     if (ht_delete(&ht, hep) != 0)
  372. printf("ttDelete failedn");
  373.     else
  374. printf("ttDelete OKn");
  375.     ht_release(hep);
  376. }
  377. else
  378.     printf("ttEntry not foundn");
  379.     }
  380.     puts("Table dump:");
  381.     ht_foreach(&ht, print_entry, NULL);
  382.     
  383.     puts("Looking up:");
  384.     
  385.     ++i;
  386.     /* Lookup entries */
  387.     for (; i < argc && strcmp(argv[i], "-") != 0; i++)
  388.     {
  389. printf("t%s:n", argv[i]);
  390. hep = ht_lookup(&ht, argv[i], 0);
  391. if (hep)
  392. {
  393.     if (hep->data)
  394. printf("ttfound (value=%s)n", hep->data);
  395.     else
  396. printf("ttfound (no value)n");
  397.     ht_release(hep);
  398. }
  399. else
  400.     printf("ttnot found (key=%s)n", argv[i]);
  401.     }
  402.     puts("Table dump:");
  403.     ht_foreach(&ht, print_entry, NULL);
  404.     
  405.     exit(0);
  406. }
  407. #endif