Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Replaced glib dependency with a custom hash table.

This greatly simplifies builds where a package system that can deal
with glib is unavailable.
  • Loading branch information...
commit ea4d0640faed655b16ec4a34e04d386684e38fdd 1 parent d4b7434
Dustin Sallings dustin authored
7 Makefile.am
@@ -4,17 +4,12 @@ bin_PROGRAMS = moxi
4 4 ##pkginclude_HEADERS = protocol_binary.h
5 5 noinst_PROGRAMS = moxi-debug sizes testapp
6 6
7   -## INCLUDES is apparently not previously set, if you set it
8   -## change this
9   -INCLUDES = $(GLIB2_CFLAGS)
10   -LIBS += $(GLIB2_LIBS)
11   -LIBS += -lgthread-2.0
12   -
13 7 BUILT_SOURCES =
14 8
15 9 testapp_SOURCES = testapp.c util.c util.h
16 10
17 11 moxi_SOURCES = memcached.c memcached.h \
  12 + genhash.c genhash.h genhash_int.h \
18 13 hash.c hash.h \
19 14 slabs.c slabs.h \
20 15 items.c items.h \
90 agent_stats.c
@@ -38,17 +38,16 @@ static void add_proxy_stats(proxy_stats *agg,
38 38 static void add_stats_cmd(proxy_stats_cmd *agg,
39 39 proxy_stats_cmd *x);
40 40
41   -void map_pstd_foreach_free(gpointer key,
42   - gpointer value,
43   - gpointer user_data);
  41 +void map_pstd_foreach_free(const void *key,
  42 + const void *value,
  43 + void *user_data);
  44 +void map_pstd_foreach_emit(const void *key,
  45 + const void *value,
  46 + void *user_data);
44 47
45   -void map_pstd_foreach_emit(gpointer key,
46   - gpointer value,
47   - gpointer user_data);
48   -
49   -void map_pstd_foreach_merge(gpointer key,
50   - gpointer value,
51   - gpointer user_data);
  48 +void map_pstd_foreach_merge(const void *key,
  49 + const void *value,
  50 + void *user_data);
52 51
53 52 struct main_stats_collect_info {
54 53 proxy_main *m;
@@ -190,9 +189,7 @@ enum conflate_mgmt_cb_result on_conflate_get_stats(void *userdata,
190 189 // is keyed by each proxy's "binding:name", and whose
191 190 // values are proxy_stats_td.
192 191 //
193   - GHashTable *map_pstd =
194   - g_hash_table_new(g_str_hash,
195   - g_str_equal);
  192 + genhash_t *map_pstd = genhash_init(128, strhash_ops);
196 193 if (map_pstd != NULL)
197 194 work_collect_init(&ca[i], -1, map_pstd);
198 195 else
@@ -213,33 +210,29 @@ enum conflate_mgmt_cb_result on_conflate_get_stats(void *userdata,
213 210 assert(m->nthreads > 0);
214 211
215 212 if (msci.do_stats) {
216   - GHashTable *end_pstd = ca[1].data;
  213 + genhash_t *end_pstd = ca[1].data;
217 214 if (end_pstd != NULL) {
218 215 // Skip the first worker thread (index 1)'s results,
219 216 // because that's where we'll aggregate final results.
220 217 //
221 218 for (i = 2; i < m->nthreads; i++) {
222   - GHashTable *map_pstd = ca[i].data;
  219 + genhash_t *map_pstd = ca[i].data;
223 220 if (map_pstd != NULL) {
224   - g_hash_table_foreach(map_pstd,
225   - map_pstd_foreach_merge,
226   - end_pstd);
  221 + genhash_iter(map_pstd, map_pstd_foreach_merge,
  222 + end_pstd);
227 223 }
228 224 }
229 225
230   - g_hash_table_foreach(end_pstd,
231   - map_pstd_foreach_emit,
232   - &msci);
  226 + genhash_iter(end_pstd, map_pstd_foreach_emit, &msci);
233 227 }
234 228 }
235 229
236 230 for (i = 1; i < m->nthreads; i++) {
237   - GHashTable *map_pstd = ca[i].data;
  231 + genhash_t *map_pstd = ca[i].data;
238 232 if (map_pstd != NULL) {
239   - g_hash_table_foreach(map_pstd,
240   - map_pstd_foreach_free,
241   - NULL);
242   - g_hash_table_destroy(map_pstd);
  233 + genhash_iter(map_pstd, map_pstd_foreach_free, NULL);
  234 + genhash_free(map_pstd);
  235 + map_pstd = NULL;
243 236 }
244 237 }
245 238
@@ -250,16 +243,14 @@ enum conflate_mgmt_cb_result on_conflate_get_stats(void *userdata,
250 243 return RV_OK;
251 244 }
252 245
253   -void map_pstd_foreach_merge(gpointer key,
254   - gpointer value,
255   - gpointer user_data) {
256   - GHashTable *map_end_pstd = user_data;
  246 +void map_pstd_foreach_merge(const void *key,
  247 + const void *value,
  248 + void *user_data) {
  249 + genhash_t *map_end_pstd = user_data;
257 250 if (key != NULL &&
258 251 map_end_pstd != NULL) {
259 252 proxy_stats_td *cur_pstd = (proxy_stats_td *) value;
260   - proxy_stats_td *end_pstd =
261   - g_hash_table_lookup(map_end_pstd,
262   - key);
  253 + proxy_stats_td *end_pstd = genhash_find(map_end_pstd, key);
263 254 if (cur_pstd != NULL &&
264 255 end_pstd != NULL) {
265 256 add_proxy_stats_td(end_pstd, cur_pstd);
@@ -346,8 +337,7 @@ static void main_stats_collect(void *data0, void *data1) {
346 337 pthread_mutex_lock(p->front_cache.lock);
347 338
348 339 if (p->front_cache.map != NULL)
349   - emit_f("front_cache_size",
350   - "%u", g_hash_table_size(p->front_cache.map));
  340 + emit_f("front_cache_size", "%u", genhash_size(p->front_cache.map));
351 341
352 342 emit_f("front_cache_max",
353 343 "%u", p->front_cache.max);
@@ -437,7 +427,7 @@ static void work_stats_collect(void *data0, void *data1) {
437 427
438 428 assert(is_listen_thread() == false); // Expecting a worker thread.
439 429
440   - GHashTable *map_pstd = c->data;
  430 + genhash_t *map_pstd = c->data;
441 431 assert(map_pstd != NULL);
442 432
443 433 pthread_mutex_lock(&p->proxy_lock);
@@ -452,14 +442,11 @@ static void work_stats_collect(void *data0, void *data1) {
452 442 pthread_mutex_unlock(&p->proxy_lock);
453 443 locked = false;
454 444
455   - proxy_stats_td *pstd =
456   - g_hash_table_lookup(map_pstd, key_buf);
  445 + proxy_stats_td *pstd = genhash_find(map_pstd, key_buf);
457 446 if (pstd == NULL) {
458 447 pstd = calloc(1, sizeof(proxy_stats_td));
459 448 if (pstd != NULL) {
460   - g_hash_table_insert(map_pstd,
461   - key_buf,
462   - pstd);
  449 + genhash_store(map_pstd, key_buf, pstd);
463 450 key_buf = NULL;
464 451 }
465 452 }
@@ -549,23 +536,24 @@ static void add_stats_cmd(proxy_stats_cmd *agg,
549 536 agg->cas += x->cas;
550 537 }
551 538
552   -void map_pstd_foreach_free(gpointer key,
553   - gpointer value,
554   - gpointer user_data) {
  539 +void map_pstd_foreach_free(const void *key,
  540 + const void *value,
  541 + void *user_data) {
555 542 assert(key != NULL);
556   - free(key);
  543 + free((void*)key);
557 544
558 545 assert(value != NULL);
559   - free(value);
  546 + free((void*)value);
560 547 }
561 548
562   -void map_pstd_foreach_emit(gpointer key,
563   - gpointer value,
564   - gpointer user_data) {
565   - char *name = key;
  549 +void map_pstd_foreach_emit(const void *k,
  550 + const void *value,
  551 + void *user_data) {
  552 +
  553 + const char *name = (const char*)k;
566 554 assert(name != NULL);
567 555
568   - proxy_stats_td *pstd = value;
  556 + proxy_stats_td *pstd = (proxy_stats_td *)value;
569 557 assert(pstd != NULL);
570 558
571 559 const struct main_stats_collect_info *emit = user_data;
3  configure.ac
@@ -300,12 +300,9 @@ AC_SEARCH_LIBS(socket, socket)
300 300 AC_SEARCH_LIBS(gethostbyname, nsl)
301 301 AC_SEARCH_LIBS(umem_cache_create, umem)
302 302
303   -PKG_CHECK_MODULES([GLIB2], [ glib-2.0 >= 2.0.6 ])
304   -AC_SUBST(GLIB2)
305 303 PKG_CHECK_MODULES([CHECK], [check >= 0.9.4])
306 304
307 305 AC_SUBST(DEPS)
308   -AC_SUBST(DEPS)
309 306
310 307 AC_HEADER_STDBOOL
311 308 AC_C_CONST
17 cproxy.c
@@ -389,8 +389,7 @@ void cproxy_on_close_upstream_conn(conn *c) {
389 389 //
390 390 if (found) {
391 391 if (d->multiget != NULL)
392   - g_hash_table_foreach(d->multiget,
393   - multiget_remove_upstream, c);
  392 + genhash_iter(d->multiget, multiget_remove_upstream, c);
394 393
395 394 // The downstream conn's might have iov's that
396 395 // point to the upstream conn's buffers. Also, the
@@ -667,9 +666,9 @@ bool cproxy_release_downstream(downstream *d, bool force) {
667 666 if (d->merger != NULL) {
668 667 // TODO: Allow merger callback to be func pointer.
669 668 //
670   - g_hash_table_foreach(d->merger,
671   - protocol_stats_foreach_write,
672   - d->upstream_conn);
  669 + genhash_iter(d->merger,
  670 + protocol_stats_foreach_write,
  671 + d->upstream_conn);
673 672
674 673 if (update_event(d->upstream_conn, EV_WRITE | EV_PERSIST)) {
675 674 conn_set_state(d->upstream_conn, conn_mwrite);
@@ -704,14 +703,14 @@ bool cproxy_release_downstream(downstream *d, bool force) {
704 703 // Free extra hash tables.
705 704 //
706 705 if (d->multiget != NULL) {
707   - g_hash_table_foreach(d->multiget, multiget_foreach_free, d);
708   - g_hash_table_destroy(d->multiget);
  706 + genhash_iter(d->multiget, multiget_foreach_free, d);
  707 + genhash_free(d->multiget);
709 708 d->multiget = NULL;
710 709 }
711 710
712 711 if (d->merger != NULL) {
713   - g_hash_table_foreach(d->merger, protocol_stats_foreach_free, NULL);
714   - g_hash_table_destroy(d->merger);
  712 + genhash_iter(d->merger, protocol_stats_foreach_free, NULL);
  713 + genhash_free(d->merger);
715 714 d->merger = NULL;
716 715 }
717 716
47 cproxy.h
@@ -3,8 +3,8 @@
3 3 #ifndef CPROXY_H
4 4 #define CPROXY_H
5 5
6   -#include <glib.h>
7 6 #include <libmemcached/memcached.h>
  7 +#include "genhash.h"
8 8 #include "work.h"
9 9 #include "matcher.h"
10 10
@@ -52,7 +52,7 @@ typedef struct {
52 52
53 53 bool key_alloc; // True if mcache must alloc key memory.
54 54
55   - GHashTable *map; // NULL-able, keyed by string, value is item.
  55 + genhash_t *map; // NULL-able, keyed by string, value is item.
56 56
57 57 uint32_t max; // Maxiumum number of items to keep.
58 58
@@ -360,8 +360,8 @@ struct downstream {
360 360 conn *upstream_conn; // Non-NULL when downstream is reserved.
361 361 char *upstream_suffix; // Last bit to write when downstreams are done.
362 362
363   - GHashTable *multiget; // Keyed by string.
364   - GHashTable *merger; // Keyed by string, for merging replies like STATS.
  363 + genhash_t *multiget; // Keyed by string.
  364 + genhash_t *merger; // Keyed by string, for merging replies like STATS.
365 365
366 366 // Timeout is in use when timeout_tv fields are non-zero.
367 367 //
@@ -537,27 +537,30 @@ bool multiget_ascii_downstream(
537 537
538 538 void multiget_ascii_downstream_response(downstream *d, item *it);
539 539
540   -void multiget_foreach_free(gpointer key,
541   - gpointer value,
542   - gpointer user_data);
  540 +void multiget_foreach_free(const void *key,
  541 + const void *value,
  542 + void *user_data);
543 543
544   -void multiget_remove_upstream(gpointer key,
545   - gpointer value,
546   - gpointer user_data);
  544 +void multiget_remove_upstream(const void *key,
  545 + const void *value,
  546 + void *user_data);
547 547
548 548 // Space or null terminated key funcs.
549 549 //
550   -size_t skey_len(const char *key);
551   -guint skey_hash(gconstpointer v);
552   -gboolean skey_equal(gconstpointer v1, gconstpointer v2);
  550 +size_t skey_len(const char *key);
  551 +int skey_hash(const void *v);
  552 +int skey_equal(const void *v1, const void *v2);
553 553
554   -void helper_g_free(gpointer data);
  554 +extern struct hash_ops strhash_ops;
  555 +extern struct hash_ops skeyhash_ops;
  556 +
  557 +void noop_free(void *v);
555 558
556 559 // Stats handling.
557 560 //
558   -bool protocol_stats_merge_line(GHashTable *merger, char *line);
  561 +bool protocol_stats_merge_line(genhash_t *merger, char *line);
559 562
560   -bool protocol_stats_merge_name_val(GHashTable *merger,
  563 +bool protocol_stats_merge_name_val(genhash_t *merger,
561 564 char *prefix,
562 565 int prefix_len,
563 566 char *name,
@@ -565,13 +568,13 @@ bool protocol_stats_merge_name_val(GHashTable *merger,
565 568 char *val,
566 569 int val_len);
567 570
568   -void protocol_stats_foreach_free(gpointer key,
569   - gpointer value,
570   - gpointer user_data);
  571 +void protocol_stats_foreach_free(const void *key,
  572 + const void *value,
  573 + void *user_data);
571 574
572   -void protocol_stats_foreach_write(gpointer key,
573   - gpointer value,
574   - gpointer user_data);
  575 +void protocol_stats_foreach_write(const void *key,
  576 + const void *value,
  577 + void *user_data);
575 578
576 579 void cproxy_optimize_to_self(downstream *d, conn *uc,
577 580 char *command);
44 cproxy_config.c
@@ -9,7 +9,6 @@
9 9 #include <pthread.h>
10 10 #include <assert.h>
11 11 #include <math.h>
12   -#include <glib.h>
13 12 #include <libmemcached/memcached.h>
14 13 #include "memcached.h"
15 14 #include "cproxy.h"
@@ -86,7 +85,7 @@ size_t skey_len(const char *key) {
86 85
87 86 /** Hash of key that may be zero or space terminated.
88 87 */
89   -guint skey_hash(gconstpointer v) {
  88 +int skey_hash(const void *v) {
90 89 assert(v);
91 90
92 91 const char *key = v;
@@ -98,7 +97,7 @@ guint skey_hash(gconstpointer v) {
98 97 /** Returns true if two keys are equal, where the
99 98 * keys may be zero or space terminated.
100 99 */
101   -gboolean skey_equal(gconstpointer v1, gconstpointer v2) {
  100 +int skey_equal(const void *v1, const void *v2) {
102 101 assert(v1);
103 102 assert(v2);
104 103
@@ -111,10 +110,43 @@ gboolean skey_equal(gconstpointer v1, gconstpointer v2) {
111 110 return (n1 == n2 && strncmp(k1, k2, n1) == 0);
112 111 }
113 112
114   -void helper_g_free(gpointer data) {
115   - free(data);
  113 +static void *noop_dup(const void *v)
  114 +{
  115 + return (void*)v;
116 116 }
117 117
  118 +void noop_free(void *v) {
  119 + /* Nothing */
  120 +}
  121 +
  122 +static int
  123 +str_eq(const void* p1, const void*p2)
  124 +{
  125 + char *str1=(char *)p1;
  126 + char *str2=(char *)p2;
  127 + assert(str1 != NULL);
  128 + assert(str2 != NULL);
  129 + return strcmp(str1, str2) == 0;
  130 +}
  131 +
  132 +struct hash_ops strhash_ops = {
  133 + .hashfunc = genhash_string_hash,
  134 + .hasheq = str_eq,
  135 + .dupKey = noop_dup,
  136 + .dupValue = noop_dup,
  137 + .freeKey = noop_free,
  138 + .freeValue = noop_free
  139 +};
  140 +
  141 +struct hash_ops skeyhash_ops = {
  142 + .hashfunc = skey_hash,
  143 + .hasheq = skey_equal,
  144 + .dupKey = noop_dup,
  145 + .dupValue = noop_dup,
  146 + .freeKey = noop_free,
  147 + .freeValue = noop_free
  148 +};
  149 +
118 150 /** Returns pointer to first non-space char in string.
119 151 */
120 152 char *skipspace(char *s) {
@@ -196,8 +228,6 @@ int cproxy_init(char *cfg_str,
196 228 if (cproxy_core_initted == false) {
197 229 cproxy_core_initted = true;
198 230
199   - g_thread_init(NULL);
200   -
201 231 gethostname(cproxy_hostname, sizeof(cproxy_hostname));
202 232
203 233 cproxy_init_a2a();
39 cproxy_front.c
@@ -99,10 +99,11 @@ void mcache_start(mcache *m, uint32_t max) {
99 99 assert(m->lru_tail == NULL);
100 100 assert(m->oldest_live == 0);
101 101
102   - m->map = g_hash_table_new_full(skey_hash,
103   - skey_equal,
104   - m->key_alloc ? helper_g_free : NULL,
105   - m->funcs->item_dec_ref);
  102 + struct hash_ops hops = skeyhash_ops;
  103 + hops.freeKey = m->key_alloc ? free : noop_free;
  104 + hops.freeValue = m->funcs->item_dec_ref;
  105 +
  106 + m->map = genhash_init(128, hops);
106 107 if (m->map != NULL) {
107 108 m->max = max;
108 109 m->lru_head = NULL;
@@ -134,7 +135,7 @@ void mcache_stop(mcache *m) {
134 135 if (m->lock)
135 136 pthread_mutex_lock(m->lock);
136 137
137   - GHashTable *x = m->map;
  138 + genhash_t *x = m->map;
138 139
139 140 m->map = NULL;
140 141 m->max = 0;
@@ -148,7 +149,7 @@ void mcache_stop(mcache *m) {
148 149 // Destroying hash table outside the lock.
149 150 //
150 151 if (x != NULL)
151   - g_hash_table_destroy(x);
  152 + genhash_free(x);
152 153 }
153 154
154 155 void *mcache_get(mcache *m, char *key, int key_len,
@@ -164,7 +165,7 @@ void *mcache_get(mcache *m, char *key, int key_len,
164 165 pthread_mutex_lock(m->lock);
165 166
166 167 if (m->map != NULL) {
167   - void *it = g_hash_table_lookup(m->map, key);
  168 + void *it = genhash_find(m->map, key);
168 169 if (it != NULL) {
169 170 mcache_item_unlink(m, it);
170 171
@@ -197,7 +198,7 @@ void *mcache_get(mcache *m, char *key, int key_len,
197 198 fprintf(stderr,
198 199 "mcache expire: %s\n", key);
199 200
200   - g_hash_table_remove(m->map, key);
  201 + genhash_delete(m->map, key);
201 202 } else {
202 203 m->tot_get_misses++;
203 204 }
@@ -230,7 +231,7 @@ void mcache_set(mcache *m, void *it,
230 231 // Evict some items if necessary.
231 232 //
232 233 for (int i = 0; m->lru_tail != NULL && i < 20; i++) {
233   - if (g_hash_table_size(m->map) < m->max)
  234 + if (genhash_size(m->map) < m->max)
234 235 break;
235 236
236 237 void *last_it = m->lru_tail;
@@ -243,16 +244,15 @@ void mcache_set(mcache *m, void *it,
243 244 memcpy(buf, m->funcs->item_key(last_it), len);
244 245 buf[len] = '\0';
245 246
246   - g_hash_table_remove(m->map, buf);
  247 + genhash_delete(m->map, buf);
247 248 } else {
248   - g_hash_table_remove(m->map,
249   - m->funcs->item_key(last_it));
  249 + genhash_delete(m->map, m->funcs->item_key(last_it));
250 250 }
251 251
252 252 m->tot_evictions++;
253 253 }
254 254
255   - if (g_hash_table_size(m->map) < m->max) {
  255 + if (genhash_size(m->map) < m->max) {
256 256 char *key = m->funcs->item_key(it);
257 257 int key_len = m->funcs->item_key_len(it);
258 258 char *key_buf = NULL;
@@ -274,10 +274,7 @@ void mcache_set(mcache *m, void *it,
274 274 }
275 275
276 276 if (key != NULL) {
277   - void *existing =
278   - add_only ?
279   - (void *) g_hash_table_lookup(m->map, key) :
280   - NULL;
  277 + void *existing = add_only ? genhash_find(m->map, key) : NULL;
281 278 if (existing != NULL) {
282 279 mcache_item_unlink(m, existing);
283 280 mcache_item_touch(m, existing);
@@ -297,7 +294,7 @@ void mcache_set(mcache *m, void *it,
297 294 m->funcs->item_set_exptime(it, exptime);
298 295 m->funcs->item_add_ref(it);
299 296
300   - g_hash_table_insert(m->map, key, it);
  297 + genhash_store(m->map, key, it);
301 298
302 299 m->tot_adds++;
303 300 m->tot_add_bytes += m->funcs->item_len(it);
@@ -331,11 +328,11 @@ void mcache_delete(mcache *m, char *key, int key_len) {
331 328 pthread_mutex_lock(m->lock);
332 329
333 330 if (m->map != NULL) {
334   - void *existing = (void *) g_hash_table_lookup(m->map, key);
  331 + void *existing = genhash_find(m->map, key);
335 332 if (existing != NULL) {
336 333 mcache_item_unlink(m, existing);
337 334
338   - g_hash_table_remove(m->map, key);
  335 + genhash_delete(m->map, key);
339 336
340 337 m->tot_deletes++;
341 338 }
@@ -353,7 +350,7 @@ void mcache_flush_all(mcache *m, uint32_t msec_exp) {
353 350 pthread_mutex_lock(m->lock);
354 351
355 352 if (m->map != NULL) {
356   - g_hash_table_remove_all(m->map);
  353 + genhash_clear(m->map);
357 354
358 355 m->lru_head = NULL;
359 356 m->lru_tail = NULL;
27 cproxy_multiget.c
@@ -6,16 +6,15 @@
6 6 #include <sysexits.h>
7 7 #include <pthread.h>
8 8 #include <assert.h>
9   -#include <glib.h>
10 9 #include <libmemcached/memcached.h>
11 10 #include "memcached.h"
12 11 #include "cproxy.h"
13 12
14 13 /* Callback to g_hash_table_foreach that frees the multiget_entry list.
15 14 */
16   -void multiget_foreach_free(gpointer key,
17   - gpointer value,
18   - gpointer user_data) {
  15 +void multiget_foreach_free(const void *key,
  16 + const void *value,
  17 + void *user_data) {
19 18 downstream *d = user_data;
20 19 assert(d);
21 20
@@ -27,7 +26,7 @@ void multiget_foreach_free(gpointer key,
27 26
28 27 int length = 0;
29 28
30   - multiget_entry *entry = value;
  29 + multiget_entry *entry = (multiget_entry*)value;
31 30
32 31 while (entry != NULL) {
33 32 if (entry->hits == 0) {
@@ -51,10 +50,10 @@ void multiget_foreach_free(gpointer key,
51 50 /* Callback to g_hash_table_foreach that clears out multiget_entries
52 51 * which have the given upstream conn (passed as user_data).
53 52 */
54   -void multiget_remove_upstream(gpointer key,
55   - gpointer value,
56   - gpointer user_data) {
57   - multiget_entry *entry = value;
  53 +void multiget_remove_upstream(const void *key,
  54 + const void *value,
  55 + void *user_data) {
  56 + multiget_entry *entry = (multiget_entry *) value;
58 57 assert(entry != NULL);
59 58
60 59 conn *uc = user_data;
@@ -108,8 +107,7 @@ bool multiget_ascii_downstream(downstream *d, conn *uc,
108 107 // More than one upstream conn, so we need a hashtable
109 108 // to track keys for de-deplication.
110 109 //
111   - d->multiget = g_hash_table_new(skey_hash,
112   - skey_equal);
  110 + d->multiget = genhash_init(128, skeyhash_ops);
113 111 if (settings.verbose > 1)
114 112 fprintf(stderr, "cproxy multiget hash table new\n");
115 113 }
@@ -284,9 +282,9 @@ bool multiget_ascii_downstream(downstream *d, conn *uc,
284 282 entry->upstream_conn = uc_cur;
285 283 entry->opaque = 0;
286 284 entry->hits = 0;
287   - entry->next = g_hash_table_lookup(d->multiget, key);
  285 + entry->next = genhash_find(d->multiget, key);
288 286
289   - g_hash_table_insert(d->multiget, key, entry);
  287 + genhash_store(d->multiget, key, entry);
290 288
291 289 if (entry->next != NULL)
292 290 first_request = false;
@@ -417,8 +415,7 @@ void multiget_ascii_downstream_response(downstream *d, item *it) {
417 415 memcpy(key_buf, ITEM_key(it), it->nkey);
418 416 key_buf[it->nkey] = '\0';
419 417
420   - multiget_entry *entry_first =
421   - g_hash_table_lookup(d->multiget, key_buf);
  418 + multiget_entry *entry_first = genhash_find(d->multiget, key_buf);
422 419
423 420 if (entry_first != NULL) {
424 421 entry_first->hits++;
1  cproxy_protocol.c
@@ -6,7 +6,6 @@
6 6 #include <sysexits.h>
7 7 #include <pthread.h>
8 8 #include <assert.h>
9   -#include <glib.h>
10 9 #include <libmemcached/memcached.h>
11 10 #include "memcached.h"
12 11 #include "cproxy.h"
4 cproxy_protocol_a2a.c
@@ -6,7 +6,6 @@
6 6 #include <sysexits.h>
7 7 #include <pthread.h>
8 8 #include <assert.h>
9   -#include <glib.h>
10 9 #include <libmemcached/memcached.h>
11 10 #include "memcached.h"
12 11 #include "cproxy.h"
@@ -287,8 +286,7 @@ bool cproxy_forward_a2a_simple_downstream(downstream *d,
287 286
288 287 if (cproxy_broadcast_a2a_downstream(d, command, uc,
289 288 "END\r\n")) {
290   - d->merger = g_hash_table_new(skey_hash,
291   - skey_equal);
  289 + d->merger = genhash_init(512, skeyhash_ops);
292 290 return true;
293 291 } else {
294 292 return false;
4 cproxy_protocol_a2b.c
@@ -7,7 +7,6 @@
7 7 #include <pthread.h>
8 8 #include <assert.h>
9 9 #include <math.h>
10   -#include <glib.h>
11 10 #include <libmemcached/memcached.h>
12 11 #include "memcached.h"
13 12 #include "cproxy.h"
@@ -965,8 +964,7 @@ bool cproxy_forward_a2b_simple_downstream(downstream *d,
965 964 out_keylen,
966 965 out_extlen, uc,
967 966 "END\r\n")) {
968   - d->merger = g_hash_table_new(skey_hash,
969   - skey_equal);
  967 + d->merger = genhash_init(128, skeyhash_ops);
970 968 return true;
971 969 }
972 970 }
30 cproxy_stats.c
@@ -74,7 +74,7 @@ mcache_funcs mcache_key_stats_funcs = {
74 74 #define VALUE_TOKEN 2
75 75 #define MERGE_BUF_SIZE 300
76 76
77   -bool protocol_stats_merge_line(GHashTable *merger, char *line) {
  77 +bool protocol_stats_merge_line(genhash_t *merger, char *line) {
78 78 assert(merger != NULL);
79 79 assert(line != NULL);
80 80
@@ -108,7 +108,7 @@ bool protocol_stats_merge_line(GHashTable *merger, char *line) {
108 108
109 109 // TODO: The stats merge assumes an ascii upstream.
110 110 //
111   -bool protocol_stats_merge_name_val(GHashTable *merger,
  111 +bool protocol_stats_merge_name_val(genhash_t *merger,
112 112 char *prefix,
113 113 int prefix_len,
114 114 char *name,
@@ -134,7 +134,7 @@ bool protocol_stats_merge_name_val(GHashTable *merger,
134 134 strncpy(buf_name, name, name_len);
135 135 buf_name[name_len] = '\0';
136 136
137   - char *prev = (char *) g_hash_table_lookup(merger, buf_name);
  137 + char *prev = (char *) genhash_find(merger, buf_name);
138 138 if (prev == NULL) {
139 139 char *hval = malloc(prefix_len + 1 +
140 140 name_len + 1 +
@@ -149,9 +149,7 @@ bool protocol_stats_merge_name_val(GHashTable *merger,
149 149 memcpy(hval + prefix_len + 1 + name_len + 1, val, val_len);
150 150 hval[prefix_len + 1 + name_len + 1 + val_len] = '\0';
151 151
152   - g_hash_table_insert(merger,
153   - hval + prefix_len + 1,
154   - hval);
  152 + genhash_store(merger, hval + prefix_len + 1, hval);
155 153 }
156 154
157 155 return true;
@@ -203,9 +201,7 @@ bool protocol_stats_merge_name_val(GHashTable *merger,
203 201 strcpy(hval + prefix_len + 1 + name_len + 1, buf_val);
204 202 hval[prefix_len + 1 + name_len + 1 + vlen] = '\0';
205 203
206   - g_hash_table_insert(merger,
207   - hval + prefix_len + 1,
208   - hval);
  204 + genhash_store(merger, hval + prefix_len + 1, hval);
209 205
210 206 free(prev);
211 207 }
@@ -266,18 +262,18 @@ bool protocol_stats_merge_smallest(char *v1, int v1len,
266 262 return false;
267 263 }
268 264
269   -/* Callback to g_hash_table_foreach that frees the multiget_entry list.
  265 +/* Callback to hash table iteration that frees the multiget_entry list.
270 266 */
271   -void protocol_stats_foreach_free(gpointer key,
272   - gpointer value,
273   - gpointer user_data) {
  267 +void protocol_stats_foreach_free(const void *key,
  268 + const void *value,
  269 + void *user_data) {
274 270 assert(value != NULL);
275   - free(value);
  271 + free((void*)value);
276 272 }
277 273
278   -void protocol_stats_foreach_write(gpointer key,
279   - gpointer value,
280   - gpointer user_data) {
  274 +void protocol_stats_foreach_write(const void *key,
  275 + const void *value,
  276 + void *user_data) {
281 277 char *line = (char *) value;
282 278 assert(line != NULL);
283 279
319 genhash.c
... ... @@ -0,0 +1,319 @@
  1 +/*
  2 + * Copyright (c) 2006 Dustin Sallings <dustin@spy.net>
  3 + */
  4 +
  5 +#include <stdio.h>
  6 +#include <stdlib.h>
  7 +#include <math.h>
  8 +#include <assert.h>
  9 +
  10 +#include "genhash.h"
  11 +#include "genhash_int.h"
  12 +
  13 +/* Table of 32 primes by their distance from the nearest power of two */
  14 +static int prime_size_table[]={
  15 + 3, 7, 13, 23, 47, 97, 193, 383, 769, 1531, 3067, 6143, 12289, 24571, 49157,
  16 + 98299, 196613, 393209, 786433, 1572869, 3145721, 6291449, 12582917,
  17 + 25165813, 50331653, 100663291, 201326611, 402653189, 805306357,
  18 + 1610612741
  19 +};
  20 +
  21 +static int
  22 +estimate_table_size(int est)
  23 +{
  24 + int rv=0;
  25 + int magn=0;
  26 + assert(est > 0);
  27 + magn=(int)log((double)est)/log(2);
  28 + magn--;
  29 + magn = (magn < 0) ? 0 : magn;
  30 + assert(magn < (sizeof(prime_size_table) / sizeof(int)));
  31 + rv=prime_size_table[magn];
  32 + return rv;
  33 +}
  34 +
  35 +genhash_t* genhash_init(int est, struct hash_ops ops)
  36 +{
  37 + genhash_t* rv=NULL;
  38 + int size=0;
  39 + if (est < 1) {
  40 + return NULL;
  41 + }
  42 +
  43 + assert(ops.hashfunc != NULL);
  44 + assert(ops.hasheq != NULL);
  45 + assert(ops.dupKey != NULL);
  46 + assert(ops.dupValue != NULL);
  47 + assert(ops.freeKey != NULL);
  48 + assert(ops.freeValue != NULL);
  49 +
  50 + size=estimate_table_size(est);
  51 + rv=calloc(1, sizeof(genhash_t)
  52 + + (size * sizeof(struct genhash_entry_t *)));
  53 + assert(rv != NULL);
  54 + rv->size=size;
  55 + rv->ops=ops;
  56 +
  57 + return rv;
  58 +}
  59 +
  60 +static void
  61 +free_bucket(genhash_t* h, struct genhash_entry_t* b)
  62 +{
  63 + if(b != NULL) {
  64 + free_bucket(h, b->next);
  65 + h->ops.freeKey(b->key);
  66 + h->ops.freeValue(b->value);
  67 + free(b);
  68 + }
  69 +}
  70 +
  71 +void
  72 +genhash_free(genhash_t* h)
  73 +{
  74 + if(h != NULL) {
  75 + int i=0;
  76 + for(i=0; i<h->size; i++) {
  77 + free_bucket(h, h->buckets[i]);
  78 + }
  79 + free(h);
  80 + }
  81 +}
  82 +
  83 +void
  84 +genhash_store(genhash_t *h, const void* k, const void* v)
  85 +{
  86 + int n=0;
  87 + struct genhash_entry_t *p;
  88 +
  89 + assert(h != NULL);
  90 +
  91 + n=h->ops.hashfunc(k) % h->size;
  92 + assert(n >= 0);
  93 + assert(n < h->size);
  94 +
  95 + p=calloc(1, sizeof(struct genhash_entry_t));
  96 + assert(p);
  97 +
  98 + p->key=h->ops.dupKey(k);
  99 + p->value=h->ops.dupValue(v);
  100 +
  101 + p->next=h->buckets[n];
  102 + h->buckets[n]=p;
  103 +}
  104 +
  105 +static struct genhash_entry_t *
  106 +genhash_find_entry(genhash_t *h, const void* k)
  107 +{
  108 + int n=0;
  109 + struct genhash_entry_t *p;
  110 +
  111 + assert(h != NULL);
  112 + n=h->ops.hashfunc(k) % h->size;
  113 + assert(n >= 0);
  114 + assert(n < h->size);
  115 +
  116 + p=h->buckets[n];
  117 + for(p=h->buckets[n]; p && !h->ops.hasheq(k, p->key); p=p->next);
  118 + return p;
  119 +}
  120 +
  121 +void*
  122 +genhash_find(genhash_t *h, const void* k)
  123 +{
  124 + struct genhash_entry_t *p;
  125 + void *rv=NULL;
  126 +
  127 + p=genhash_find_entry(h, k);
  128 +
  129 + if(p) {
  130 + rv=p->value;
  131 + }
  132 + return rv;
  133 +}
  134 +
  135 +enum update_type
  136 +genhash_update(genhash_t* h, const void* k, const void* v)
  137 +{
  138 + struct genhash_entry_t *p;
  139 + enum update_type rv=0;
  140 +
  141 + p=genhash_find_entry(h, k);
  142 +
  143 + if(p) {
  144 + h->ops.freeValue(p->value);
  145 + p->value=h->ops.dupValue(v);
  146 + rv=MODIFICATION;
  147 + } else {
  148 + genhash_store(h, k, v);
  149 + rv=NEW;
  150 + }
  151 +
  152 + return rv;
  153 +}
  154 +
  155 +enum update_type
  156 +genhash_fun_update(genhash_t* h, const void* k,
  157 + void *(*upd)(const void *, const void *),
  158 + void (*fr)(void*),
  159 + const void *def)
  160 +{
  161 + struct genhash_entry_t *p;
  162 + enum update_type rv=0;
  163 +
  164 + p=genhash_find_entry(h, k);
  165 +
  166 + if(p) {
  167 + void *newValue=upd(k, p->value);
  168 + h->ops.freeValue(p->value);
  169 + p->value=h->ops.dupValue(newValue);
  170 + fr(newValue);
  171 + rv=MODIFICATION;
  172 + } else {
  173 + void *newValue=upd(k, def);
  174 + genhash_store(h, k, newValue);
  175 + fr(newValue);
  176 + rv=NEW;
  177 + }
  178 +
  179 + return rv;
  180 +}
  181 +
  182 +int
  183 +genhash_delete(genhash_t* h, const void* k)
  184 +{
  185 + struct genhash_entry_t *deleteme=NULL;
  186 + int n=0;
  187 + int rv=0;
  188 +
  189 + assert(h != NULL);
  190 + n=h->ops.hashfunc(k) % h->size;
  191 + assert(n >= 0);
  192 + assert(n < h->size);
  193 +
  194 + if(h->buckets[n] != NULL) {
  195 + /* Special case the first one */
  196 + if(h->ops.hasheq(h->buckets[n]->key, k)) {
  197 + deleteme=h->buckets[n];
  198 + h->buckets[n]=deleteme->next;
  199 + } else {
  200 + struct genhash_entry_t *p=NULL;
  201 + for(p=h->buckets[n]; deleteme==NULL && p->next != NULL; p=p->next) {
  202 + if(h->ops.hasheq(p->next->key, k)) {
  203 + deleteme=p->next;
  204 + p->next=deleteme->next;
  205 + }
  206 + }
  207 + }
  208 + }
  209 + if(deleteme != NULL) {
  210 + h->ops.freeKey(deleteme->key);
  211 + h->ops.freeValue(deleteme->value);
  212 + free(deleteme);
  213 + rv++;
  214 + }
  215 +
  216 + return rv;
  217 +}
  218 +
  219 +int
  220 +genhash_delete_all(genhash_t* h, const void* k)
  221 +{
  222 + int rv=0;
  223 + while(genhash_delete(h, k) == 1) {
  224 + rv++;
  225 + }
  226 + return rv;
  227 +}
  228 +
  229 +void
  230 +genhash_iter(genhash_t* h,
  231 + void (*iterfunc)(const void* key, const void* val, void *arg), void *arg)
  232 +{
  233 + int i=0;
  234 + struct genhash_entry_t *p=NULL;
  235 + assert(h != NULL);
  236 +
  237 + for(i=0; i<h->size; i++) {
  238 + for(p=h->buckets[i]; p!=NULL; p=p->next) {
  239 + iterfunc(p->key, p->value, arg);
  240 + }
  241 + }
  242 +}
  243 +
  244 +int
  245 +genhash_clear(genhash_t *h)
  246 +{
  247 + int i = 0, rv = 0;
  248 + assert(h != NULL);
  249 +
  250 + for(i = 0; i < h->size; i++) {
  251 + while(h->buckets[i]) {
  252 + struct genhash_entry_t *p = NULL;
  253 + p = h->buckets[i];
  254 + h->buckets[i] = p->next;
  255 + h->ops.freeKey(p->key);
  256 + h->ops.freeValue(p->value);
  257 + free(p);
  258 + }
  259 + }
  260 +
  261 + return rv;
  262 +}
  263 +
  264 +static void
  265 +count_entries(const void *key, const void *val, void *arg)
  266 +{
  267 + int *count=(int *)arg;
  268 + (*count)++;
  269 +}
  270 +
  271 +int
  272 +genhash_size(genhash_t* h) {
  273 + int rv=0;
  274 + assert(h != NULL);
  275 + genhash_iter(h, count_entries, &rv);
  276 + return rv;
  277 +}
  278 +
  279 +int
  280 +genhash_size_for_key(genhash_t* h, const void* k)
  281 +{
  282 + int rv=0;
  283 + assert(h != NULL);
  284 + genhash_iter_key(h, k, count_entries, &rv);
  285 + return rv;
  286 +}
  287 +
  288 +void
  289 +genhash_iter_key(genhash_t* h, const void* key,
  290 + void (*iterfunc)(const void* key, const void* val, void *arg), void *arg)
  291 +{
  292 + int n=0;
  293 + struct genhash_entry_t *p=NULL;
  294 +
  295 + assert(h != NULL);
  296 + n=h->ops.hashfunc(key) % h->size;
  297 + assert(n >= 0);
  298 + assert(n < h->size);
  299 +
  300 + for(p=h->buckets[n]; p!=NULL; p=p->next) {
  301 + if(h->ops.hasheq(key, p->key)) {
  302 + iterfunc(p->key, p->value, arg);
  303 + }
  304 + }
  305 +}
  306 +
  307 +int
  308 +genhash_string_hash(const void* p)
  309 +{
  310 + int rv=5381;
  311 + int i=0;
  312 + char *str=(char *)p;
  313 +
  314 + for(i=0; str[i] != 0x00; i++) {
  315 + rv = ((rv << 5) + rv) ^ str[i];
  316 + }
  317 +
  318 + return rv;
  319 +}
226 genhash.h
... ... @@ -0,0 +1,226 @@
  1 +/*
  2 + * Generic hash table implementation.
  3 + *
  4 + * Copyright (c) 2006 Dustin Sallings <dustin@spy.net>
  5 + */
  6 +
  7 +#ifndef GENHASH_H
  8 +#define GENHASH_H 1
  9 +
  10 +/*! \mainpage genhash
  11 + *
  12 + * \section intro_sec Introduction
  13 + *
  14 + * genhash is a generic hash table implementation in C. It's
  15 + * well-tested, freely available (MIT-license) and does what you need.
  16 + *
  17 + * \section docs_sec API Documentation
  18 + *
  19 + * Jump right into <a href="group___core.html">the API docs</a> to get started.
  20 + */
  21 +
  22 +/**
  23 + * \defgroup Core genhash core
  24 + */
  25 +
  26 +/**
  27 + * \addtogroup Core
  28 + * @{
  29 + */
  30 +
  31 +/**
  32 + * Operations on keys and values in the hash table.
  33 + */
  34 +struct hash_ops {
  35 + /**
  36 + * Function to compute a hash for the given value.
  37 + */
  38 + int (*hashfunc)(const void *);
  39 + /**
  40 + * Function that returns true if the given keys are equal.
  41 + */
  42 + int (*hasheq)(const void *, const void *);
  43 + /**
  44 + * Function to duplicate a key for storage.
  45 + */
  46 + void* (*dupKey)(const void *);
  47 + /**
  48 + * Function to duplicate a value for storage.
  49 + */
  50 + void* (*dupValue)(const void *);
  51 + /**
  52 + * Function to free a key.
  53 + */
  54 + void (*freeKey)(void *);
  55 + /**
  56 + * Function to free a value.
  57 + */
  58 + void (*freeValue)(void *);
  59 +};
  60 +
  61 +/**
  62 + * The hash table structure.
  63 + */
  64 +typedef struct _genhash genhash_t ;
  65 +
  66 +/**
  67 + * Type of update performed by an update function.
  68 + */
  69 +enum update_type {
  70 + MODIFICATION, /**< This update is modifying an existing entry */
  71 + NEW /**< This update is creating a new entry */
  72 +};
  73 +
  74 +/**
  75 + * Create a new generic hashtable.
  76 + *
  77 + * @param est the estimated number of items to store (must be > 0)
  78 + * @param ops the key and value operations
  79 + *
  80 + * @return the new genhash_t or NULL if one cannot be created
  81 + */
  82 +genhash_t* genhash_init(int est, struct hash_ops ops);
  83 +
  84 +/**
  85 + * Free a gen hash.
  86 + *
  87 + * @param h the genhash to free (may be NULL)
  88 + */
  89 +void genhash_free(genhash_t *h);
  90 +
  91 +/**
  92 + * Store an item.
  93 + *
  94 + * @param h the genhash
  95 + * @param k the key
  96 + * @param v the value
  97 + */
  98 +void genhash_store(genhash_t *h, const void *k, const void *v);
  99 +
  100 +/**
  101 + * Get the most recent value stored for the given key.
  102 + *
  103 + * @param h the genhash
  104 + * @param k the key
  105 + *
  106 + * @return the value, or NULL if one cannot be found
  107 + */
  108 +void* genhash_find(genhash_t *h, const void *k);
  109 +
  110 +/**
  111 + * Delete the most recent value stored for a key.
  112 + *
  113 + * @param h the genhash
  114 + * @param k the key
  115 + *
  116 + * @return the number of items deleted
  117 + */
  118 +int genhash_delete(genhash_t *h, const void *k);
  119 +
  120 +/**
  121 + * Delete all mappings of a given key.
  122 + *
  123 + * @param h the genhash
  124 + * @param k the key
  125 + *
  126 + * @return the number of items deleted
  127 + */
  128 +int genhash_delete_all(genhash_t *h, const void *k);
  129 +
  130 +/**
  131 + * Create or update an item in-place.
  132 + *
  133 + * @param h the genhash
  134 + * @param k the key
  135 + * @param v the new value to store for this key
  136 + *
  137 + * @return an indicator of whether this created a new item or updated
  138 + * an existing one
  139 + */
  140 +enum update_type genhash_update(genhash_t *h, const void *k, const void *v);
  141 +
  142 +/**
  143 + * Create or update an item in-place with a function.
  144 + *
  145 + * @param h hashtable
  146 + * @param key the key of the item
  147 + * @param upd function that will be called with the key and current
  148 + * value. Should return the new value.
  149 + * @param fr function to free the return value returned by the update
  150 + * function
  151 + * @param def default value
  152 + *
  153 + * @return an indicator of whether this created a new item or updated
  154 + * an existing one
  155 + */
  156 +enum update_type genhash_fun_update(genhash_t *h, const void *key,
  157 + void *(*upd)(const void *k, const void *oldv),