summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Norbye <trond.norbye@gmail.com>2011-09-23 09:35:44 +0200
committerTrond Norbye <trond.norbye@gmail.com>2011-09-25 01:02:53 +0200
commite70f5ace86dc71a2683b884182fa46d57965a25a (patch)
treeda01cc41e9af70095bca2b86b1ab66d612756f4f
parenta707c60919e222838c863b296f94b8bc0f8dcec1 (diff)
downloadmemcached-e70f5ace86dc71a2683b884182fa46d57965a25a.tar.gz
Removed topkeys implementation
Measurements showed memcached only able to handle about 50% of the operations with top keys on vs. when it was off.
-rw-r--r--Makefile.am6
-rw-r--r--daemon/memcached.c119
-rw-r--r--daemon/memcached.h10
-rw-r--r--daemon/topkeys.c180
-rw-r--r--daemon/topkeys.h56
-rw-r--r--include/memcached/engine.h33
-rw-r--r--include/memcached/genhash.h256
-rwxr-xr-xt/binary.t2
-rwxr-xr-xt/topkeys.t115
-rw-r--r--utilities/genhash.c351
-rw-r--r--utilities/genhash_int.h21
-rw-r--r--win32/Makefile.mingw2
12 files changed, 71 insertions, 1080 deletions
diff --git a/Makefile.am b/Makefile.am
index b456398..e3a898f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,6 @@ pkginclude_HEADERS = \
include/memcached/engine_testapp.h \
include/memcached/extension.h \
include/memcached/extension_loggers.h \
- include/memcached/genhash.h \
include/memcached/protocol_binary.h \
include/memcached/protocol_plugin.h \
include/memcached/server_api.h \
@@ -76,14 +75,11 @@ libmemcached_utilities_la_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir)/utilities
libmemcached_utilities_la_LDFLAGS =-R '$(pkglibdir)' -R '$(libdir)'
libmemcached_utilities_la_SOURCES= \
include/memcached/config_parser.h \
- include/memcached/genhash.h \
include/memcached/util.h \
utilities/config_parser.c \
utilities/engine_loader.c \
utilities/engine_loader.h \
utilities/extension_loggers.c \
- utilities/genhash.c \
- utilities/genhash_int.h \
utilities/util.c
memcached_SOURCES = \
@@ -98,8 +94,6 @@ memcached_SOURCES = \
daemon/stats.c \
daemon/stats.h \
daemon/thread.c \
- daemon/topkeys.c \
- daemon/topkeys.h \
trace.h
memcached_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir)/daemon
memcached_LDFLAGS =-R '$(pkglibdir)' -R '$(libdir)'
diff --git a/daemon/memcached.c b/daemon/memcached.c
index 226fa1c..cd7ec33 100644
--- a/daemon/memcached.c
+++ b/daemon/memcached.c
@@ -51,15 +51,12 @@ static inline void item_set_cas(const void *cookie, item *it, uint64_t cas) {
SLAB_GUTS(conn, thread_stats, slab_op, thread_op) \
THREAD_GUTS(conn, thread_stats, slab_op, thread_op)
-#define STATS_INCR1(GUTS, conn, slab_op, thread_op, key, nkey) { \
- struct independent_stats *independent_stats = get_independent_stats(conn); \
- struct thread_stats *thread_stats = \
- &independent_stats->thread_stats[conn->thread->index]; \
- topkeys_t *topkeys = independent_stats->topkeys; \
+#define STATS_INCR1(GUTS, conn, slab_op, thread_op, key, nkey) \
+{ \
+ struct thread_stats *thread_stats = get_thread_stats(conn); \
pthread_mutex_lock(&thread_stats->mutex); \
GUTS(conn, thread_stats, slab_op, thread_op); \
pthread_mutex_unlock(&thread_stats->mutex); \
- TK(topkeys, slab_op, key, nkey, current_time); \
}
#define STATS_INCR(conn, op, key, nkey) \
@@ -122,7 +119,6 @@ volatile rel_time_t current_time;
*/
static SOCKET new_socket(struct addrinfo *ai);
static int try_read_command(conn *c);
-static inline struct independent_stats *get_independent_stats(conn *c);
static inline struct thread_stats *get_thread_stats(conn *c);
static void register_callback(ENGINE_HANDLE *eh,
ENGINE_EVENT_TYPE type,
@@ -165,7 +161,7 @@ static time_t process_started; /* when the process was started */
/** file scope variables **/
static conn *listen_conn = NULL;
static struct event_base *main_base;
-static struct independent_stats *default_independent_stats;
+static struct thread_stats *default_thread_stats;
static struct engine_event_handler *engine_event_handlers[MAX_ENGINE_EVENT_TYPE + 1];
@@ -238,7 +234,7 @@ static void stats_reset(const void *cookie) {
stats.total_conns = 0;
stats_prefix_clear();
STATS_UNLOCK();
- threadlocal_stats_reset(get_independent_stats(conn)->thread_stats);
+ threadlocal_stats_reset(get_thread_stats(conn));
settings.engine.v1->reset_stats(settings.engine.v0, cookie);
}
@@ -266,7 +262,6 @@ static void settings_init(void) {
settings.backlog = 1024;
settings.binding_protocol = negotiating_prot;
settings.item_size_max = 1024 * 1024; /* The famous 1MB upper limit. */
- settings.topkeys = 0;
settings.require_sasl = false;
settings.extensions.logger = get_stderr_logger();
}
@@ -1950,14 +1945,6 @@ static void process_bin_stat(conn *c) {
}
} else if (strncmp(subcommand, "aggregate", 9) == 0) {
server_stats(&append_stats, c, true);
- } else if (strncmp(subcommand, "topkeys", 7) == 0) {
- topkeys_t *tk = get_independent_stats(c)->topkeys;
- if (tk != NULL) {
- topkeys_stats(tk, c, current_time, append_stats);
- } else {
- write_bin_packet(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
- return;
- }
} else {
ret = settings.engine.v1->get_stats(settings.engine.v0, c,
subcommand, nkey,
@@ -3676,10 +3663,7 @@ inline static void process_stats_detail(conn *c, const char *command) {
}
static void aggregate_callback(void *in, void *out) {
- struct thread_stats *out_thread_stats = out;
- struct independent_stats *in_independent_stats = in;
- threadlocal_stats_aggregate(in_independent_stats->thread_stats,
- out_thread_stats);
+ threadlocal_stats_aggregate(in, out);
}
/* return server specific stats only */
@@ -3696,7 +3680,7 @@ static void server_stats(ADD_STAT add_stats, conn *c, bool aggregate) {
aggregate_callback,
&thread_stats);
} else {
- threadlocal_stats_aggregate(get_independent_stats(c)->thread_stats,
+ threadlocal_stats_aggregate(get_thread_stats(c),
&thread_stats);
}
@@ -3859,7 +3843,6 @@ static void process_stat_settings(ADD_STAT add_stats, void *c) {
#endif
APPEND_STAT("auth_required_sasl", "%s", settings.require_sasl ? "yes" : "no");
APPEND_STAT("item_size_max", "%d", settings.item_size_max);
- APPEND_STAT("topkeys", "%d", settings.topkeys);
for (EXTENSION_DAEMON_DESCRIPTOR *ptr = settings.extensions.daemons;
ptr != NULL;
@@ -3941,14 +3924,6 @@ static char *process_stat(conn *c, token_t *tokens, const size_t ntokens) {
return NULL;
} else if (strcmp(subcommand, "aggregate") == 0) {
server_stats(&append_stats, c, true);
- } else if (strcmp(subcommand, "topkeys") == 0) {
- topkeys_t *tk = get_independent_stats(c)->topkeys;
- if (tk != NULL) {
- topkeys_stats(tk, c, current_time, append_stats);
- } else {
- out_string(c, "ERROR");
- return NULL;
- }
} else {
/* getting here means that the subcommand is either engine specific or
is invalid. query the engine and see. */
@@ -6154,7 +6129,6 @@ static void usage(void) {
printf("-e config Pass config as configuration options to the storage engine\n");
printf("\nEnvironment variables:\n"
"MEMCACHED_PORT_FILENAME File to write port information to\n"
- "MEMCACHED_TOP_KEYS Number of top keys to keep track of\n"
"MEMCACHED_REQS_TAP_EVENT Similar to -R but for tap_ship_log\n");
}
@@ -6373,48 +6347,46 @@ static ENGINE_ERROR_CODE release_cookie(const void *cookie) {
return ENGINE_SUCCESS;
}
-static int num_independent_stats(void) {
+static inline int num_thread_stats(void) {
return settings.num_threads + 1;
}
-static void *new_independent_stats(void) {
- int ii;
- int nrecords = num_independent_stats();
- struct independent_stats *independent_stats = calloc(sizeof(independent_stats) + sizeof(struct thread_stats) * nrecords, 1);
- if (settings.topkeys > 0)
- independent_stats->topkeys = topkeys_init(settings.topkeys);
- for (ii = 0; ii < nrecords; ii++)
- pthread_mutex_init(&independent_stats->thread_stats[ii].mutex, NULL);
- return independent_stats;
+static void *new_thread_stats(void) {
+ int nrecords = num_thread_stats();
+
+ struct thread_stats *ts = calloc(nrecords, sizeof(*ts));
+ if (ts != NULL) {
+ for (int ii = 0; ii < nrecords; ii++) {
+ pthread_mutex_init(&ts[ii].mutex, NULL);
+ }
+ }
+ return ts;
}
-static void release_independent_stats(void *stats) {
- int ii;
- int nrecords = num_independent_stats();
- struct independent_stats *independent_stats = stats;
- if (independent_stats->topkeys)
- topkeys_free(independent_stats->topkeys);
- for (ii = 0; ii < nrecords; ii++)
- pthread_mutex_destroy(&independent_stats->thread_stats[ii].mutex);
- free(independent_stats);
+static void release_thread_stats(void *stats) {
+ struct thread_stats *ts = stats;
+ if (ts != NULL) {
+ int nrecords = num_thread_stats();
+ for (int ii = 0; ii < nrecords; ii++) {
+ pthread_mutex_destroy(&ts[ii].mutex);
+ }
+ free(ts);
+ }
}
-static inline struct independent_stats *get_independent_stats(conn *c) {
- struct independent_stats *independent_stats;
+static inline struct thread_stats *get_thread_stats(conn *c) {
+ struct thread_stats *ts;
if (settings.engine.v1->get_stats_struct != NULL) {
- independent_stats = settings.engine.v1->get_stats_struct(settings.engine.v0, (const void *)c);
- if (independent_stats == NULL)
- independent_stats = default_independent_stats;
+ ts = settings.engine.v1->get_stats_struct(settings.engine.v0, c);
+ if (ts == NULL) {
+ ts = default_thread_stats;
+ }
} else {
- independent_stats = default_independent_stats;
+ ts = default_thread_stats;
}
- return independent_stats;
-}
-static inline struct thread_stats *get_thread_stats(conn *c) {
- struct independent_stats *independent_stats = get_independent_stats(c);
- assert(c->thread->index < num_independent_stats());
- return &independent_stats->thread_stats[c->thread->index];
+ assert(c->thread->index < num_thread_stats());
+ return &ts[c->thread->index];
}
static void register_callback(ENGINE_HANDLE *eh,
@@ -6436,8 +6408,9 @@ static rel_time_t get_current_time(void)
}
static void count_eviction(const void *cookie, const void *key, const int nkey) {
- topkeys_t *tk = get_independent_stats((conn*)cookie)->topkeys;
- TK(tk, evictions, key, nkey, get_current_time());
+ (void)cookie;
+ (void)key;
+ (void)nkey;
}
/**
@@ -6814,8 +6787,8 @@ static SERVER_HANDLE_V1 *get_server_api(void)
};
static SERVER_STAT_API server_stat_api = {
- .new_stats = new_independent_stats,
- .release_stats = release_independent_stats,
+ .new_stats = new_thread_stats,
+ .release_stats = release_thread_stats,
.evicting = count_eviction
};
@@ -7261,14 +7234,6 @@ int main (int argc, char **argv) {
exit(EXIT_FAILURE);
}
- char *topkeys_env = getenv("MEMCACHED_TOP_KEYS");
- if (topkeys_env != NULL) {
- settings.topkeys = atoi(topkeys_env);
- if (settings.topkeys < 0) {
- settings.topkeys = 0;
- }
- }
-
if (settings.require_sasl) {
if (!protocol_specified) {
settings.binding_protocol = binary_prot;
@@ -7469,7 +7434,7 @@ int main (int argc, char **argv) {
exit(EXIT_FAILURE);
}
- default_independent_stats = new_independent_stats();
+ default_thread_stats = new_thread_stats();
#ifndef __WIN32__
/*
diff --git a/daemon/memcached.h b/daemon/memcached.h
index 9b1e184..625b841 100644
--- a/daemon/memcached.h
+++ b/daemon/memcached.h
@@ -14,7 +14,6 @@
#include <memcached/extension.h>
#include "cache.h"
-#include "topkeys.h"
#include "sasl_defs.h"
@@ -143,15 +142,6 @@ struct thread_stats {
struct slab_stats slab_stats[MAX_NUMBER_OF_SLAB_CLASSES];
};
-
-/**
- * The stats structure the engine keeps track of
- */
-struct independent_stats {
- topkeys_t *topkeys;
- struct thread_stats thread_stats[];
-};
-
/**
* Global stats.
*/
diff --git a/daemon/topkeys.c b/daemon/topkeys.c
deleted file mode 100644
index 3dc3e1d..0000000
--- a/daemon/topkeys.c
+++ /dev/null
@@ -1,180 +0,0 @@
-#include <sys/types.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <inttypes.h>
-#include <string.h>
-#include <pthread.h>
-#include <memcached/genhash.h>
-#include "topkeys.h"
-
-static topkey_item_t *topkey_item_init(const void *key, int nkey, rel_time_t ctime) {
- topkey_item_t *item = calloc(sizeof(topkey_item_t) + nkey, 1);
- assert(item);
- assert(key);
- assert(nkey > 0);
- item->nkey = nkey;
- item->ctime = ctime;
- item->atime = ctime;
- /* Copy the key into the part trailing the struct */
- memcpy(item->key, key, nkey);
- return item;
-}
-
-static inline size_t topkey_item_size(const topkey_item_t *item) {
- return sizeof(topkey_item_t) + item->nkey;
-}
-
-static inline topkey_item_t* topkeys_tail(topkeys_t *tk) {
- return (topkey_item_t*)(tk->list.prev);
-}
-
-static int my_hash_eq(const void *k1, size_t nkey1,
- const void *k2, size_t nkey2) {
- return nkey1 == nkey2 && memcmp(k1, k2, nkey1) == 0;
-}
-
-topkeys_t *topkeys_init(int max_keys) {
- topkeys_t *tk = calloc(sizeof(topkeys_t), 1);
- if (tk == NULL) {
- return NULL;
- }
-
- pthread_mutex_init(&tk->mutex, NULL);
- tk->max_keys = max_keys;
- tk->list.next = &tk->list;
- tk->list.prev = &tk->list;
-
- static struct hash_ops my_hash_ops = {
- .hashfunc = genhash_string_hash,
- .hasheq = my_hash_eq,
- .dupKey = NULL,
- .dupValue = NULL,
- .freeKey = NULL,
- .freeValue = NULL,
- };
-
- tk->hash = genhash_init(max_keys, my_hash_ops);
- if (tk->hash == NULL) {
- return NULL;
- }
- return tk;
-}
-
-void topkeys_free(topkeys_t *tk) {
- pthread_mutex_destroy(&tk->mutex);
- genhash_free(tk->hash);
- dlist_t *p = tk->list.next;
- while (p != &tk->list) {
- dlist_t *tmp = p->next;
- free(p);
- p = tmp;
- }
-}
-
-static inline void dlist_remove(dlist_t *list) {
- assert(list->prev->next == list);
- assert(list->next->prev == list);
- list->prev->next = list->next;
- list->next->prev = list->prev;
-}
-
-static inline void dlist_insert_after(dlist_t *list, dlist_t *new) {
- new->next = list->next;
- new->prev = list;
- list->next->prev = new;
- list->next = new;
-}
-
-static inline void dlist_iter(dlist_t *list,
- void (*iterfunc)(dlist_t *item, void *arg),
- void *arg)
-{
- dlist_t *p = list;
- while ((p = p->next) != list) {
- iterfunc(p, arg);
- }
-}
-
-static inline void topkeys_item_delete(topkeys_t *tk, topkey_item_t *item) {
- genhash_delete(tk->hash, item->key, item->nkey);
- dlist_remove(&item->list);
- --tk->nkeys;
- free(item);
-}
-
-topkey_item_t *topkeys_item_get_or_create(topkeys_t *tk, const void *key, size_t nkey, const rel_time_t ctime) {
- topkey_item_t *item = genhash_find(tk->hash, key, nkey);
- if (item == NULL) {
- item = topkey_item_init(key, nkey, ctime);
- if (item != NULL) {
- if (++tk->nkeys > tk->max_keys) {
- topkeys_item_delete(tk, topkeys_tail(tk));
- }
- genhash_update(tk->hash, item->key, item->nkey,
- item, topkey_item_size(item));
- } else {
- return NULL;
- }
- } else {
- dlist_remove(&item->list);
- }
- dlist_insert_after(&tk->list, &item->list);
- return item;
-}
-
-static inline void append_stat(const void *cookie,
- const char *name,
- size_t namelen,
- const char *key,
- size_t nkey,
- int value,
- ADD_STAT add_stats) {
- char key_str[128];
- char val_str[128];
- int klen, vlen;
-
- klen = sizeof(key_str) - namelen - 2;
- if (nkey < klen) {
- klen = nkey;
- }
- memcpy(key_str, key, klen);
- key_str[klen] = '.';
- memcpy(&key_str[klen+1], name, namelen + 1);
- klen += namelen + 1;
- vlen = snprintf(val_str, sizeof(val_str) - 1, "%d", value);
- add_stats(key_str, klen, val_str, vlen, cookie);
-}
-
-struct tk_context {
- const void *cookie;
- ADD_STAT add_stat;
- rel_time_t current_time;
-};
-
-#define TK_FMT(name) #name "=%d,"
-#define TK_ARGS(name) item->name,
-
-static void tk_iterfunc(dlist_t *list, void *arg) {
- struct tk_context *c = arg;
- topkey_item_t *item = (topkey_item_t*)list;
- char val_str[TK_MAX_VAL_LEN];
- /* This line is magical. The missing comma before item->ctime is because the TK_ARGS macro ends with a comma. */
- int vlen = snprintf(val_str, sizeof(val_str) - 1, TK_OPS(TK_FMT)"ctime=%"PRIu32",atime=%"PRIu32, TK_OPS(TK_ARGS)
- c->current_time - item->ctime, c->current_time - item->atime);
- c->add_stat(item->key, item->nkey, val_str, vlen, c->cookie);
-}
-
-ENGINE_ERROR_CODE topkeys_stats(topkeys_t *tk,
- const void *cookie,
- const rel_time_t current_time,
- ADD_STAT add_stat) {
- struct tk_context context;
- context.cookie = cookie;
- context.add_stat = add_stat;
- context.current_time = current_time;
- assert(tk);
- pthread_mutex_lock(&tk->mutex);
- dlist_iter(&tk->list, tk_iterfunc, &context);
- pthread_mutex_unlock(&tk->mutex);
- return ENGINE_SUCCESS;
-}
diff --git a/daemon/topkeys.h b/daemon/topkeys.h
deleted file mode 100644
index 35102ca..0000000
--- a/daemon/topkeys.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef TOPKEYS_H
-#define TOPKEYS_H 1
-
-#include <memcached/engine.h>
-#include <memcached/genhash.h>
-
-/* A list of operations for which we have int stats */
-#define TK_OPS(C) C(get_hits) C(get_misses) C(cmd_set) C(incr_hits) \
- C(incr_misses) C(decr_hits) C(decr_misses) \
- C(delete_hits) C(delete_misses) C(evictions) \
- C(cas_hits) C(cas_badval) C(cas_misses)
-
-#define TK_MAX_VAL_LEN 250
-
-/* Update the correct stat for a given operation */
-#define TK(tk, op, key, nkey, ctime) { \
- if (tk) { \
- assert(key); \
- assert(nkey > 0); \
- pthread_mutex_lock(&tk->mutex); \
- topkey_item_t *tmp = topkeys_item_get_or_create( \
- (tk), (key), (nkey), (ctime)); \
- tmp->op++; \
- pthread_mutex_unlock(&tk->mutex); \
- } \
-}
-
-typedef struct dlist {
- struct dlist *next;
- struct dlist *prev;
-} dlist_t;
-
-typedef struct topkey_item {
- dlist_t list; /* Must be at the beginning because we downcast! */
- int nkey;
- rel_time_t ctime, atime; /* Time this item was created/last accessed */
-#define TK_CUR(name) int name;
- TK_OPS(TK_CUR)
-#undef TK_CUR
- char key[]; /* A variable length array in the struct itself */
-} topkey_item_t;
-
-typedef struct topkeys {
- dlist_t list;
- pthread_mutex_t mutex;
- genhash_t *hash;
- int nkeys;
- int max_keys;
-} topkeys_t;
-
-topkeys_t *topkeys_init(int max_keys);
-void topkeys_free(topkeys_t *topkeys);
-topkey_item_t *topkeys_item_get_or_create(topkeys_t *tk, const void *key, size_t nkey, const rel_time_t ctime);
-ENGINE_ERROR_CODE topkeys_stats(topkeys_t *tk, const void *cookie, const rel_time_t current_time, ADD_STAT add_stat);
-
-#endif
diff --git a/include/memcached/engine.h b/include/memcached/engine.h
index c42daa2..08c2b74 100644
--- a/include/memcached/engine.h
+++ b/include/memcached/engine.h
@@ -380,19 +380,42 @@ extern "C" {
void (*reset_stats)(ENGINE_HANDLE* handle, const void *cookie);
/**
- * Get an array of per-thread stats. Set to NULL if you don't need it.
+ * Get an array of per-thread stats. This allows the engine to
+ * keep separate stats per cookie. Your implementation of this
+ * callback <b>must</b> return a memory area returned from the
+ * server API's new_stats. If all of your connections belong
+ * to the same "stats pool" you should set this callback to
+ * NULL.
+ *
+ * @param handle the engine handle
+ * @param cookie the cookie representing the connection
+ * @return A pointer to a stats structure (or NULL if allocation
+ * failed)
*/
void *(*get_stats_struct)(ENGINE_HANDLE* handle,
const void* cookie);
/**
- * Aggregate stats among all per-connection stats. Set to NULL if you don't need it.
+ * Aggregate stats among all per-connection stats. This allows
+ * the engine to call the aggregation callback for a number of
+ * stat structures. You would normally not use this if you
+ * didn't implement a special get_stats_struct().
+ *
+ *
+ * @param handle the engine handle
+ * @param cookie the cookie representing the connection
+ * @param callback the callback function you should call for all
+ * of the stats structures you want to include in the
+ * aggregatioin.
+ * @param dest This is the second parameter to the callback
+ * function.
+ * @return ENGINE_SUCCESS unless you had a failure
*/
ENGINE_ERROR_CODE (*aggregate_stats)(ENGINE_HANDLE* handle,
const void* cookie,
- void (*callback)(void*, void*),
- void*);
-
+ void (*callback)(void* src,
+ void* dest),
+ void* dest);
/**
* Any unknown command will be considered engine specific.
diff --git a/include/memcached/genhash.h b/include/memcached/genhash.h
deleted file mode 100644
index 235ef47..0000000
--- a/include/memcached/genhash.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Generic hash table implementation.
- *
- * Copyright (c) 2006 Dustin Sallings <dustin@spy.net>
- */
-
-#ifndef GENHASH_H
-#define GENHASH_H 1
-
-#include <memcached/visibility.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*! \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 *, size_t);
- /**
- * Function that returns true if the given keys are equal.
- */
- int (*hasheq)(const void *, size_t, const void *, size_t);
- /**
- * Function to duplicate a key for storage.
- */
- void* (*dupKey)(const void *, size_t);
- /**
- * Function to duplicate a value for storage.
- */
- void* (*dupValue)(const void *, size_t);
- /**
- * 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
- */
-MEMCACHED_PUBLIC_API
-genhash_t* genhash_init(int est, struct hash_ops ops);
-
-/**
- * Free a gen hash.
- *
- * @param h the genhash to free (may be NULL)
- */
-MEMCACHED_PUBLIC_API
-void genhash_free(genhash_t *h);
-
-/**
- * Store an item.
- *
- * @param h the genhash
- * @param k the key
- * @param v the value
- */
-MEMCACHED_PUBLIC_API
-void genhash_store(genhash_t *h, const void *k, size_t klen,
- const void *v, size_t vlen);
-
-/**
- * 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
- */
-MEMCACHED_PUBLIC_API
-void* genhash_find(genhash_t *h, const void *k, size_t klen);
-
-/**
- * Delete the most recent value stored for a key.
- *
- * @param h the genhash
- * @param k the key
- *
- * @return the number of items deleted
- */
-MEMCACHED_PUBLIC_API
-int genhash_delete(genhash_t *h, const void *k, size_t klen);
-
-/**
- * Delete all mappings of a given key.
- *
- * @param h the genhash
- * @param k the key
- *
- * @return the number of items deleted
- */
-MEMCACHED_PUBLIC_API
-int genhash_delete_all(genhash_t *h, const void *k, size_t klen);
-
-/**
- * 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
- */
-MEMCACHED_PUBLIC_API
-enum update_type genhash_update(genhash_t *h, const void *k, size_t klen,
- const void *v, size_t vlen);
-
-/**
- * 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
- */
-MEMCACHED_PUBLIC_API
-enum update_type genhash_fun_update(genhash_t *h, const void *key, size_t klen,
- void *(*upd)(const void *k, const void *oldv,
- size_t *ns, void *a),
- void (*fr)(void*),
- void *arg,
- const void *def, size_t deflen);
-
-/**
- * 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
- */
-MEMCACHED_PUBLIC_API
-void genhash_iter(genhash_t *h,
- void (*iterfunc)(const void* key, size_t nkey,
- const void* val, size_t nval,
- 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
- */
-MEMCACHED_PUBLIC_API
-void genhash_iter_key(genhash_t *h, const void* key, size_t nkey,
- void (*iterfunc)(const void* key, size_t inkey,
- const void* val, size_t inval,
- 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
- */
-MEMCACHED_PUBLIC_API
-int genhash_size(genhash_t *h);
-
-/**
- * Remove all items from a genhash.
- *
- * @param h the genhash
- *
- * @return the number of items removed
- */
-MEMCACHED_PUBLIC_API
-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
- */
-MEMCACHED_PUBLIC_API
-int genhash_size_for_key(genhash_t *h, const void *k, size_t nkey);
-
-/**
- * Convenient hash function for strings.
- *
- * @param k a null-terminated string key.
- *
- * @return a hash value for this string.
- */
-MEMCACHED_PUBLIC_API
-int genhash_string_hash(const void *k, size_t nkey);
-
-/**
- * @}
- */
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* GENHASH_H */
diff --git a/t/binary.t b/t/binary.t
index 865f0c9..2d5a6bd 100755
--- a/t/binary.t
+++ b/t/binary.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use Test::More tests => 3430;
+use Test::More tests => 3427;
use FindBin qw($Bin);
use lib "$Bin/lib";
use MemcachedTest;
diff --git a/t/topkeys.t b/t/topkeys.t
deleted file mode 100755
index e429077..0000000
--- a/t/topkeys.t
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use Test::More tests => 252;
-use FindBin qw($Bin);
-use lib "$Bin/lib";
-use MemcachedTest;
-
-my $server = new_memcached();
-my $sock = $server->sock;
-
-print $sock "stats topkeys\r\n";
-
-is(scalar <$sock>, "ERROR\r\n", "No topkeys without command line option.");
-
-$ENV{"MEMCACHED_TOP_KEYS"} = "100";
-$server = new_memcached();
-$sock = $server->sock;
-
-print $sock "stats topkeys\r\n";
-is(scalar <$sock>, "END\r\n", "No top keys yet.");
-
-# Do some operations
-
-print $sock "set foo 0 0 6\r\nfooval\r\n";
-is(scalar <$sock>, "STORED\r\n", "stored foo");
-mem_get_is($sock, "foo", "fooval");
-
-sub parse_stats {
- my ($stats) = @_;
- my %ret = ();
- my $key;
- foreach $key (keys %$stats) {
- my %h = split /[,=]/,$stats->{$key};
- $ret{$key} = \%h;
- }
- return \%ret;
-}
-
-
-my $stats = parse_stats(mem_stats($sock, 'topkeys'));
-
-is($stats->{'foo'}->{'cmd_set'}, '1');
-is($stats->{'foo'}->{'get_hits'}, '1');
-
-foreach my $key (qw(get_misses incr_hits incr_misses decr_hits decr_misses delete_hits delete_misses evictions)) {
- is($stats->{'foo'}->{$key}, 0, "all stats except cmd_set are zero");
-}
-
-print $sock "set foo 0 0 6\r\nfooval\r\n";
-is(scalar <$sock>, "STORED\r\n", "stored foo");
-print $sock "set bar 0 0 6\r\nbarval\r\n";
-is(scalar <$sock>, "STORED\r\n", "stored bar");
-mem_get_is($sock, "bar", "barval");
-
-$stats = parse_stats(mem_stats($sock, 'topkeys'));
-
-is($stats->{'foo'}->{'cmd_set'}, '2');
-is($stats->{'bar'}->{'cmd_set'}, '1');
-
-print $sock "delete foo\r\n";
-is(scalar <$sock>, "DELETED\r\n", "deleted foo");
-
-$stats = parse_stats(mem_stats($sock, 'topkeys'));
-is($stats->{'foo'}->{'delete_hits'}, 1);
-is($stats->{'foo'}->{'delete_misses'}, 0);
-is($stats->{'foo'}->{'cmd_set'}, 2);
-
-#print $sock "delete foo\r\n";
-#is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't delete foo again");
-
-sub check_incr_stats {
- my ($key, $ih, $im, $dh, $dm) = @_;
- my $stats = parse_stats(mem_stats($sock, 'topkeys'));
-
- is($stats->{$key}->{'incr_hits'}, $ih);
- is($stats->{$key}->{'incr_misses'}, $im);
- is($stats->{$key}->{'decr_hits'}, $dh);
- is($stats->{$key}->{'decr_misses'}, $dm);
-}
-
-print $sock "incr i 1\r\n";
-is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't incr a missing thing");
-check_incr_stats("i", 0, 1, 0, 0);
-
-print $sock "decr d 1\r\n";
-is(scalar <$sock>, "NOT_FOUND\r\n", "shouldn't decr a missing thing");
-check_incr_stats("d", 0, 0, 0, 1);
-
-print $sock "set n 0 0 1\r\n0\r\n";
-is(scalar <$sock>, "STORED\r\n", "stored n");
-
-print $sock "incr n 3\r\n";
-is(scalar <$sock>, "3\r\n", "incr works");
-check_incr_stats("n", 1, 0, 0, 0);
-
-print $sock "decr n 1\r\n";
-is(scalar <$sock>, "2\r\n", "decr works");
-check_incr_stats("n", 1, 0, 1, 0);
-
-print $sock "decr n 1\r\n";
-is(scalar <$sock>, "1\r\n", "decr works");
-check_incr_stats("n", 1, 0, 2, 0);
-
-my $i;
-# Make sure older keys fall out of the LRU
-for ($i = 0; $i < 200; $i++) {
- print $sock "set foo$i 0 0 6\r\nfooval\r\n";
- is(scalar <$sock>, "STORED\r\n", "stored foo$i");
-}
-
-$stats = parse_stats(mem_stats($sock, 'topkeys'));
-is($stats->{'foo99'}->{'cmd_set'}, undef);
-is($stats->{'foo100'}->{'cmd_set'}, 1);
-is($stats->{'foo199'}->{'cmd_set'}, 1);
diff --git a/utilities/genhash.c b/utilities/genhash.c
deleted file mode 100644
index b8bbb87..0000000
--- a/utilities/genhash.c
+++ /dev/null
@@ -1,351 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <assert.h>
-
-#include <memcached/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 inline void*
-dup_key(genhash_t *h, const void *key, size_t klen)
-{
- if (h->ops.dupKey != NULL) {
- return h->ops.dupKey(key, klen);
- } else {
- return (void*)key;
- }
-}
-
-static inline void*
-dup_value(genhash_t *h, const void *value, size_t vlen)
-{
- if (h->ops.dupValue != NULL) {
- return h->ops.dupValue(value, vlen);
- } else {
- return (void*)value;
- }
-}
-
-static inline void
-free_key(genhash_t *h, void *key)
-{
- if (h->ops.freeKey != NULL) {
- h->ops.freeKey(key);
- }
-}
-
-static inline void
-free_value(genhash_t *h, void *value)
-{
- if (h->ops.freeValue != NULL) {
- h->ops.freeValue(value);
- }
-}
-
-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 && ops.freeKey != NULL) || ops.freeKey == NULL);
- assert((ops.dupValue != NULL && ops.freeValue != NULL) || 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;
-}
-
-void
-genhash_free(genhash_t* h)
-{
- if(h != NULL) {
- genhash_clear(h);
- free(h);
- }
-}
-
-void
-genhash_store(genhash_t *h, const void* k, size_t klen,
- const void* v, size_t vlen)
-{
- int n=0;
- struct genhash_entry_t *p;
-
- assert(h != NULL);
-
- n=h->ops.hashfunc(k, klen) % h->size;
- assert(n >= 0);
- assert(n < h->size);
-
- p=calloc(1, sizeof(struct genhash_entry_t));
- assert(p);
-
- p->key=dup_key(h, k, klen);
- p->nkey = klen;
- p->value=dup_value(h, v, vlen);
- p->nvalue = vlen;
-
- p->next=h->buckets[n];
- h->buckets[n]=p;
-}
-
-static struct genhash_entry_t *
-genhash_find_entry(genhash_t *h, const void* k, size_t klen)
-{
- int n=0;
- struct genhash_entry_t *p;
-
- assert(h != NULL);
- n=h->ops.hashfunc(k, klen) % h->size;
- assert(n >= 0);
- assert(n < h->size);
-
- p=h->buckets[n];
- for(p=h->buckets[n]; p && !h->ops.hasheq(k, klen, p->key, p->nkey); p=p->next);
- return p;
-}
-
-void*
-genhash_find(genhash_t *h, const void* k, size_t klen)
-{
- struct genhash_entry_t *p;
- void *rv=NULL;
-
- p=genhash_find_entry(h, k, klen);
-
- if(p) {
- rv=p->value;
- }
- return rv;
-}
-
-enum update_type
-genhash_update(genhash_t* h, const void* k, size_t klen,
- const void* v, size_t vlen)
-{
- struct genhash_entry_t *p;
- enum update_type rv=0;
-
- p=genhash_find_entry(h, k, klen);
-
- if(p) {
- free_value(h, p->value);
- p->value=dup_value(h, v, vlen);
- rv=MODIFICATION;
- } else {
- genhash_store(h, k, klen, v, vlen);
- rv=NEW;
- }
-
- return rv;
-}
-
-enum update_type
-genhash_fun_update(genhash_t* h, const void* k, size_t klen,
- void *(*upd)(const void *, const void *, size_t *, void *),
- void (*fr)(void*),
- void *arg,
- const void *def, size_t deflen)
-{
- struct genhash_entry_t *p;
- enum update_type rv=0;
- size_t newSize = 0;
-
- p=genhash_find_entry(h, k, klen);
-
- if(p) {
- void *newValue=upd(k, p->value, &newSize, arg);
- free_value(h, p->value);
- p->value=dup_value(h, newValue, newSize);
- fr(newValue);
- rv=MODIFICATION;
- } else {
- void *newValue=upd(k, def, &newSize, arg);
- genhash_store(h, k, klen, newValue, newSize);
- fr(newValue);
- rv=NEW;
- }
-
- return rv;
-}
-
-static void
-free_item(genhash_t *h, struct genhash_entry_t *i)
-{
- assert(i);
- free_key(h, i->key);
- free_value(h, i->value);
- free(i);
-}
-
-int
-genhash_delete(genhash_t* h, const void* k, size_t klen)
-{
- struct genhash_entry_t *deleteme=NULL;
- int n=0;
- int rv=0;
-
- assert(h != NULL);
- n=h->ops.hashfunc(k, klen) % 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, h->buckets[n]->nkey, k, klen)) {
- 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, p->next->nkey, k, klen)) {
- deleteme=p->next;
- p->next=deleteme->next;
- }
- }
- }
- }
- if(deleteme != NULL) {
- free_item(h, deleteme);
- rv++;
- }
-
- return rv;
-}
-
-int
-genhash_delete_all(genhash_t* h, const void* k, size_t klen)
-{
- int rv=0;
- while(genhash_delete(h, k, klen) == 1) {
- rv++;
- }
- return rv;
-}
-
-void
-genhash_iter(genhash_t* h,
- void (*iterfunc)(const void* key, size_t nkey,
- const void* val, size_t nval,
- 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->nkey, p->value, p->nvalue, 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;
- free_item(h, p);
- }
- }
-
- return rv;
-}
-
-static void
-count_entries(const void *key, size_t klen,
- const void *val, size_t vlen, 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, size_t klen)
-{
- int rv=0;
- assert(h != NULL);
- genhash_iter_key(h, k, klen, count_entries, &rv);
- return rv;
-}
-
-void
-genhash_iter_key(genhash_t* h, const void* key, size_t klen,
- void (*iterfunc)(const void* key, size_t klen,
- const void* val, size_t vlen,
- void *arg), void *arg)
-{
- int n=0;
- struct genhash_entry_t *p=NULL;
-
- assert(h != NULL);
- n=h->ops.hashfunc(key, klen) % h->size;
- assert(n >= 0);
- assert(n < h->size);
-
- for(p=h->buckets[n]; p!=NULL; p=p->next) {
- if(h->ops.hasheq(key, klen, p->key, p->nkey)) {
- iterfunc(p->key, p->nkey, p->value, p->nvalue, arg);
- }
- }
-}
-
-int
-genhash_string_hash(const void* p, size_t nkey)
-{
- int rv=5381;
- int i=0;
- char *str=(char *)p;
-
- for(i=0; i < nkey; i++) {
- rv = ((rv << 5) + rv) ^ str[i];
- }
-
- return rv;
-}
diff --git a/utilities/genhash_int.h b/utilities/genhash_int.h
deleted file mode 100644
index f270d8e..0000000
--- a/utilities/genhash_int.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * \private
- */
-struct genhash_entry_t {
- /** The key for this entry */
- void *key;
- /** Size of the key */
- size_t nkey;
- /** The value for this entry */
- void *value;
- /** Size of the value */
- size_t nvalue;
- /** Pointer to the next entry */
- struct genhash_entry_t *next;
-};
-
-struct _genhash {
- size_t size;
- struct hash_ops ops;
- struct genhash_entry_t *buckets[];
-};
diff --git a/win32/Makefile.mingw b/win32/Makefile.mingw
index 024033d..7a4a704 100644
--- a/win32/Makefile.mingw
+++ b/win32/Makefile.mingw
@@ -64,11 +64,9 @@ MEMCACHED_SRC = \
daemon/sasl_defs.c \
daemon/stats.c \
daemon/thread.c \
- daemon/topkeys.c \
utilities/config_parser.c \
utilities/engine_loader.c \
utilities/extension_loggers.c\
- utilities/genhash.c \
utilities/util.c \
win32/defs.c \
win32/dlfcn.c \