jabberd2  2.3.4
xhash.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
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  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "xhash.h"
22 #include "util.h"
23 
24 
25 /* Generates a hash code for a string.
26  * This function uses the ELF hashing algorithm as reprinted in
27  * Andrew Binstock, "Hashing Rehashed," Dr. Dobb's Journal, April 1996.
28  */
29 static int _xhasher(const char *s, int len)
30 {
31  /* ELF hash uses unsigned chars and unsigned arithmetic for portability */
32  const unsigned char *name = (const unsigned char *)s;
33  unsigned long h = 0, g;
34  int i;
35 
36  for(i=0;i<len;i++)
37  { /* do some fancy bitwanking on the string */
38  h = (h << 4) + (unsigned long)(name[i]);
39  if ((g = (h & 0xF0000000UL))!=0)
40  h ^= (g >> 24);
41  h &= ~g;
42 
43  }
44 
45  return (int)h;
46 }
47 
48 
49 static xhn _xhash_node_new(xht h, int index)
50 {
51  xhn n;
52  int i = index % h->prime;
53 
54  /* track total */
55  h->count++;
56 
57 #ifdef XHASH_DEBUG
58  h->stat[i]++;
59 #endif
60 
61  // if the zen[i] is empty, reuse it, else get a new one.
62  n = &h->zen[i];
63 
64  if( n->key != NULL )
65  {
66  if( h->free_list )
67  {
68  n = h->free_list;
69  h->free_list = h->free_list->next;
70  }else
71  n = pmalloco(h->p, sizeof(_xhn));
72 
73  //add it to the bucket list head.
74  n->prev = &h->zen[i];
75  n->next = h->zen[i].next;
76 
77  if( n->next ) n->next->prev = n;
78  h->zen[i].next = n;
79  }
80 
81  return n;
82 }
83 
84 
85 static xhn _xhash_node_get(xht h, const char *key, int len, int index)
86 {
87  xhn n;
88  int i = index % h->prime;
89  for(n = &h->zen[i]; n != NULL; n = n->next)
90  if(n->key != NULL && (n->keylen==len) && (strncmp(key, n->key, len) == 0))
91  return n;
92  return NULL;
93 }
94 
95 
96 xht xhash_new(int prime)
97 {
98  xht xnew;
99  pool_t p;
100 
101 /* log_debug(ZONE,"creating new hash table of size %d",prime); */
102 
109  p = pool_heap(sizeof(_xhn)*prime + sizeof(_xht));
110  xnew = pmalloco(p, sizeof(_xht));
111  xnew->prime = prime;
112  xnew->p = p;
113  xnew->zen = pmalloco(p, sizeof(_xhn)*prime); /* array of xhn size of prime */
114 
115  xnew->free_list = NULL;
116 
117  xnew->iter_bucket = -1;
118  xnew->iter_node = NULL;
119 
120 #ifdef XHASH_DEBUG
121  xnew->stat = pmalloco(p, sizeof(int)*prime );
122 #else
123  xnew->stat = NULL;
124 #endif
125 
126  return xnew;
127 }
128 
129 
130 void xhash_putx(xht h, const char *key, int len, void *val)
131 {
132  int index;
133  xhn n;
134 
135  if(h == NULL || key == NULL)
136  return;
137 
138  index = _xhasher(key,len);
139 
140  /* dirty the xht */
141  h->dirty++;
142 
143  /* if existing key, replace it */
144  if((n = _xhash_node_get(h, key, len, index)) != NULL)
145  {
146 /* log_debug(ZONE,"replacing %s with new val %X",key,val); */
147 
148  n->key = key;
149  n->keylen = len;
150  n->val = val;
151  return;
152  }
153 
154 /* log_debug(ZONE,"saving %s val %X",key,val); */
155 
156  /* new node */
157  n = _xhash_node_new(h, index);
158  n->key = key;
159  n->keylen = len;
160  n->val = val;
161 }
162 
163 void xhash_put(xht h, const char *key, void *val)
164 {
165  if(h == NULL || key == NULL) return;
166  xhash_putx(h,key,strlen(key),val);
167 }
168 
169 
170 void *xhash_getx(xht h, const char *key, int len)
171 {
172  xhn n;
173 
174  if(h == NULL || key == NULL || len <= 0 || (n = _xhash_node_get(h, key, len, _xhasher(key,len))) == NULL)
175  {
176 /* log_debug(ZONE,"failed lookup of %s",key); */
177  return NULL;
178  }
179 
180 /* log_debug(ZONE,"found %s returning %X",key,n->val); */
181  return n->val;
182 }
183 
184 void *xhash_get(xht h, const char *key)
185 {
186  if(h == NULL || key == NULL) return NULL;
187  return xhash_getx(h,key,strlen(key));
188 }
189 
190 void xhash_zap_inner( xht h, xhn n, int index)
191 {
192  int i = index % h->prime;
193 
194  // if element:n is in bucket list and it's not the current iter
195  if( &h->zen[i] != n && h->iter_node != n )
196  {
197  if(n->prev) n->prev->next = n->next;
198  if(n->next) n->next->prev = n->prev;
199 
200  // add it to the free_list head.
201  n->prev = NULL;
202  n->next = h->free_list;
203  h->free_list = n;
204  }
205 
206  //empty the value.
207  n->key = NULL;
208  n->val = NULL;
209 
210  /* dirty the xht and track the total */
211  h->dirty++;
212  h->count--;
213 
214 #ifdef XHASH_DEBUG
215  h->stat[i]--;
216 #endif
217 }
218 
219 void xhash_zapx(xht h, const char *key, int len)
220 {
221  xhn n;
222  int index;
223 
224  if( !h || !key ) return;
225 
226  index = _xhasher(key,len);
227  n = _xhash_node_get(h, key, len, index);
228  if( !n ) return;
229 
230 /* log_debug(ZONE,"zapping %s",key); */
231 
232  xhash_zap_inner(h ,n, index );
233 }
234 
235 void xhash_zap(xht h, const char *key)
236 {
237  if(h == NULL || key == NULL) return;
238  xhash_zapx(h,key,strlen(key));
239 }
240 
242 {
243 /* log_debug(ZONE,"hash free %X",h); */
244 
246  if(h) pool_free(h->p);
247 
248 }
249 
250 void xhash_stat( xht h )
251 {
252 #ifdef XHASH_DEBUG
253  if( !h ) return;
254 
255  fprintf(stderr, "XHASH: table prime: %d , number of elements: %d\n", h->prime, h->count );
256 
257  int i;
258  for( i = 0; i< h->prime ; ++i )
259  {
260  if( h->stat[i] > 1 )
261  fprintf(stderr, "%d: %d\t", i, h->stat[i]);
262  }
263  fprintf(stderr, "\n");
264 
265 #endif
266 }
267 
268 void xhash_walk(xht h, xhash_walker w, void *arg)
269 {
270  int i;
271  xhn n;
272 
273  if(h == NULL || w == NULL)
274  return;
275 
276 /* log_debug(ZONE,"walking %X",h); */
277 
278  for(i = 0; i < h->prime; i++)
279  for(n = &h->zen[i]; n != NULL; n = n->next)
280  if(n->key != NULL && n->val != NULL)
281  (*w)(n->key, n->keylen, n->val, arg);
282 }
283 
286 {
287  int dirty;
288 
289  if(h == NULL) return 1;
290 
291  dirty = h->dirty;
292  h->dirty = 0;
293  return dirty;
294 }
295 
298 {
299  if(h == NULL) return 0;
300 
301  return h->count;
302 }
303 
306 {
307  return h->p;
308 }
309 
312  if(h == NULL) return 0;
313 
314  h->iter_bucket = -1;
315  h->iter_node = NULL;
316 
317  return xhash_iter_next(h);
318 }
319 
321  if(h == NULL) return 0;
322 
323  /* next in this bucket */
324  h->iter_node = h->iter_node ? h->iter_node->next : NULL;
325  while(h->iter_node != NULL) {
326  xhn n = h->iter_node;
327 
328  if(n->key != NULL && n->val != NULL)
329  return 1;
330 
331  h->iter_node = n->next;
332 
333  if (n != &h->zen[h->iter_bucket]) {
334  if(n->prev) n->prev->next = n->next;
335  if(n->next) n->next->prev = n->prev;
336 
337  // add it to the free_list head.
338  n->prev = NULL;
339  n->next = h->free_list;
340  h->free_list = n;
341  }
342  }
343 
344  /* next bucket */
345  for(h->iter_bucket++; h->iter_bucket < h->prime; h->iter_bucket++) {
346  h->iter_node = &h->zen[h->iter_bucket];
347 
348  while(h->iter_node != NULL) {
349  if(h->iter_node->key != NULL && h->iter_node->val != NULL)
350  return 1;
351 
352  h->iter_node = h->iter_node->next;
353  }
354  }
355 
356  /* there is no next */
357  h->iter_bucket = -1;
358  h->iter_node = NULL;
359 
360  return 0;
361 }
362 
364 {
365  int index;
366 
367  if( !h || !h->iter_node ) return;
368 
369  index = _xhasher( h->iter_node->key, h->iter_node->keylen );
370 
371  xhash_zap_inner( h ,h->iter_node, index);
372 }
373 
374 int xhash_iter_get(xht h, const char **key, int *keylen, void **val) {
375  if(h == NULL || (key == NULL && val == NULL) || (key != NULL && keylen == NULL)) return 0;
376 
377  if(h->iter_node == NULL) {
378  if(key != NULL) *key = NULL;
379  if(val != NULL) *val = NULL;
380  return 0;
381  }
382 
383  if(key != NULL) {
384  *key = h->iter_node->key;
385  *keylen = h->iter_node->keylen;
386  }
387  if(val != NULL) *val = h->iter_node->val;
388 
389  return 1;
390 }
int count
Definition: xhash.h:50
void pool_free(pool_t p)
Definition: pool.c:226
void xhash_free(xht h)
Definition: xhash.c:241
int * stat
Definition: xhash.h:55
struct xhn_struct * free_list
Definition: xhash.h:52
void * xhash_getx(xht h, const char *key, int len)
Definition: xhash.c:170
void xhash_iter_zap(xht h)
Definition: xhash.c:363
int prime
Definition: xhash.h:48
static xhn _xhash_node_new(xht h, int index)
Definition: xhash.c:49
int xhash_iter_next(xht h)
Definition: xhash.c:320
int keylen
Definition: xhash.h:41
#define pool_heap(i)
Definition: pool.h:96
int dirty
Definition: xhash.h:49
pool_t p
Definition: xhash.h:47
void(* xhash_walker)(const char *key, int keylen, void *val, void *arg)
Definition: xhash.h:67
void * pmalloco(pool_t p, int size)
easy safety utility (for creating blank mem for structs, etc)
Definition: pool.c:183
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
static int _xhasher(const char *s, int len)
Definition: xhash.c:29
const char * key
Definition: xhash.h:40
int xhash_iter_get(xht h, const char **key, int *keylen, void **val)
Definition: xhash.c:374
void * val
Definition: xhash.h:42
void xhash_zap(xht h, const char *key)
Definition: xhash.c:235
void xhash_stat(xht h)
Definition: xhash.c:250
void xhash_zapx(xht h, const char *key, int len)
Definition: xhash.c:219
int iter_bucket
Definition: xhash.h:53
static xhn _xhash_node_get(xht h, const char *key, int len, int index)
Definition: xhash.c:85
int xhash_dirty(xht h)
return the dirty flag (and reset)
Definition: xhash.c:285
xhn iter_node
Definition: xhash.h:54
void xhash_zap_inner(xht h, xhn n, int index)
Definition: xhash.c:190
int xhash_count(xht h)
return the total number of entries in this xht
Definition: xhash.c:297
int xhash_iter_first(xht h)
iteration
Definition: xhash.c:311
void xhash_walk(xht h, xhash_walker w, void *arg)
Definition: xhash.c:268
pool_t xhash_pool(xht h)
get our pool
Definition: xhash.c:305
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
void xhash_putx(xht h, const char *key, int len, void *val)
Definition: xhash.c:130
struct xhn_struct * prev
Definition: xhash.h:39
xht xhash_new(int prime)
Definition: xhash.c:96
struct xhn_struct * zen
Definition: xhash.h:51
pool - base node for a pool.
Definition: pool.h:80
hashtables
struct xhn_struct * next
Definition: xhash.h:38