]> git.proxmox.com Git - mirror_frr.git/blob - lib/hash.c
Merge pull request #2373 from rubenk/specfile-cleanups
[mirror_frr.git] / lib / hash.c
1 /* Hash routine.
2 * Copyright (C) 1998 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your
9 * option) any later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22 #include <math.h>
23
24 #include "hash.h"
25 #include "memory.h"
26 #include "linklist.h"
27 #include "termtable.h"
28 #include "vty.h"
29 #include "command.h"
30 #include "libfrr.h"
31
32 DEFINE_MTYPE(LIB, HASH, "Hash")
33 DEFINE_MTYPE(LIB, HASH_BACKET, "Hash Bucket")
34 DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
35
36 pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
37 static struct list *_hashes;
38
39 struct hash *hash_create_size(unsigned int size,
40 unsigned int (*hash_key)(void *),
41 int (*hash_cmp)(const void *, const void *),
42 const char *name)
43 {
44 struct hash *hash;
45
46 assert((size & (size - 1)) == 0);
47 hash = XCALLOC(MTYPE_HASH, sizeof(struct hash));
48 hash->index =
49 XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_backet *) * size);
50 hash->size = size;
51 hash->hash_key = hash_key;
52 hash->hash_cmp = hash_cmp;
53 hash->count = 0;
54 hash->name = name ? XSTRDUP(MTYPE_HASH, name) : NULL;
55 hash->stats.empty = hash->size;
56
57 pthread_mutex_lock(&_hashes_mtx);
58 {
59 if (!_hashes)
60 _hashes = list_new();
61
62 listnode_add(_hashes, hash);
63 }
64 pthread_mutex_unlock(&_hashes_mtx);
65
66 return hash;
67 }
68
69 struct hash *hash_create(unsigned int (*hash_key)(void *),
70 int (*hash_cmp)(const void *, const void *),
71 const char *name)
72 {
73 return hash_create_size(HASH_INITIAL_SIZE, hash_key, hash_cmp, name);
74 }
75
76 void *hash_alloc_intern(void *arg)
77 {
78 return arg;
79 }
80
81 #define hash_update_ssq(hz, old, new) \
82 atomic_fetch_add_explicit(&hz->stats.ssq, (new + old) * (new - old), \
83 memory_order_relaxed);
84
85 /* Expand hash if the chain length exceeds the threshold. */
86 static void hash_expand(struct hash *hash)
87 {
88 unsigned int i, new_size;
89 struct hash_backet *hb, *hbnext, **new_index;
90
91 new_size = hash->size * 2;
92
93 if (hash->max_size && new_size > hash->max_size)
94 return;
95
96 new_index = XCALLOC(MTYPE_HASH_INDEX,
97 sizeof(struct hash_backet *) * new_size);
98 if (new_index == NULL)
99 return;
100
101 hash->stats.empty = new_size;
102
103 for (i = 0; i < hash->size; i++)
104 for (hb = hash->index[i]; hb; hb = hbnext) {
105 unsigned int h = hb->key & (new_size - 1);
106
107 hbnext = hb->next;
108 hb->next = new_index[h];
109
110 int oldlen = hb->next ? hb->next->len : 0;
111 int newlen = oldlen + 1;
112
113 if (newlen == 1)
114 hash->stats.empty--;
115 else
116 hb->next->len = 0;
117
118 hb->len = newlen;
119
120 hash_update_ssq(hash, oldlen, newlen);
121
122 new_index[h] = hb;
123 }
124
125 /* Switch to new table */
126 XFREE(MTYPE_HASH_INDEX, hash->index);
127 hash->size = new_size;
128 hash->index = new_index;
129 }
130
131 void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *))
132 {
133 unsigned int key;
134 unsigned int index;
135 void *newdata;
136 struct hash_backet *backet;
137
138 if (!alloc_func && !hash->count)
139 return NULL;
140
141 key = (*hash->hash_key)(data);
142 index = key & (hash->size - 1);
143
144 for (backet = hash->index[index]; backet != NULL;
145 backet = backet->next) {
146 if (backet->key == key && (*hash->hash_cmp)(backet->data, data))
147 return backet->data;
148 }
149
150 if (alloc_func) {
151 newdata = (*alloc_func)(data);
152 if (newdata == NULL)
153 return NULL;
154
155 if (HASH_THRESHOLD(hash->count + 1, hash->size)) {
156 hash_expand(hash);
157 index = key & (hash->size - 1);
158 }
159
160 backet = XCALLOC(MTYPE_HASH_BACKET, sizeof(struct hash_backet));
161 backet->data = newdata;
162 backet->key = key;
163 backet->next = hash->index[index];
164 hash->index[index] = backet;
165 hash->count++;
166
167 int oldlen = backet->next ? backet->next->len : 0;
168 int newlen = oldlen + 1;
169
170 if (newlen == 1)
171 hash->stats.empty--;
172 else
173 backet->next->len = 0;
174
175 backet->len = newlen;
176
177 hash_update_ssq(hash, oldlen, newlen);
178
179 return backet->data;
180 }
181 return NULL;
182 }
183
184 void *hash_lookup(struct hash *hash, void *data)
185 {
186 return hash_get(hash, data, NULL);
187 }
188
189 unsigned int string_hash_make(const char *str)
190 {
191 unsigned int hash = 0;
192
193 while (*str)
194 hash = (hash * 33) ^ (unsigned int)*str++;
195
196 return hash;
197 }
198
199 void *hash_release(struct hash *hash, void *data)
200 {
201 void *ret;
202 unsigned int key;
203 unsigned int index;
204 struct hash_backet *backet;
205 struct hash_backet *pp;
206
207 key = (*hash->hash_key)(data);
208 index = key & (hash->size - 1);
209
210 for (backet = pp = hash->index[index]; backet; backet = backet->next) {
211 if (backet->key == key
212 && (*hash->hash_cmp)(backet->data, data)) {
213 int oldlen = hash->index[index]->len;
214 int newlen = oldlen - 1;
215
216 if (backet == pp)
217 hash->index[index] = backet->next;
218 else
219 pp->next = backet->next;
220
221 if (hash->index[index])
222 hash->index[index]->len = newlen;
223 else
224 hash->stats.empty++;
225
226 hash_update_ssq(hash, oldlen, newlen);
227
228 ret = backet->data;
229 XFREE(MTYPE_HASH_BACKET, backet);
230 hash->count--;
231 return ret;
232 }
233 pp = backet;
234 }
235 return NULL;
236 }
237
238 void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *),
239 void *arg)
240 {
241 unsigned int i;
242 struct hash_backet *hb;
243 struct hash_backet *hbnext;
244 uint32_t count = 0;
245
246 for (i = 0; i < hash->size; i++) {
247 for (hb = hash->index[i]; hb; hb = hbnext) {
248 /* get pointer to next hash backet here, in case (*func)
249 * decides to delete hb by calling hash_release
250 */
251 hbnext = hb->next;
252 (*func)(hb, arg);
253 count++;
254
255 }
256 if (count == hash->count)
257 return;
258 }
259 }
260
261 void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *),
262 void *arg)
263 {
264 unsigned int i;
265 struct hash_backet *hb;
266 struct hash_backet *hbnext;
267 int ret = HASHWALK_CONTINUE;
268 uint32_t count = 0;
269
270 for (i = 0; i < hash->size; i++) {
271 for (hb = hash->index[i]; hb; hb = hbnext) {
272 /* get pointer to next hash backet here, in case (*func)
273 * decides to delete hb by calling hash_release
274 */
275 hbnext = hb->next;
276 ret = (*func)(hb, arg);
277 if (ret == HASHWALK_ABORT)
278 return;
279 count++;
280 }
281 if (count == hash->count)
282 return;
283 }
284 }
285
286 void hash_clean(struct hash *hash, void (*free_func)(void *))
287 {
288 unsigned int i;
289 struct hash_backet *hb;
290 struct hash_backet *next;
291
292 for (i = 0; i < hash->size; i++) {
293 for (hb = hash->index[i]; hb; hb = next) {
294 next = hb->next;
295
296 if (free_func)
297 (*free_func)(hb->data);
298
299 XFREE(MTYPE_HASH_BACKET, hb);
300 hash->count--;
301 }
302 hash->index[i] = NULL;
303 }
304
305 hash->stats.ssq = 0;
306 hash->stats.empty = hash->size;
307 }
308
309 static void hash_to_list_iter(struct hash_backet *hb, void *arg)
310 {
311 struct list *list = arg;
312
313 listnode_add(list, hb->data);
314 }
315
316 struct list *hash_to_list(struct hash *hash)
317 {
318 struct list *list = list_new();
319
320 hash_iterate(hash, hash_to_list_iter, list);
321 return list;
322 }
323
324 void hash_free(struct hash *hash)
325 {
326 pthread_mutex_lock(&_hashes_mtx);
327 {
328 if (_hashes) {
329 listnode_delete(_hashes, hash);
330 if (_hashes->count == 0) {
331 list_delete_and_null(&_hashes);
332 }
333 }
334 }
335 pthread_mutex_unlock(&_hashes_mtx);
336
337 if (hash->name)
338 XFREE(MTYPE_HASH, hash->name);
339
340 XFREE(MTYPE_HASH_INDEX, hash->index);
341 XFREE(MTYPE_HASH, hash);
342 }
343
344
345 /* CLI commands ------------------------------------------------------------ */
346
347 DEFUN_NOSH(show_hash_stats,
348 show_hash_stats_cmd,
349 "show debugging hashtable [statistics]",
350 SHOW_STR
351 DEBUG_STR
352 "Statistics about hash tables\n"
353 "Statistics about hash tables\n")
354 {
355 struct hash *h;
356 struct listnode *ln;
357 struct ttable *tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
358
359 ttable_add_row(tt, "Hash table|Buckets|Entries|Empty|LF|SD|FLF|SD");
360 tt->style.cell.lpad = 2;
361 tt->style.cell.rpad = 1;
362 tt->style.corner = '+';
363 ttable_restyle(tt);
364 ttable_rowseps(tt, 0, BOTTOM, true, '-');
365
366 /* Summary statistics calculated are:
367 *
368 * - Load factor: This is the number of elements in the table divided
369 * by the number of buckets. Since this hash table implementation
370 * uses chaining, this value can be greater than 1.
371 * This number provides information on how 'full' the table is, but
372 * does not provide information on how evenly distributed the
373 * elements are.
374 * Notably, a load factor >= 1 does not imply that every bucket has
375 * an element; with a pathological hash function, all elements could
376 * be in a single bucket.
377 *
378 * - Full load factor: this is the number of elements in the table
379 * divided by the number of buckets that have some elements in them.
380 *
381 * - Std. Dev.: This is the standard deviation calculated from the
382 * relevant load factor. If the load factor is the mean of number of
383 * elements per bucket, the standard deviation measures how much any
384 * particular bucket is likely to deviate from the mean.
385 * As a rule of thumb this number should be less than 2, and ideally
386 * <= 1 for optimal performance. A number larger than 3 generally
387 * indicates a poor hash function.
388 */
389
390 double lf; // load factor
391 double flf; // full load factor
392 double var; // overall variance
393 double fvar; // full variance
394 double stdv; // overall stddev
395 double fstdv; // full stddev
396
397 long double x2; // h->count ^ 2
398 long double ldc; // (long double) h->count
399 long double full; // h->size - h->stats.empty
400 long double ssq; // ssq casted to long double
401
402 pthread_mutex_lock(&_hashes_mtx);
403 if (!_hashes) {
404 pthread_mutex_unlock(&_hashes_mtx);
405 ttable_del(tt);
406 vty_out(vty, "No hash tables in use.\n");
407 return CMD_SUCCESS;
408 }
409
410 for (ALL_LIST_ELEMENTS_RO(_hashes, ln, h)) {
411 if (!h->name)
412 continue;
413
414 ssq = (long double)h->stats.ssq;
415 x2 = h->count * h->count;
416 ldc = (long double)h->count;
417 full = h->size - h->stats.empty;
418 lf = h->count / (double)h->size;
419 flf = full ? h->count / (double)(full) : 0;
420 var = ldc ? (1.0 / ldc) * (ssq - x2 / ldc) : 0;
421 fvar = full ? (1.0 / full) * (ssq - x2 / full) : 0;
422 var = (var < .0001) ? 0 : var;
423 fvar = (fvar < .0001) ? 0 : fvar;
424 stdv = sqrt(var);
425 fstdv = sqrt(fvar);
426
427 ttable_add_row(tt, "%s|%d|%ld|%.0f%%|%.2lf|%.2lf|%.2lf|%.2lf",
428 h->name, h->size, h->count,
429 (h->stats.empty / (double)h->size) * 100, lf,
430 stdv, flf, fstdv);
431 }
432 pthread_mutex_unlock(&_hashes_mtx);
433
434 /* display header */
435 char header[] = "Showing hash table statistics for ";
436 char underln[sizeof(header) + strlen(frr_protonameinst)];
437 memset(underln, '-', sizeof(underln));
438 underln[sizeof(underln) - 1] = '\0';
439 vty_out(vty, "%s%s\n", header, frr_protonameinst);
440 vty_out(vty, "%s\n", underln);
441
442 vty_out(vty, "# allocated: %d\n", _hashes->count);
443 vty_out(vty, "# named: %d\n\n", tt->nrows - 1);
444
445 if (tt->nrows > 1) {
446 ttable_colseps(tt, 0, RIGHT, true, '|');
447 char *table = ttable_dump(tt, "\n");
448 vty_out(vty, "%s\n", table);
449 XFREE(MTYPE_TMP, table);
450 } else
451 vty_out(vty, "No named hash tables to display.\n");
452
453 ttable_del(tt);
454
455 return CMD_SUCCESS;
456 }
457
458 void hash_cmd_init()
459 {
460 install_element(ENABLE_NODE, &show_hash_stats_cmd);
461 }