Permalink
Browse files

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...
1 parent d4b7434 commit ea4d0640faed655b16ec4a34e04d386684e38fdd @dustin dustin committed Sep 2, 2009
Showing with 718 additions and 159 deletions.
  1. +1 −6 Makefile.am
  2. +39 −51 agent_stats.c
  3. +0 −3 configure.ac
  4. +8 −9 cproxy.c
  5. +25 −22 cproxy.h
  6. +37 −7 cproxy_config.c
  7. +18 −21 cproxy_front.c
  8. +12 −15 cproxy_multiget.c
  9. +0 −1 cproxy_protocol.c
  10. +1 −3 cproxy_protocol_a2a.c
  11. +1 −3 cproxy_protocol_a2b.c
  12. +13 −17 cproxy_stats.c
  13. +319 −0 genhash.c
  14. +226 −0 genhash.h
  15. +17 −0 genhash_int.h
  16. +1 −1 thread.c
View
7 Makefile.am
@@ -4,17 +4,12 @@ bin_PROGRAMS = moxi
##pkginclude_HEADERS = protocol_binary.h
noinst_PROGRAMS = moxi-debug sizes testapp
-## INCLUDES is apparently not previously set, if you set it
-## change this
-INCLUDES = $(GLIB2_CFLAGS)
-LIBS += $(GLIB2_LIBS)
-LIBS += -lgthread-2.0
-
BUILT_SOURCES =
testapp_SOURCES = testapp.c util.c util.h
moxi_SOURCES = memcached.c memcached.h \
+ genhash.c genhash.h genhash_int.h \
hash.c hash.h \
slabs.c slabs.h \
items.c items.h \
View
90 agent_stats.c
@@ -38,17 +38,16 @@ static void add_proxy_stats(proxy_stats *agg,
static void add_stats_cmd(proxy_stats_cmd *agg,
proxy_stats_cmd *x);
-void map_pstd_foreach_free(gpointer key,
- gpointer value,
- gpointer user_data);
+void map_pstd_foreach_free(const void *key,
+ const void *value,
+ void *user_data);
+void map_pstd_foreach_emit(const void *key,
+ const void *value,
+ void *user_data);
-void map_pstd_foreach_emit(gpointer key,
- gpointer value,
- gpointer user_data);
-
-void map_pstd_foreach_merge(gpointer key,
- gpointer value,
- gpointer user_data);
+void map_pstd_foreach_merge(const void *key,
+ const void *value,
+ void *user_data);
struct main_stats_collect_info {
proxy_main *m;
@@ -190,9 +189,7 @@ enum conflate_mgmt_cb_result on_conflate_get_stats(void *userdata,
// is keyed by each proxy's "binding:name", and whose
// values are proxy_stats_td.
//
- GHashTable *map_pstd =
- g_hash_table_new(g_str_hash,
- g_str_equal);
+ genhash_t *map_pstd = genhash_init(128, strhash_ops);
if (map_pstd != NULL)
work_collect_init(&ca[i], -1, map_pstd);
else
@@ -213,33 +210,29 @@ enum conflate_mgmt_cb_result on_conflate_get_stats(void *userdata,
assert(m->nthreads > 0);
if (msci.do_stats) {
- GHashTable *end_pstd = ca[1].data;
+ genhash_t *end_pstd = ca[1].data;
if (end_pstd != NULL) {
// Skip the first worker thread (index 1)'s results,
// because that's where we'll aggregate final results.
//
for (i = 2; i < m->nthreads; i++) {
- GHashTable *map_pstd = ca[i].data;
+ genhash_t *map_pstd = ca[i].data;
if (map_pstd != NULL) {
- g_hash_table_foreach(map_pstd,
- map_pstd_foreach_merge,
- end_pstd);
+ genhash_iter(map_pstd, map_pstd_foreach_merge,
+ end_pstd);
}
}
- g_hash_table_foreach(end_pstd,
- map_pstd_foreach_emit,
- &msci);
+ genhash_iter(end_pstd, map_pstd_foreach_emit, &msci);
}
}
for (i = 1; i < m->nthreads; i++) {
- GHashTable *map_pstd = ca[i].data;
+ genhash_t *map_pstd = ca[i].data;
if (map_pstd != NULL) {
- g_hash_table_foreach(map_pstd,
- map_pstd_foreach_free,
- NULL);
- g_hash_table_destroy(map_pstd);
+ genhash_iter(map_pstd, map_pstd_foreach_free, NULL);
+ genhash_free(map_pstd);
+ map_pstd = NULL;
}
}
@@ -250,16 +243,14 @@ enum conflate_mgmt_cb_result on_conflate_get_stats(void *userdata,
return RV_OK;
}
-void map_pstd_foreach_merge(gpointer key,
- gpointer value,
- gpointer user_data) {
- GHashTable *map_end_pstd = user_data;
+void map_pstd_foreach_merge(const void *key,
+ const void *value,
+ void *user_data) {
+ genhash_t *map_end_pstd = user_data;
if (key != NULL &&
map_end_pstd != NULL) {
proxy_stats_td *cur_pstd = (proxy_stats_td *) value;
- proxy_stats_td *end_pstd =
- g_hash_table_lookup(map_end_pstd,
- key);
+ proxy_stats_td *end_pstd = genhash_find(map_end_pstd, key);
if (cur_pstd != NULL &&
end_pstd != NULL) {
add_proxy_stats_td(end_pstd, cur_pstd);
@@ -346,8 +337,7 @@ static void main_stats_collect(void *data0, void *data1) {
pthread_mutex_lock(p->front_cache.lock);
if (p->front_cache.map != NULL)
- emit_f("front_cache_size",
- "%u", g_hash_table_size(p->front_cache.map));
+ emit_f("front_cache_size", "%u", genhash_size(p->front_cache.map));
emit_f("front_cache_max",
"%u", p->front_cache.max);
@@ -437,7 +427,7 @@ static void work_stats_collect(void *data0, void *data1) {
assert(is_listen_thread() == false); // Expecting a worker thread.
- GHashTable *map_pstd = c->data;
+ genhash_t *map_pstd = c->data;
assert(map_pstd != NULL);
pthread_mutex_lock(&p->proxy_lock);
@@ -452,14 +442,11 @@ static void work_stats_collect(void *data0, void *data1) {
pthread_mutex_unlock(&p->proxy_lock);
locked = false;
- proxy_stats_td *pstd =
- g_hash_table_lookup(map_pstd, key_buf);
+ proxy_stats_td *pstd = genhash_find(map_pstd, key_buf);
if (pstd == NULL) {
pstd = calloc(1, sizeof(proxy_stats_td));
if (pstd != NULL) {
- g_hash_table_insert(map_pstd,
- key_buf,
- pstd);
+ genhash_store(map_pstd, key_buf, pstd);
key_buf = NULL;
}
}
@@ -549,23 +536,24 @@ static void add_stats_cmd(proxy_stats_cmd *agg,
agg->cas += x->cas;
}
-void map_pstd_foreach_free(gpointer key,
- gpointer value,
- gpointer user_data) {
+void map_pstd_foreach_free(const void *key,
+ const void *value,
+ void *user_data) {
assert(key != NULL);
- free(key);
+ free((void*)key);
assert(value != NULL);
- free(value);
+ free((void*)value);
}
-void map_pstd_foreach_emit(gpointer key,
- gpointer value,
- gpointer user_data) {
- char *name = key;
+void map_pstd_foreach_emit(const void *k,
+ const void *value,
+ void *user_data) {
+
+ const char *name = (const char*)k;
assert(name != NULL);
- proxy_stats_td *pstd = value;
+ proxy_stats_td *pstd = (proxy_stats_td *)value;
assert(pstd != NULL);
const struct main_stats_collect_info *emit = user_data;
View
3 configure.ac
@@ -300,12 +300,9 @@ AC_SEARCH_LIBS(socket, socket)
AC_SEARCH_LIBS(gethostbyname, nsl)
AC_SEARCH_LIBS(umem_cache_create, umem)
-PKG_CHECK_MODULES([GLIB2], [ glib-2.0 >= 2.0.6 ])
-AC_SUBST(GLIB2)
PKG_CHECK_MODULES([CHECK], [check >= 0.9.4])
AC_SUBST(DEPS)
-AC_SUBST(DEPS)
AC_HEADER_STDBOOL
AC_C_CONST
View
17 cproxy.c
@@ -389,8 +389,7 @@ void cproxy_on_close_upstream_conn(conn *c) {
//
if (found) {
if (d->multiget != NULL)
- g_hash_table_foreach(d->multiget,
- multiget_remove_upstream, c);
+ genhash_iter(d->multiget, multiget_remove_upstream, c);
// The downstream conn's might have iov's that
// point to the upstream conn's buffers. Also, the
@@ -667,9 +666,9 @@ bool cproxy_release_downstream(downstream *d, bool force) {
if (d->merger != NULL) {
// TODO: Allow merger callback to be func pointer.
//
- g_hash_table_foreach(d->merger,
- protocol_stats_foreach_write,
- d->upstream_conn);
+ genhash_iter(d->merger,
+ protocol_stats_foreach_write,
+ d->upstream_conn);
if (update_event(d->upstream_conn, EV_WRITE | EV_PERSIST)) {
conn_set_state(d->upstream_conn, conn_mwrite);
@@ -704,14 +703,14 @@ bool cproxy_release_downstream(downstream *d, bool force) {
// Free extra hash tables.
//
if (d->multiget != NULL) {
- g_hash_table_foreach(d->multiget, multiget_foreach_free, d);
- g_hash_table_destroy(d->multiget);
+ genhash_iter(d->multiget, multiget_foreach_free, d);
+ genhash_free(d->multiget);
d->multiget = NULL;
}
if (d->merger != NULL) {
- g_hash_table_foreach(d->merger, protocol_stats_foreach_free, NULL);
- g_hash_table_destroy(d->merger);
+ genhash_iter(d->merger, protocol_stats_foreach_free, NULL);
+ genhash_free(d->merger);
d->merger = NULL;
}
View
47 cproxy.h
@@ -3,8 +3,8 @@
#ifndef CPROXY_H
#define CPROXY_H
-#include <glib.h>
#include <libmemcached/memcached.h>
+#include "genhash.h"
#include "work.h"
#include "matcher.h"
@@ -52,7 +52,7 @@ typedef struct {
bool key_alloc; // True if mcache must alloc key memory.
- GHashTable *map; // NULL-able, keyed by string, value is item.
+ genhash_t *map; // NULL-able, keyed by string, value is item.
uint32_t max; // Maxiumum number of items to keep.
@@ -360,8 +360,8 @@ struct downstream {
conn *upstream_conn; // Non-NULL when downstream is reserved.
char *upstream_suffix; // Last bit to write when downstreams are done.
- GHashTable *multiget; // Keyed by string.
- GHashTable *merger; // Keyed by string, for merging replies like STATS.
+ genhash_t *multiget; // Keyed by string.
+ genhash_t *merger; // Keyed by string, for merging replies like STATS.
// Timeout is in use when timeout_tv fields are non-zero.
//
@@ -537,41 +537,44 @@ bool multiget_ascii_downstream(
void multiget_ascii_downstream_response(downstream *d, item *it);
-void multiget_foreach_free(gpointer key,
- gpointer value,
- gpointer user_data);
+void multiget_foreach_free(const void *key,
+ const void *value,
+ void *user_data);
-void multiget_remove_upstream(gpointer key,
- gpointer value,
- gpointer user_data);
+void multiget_remove_upstream(const void *key,
+ const void *value,
+ void *user_data);
// Space or null terminated key funcs.
//
-size_t skey_len(const char *key);
-guint skey_hash(gconstpointer v);
-gboolean skey_equal(gconstpointer v1, gconstpointer v2);
+size_t skey_len(const char *key);
+int skey_hash(const void *v);
+int skey_equal(const void *v1, const void *v2);
-void helper_g_free(gpointer data);
+extern struct hash_ops strhash_ops;
+extern struct hash_ops skeyhash_ops;
+
+void noop_free(void *v);
// Stats handling.
//
-bool protocol_stats_merge_line(GHashTable *merger, char *line);
+bool protocol_stats_merge_line(genhash_t *merger, char *line);
-bool protocol_stats_merge_name_val(GHashTable *merger,
+bool protocol_stats_merge_name_val(genhash_t *merger,
char *prefix,
int prefix_len,
char *name,
int name_len,
char *val,
int val_len);
-void protocol_stats_foreach_free(gpointer key,
- gpointer value,
- gpointer user_data);
+void protocol_stats_foreach_free(const void *key,
+ const void *value,
+ void *user_data);
-void protocol_stats_foreach_write(gpointer key,
- gpointer value,
- gpointer user_data);
+void protocol_stats_foreach_write(const void *key,
+ const void *value,
+ void *user_data);
void cproxy_optimize_to_self(downstream *d, conn *uc,
char *command);
View
44 cproxy_config.c
@@ -9,7 +9,6 @@
#include <pthread.h>
#include <assert.h>
#include <math.h>
-#include <glib.h>
#include <libmemcached/memcached.h>
#include "memcached.h"
#include "cproxy.h"
@@ -86,7 +85,7 @@ size_t skey_len(const char *key) {
/** Hash of key that may be zero or space terminated.
*/
-guint skey_hash(gconstpointer v) {
+int skey_hash(const void *v) {
assert(v);
const char *key = v;
@@ -98,7 +97,7 @@ guint skey_hash(gconstpointer v) {
/** Returns true if two keys are equal, where the
* keys may be zero or space terminated.
*/
-gboolean skey_equal(gconstpointer v1, gconstpointer v2) {
+int skey_equal(const void *v1, const void *v2) {
assert(v1);
assert(v2);
@@ -111,10 +110,43 @@ gboolean skey_equal(gconstpointer v1, gconstpointer v2) {
return (n1 == n2 && strncmp(k1, k2, n1) == 0);
}
-void helper_g_free(gpointer data) {
- free(data);
+static void *noop_dup(const void *v)
+{
+ return (void*)v;
}
+void noop_free(void *v) {
+ /* Nothing */
+}
+
+static int
+str_eq(const void* p1, const void*p2)
+{
+ char *str1=(char *)p1;
+ char *str2=(char *)p2;
+ assert(str1 != NULL);
+ assert(str2 != NULL);
+ return strcmp(str1, str2) == 0;
+}
+
+struct hash_ops strhash_ops = {
+ .hashfunc = genhash_string_hash,
+ .hasheq = str_eq,
+ .dupKey = noop_dup,
+ .dupValue = noop_dup,
+ .freeKey = noop_free,
+ .freeValue = noop_free
+};
+
+struct hash_ops skeyhash_ops = {
+ .hashfunc = skey_hash,
+ .hasheq = skey_equal,
+ .dupKey = noop_dup,
+ .dupValue = noop_dup,
+ .freeKey = noop_free,
+ .freeValue = noop_free
+};
+
/** Returns pointer to first non-space char in string.
*/
char *skipspace(char *s) {
@@ -196,8 +228,6 @@ int cproxy_init(char *cfg_str,
if (cproxy_core_initted == false) {
cproxy_core_initted = true;
- g_thread_init(NULL);
-
gethostname(cproxy_hostname, sizeof(cproxy_hostname));
cproxy_init_a2a();
View
39 cproxy_front.c
@@ -99,10 +99,11 @@ void mcache_start(mcache *m, uint32_t max) {
assert(m->lru_tail == NULL);
assert(m->oldest_live == 0);
- m->map = g_hash_table_new_full(skey_hash,
- skey_equal,
- m->key_alloc ? helper_g_free : NULL,
- m->funcs->item_dec_ref);
+ struct hash_ops hops = skeyhash_ops;
+ hops.freeKey = m->key_alloc ? free : noop_free;
+ hops.freeValue = m->funcs->item_dec_ref;
+
+ m->map = genhash_init(128, hops);
if (m->map != NULL) {
m->max = max;
m->lru_head = NULL;
@@ -134,7 +135,7 @@ void mcache_stop(mcache *m) {
if (m->lock)
pthread_mutex_lock(m->lock);
- GHashTable *x = m->map;
+ genhash_t *x = m->map;
m->map = NULL;
m->max = 0;
@@ -148,7 +149,7 @@ void mcache_stop(mcache *m) {
// Destroying hash table outside the lock.
//
if (x != NULL)
- g_hash_table_destroy(x);
+ genhash_free(x);
}
void *mcache_get(mcache *m, char *key, int key_len,
@@ -164,7 +165,7 @@ void *mcache_get(mcache *m, char *key, int key_len,
pthread_mutex_lock(m->lock);
if (m->map != NULL) {
- void *it = g_hash_table_lookup(m->map, key);
+ void *it = genhash_find(m->map, key);
if (it != NULL) {
mcache_item_unlink(m, it);
@@ -197,7 +198,7 @@ void *mcache_get(mcache *m, char *key, int key_len,
fprintf(stderr,
"mcache expire: %s\n", key);
- g_hash_table_remove(m->map, key);
+ genhash_delete(m->map, key);
} else {
m->tot_get_misses++;
}
@@ -230,7 +231,7 @@ void mcache_set(mcache *m, void *it,
// Evict some items if necessary.
//
for (int i = 0; m->lru_tail != NULL && i < 20; i++) {
- if (g_hash_table_size(m->map) < m->max)
+ if (genhash_size(m->map) < m->max)
break;
void *last_it = m->lru_tail;
@@ -243,16 +244,15 @@ void mcache_set(mcache *m, void *it,
memcpy(buf, m->funcs->item_key(last_it), len);
buf[len] = '\0';
- g_hash_table_remove(m->map, buf);
+ genhash_delete(m->map, buf);
} else {
- g_hash_table_remove(m->map,
- m->funcs->item_key(last_it));
+ genhash_delete(m->map, m->funcs->item_key(last_it));
}
m->tot_evictions++;
}
- if (g_hash_table_size(m->map) < m->max) {
+ if (genhash_size(m->map) < m->max) {
char *key = m->funcs->item_key(it);
int key_len = m->funcs->item_key_len(it);
char *key_buf = NULL;
@@ -274,10 +274,7 @@ void mcache_set(mcache *m, void *it,
}
if (key != NULL) {
- void *existing =
- add_only ?
- (void *) g_hash_table_lookup(m->map, key) :
- NULL;
+ void *existing = add_only ? genhash_find(m->map, key) : NULL;
if (existing != NULL) {
mcache_item_unlink(m, existing);
mcache_item_touch(m, existing);
@@ -297,7 +294,7 @@ void mcache_set(mcache *m, void *it,
m->funcs->item_set_exptime(it, exptime);
m->funcs->item_add_ref(it);
- g_hash_table_insert(m->map, key, it);
+ genhash_store(m->map, key, it);
m->tot_adds++;
m->tot_add_bytes += m->funcs->item_len(it);
@@ -331,11 +328,11 @@ void mcache_delete(mcache *m, char *key, int key_len) {
pthread_mutex_lock(m->lock);
if (m->map != NULL) {
- void *existing = (void *) g_hash_table_lookup(m->map, key);
+ void *existing = genhash_find(m->map, key);
if (existing != NULL) {
mcache_item_unlink(m, existing);
- g_hash_table_remove(m->map, key);
+ genhash_delete(m->map, key);
m->tot_deletes++;
}
@@ -353,7 +350,7 @@ void mcache_flush_all(mcache *m, uint32_t msec_exp) {
pthread_mutex_lock(m->lock);
if (m->map != NULL) {
- g_hash_table_remove_all(m->map);
+ genhash_clear(m->map);
m->lru_head = NULL;
m->lru_tail = NULL;
View
27 cproxy_multiget.c
@@ -6,16 +6,15 @@
#include <sysexits.h>
#include <pthread.h>
#include <assert.h>
-#include <glib.h>
#include <libmemcached/memcached.h>
#include "memcached.h"
#include "cproxy.h"
/* Callback to g_hash_table_foreach that frees the multiget_entry list.
*/
-void multiget_foreach_free(gpointer key,
- gpointer value,
- gpointer user_data) {
+void multiget_foreach_free(const void *key,
+ const void *value,
+ void *user_data) {
downstream *d = user_data;
assert(d);
@@ -27,7 +26,7 @@ void multiget_foreach_free(gpointer key,
int length = 0;
- multiget_entry *entry = value;
+ multiget_entry *entry = (multiget_entry*)value;
while (entry != NULL) {
if (entry->hits == 0) {
@@ -51,10 +50,10 @@ void multiget_foreach_free(gpointer key,
/* Callback to g_hash_table_foreach that clears out multiget_entries
* which have the given upstream conn (passed as user_data).
*/
-void multiget_remove_upstream(gpointer key,
- gpointer value,
- gpointer user_data) {
- multiget_entry *entry = value;
+void multiget_remove_upstream(const void *key,
+ const void *value,
+ void *user_data) {
+ multiget_entry *entry = (multiget_entry *) value;
assert(entry != NULL);
conn *uc = user_data;
@@ -108,8 +107,7 @@ bool multiget_ascii_downstream(downstream *d, conn *uc,
// More than one upstream conn, so we need a hashtable
// to track keys for de-deplication.
//
- d->multiget = g_hash_table_new(skey_hash,
- skey_equal);
+ d->multiget = genhash_init(128, skeyhash_ops);
if (settings.verbose > 1)
fprintf(stderr, "cproxy multiget hash table new\n");
}
@@ -284,9 +282,9 @@ bool multiget_ascii_downstream(downstream *d, conn *uc,
entry->upstream_conn = uc_cur;
entry->opaque = 0;
entry->hits = 0;
- entry->next = g_hash_table_lookup(d->multiget, key);
+ entry->next = genhash_find(d->multiget, key);
- g_hash_table_insert(d->multiget, key, entry);
+ genhash_store(d->multiget, key, entry);
if (entry->next != NULL)
first_request = false;
@@ -417,8 +415,7 @@ void multiget_ascii_downstream_response(downstream *d, item *it) {
memcpy(key_buf, ITEM_key(it), it->nkey);
key_buf[it->nkey] = '\0';
- multiget_entry *entry_first =
- g_hash_table_lookup(d->multiget, key_buf);
+ multiget_entry *entry_first = genhash_find(d->multiget, key_buf);
if (entry_first != NULL) {
entry_first->hits++;
View
1 cproxy_protocol.c
@@ -6,7 +6,6 @@
#include <sysexits.h>
#include <pthread.h>
#include <assert.h>
-#include <glib.h>
#include <libmemcached/memcached.h>
#include "memcached.h"
#include "cproxy.h"
View
4 cproxy_protocol_a2a.c
@@ -6,7 +6,6 @@
#include <sysexits.h>
#include <pthread.h>
#include <assert.h>
-#include <glib.h>
#include <libmemcached/memcached.h>
#include "memcached.h"
#include "cproxy.h"
@@ -287,8 +286,7 @@ bool cproxy_forward_a2a_simple_downstream(downstream *d,
if (cproxy_broadcast_a2a_downstream(d, command, uc,
"END\r\n")) {
- d->merger = g_hash_table_new(skey_hash,
- skey_equal);
+ d->merger = genhash_init(512, skeyhash_ops);
return true;
} else {
return false;
View
4 cproxy_protocol_a2b.c
@@ -7,7 +7,6 @@
#include <pthread.h>
#include <assert.h>
#include <math.h>
-#include <glib.h>
#include <libmemcached/memcached.h>
#include "memcached.h"
#include "cproxy.h"
@@ -965,8 +964,7 @@ bool cproxy_forward_a2b_simple_downstream(downstream *d,
out_keylen,
out_extlen, uc,
"END\r\n")) {
- d->merger = g_hash_table_new(skey_hash,
- skey_equal);
+ d->merger = genhash_init(128, skeyhash_ops);
return true;
}
}
View
30 cproxy_stats.c
@@ -74,7 +74,7 @@ mcache_funcs mcache_key_stats_funcs = {
#define VALUE_TOKEN 2
#define MERGE_BUF_SIZE 300
-bool protocol_stats_merge_line(GHashTable *merger, char *line) {
+bool protocol_stats_merge_line(genhash_t *merger, char *line) {
assert(merger != NULL);
assert(line != NULL);
@@ -108,7 +108,7 @@ bool protocol_stats_merge_line(GHashTable *merger, char *line) {
// TODO: The stats merge assumes an ascii upstream.
//
-bool protocol_stats_merge_name_val(GHashTable *merger,
+bool protocol_stats_merge_name_val(genhash_t *merger,
char *prefix,
int prefix_len,
char *name,
@@ -134,7 +134,7 @@ bool protocol_stats_merge_name_val(GHashTable *merger,
strncpy(buf_name, name, name_len);
buf_name[name_len] = '\0';
- char *prev = (char *) g_hash_table_lookup(merger, buf_name);
+ char *prev = (char *) genhash_find(merger, buf_name);
if (prev == NULL) {
char *hval = malloc(prefix_len + 1 +
name_len + 1 +
@@ -149,9 +149,7 @@ bool protocol_stats_merge_name_val(GHashTable *merger,
memcpy(hval + prefix_len + 1 + name_len + 1, val, val_len);
hval[prefix_len + 1 + name_len + 1 + val_len] = '\0';
- g_hash_table_insert(merger,
- hval + prefix_len + 1,
- hval);
+ genhash_store(merger, hval + prefix_len + 1, hval);
}
return true;
@@ -203,9 +201,7 @@ bool protocol_stats_merge_name_val(GHashTable *merger,
strcpy(hval + prefix_len + 1 + name_len + 1, buf_val);
hval[prefix_len + 1 + name_len + 1 + vlen] = '\0';
- g_hash_table_insert(merger,
- hval + prefix_len + 1,
- hval);
+ genhash_store(merger, hval + prefix_len + 1, hval);
free(prev);
}
@@ -266,18 +262,18 @@ bool protocol_stats_merge_smallest(char *v1, int v1len,
return false;
}
-/* Callback to g_hash_table_foreach that frees the multiget_entry list.
+/* Callback to hash table iteration that frees the multiget_entry list.
*/
-void protocol_stats_foreach_free(gpointer key,
- gpointer value,
- gpointer user_data) {
+void protocol_stats_foreach_free(const void *key,
+ const void *value,
+ void *user_data) {
assert(value != NULL);
- free(value);
+ free((void*)value);
}
-void protocol_stats_foreach_write(gpointer key,
- gpointer value,
- gpointer user_data) {
+void protocol_stats_foreach_write(const void *key,
+ const void *value,
+ void *user_data) {
char *line = (char *) value;
assert(line != NULL);
View
319 genhash.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2006 Dustin Sallings <dustin@spy.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+#include "genhash.h"
+#include "genhash_int.h"
+
+/* Table of 32 primes by their distance from the nearest power of two */
+static int prime_size_table[]={
+ 3, 7, 13, 23, 47, 97, 193, 383, 769, 1531, 3067, 6143, 12289, 24571, 49157,
+ 98299, 196613, 393209, 786433, 1572869, 3145721, 6291449, 12582917,
+ 25165813, 50331653, 100663291, 201326611, 402653189, 805306357,
+ 1610612741
+};
+
+static int
+estimate_table_size(int est)
+{
+ int rv=0;
+ int magn=0;
+ assert(est > 0);
+ magn=(int)log((double)est)/log(2);
+ magn--;
+ magn = (magn < 0) ? 0 : magn;
+ assert(magn < (sizeof(prime_size_table) / sizeof(int)));
+ rv=prime_size_table[magn];
+ return rv;
+}
+
+genhash_t* genhash_init(int est, struct hash_ops ops)
+{
+ genhash_t* rv=NULL;
+ int size=0;
+ if (est < 1) {
+ return NULL;
+ }
+
+ assert(ops.hashfunc != NULL);
+ assert(ops.hasheq != NULL);
+ assert(ops.dupKey != NULL);
+ assert(ops.dupValue != NULL);
+ assert(ops.freeKey != NULL);
+ assert(ops.freeValue != NULL);
+
+ size=estimate_table_size(est);
+ rv=calloc(1, sizeof(genhash_t)
+ + (size * sizeof(struct genhash_entry_t *)));
+ assert(rv != NULL);
+ rv->size=size;
+ rv->ops=ops;
+
+ return rv;
+}
+
+static void
+free_bucket(genhash_t* h, struct genhash_entry_t* b)
+{
+ if(b != NULL) {
+ free_bucket(h, b->next);
+ h->ops.freeKey(b->key);
+ h->ops.freeValue(b->value);
+ free(b);
+ }
+}
+
+void
+genhash_free(genhash_t* h)
+{
+ if(h != NULL) {
+ int i=0;
+ for(i=0; i<h->size; i++) {
+ free_bucket(h, h->buckets[i]);
+ }
+ free(h);
+ }
+}
+
+void
+genhash_store(genhash_t *h, const void* k, const void* v)
+{
+ int n=0;
+ struct genhash_entry_t *p;
+
+ assert(h != NULL);
+
+ n=h->ops.hashfunc(k) % h->size;
+ assert(n >= 0);
+ assert(n < h->size);
+
+ p=calloc(1, sizeof(struct genhash_entry_t));
+ assert(p);
+
+ p->key=h->ops.dupKey(k);
+ p->value=h->ops.dupValue(v);
+
+ p->next=h->buckets[n];
+ h->buckets[n]=p;
+}
+
+static struct genhash_entry_t *
+genhash_find_entry(genhash_t *h, const void* k)
+{
+ int n=0;
+ struct genhash_entry_t *p;
+
+ assert(h != NULL);
+ n=h->ops.hashfunc(k) % h->size;
+ assert(n >= 0);
+ assert(n < h->size);
+
+ p=h->buckets[n];
+ for(p=h->buckets[n]; p && !h->ops.hasheq(k, p->key); p=p->next);
+ return p;
+}
+
+void*
+genhash_find(genhash_t *h, const void* k)
+{
+ struct genhash_entry_t *p;
+ void *rv=NULL;
+
+ p=genhash_find_entry(h, k);
+
+ if(p) {
+ rv=p->value;
+ }
+ return rv;
+}
+
+enum update_type
+genhash_update(genhash_t* h, const void* k, const void* v)
+{
+ struct genhash_entry_t *p;
+ enum update_type rv=0;
+
+ p=genhash_find_entry(h, k);
+
+ if(p) {
+ h->ops.freeValue(p->value);
+ p->value=h->ops.dupValue(v);
+ rv=MODIFICATION;
+ } else {
+ genhash_store(h, k, v);
+ rv=NEW;
+ }
+
+ return rv;
+}
+
+enum update_type
+genhash_fun_update(genhash_t* h, const void* k,
+ void *(*upd)(const void *, const void *),
+ void (*fr)(void*),
+ const void *def)
+{
+ struct genhash_entry_t *p;
+ enum update_type rv=0;
+
+ p=genhash_find_entry(h, k);
+
+ if(p) {
+ void *newValue=upd(k, p->value);
+ h->ops.freeValue(p->value);
+ p->value=h->ops.dupValue(newValue);
+ fr(newValue);
+ rv=MODIFICATION;
+ } else {
+ void *newValue=upd(k, def);
+ genhash_store(h, k, newValue);
+ fr(newValue);
+ rv=NEW;
+ }
+
+ return rv;
+}
+
+int
+genhash_delete(genhash_t* h, const void* k)
+{
+ struct genhash_entry_t *deleteme=NULL;
+ int n=0;
+ int rv=0;
+
+ assert(h != NULL);
+ n=h->ops.hashfunc(k) % h->size;
+ assert(n >= 0);
+ assert(n < h->size);
+
+ if(h->buckets[n] != NULL) {
+ /* Special case the first one */
+ if(h->ops.hasheq(h->buckets[n]->key, k)) {
+ deleteme=h->buckets[n];
+ h->buckets[n]=deleteme->next;
+ } else {
+ struct genhash_entry_t *p=NULL;
+ for(p=h->buckets[n]; deleteme==NULL && p->next != NULL; p=p->next) {
+ if(h->ops.hasheq(p->next->key, k)) {
+ deleteme=p->next;
+ p->next=deleteme->next;
+ }
+ }
+ }
+ }
+ if(deleteme != NULL) {
+ h->ops.freeKey(deleteme->key);
+ h->ops.freeValue(deleteme->value);
+ free(deleteme);
+ rv++;
+ }
+
+ return rv;
+}
+
+int
+genhash_delete_all(genhash_t* h, const void* k)
+{
+ int rv=0;
+ while(genhash_delete(h, k) == 1) {
+ rv++;
+ }
+ return rv;
+}
+
+void
+genhash_iter(genhash_t* h,
+ void (*iterfunc)(const void* key, const void* val, void *arg), void *arg)
+{
+ int i=0;
+ struct genhash_entry_t *p=NULL;
+ assert(h != NULL);
+
+ for(i=0; i<h->size; i++) {
+ for(p=h->buckets[i]; p!=NULL; p=p->next) {
+ iterfunc(p->key, p->value, arg);
+ }
+ }
+}
+
+int
+genhash_clear(genhash_t *h)
+{
+ int i = 0, rv = 0;
+ assert(h != NULL);
+
+ for(i = 0; i < h->size; i++) {
+ while(h->buckets[i]) {
+ struct genhash_entry_t *p = NULL;
+ p = h->buckets[i];
+ h->buckets[i] = p->next;
+ h->ops.freeKey(p->key);
+ h->ops.freeValue(p->value);
+ free(p);
+ }
+ }
+
+ return rv;
+}
+
+static void
+count_entries(const void *key, const void *val, void *arg)
+{
+ int *count=(int *)arg;
+ (*count)++;
+}
+
+int
+genhash_size(genhash_t* h) {
+ int rv=0;
+ assert(h != NULL);
+ genhash_iter(h, count_entries, &rv);
+ return rv;
+}
+
+int
+genhash_size_for_key(genhash_t* h, const void* k)
+{
+ int rv=0;
+ assert(h != NULL);
+ genhash_iter_key(h, k, count_entries, &rv);
+ return rv;
+}
+
+void
+genhash_iter_key(genhash_t* h, const void* key,
+ void (*iterfunc)(const void* key, const void* val, void *arg), void *arg)
+{
+ int n=0;
+ struct genhash_entry_t *p=NULL;
+
+ assert(h != NULL);
+ n=h->ops.hashfunc(key) % h->size;
+ assert(n >= 0);
+ assert(n < h->size);
+
+ for(p=h->buckets[n]; p!=NULL; p=p->next) {
+ if(h->ops.hasheq(key, p->key)) {
+ iterfunc(p->key, p->value, arg);
+ }
+ }
+}
+
+int
+genhash_string_hash(const void* p)
+{
+ int rv=5381;
+ int i=0;
+ char *str=(char *)p;
+
+ for(i=0; str[i] != 0x00; i++) {
+ rv = ((rv << 5) + rv) ^ str[i];
+ }
+
+ return rv;
+}
View
226 genhash.h
@@ -0,0 +1,226 @@
+/*
+ * Generic hash table implementation.
+ *
+ * Copyright (c) 2006 Dustin Sallings <dustin@spy.net>
+ */
+
+#ifndef GENHASH_H
+#define GENHASH_H 1
+
+/*! \mainpage genhash
+ *
+ * \section intro_sec Introduction
+ *
+ * genhash is a generic hash table implementation in C. It's
+ * well-tested, freely available (MIT-license) and does what you need.
+ *
+ * \section docs_sec API Documentation
+ *
+ * Jump right into <a href="group___core.html">the API docs</a> to get started.
+ */
+
+/**
+ * \defgroup Core genhash core
+ */
+
+/**
+ * \addtogroup Core
+ * @{
+ */
+
+/**
+ * Operations on keys and values in the hash table.
+ */
+struct hash_ops {
+ /**
+ * Function to compute a hash for the given value.
+ */
+ int (*hashfunc)(const void *);
+ /**
+ * Function that returns true if the given keys are equal.
+ */
+ int (*hasheq)(const void *, const void *);
+ /**
+ * Function to duplicate a key for storage.
+ */
+ void* (*dupKey)(const void *);
+ /**
+ * Function to duplicate a value for storage.
+ */
+ void* (*dupValue)(const void *);
+ /**
+ * Function to free a key.
+ */
+ void (*freeKey)(void *);
+ /**
+ * Function to free a value.
+ */
+ void (*freeValue)(void *);
+};
+
+/**
+ * The hash table structure.
+ */
+typedef struct _genhash genhash_t ;
+
+/**
+ * Type of update performed by an update function.
+ */
+enum update_type {
+ MODIFICATION, /**< This update is modifying an existing entry */
+ NEW /**< This update is creating a new entry */
+};
+
+/**
+ * Create a new generic hashtable.
+ *
+ * @param est the estimated number of items to store (must be > 0)
+ * @param ops the key and value operations
+ *
+ * @return the new genhash_t or NULL if one cannot be created
+ */
+genhash_t* genhash_init(int est, struct hash_ops ops);
+
+/**
+ * Free a gen hash.
+ *
+ * @param h the genhash to free (may be NULL)
+ */
+void genhash_free(genhash_t *h);
+
+/**
+ * Store an item.
+ *
+ * @param h the genhash
+ * @param k the key
+ * @param v the value
+ */
+void genhash_store(genhash_t *h, const void *k, const void *v);
+
+/**
+ * Get the most recent value stored for the given key.
+ *
+ * @param h the genhash
+ * @param k the key
+ *
+ * @return the value, or NULL if one cannot be found
+ */
+void* genhash_find(genhash_t *h, const void *k);
+
+/**
+ * Delete the most recent value stored for a key.
+ *
+ * @param h the genhash
+ * @param k the key
+ *
+ * @return the number of items deleted
+ */
+int genhash_delete(genhash_t *h, const void *k);
+
+/**
+ * Delete all mappings of a given key.
+ *
+ * @param h the genhash
+ * @param k the key
+ *
+ * @return the number of items deleted
+ */
+int genhash_delete_all(genhash_t *h, const void *k);
+
+/**
+ * Create or update an item in-place.
+ *
+ * @param h the genhash
+ * @param k the key
+ * @param v the new value to store for this key
+ *
+ * @return an indicator of whether this created a new item or updated
+ * an existing one
+ */
+enum update_type genhash_update(genhash_t *h, const void *k, const void *v);
+
+/**
+ * Create or update an item in-place with a function.
+ *
+ * @param h hashtable
+ * @param key the key of the item
+ * @param upd function that will be called with the key and current
+ * value. Should return the new value.
+ * @param fr function to free the return value returned by the update
+ * function
+ * @param def default value
+ *
+ * @return an indicator of whether this created a new item or updated
+ * an existing one
+ */
+enum update_type genhash_fun_update(genhash_t *h, const void *key,
+ void *(*upd)(const void *k, const void *oldv),
+ void (*fr)(void*),
+ const void *def);
+
+/**
+ * Iterate all keys and values in a hash table.
+ *
+ * @param h the genhash
+ * @param iterfunc a function that will be called once for every k/v pair
+ * @param arg an argument to be passed to the iterfunc on each iteration
+ */
+void genhash_iter(genhash_t *h,
+ void (*iterfunc)(const void* key, const void* val, void *arg),
+ void *arg);
+
+/**
+ * Iterate all values for a given key in a hash table.
+ *
+ * @param h the genhash
+ * @param key the key to iterate
+ * @param iterfunc a function that will be called once for every k/v pair
+ * @param arg an argument to be passed to the iterfunc on each iteration
+ */
+void genhash_iter_key(genhash_t *h, const void* key,
+ void (*iterfunc)(const void* key, const void* val, void *arg),
+ void *arg);
+
+/**
+ * Get the total number of entries in this hash table.
+ *
+ * @param h the genhash
+ *
+ * @return the number of entries in the hash table
+ */
+int genhash_size(genhash_t *h);
+
+/**
+ * Remove all items from a genhash.
+ *
+ * @param h the genhash
+ *
+ * @return the number of items removed
+ */
+int genhash_clear(genhash_t *h);
+
+/**
+ * Get the total number of entries in this hash table that map to the given
+ * key.
+ *
+ * @param h the genhash
+ * @param k a key
+ *
+ * @return the number of entries keyed with the given key
+ */
+int genhash_size_for_key(genhash_t *h, const void *k);
+
+/**
+ * Convenient hash function for strings.
+ *
+ * @param k a null-terminated string key.
+ *
+ * @return a hash value for this string.
+ */
+int genhash_string_hash(const void *k);
+
+/**
+ * @}
+ */
+
+#endif /* GENHASH_H */
View
17 genhash_int.h
@@ -0,0 +1,17 @@
+/**
+ * \private
+ */
+struct genhash_entry_t {
+ /** The key for this entry */
+ void *key;
+ /** The value for this entry */
+ void *value;
+ /** Pointer to the next entry */
+ struct genhash_entry_t *next;
+};
+
+struct _genhash {
+ size_t size;
+ struct hash_ops ops;
+ struct genhash_entry_t *buckets[];
+};
View
2 thread.c
@@ -250,7 +250,7 @@ static void *worker_libevent(void *arg) {
*/
me->thread_id = pthread_self();
if (settings.verbose > 1)
- fprintf(stderr, "worker_libevent thread_id %x\n", (unsigned int) me->thread_id);
+ fprintf(stderr, "worker_libevent thread_id %ld\n", (long)me->thread_id);
pthread_mutex_lock(&init_lock);
init_count++;

0 comments on commit ea4d064

Please sign in to comment.