jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 #include "xhash.h" 00022 #include "util.h" 00023 00024 00025 /* Generates a hash code for a string. 00026 * This function uses the ELF hashing algorithm as reprinted in 00027 * Andrew Binstock, "Hashing Rehashed," Dr. Dobb's Journal, April 1996. 00028 */ 00029 static int _xhasher(const char *s, int len) 00030 { 00031 /* ELF hash uses unsigned chars and unsigned arithmetic for portability */ 00032 const unsigned char *name = (const unsigned char *)s; 00033 unsigned long h = 0, g; 00034 int i; 00035 00036 for(i=0;i<len;i++) 00037 { /* do some fancy bitwanking on the string */ 00038 h = (h << 4) + (unsigned long)(name[i]); 00039 if ((g = (h & 0xF0000000UL))!=0) 00040 h ^= (g >> 24); 00041 h &= ~g; 00042 00043 } 00044 00045 return (int)h; 00046 } 00047 00048 00049 static xhn _xhash_node_new(xht h, int index) 00050 { 00051 xhn n; 00052 int i = index % h->prime; 00053 00054 /* track total */ 00055 h->count++; 00056 00057 #ifdef XHASH_DEBUG 00058 h->stat[i]++; 00059 #endif 00060 00061 // if the zen[i] is empty, reuse it, else get a new one. 00062 n = &h->zen[i]; 00063 00064 if( n->key != NULL ) 00065 { 00066 if( h->free_list ) 00067 { 00068 n = h->free_list; 00069 h->free_list = h->free_list->next; 00070 }else 00071 n = pmalloco(h->p, sizeof(_xhn)); 00072 00073 //add it to the bucket list head. 00074 n->prev = &h->zen[i]; 00075 n->next = h->zen[i].next; 00076 00077 if( n->next ) n->next->prev = n; 00078 h->zen[i].next = n; 00079 } 00080 00081 return n; 00082 } 00083 00084 00085 static xhn _xhash_node_get(xht h, const char *key, int len, int index) 00086 { 00087 xhn n; 00088 int i = index % h->prime; 00089 for(n = &h->zen[i]; n != NULL; n = n->next) 00090 if(n->key != NULL && (n->keylen==len) && (strncmp(key, n->key, len) == 0)) 00091 return n; 00092 return NULL; 00093 } 00094 00095 00096 xht xhash_new(int prime) 00097 { 00098 xht xnew; 00099 pool_t p; 00100 00101 /* log_debug(ZONE,"creating new hash table of size %d",prime); */ 00102 00109 p = pool_heap(sizeof(_xhn)*prime + sizeof(_xht)); 00110 xnew = pmalloco(p, sizeof(_xht)); 00111 xnew->prime = prime; 00112 xnew->p = p; 00113 xnew->zen = pmalloco(p, sizeof(_xhn)*prime); /* array of xhn size of prime */ 00114 00115 xnew->free_list = NULL; 00116 00117 xnew->iter_bucket = -1; 00118 xnew->iter_node = NULL; 00119 00120 #ifdef XHASH_DEBUG 00121 xnew->stat = pmalloco(p, sizeof(int)*prime ); 00122 #else 00123 xnew->stat = NULL; 00124 #endif 00125 00126 return xnew; 00127 } 00128 00129 00130 void xhash_putx(xht h, const char *key, int len, void *val) 00131 { 00132 int index; 00133 xhn n; 00134 00135 if(h == NULL || key == NULL) 00136 return; 00137 00138 index = _xhasher(key,len); 00139 00140 /* dirty the xht */ 00141 h->dirty++; 00142 00143 /* if existing key, replace it */ 00144 if((n = _xhash_node_get(h, key, len, index)) != NULL) 00145 { 00146 /* log_debug(ZONE,"replacing %s with new val %X",key,val); */ 00147 00148 n->key = key; 00149 n->keylen = len; 00150 n->val = val; 00151 return; 00152 } 00153 00154 /* log_debug(ZONE,"saving %s val %X",key,val); */ 00155 00156 /* new node */ 00157 n = _xhash_node_new(h, index); 00158 n->key = key; 00159 n->keylen = len; 00160 n->val = val; 00161 } 00162 00163 void xhash_put(xht h, const char *key, void *val) 00164 { 00165 if(h == NULL || key == NULL) return; 00166 xhash_putx(h,key,strlen(key),val); 00167 } 00168 00169 00170 void *xhash_getx(xht h, const char *key, int len) 00171 { 00172 xhn n; 00173 00174 if(h == NULL || key == NULL || len <= 0 || (n = _xhash_node_get(h, key, len, _xhasher(key,len))) == NULL) 00175 { 00176 /* log_debug(ZONE,"failed lookup of %s",key); */ 00177 return NULL; 00178 } 00179 00180 /* log_debug(ZONE,"found %s returning %X",key,n->val); */ 00181 return n->val; 00182 } 00183 00184 void *xhash_get(xht h, const char *key) 00185 { 00186 if(h == NULL || key == NULL) return NULL; 00187 return xhash_getx(h,key,strlen(key)); 00188 } 00189 00190 void xhash_zap_inner( xht h, xhn n, int index) 00191 { 00192 int i = index % h->prime; 00193 00194 // if element:n is in bucket list and it's not the current iter 00195 if( &h->zen[i] != n && h->iter_node != n ) 00196 { 00197 if(n->prev) n->prev->next = n->next; 00198 if(n->next) n->next->prev = n->prev; 00199 00200 // add it to the free_list head. 00201 n->prev = NULL; 00202 n->next = h->free_list; 00203 h->free_list = n; 00204 } 00205 00206 //empty the value. 00207 n->key = NULL; 00208 n->val = NULL; 00209 00210 /* dirty the xht and track the total */ 00211 h->dirty++; 00212 h->count--; 00213 00214 #ifdef XHASH_DEBUG 00215 h->stat[i]--; 00216 #endif 00217 } 00218 00219 void xhash_zapx(xht h, const char *key, int len) 00220 { 00221 xhn n; 00222 int index; 00223 00224 if( !h || !key ) return; 00225 00226 index = _xhasher(key,len); 00227 n = _xhash_node_get(h, key, len, index); 00228 if( !n ) return; 00229 00230 /* log_debug(ZONE,"zapping %s",key); */ 00231 00232 xhash_zap_inner(h ,n, index ); 00233 } 00234 00235 void xhash_zap(xht h, const char *key) 00236 { 00237 if(h == NULL || key == NULL) return; 00238 xhash_zapx(h,key,strlen(key)); 00239 } 00240 00241 void xhash_free(xht h) 00242 { 00243 /* log_debug(ZONE,"hash free %X",h); */ 00244 00246 if(h) pool_free(h->p); 00247 00248 } 00249 00250 void xhash_stat( xht h ) 00251 { 00252 #ifdef XHASH_DEBUG 00253 if( !h ) return; 00254 00255 fprintf(stderr, "XHASH: table prime: %d , number of elements: %d\n", h->prime, h->count ); 00256 00257 int i; 00258 for( i = 0; i< h->prime ; ++i ) 00259 { 00260 if( h->stat[i] > 1 ) 00261 fprintf(stderr, "%d: %d\t", i, h->stat[i]); 00262 } 00263 fprintf(stderr, "\n"); 00264 00265 #endif 00266 } 00267 00268 void xhash_walk(xht h, xhash_walker w, void *arg) 00269 { 00270 int i; 00271 xhn n; 00272 00273 if(h == NULL || w == NULL) 00274 return; 00275 00276 /* log_debug(ZONE,"walking %X",h); */ 00277 00278 for(i = 0; i < h->prime; i++) 00279 for(n = &h->zen[i]; n != NULL; n = n->next) 00280 if(n->key != NULL && n->val != NULL) 00281 (*w)(n->key, n->keylen, n->val, arg); 00282 } 00283 00285 int xhash_dirty(xht h) 00286 { 00287 int dirty; 00288 00289 if(h == NULL) return 1; 00290 00291 dirty = h->dirty; 00292 h->dirty = 0; 00293 return dirty; 00294 } 00295 00297 int xhash_count(xht h) 00298 { 00299 if(h == NULL) return 0; 00300 00301 return h->count; 00302 } 00303 00305 pool_t xhash_pool(xht h) 00306 { 00307 return h->p; 00308 } 00309 00311 int xhash_iter_first(xht h) { 00312 if(h == NULL) return 0; 00313 00314 h->iter_bucket = -1; 00315 h->iter_node = NULL; 00316 00317 return xhash_iter_next(h); 00318 } 00319 00320 int xhash_iter_next(xht h) { 00321 if(h == NULL) return 0; 00322 00323 /* next in this bucket */ 00324 h->iter_node = h->iter_node ? h->iter_node->next : NULL; 00325 while(h->iter_node != NULL) { 00326 xhn n = h->iter_node; 00327 00328 if(n->key != NULL && n->val != NULL) 00329 return 1; 00330 00331 h->iter_node = n->next; 00332 00333 if (n != &h->zen[h->iter_bucket]) { 00334 if(n->prev) n->prev->next = n->next; 00335 if(n->next) n->next->prev = n->prev; 00336 00337 // add it to the free_list head. 00338 n->prev = NULL; 00339 n->next = h->free_list; 00340 h->free_list = n; 00341 } 00342 } 00343 00344 /* next bucket */ 00345 for(h->iter_bucket++; h->iter_bucket < h->prime; h->iter_bucket++) { 00346 h->iter_node = &h->zen[h->iter_bucket]; 00347 00348 while(h->iter_node != NULL) { 00349 if(h->iter_node->key != NULL && h->iter_node->val != NULL) 00350 return 1; 00351 00352 h->iter_node = h->iter_node->next; 00353 } 00354 } 00355 00356 /* there is no next */ 00357 h->iter_bucket = -1; 00358 h->iter_node = NULL; 00359 00360 return 0; 00361 } 00362 00363 void xhash_iter_zap(xht h) 00364 { 00365 int index; 00366 00367 if( !h || !h->iter_node ) return; 00368 00369 index = _xhasher( h->iter_node->key, h->iter_node->keylen ); 00370 00371 xhash_zap_inner( h ,h->iter_node, index); 00372 } 00373 00374 int xhash_iter_get(xht h, const char **key, int *keylen, void **val) { 00375 if(h == NULL || (key == NULL && val == NULL) || (key != NULL && keylen == NULL)) return 0; 00376 00377 if(h->iter_node == NULL) { 00378 if(key != NULL) *key = NULL; 00379 if(val != NULL) *val = NULL; 00380 return 0; 00381 } 00382 00383 if(key != NULL) { 00384 *key = h->iter_node->key; 00385 *keylen = h->iter_node->keylen; 00386 } 00387 if(val != NULL) *val = h->iter_node->val; 00388 00389 return 1; 00390 }