hashmap: add disallow_rehash setting

Teach hashmap to allow rehashes to be suppressed. This is useful when hashmaps are accessed by multiple threads. It still requires the caller to properly manage their locking. This just prevents unexpected rehashing during inserts and deletes. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Hostetler committed Mar 22, 2017 at 17:14 UTC 0607e10009ee4e37cb49b4cec8d28a9dda1656a4
2 files changed +35 -1
hashmap.c
+11 -1
@@ -104,11 +104,19 @@ static inline unsigned int bucket(const struct hashmap *map,
104 return key->hash & (map->tablesize - 1);
105 }
106
107 +int hashmap_bucket(const struct hashmap *map, unsigned int hash)
108 +{
109 + return hash & (map->tablesize - 1);
110 +}
111 +
112 static void rehash(struct hashmap *map, unsigned int newsize)
113 {
114 unsigned int i, oldsize = map->tablesize;
115 struct hashmap_entry **oldtable = map->table;
116
117 + if (map->disallow_rehash)
118 + return;
119 +
120 alloc_table(map, newsize);
121 for (i = 0; i < oldsize; i++) {
122 struct hashmap_entry *e = oldtable[i];
@@ -141,7 +149,9 @@ void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function,
149 size_t initial_size)
150 {
151 unsigned int size = HASHMAP_INITIAL_SIZE;
144 - map->size = 0;
152 +
153 + memset(map, 0, sizeof(*map));
154 +
155 map->cmpfn = equals_function ? equals_function : always_equal;
156
157 /* calculate initial table size and allocate the table */
hashmap.h
+24
@@ -39,6 +39,7 @@ struct hashmap {
39 struct hashmap_entry **table;
40 hashmap_cmp_fn cmpfn;
41 unsigned int size, tablesize, grow_at, shrink_at;
42 + unsigned disallow_rehash : 1;
43 };
44
45 struct hashmap_iter {
@@ -77,6 +78,29 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map,
78 return hashmap_get(map, &key, keydata);
79 }
80
81 +int hashmap_bucket(const struct hashmap *map, unsigned int hash);
82 +
83 +/*
84 + * Disallow/allow rehashing of the hashmap.
85 + * This is useful if the caller knows that the hashmap
86 + * needs multi-threaded access. The caller is still
87 + * required to guard/lock searches and inserts in a
88 + * manner appropriate to their usage. This simply
89 + * prevents the table from being unexpectedly re-mapped.
90 + *
91 + * If is up to the caller to ensure that the hashmap is
92 + * initialized to a reasonable size to prevent poor
93 + * performance.
94 + *
95 + * When value=1, prevent future rehashes on adds and deleted.
96 + * When value=0, allow future rehahses. This DOES NOT force
97 + * a rehash now.
98 + */
99 +static inline void hashmap_disallow_rehash(struct hashmap *map, unsigned value)
100 +{
101 + map->disallow_rehash = value;
102 +}
103 +
104 /* hashmap_iter functions */
105
106 extern void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter);