Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

v0.2 code, multiple queue hashtable changed for per-queue stats

  • Loading branch information...
commit e31d46547e58385f98e532bffa50d286f854f15c 1 parent eb4948b
Steve Chu authored
View
2  Makefile.am
@@ -1,4 +1,4 @@
bin_PROGRAMS = memcacheq
-memcacheq_SOURCES = memcacheq.c item.c memcacheq.h thread.c bdb.c
+memcacheq_SOURCES = memcacheq.c item.c memcacheq.h thread.c bdb.c hashtable.c hash.c daemon.c
EXTRA_DIST = AUTHORS LICENSE INSTALL.html README.html
View
8 Makefile.in
@@ -49,7 +49,8 @@ am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am_memcacheq_OBJECTS = memcacheq.$(OBJEXT) item.$(OBJEXT) \
- thread.$(OBJEXT) bdb.$(OBJEXT)
+ thread.$(OBJEXT) bdb.$(OBJEXT) hashtable.$(OBJEXT) \
+ hash.$(OBJEXT) daemon.$(OBJEXT)
memcacheq_OBJECTS = $(am_memcacheq_OBJECTS)
memcacheq_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I.@am__isrc@
@@ -158,7 +159,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-memcacheq_SOURCES = memcacheq.c item.c memcacheq.h thread.c bdb.c
+memcacheq_SOURCES = memcacheq.c item.c memcacheq.h thread.c bdb.c hashtable.c hash.c daemon.c
EXTRA_DIST = AUTHORS LICENSE INSTALL.html README.html
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -249,6 +250,9 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashtable.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/item.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memcacheq.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@
View
1,002 bdb.c
@@ -29,53 +29,80 @@
#include <sys/types.h>
#include <signal.h>
#include <db.h>
-
-static int open_exsited_queue_db(DB_TXN *txn, char *queue_name, DB **queue_dbp);
-static int create_queue_db(DB_TXN *txn, char *queue_name, size_t queue_name_size, DB **queue_dbp);
-static int get_queue_db_handle(DB_TXN *txn, char *queue_name, size_t queue_name_size, DB **queue_dbp);
-static int update_queue_length(DB_TXN *txn, char *queue_name, size_t queue_name_size, int64_t delta);
-static void close_queue_db_list(void);
-
-static void *bdb_chkpoint_thread __P((void *));
-static void *bdb_memp_trickle_thread __P((void *));
-static void *bdb_dl_detect_thread __P((void *));
-static void bdb_event_callback __P((DB_ENV *, u_int32_t, void *));
+#include <assert.h>
+
+#define CHECK_DB_RET(ret) \
+ if (0!=ret) \
+ goto dberr
+
+static void open_exsited_queue_db(DB_TXN *txn, char *qn, qstats_t *qs);
+static void dump_qstats(void);
+static void *bdb_checkpoint_thread __P((void *));
+static void *bdb_mempool_trickle_thread __P((void *));
+static void *bdb_deadlock_detect_thread __P((void *));
+static void *bdb_qstats_dump_thread __P((void *));
static void bdb_err_callback(const DB_ENV *dbenv, const char *errpfx, const char *msg);
static void bdb_msg_callback(const DB_ENV *dbenv, const char *msg);
-static pthread_t chk_ptid;
-static pthread_t mtri_ptid;
-static pthread_t dld_ptid;
+static unsigned int
+hashfromkey(void *ky)
+{
+ char *k = (char *)ky;
+ unsigned int hash;
+ hash = murmurhash2(k, strlen(k), 0);
+ return hash;
+}
-void bdb_settings_init(void)
+static int
+equalkeys(void *k1, void *k2)
{
+ return (0 == strcmp(k1,k2));
+}
+
+static struct hashtable *qlist_htp;
+static pthread_rwlock_t qlist_ht_lock;
+static DB *qlist_dbp = NULL;
+
+void qlist_ht_init(void) {
+ pthread_rwlock_init(&qlist_ht_lock, NULL);
+ qlist_htp = create_hashtable(64, hashfromkey, equalkeys);
+ if (NULL == qlist_htp) {
+ fprintf(stderr, "create_hashtable fail\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void qlist_ht_close(void) {
+ hashtable_destroy(qlist_htp, 1);
+ pthread_rwlock_destroy(&qlist_ht_lock);
+}
+
+void bdb_settings_init(void){
bdb_settings.env_home = DBHOME;
bdb_settings.cache_size = 64 * 1024 * 1024; /* default is 64MB */
bdb_settings.txn_lg_bsize = 32 * 1024; /* default is 32KB */
- /* queue only */
bdb_settings.re_len = 1024;
- bdb_settings.q_extentsize = 131072;
+ bdb_settings.q_extentsize = 16 * 1024; // 64MB extent file each
bdb_settings.page_size = 4096; /* default is 4K */
bdb_settings.txn_nosync = 0; /* default DB_TXN_NOSYNC is off */
- bdb_settings.dldetect_val = 100 * 1000; /* default is 100 millisecond */
- bdb_settings.chkpoint_val = 60 * 5;
- bdb_settings.memp_trickle_val = 30;
- bdb_settings.memp_trickle_percent = 60;
- bdb_settings.db_flags = DB_CREATE | DB_AUTO_COMMIT;
- bdb_settings.env_flags = DB_CREATE
- | DB_INIT_LOCK
- | DB_THREAD
- | DB_INIT_MPOOL
- | DB_INIT_LOG
- | DB_INIT_TXN
- | DB_RECOVER;
-
+ bdb_settings.deadlock_detect_val = 100 * 1000; /* default is 100 millisecond */
+ bdb_settings.checkpoint_val = 60 * 5; /* seconds */
+ bdb_settings.mempool_trickle_val = 30; /* seconds */
+ bdb_settings.mempool_trickle_percent = 60;
+ bdb_settings.qstats_dump_val = 30; /* seconds */
}
void bdb_env_init(void){
int ret;
+ u_int32_t env_flags = DB_CREATE
+ | DB_INIT_LOCK
+ | DB_THREAD
+ | DB_INIT_MPOOL
+ | DB_INIT_LOG
+ | DB_INIT_TXN
+ | DB_RECOVER;
/* db env init */
if ((ret = db_env_create(&envp, 0)) != 0) {
fprintf(stderr, "db_env_create: %s\n", db_strerror(ret));
@@ -84,30 +111,9 @@ void bdb_env_init(void){
/* set err&msg display */
envp->set_errpfx(envp, PACKAGE);
- /* env->set_errfile(env, stderr); */
- /* env->set_msgfile(env, stderr); */
envp->set_errcall(envp, bdb_err_callback);
envp->set_msgcall(envp, bdb_msg_callback);
- /* set BerkeleyDB verbose*/
- if (settings.verbose > 1) {
- if ((ret = envp->set_verbose(envp, DB_VERB_FILEOPS_ALL, 1)) != 0) {
- fprintf(stderr, "envp->set_verbose[DB_VERB_FILEOPS_ALL]: %s\n",
- db_strerror(ret));
- exit(EXIT_FAILURE);
- }
- if ((ret = envp->set_verbose(envp, DB_VERB_DEADLOCK, 1)) != 0) {
- fprintf(stderr, "envp->set_verbose[DB_VERB_DEADLOCK]: %s\n",
- db_strerror(ret));
- exit(EXIT_FAILURE);
- }
- if ((ret = envp->set_verbose(envp, DB_VERB_RECOVERY, 1)) != 0) {
- fprintf(stderr, "envp->set_verbose[DB_VERB_RECOVERY]: %s\n",
- db_strerror(ret));
- exit(EXIT_FAILURE);
- }
- }
-
/* set MPOOL size */
envp->set_cachesize(envp, 0, bdb_settings.cache_size, 0);
@@ -117,13 +123,12 @@ void bdb_env_init(void){
}
/* set locking */
- envp->set_lk_max_lockers(envp, 20000);
- envp->set_lk_max_locks(envp, 20000);
- envp->set_lk_max_objects(envp, 20000);
- envp->set_tx_max(envp, 20000);
+ envp->set_lk_max_lockers(envp, 40000);
+ envp->set_lk_max_locks(envp, 40000);
+ envp->set_lk_max_objects(envp, 40000);
/* at least max active transactions */
- envp->set_tx_max(envp, 10000);
+ envp->set_tx_max(envp, 40000);
/* set transaction log buffer */
envp->set_lg_bsize(envp, bdb_settings.txn_lg_bsize);
@@ -136,561 +141,411 @@ void bdb_env_init(void){
}
}
- if ((ret = envp->open(envp, bdb_settings.env_home, bdb_settings.env_flags, 0)) != 0) {
- fprintf(stderr, "db_env_open: %s\n", db_strerror(ret));
+ if ((ret = envp->open(envp, bdb_settings.env_home, env_flags, 0)) != 0) {
+ fprintf(stderr, "envp->open: %s\n", db_strerror(ret));
exit(EXIT_FAILURE);
}
-
}
+/* for atexit cleanup */
+void bdb_env_close(void){
+ int ret = 0;
+ if (envp != NULL) {
+ ret = envp->close(envp, 0);
+ if (0 != ret){
+ fprintf(stderr, "envp->close: %s\n", db_strerror(ret));
+ }else{
+ envp = NULL;
+ fprintf(stderr, "envp->close: OK\n");
+ }
+ }
+}
void bdb_qlist_db_open(void){
int ret;
- int db_open = 0;
DBC *cursorp = NULL;
- DB_TXN *txn = NULL;
- DBT dbkey, dbdata;
- char queue_name[512];
- DB *queue_dbp = NULL;
-
- u_int32_t qlist_db_flags = DB_CREATE;
-
- ret = envp->txn_begin(envp, NULL, &txn, 0);
- if (ret != 0) {
- goto err;
- }
-
- /* for replicas to get a full master copy, then open db */
- while(!db_open) {
- /* close the queue list db */
- if (qlist_dbp != NULL) {
- qlist_dbp->close(qlist_dbp, 0);
- qlist_dbp = NULL;
- }
-
- if ((ret = db_create(&qlist_dbp, envp, 0)) != 0) {
- fprintf(stderr, "db_create: %s\n", db_strerror(ret));
- exit(EXIT_FAILURE);
- }
-
- if ((ret = qlist_dbp->set_priority(qlist_dbp, DB_PRIORITY_VERY_HIGH)) != 0){
- fprintf(stderr, "qlist_dbp->set_priority: %s\n", db_strerror(ret));
- exit(EXIT_FAILURE);
- }
+ DB_TXN *txnp = NULL;
- /*
- if ((ret = qlist_dbp->set_pagesize(qlist_dbp, 512)) != 0){
- fprintf(stderr, "qlist_dbp->set_pagesize: %s\n", db_strerror(ret));
- exit(EXIT_FAILURE);
- }
- */
-
- /* try to open qlist db*/
- ret = qlist_dbp->open(qlist_dbp, txn, "queue.list", NULL, DB_BTREE, qlist_db_flags, 0664);
- switch (ret){
- case 0:
- db_open = 1;
- break;
- case ENOENT:
- case DB_LOCK_DEADLOCK:
- fprintf(stderr, "bdb_qlist_db_open: %s\n", db_strerror(ret));
- sleep(3);
- break;
- default:
- fprintf(stderr, "bdb_qlist_db_open: %s\n", db_strerror(ret));
- goto err;
- }
- }
-
- /* Get a cursor */
- ret = qlist_dbp->cursor(qlist_dbp, txn, &cursorp, 0);
- if (ret != 0) {
- goto err;
- }
+ ret = envp->txn_begin(envp, NULL, &txnp, 0);
+ CHECK_DB_RET(ret);
+ ret = db_create(&qlist_dbp, envp, 0);
+ CHECK_DB_RET(ret);
+ ret = qlist_dbp->open(qlist_dbp, txnp, "queue.list", NULL, DB_BTREE, DB_CREATE, 0664);
+ CHECK_DB_RET(ret);
+ ret = qlist_dbp->cursor(qlist_dbp, txnp, &cursorp, 0);
+ CHECK_DB_RET(ret);
/* Initialize our DBTs. */
+ DBT dbkey, dbdata;
+ char qname[512];
+ qstats_t qs;
BDB_CLEANUP_DBT();
- memset(queue_name, 0, 512);
-
- dbkey.data = (void *)queue_name;
+ memset(qname, 0, 512);
+ memset(&qs, 0, sizeof(qs));
+ dbkey.data = (void *)qname;
dbkey.ulen = 512;
dbkey.flags = DB_DBT_USERMEM;
- dbdata.data = (void *)&queue_dbp;
- dbdata.ulen = sizeof(queue_dbp);
+ dbdata.data = (void *)&qs;
+ dbdata.ulen = sizeof(qs);
dbdata.flags = DB_DBT_USERMEM;
- /* Iterate over the database, retrieving each record in turn. */
while ((ret = cursorp->get(cursorp, &dbkey, &dbdata, DB_NEXT)) == 0) {
- ret = open_exsited_queue_db(txn, queue_name, &queue_dbp);
- if (ret != 0){
- goto err;
- }
- ret = cursorp->put(cursorp, &dbkey, &dbdata, DB_CURRENT);
- if (ret != 0){
- goto err;
- }
+ open_exsited_queue_db(txnp, qname, &qs);
}
if (ret != DB_NOTFOUND) {
- goto err;
+ goto dberr;
}
- if (cursorp != NULL){
- cursorp->close(cursorp);
- }
-
- ret = txn->commit(txn, 0);
- if (ret != 0) {
- goto err;
- }
+ ret = cursorp->close(cursorp);
+ CHECK_DB_RET(ret);
+ ret = txnp->commit(txnp, 0);
+ CHECK_DB_RET(ret);
return;
-err:
+dberr:
if (cursorp != NULL){
cursorp->close(cursorp);
}
- if (txn != NULL){
- txn->abort(txn);
+ if (txnp != NULL){
+ txnp->abort(txnp);
}
- fprintf(stderr, "bdb_qlist_db_open: %s %s\n", queue_name, db_strerror(ret));
+ fprintf(stderr, "bdb_qlist_db_open: %s\n", db_strerror(ret));
exit(EXIT_FAILURE);
-
}
-static int open_exsited_queue_db(DB_TXN *txn, char *queue_name, DB **queue_dbp){
- int ret, db_open;
- u_int32_t db_flags = DB_CREATE;
- DB *temp_dbp = NULL;
- db_open = 0;
-
- /* for replicas to get a full master copy, then open db */
- while(!db_open) {
- if (temp_dbp != NULL){
- temp_dbp->close(temp_dbp, 0);
- temp_dbp = NULL;
- }
-
- if ((ret = db_create(&temp_dbp, envp, 0)) != 0) {
- fprintf(stderr, "db_create: %s\n", db_strerror(ret));
- goto err;
- }
-
- /* set record length */
- if (bdb_settings.q_extentsize != 0){
- if((ret = temp_dbp->set_q_extentsize(temp_dbp, bdb_settings.q_extentsize)) != 0){
- fprintf(stderr, "temp_dbp[%s]->set_q_extentsize: %s\n", queue_name, db_strerror(ret));
- goto err;
- }
- }
-
- /* set record length */
- if((ret = temp_dbp->set_re_len(temp_dbp, bdb_settings.re_len)) != 0){
- fprintf(stderr, "temp_dbp[%s]->set_re_len: %s\n", queue_name, db_strerror(ret));
- goto err;
- }
-
- /* set page size */
- if((ret = temp_dbp->set_pagesize(temp_dbp, bdb_settings.page_size)) != 0){
- fprintf(stderr, "temp_dbp[%s]->set_pagesize: %s\n", queue_name, db_strerror(ret));
- goto err;
- }
-
- /* try to open db*/
- ret = temp_dbp->open(temp_dbp, txn, queue_name, NULL, DB_QUEUE, db_flags, 0664);
- switch (ret){
- case 0:
- db_open = 1;
- *queue_dbp = temp_dbp;
- break;
- case ENOENT:
- case DB_LOCK_DEADLOCK:
- fprintf(stderr, "temp_dbp[%s]->open: %s\n", queue_name, db_strerror(ret));
- sleep(2);
- break;
- default:
- goto err;
- }
- }
- return 0;
-
-err:
- if (temp_dbp != NULL){
- temp_dbp->close(temp_dbp, 0);
- }
- return ret;
-}
-
-static int create_queue_db(DB_TXN *txn, char *queue_name, size_t queue_name_size, DB **queue_dbp){
+static void open_exsited_queue_db(DB_TXN *txnp, char *queue_name, qstats_t *qsp){
int ret;
- u_int32_t db_flags = DB_CREATE;
- DB *temp_dbp = NULL;
- DBT dbkey,dbdata;
- /* DB handle */
- if ((ret = db_create(&temp_dbp, envp, 0)) != 0) {
- goto err;
- }
+ char *k = strdup(queue_name);
+ assert(k != NULL);
+ queue_t *q = (queue_t *)calloc(1, sizeof(queue_t));
+ assert(q != NULL);
- /* configure */
- if (bdb_settings.q_extentsize != 0){
- if((ret = temp_dbp->set_q_extentsize(temp_dbp, bdb_settings.q_extentsize)) != 0){
- goto err;
- }
- }
- if((ret = temp_dbp->set_re_len(temp_dbp, bdb_settings.re_len)) != 0){
- goto err;
- }
- if((ret = temp_dbp->set_pagesize(temp_dbp, bdb_settings.page_size)) != 0){
- goto err;
- }
+ /* init hash_key and hash_value */
+ q->dbp = NULL;
+ q->set_hits = q->old_set_hits = qsp->set_hits;
+ q->get_hits = q->old_get_hits = qsp->get_hits;
+ pthread_mutex_init(&(q->lock), NULL);
- /* try to open db*/
- ret = temp_dbp->open(temp_dbp, txn, queue_name, NULL, DB_QUEUE, db_flags, 0664);
- if (ret != 0){
- goto err;
- }
+ ret = db_create(&(q->dbp), envp, 0);
+ CHECK_DB_RET(ret);
+ ret = q->dbp->open(q->dbp, txnp, queue_name, NULL, DB_QUEUE, DB_CREATE, 0664);
+ CHECK_DB_RET(ret);
- BDB_CLEANUP_DBT();
- dbkey.data = (void *)queue_name;
- dbkey.size = queue_name_size;
- dbdata.data = (void *)&temp_dbp;
- dbdata.size = sizeof(temp_dbp);
-
- ret = qlist_dbp->put(qlist_dbp, txn, &dbkey, &dbdata, 0);
- if (ret != 0){
- goto err;
- }
-
- *queue_dbp = temp_dbp;
- return 0;
+ int result = hashtable_insert(qlist_htp, (void *)k, (void *)q);
+ assert(result != 0);
+ return;
-err:
- if (temp_dbp != NULL){
- temp_dbp->close(temp_dbp, 0);
- }
- return ret;
+dberr:
+ fprintf(stderr, "open_exsited_queue_db: %s\n", db_strerror(ret));
+ exit(EXIT_FAILURE);
}
-int delete_queue_db(char *queue_name, size_t queue_name_size){
- DBT dbkey, dbdata;
- int ret;
- DB_TXN *txn = NULL;
- DB *queue_dbp = NULL;
-
- BDB_CLEANUP_DBT();
- dbkey.data = (void *)queue_name;
- dbkey.size = queue_name_size;
-
- ret = envp->txn_begin(envp, NULL, &txn, 0);
- if (ret != 0) {
- goto err;
- }
-
- ret = get_queue_db_handle(txn, queue_name, queue_name_size, &queue_dbp);
- if (ret != 0 || queue_dbp == NULL){
- goto err;
- }
-
- ret = queue_dbp->close(queue_dbp, 0);
- if (ret != 0 ){
- goto err;
- }
-
- ret = envp->dbremove(envp, txn, queue_name, NULL, 0);
- if (ret != 0){
- goto err;
- }
-
- ret = qlist_dbp->del(qlist_dbp, txn, &dbkey, 0);
- if (ret != 0){
- goto err;
- }
+/* for atexit cleanup */
+void bdb_qlist_db_close(void){
+ dump_qstats();
+
+ struct hashtable_itr *itr = NULL;
+ queue_t *q;
+ itr = hashtable_iterator(qlist_htp);
+ assert(itr != NULL);
+ if (hashtable_count(qlist_htp) > 0)
+ {
+ do {
+ q = hashtable_iterator_value(itr);
+ q->dbp->close(q->dbp, 0);
+ pthread_mutex_destroy(&(q->lock));
+ } while (hashtable_iterator_advance(itr));
+ }
+ free(itr);
+ qlist_dbp->close(qlist_dbp, 0);
+ fprintf(stderr, "qlist_dbp->close: OK\n");
+}
+
+int bdb_create_queue(char *queue_name) {
+ pthread_rwlock_wrlock(&qlist_ht_lock);
+
+ char *k = strdup(queue_name);
+ assert(k != NULL);
+ queue_t *q = (queue_t *)calloc(1, sizeof(queue_t));
+ assert(q != NULL);
+
+ q->dbp = NULL;
+ q->set_hits = q->old_set_hits = 0;
+ q->get_hits = q->old_get_hits = 0;
+ pthread_mutex_init(&(q->lock), NULL);
- ret = txn->commit(txn, 0);
- if (ret != 0) {
- goto err;
- }
- return 0;
+ int ret;
+ DB_TXN *txnp = NULL;
+ ret = db_create(&(q->dbp), envp, 0);
+ CHECK_DB_RET(ret);
-err:
- if (txn != NULL){
- txn->abort(txn);
- }
- if (settings.verbose > 1) {
- fprintf(stderr, "delete_queue_db: %s\n", db_strerror(ret));
+ if (bdb_settings.q_extentsize != 0){
+ ret = q->dbp->set_q_extentsize(q->dbp, bdb_settings.q_extentsize);
+ CHECK_DB_RET(ret);
}
- return 1;
-}
+ ret = q->dbp->set_re_len(q->dbp, bdb_settings.re_len);
+ CHECK_DB_RET(ret);
+ ret = q->dbp->set_pagesize(q->dbp, bdb_settings.page_size);
+ CHECK_DB_RET(ret);
-static int get_queue_db_handle(DB_TXN *txn, char *queue_name, size_t queue_name_size, DB **queue_dbp){
- DBT dbkey, dbdata;
- int ret;
- DB *temp_dbp = NULL;
+ ret = envp->txn_begin(envp, NULL, &txnp, 0);
+ ret = q->dbp->open(q->dbp, txnp, queue_name, NULL, DB_QUEUE, DB_CREATE, 0664);
+ CHECK_DB_RET(ret);
+ DBT dbkey,dbdata;
+ qstats_t qs;
+ memset(&qs, 0, sizeof(qs));
BDB_CLEANUP_DBT();
dbkey.data = (void *)queue_name;
- dbkey.size = queue_name_size;
- dbdata.data = (void *)&temp_dbp;
- dbdata.ulen = sizeof(temp_dbp);
- dbdata.flags = DB_DBT_USERMEM;
-
- ret = qlist_dbp->get(qlist_dbp, txn, &dbkey, &dbdata, 0);
- if (ret == 0){
- *queue_dbp = temp_dbp;
- } else if (ret == DB_NOTFOUND){
- *queue_dbp = NULL;
- } else {
- return ret;
- }
-
+ dbkey.size = strlen(queue_name)+1;
+ dbdata.data = (void *)&qs;
+ dbdata.size = sizeof(qstats_t);
+ CHECK_DB_RET(ret);
+ ret = qlist_dbp->put(qlist_dbp, txnp, &dbkey, &dbdata, 0);
+ CHECK_DB_RET(ret);
+ ret = txnp->commit(txnp, 0);
+ CHECK_DB_RET(ret);
+ int result = hashtable_insert(qlist_htp, (void *)k, (void *)q);
+ assert(result != 0);
+ pthread_rwlock_unlock(&qlist_ht_lock);
return 0;
+dberr:
+ if (txnp != NULL){
+ txnp->abort(txnp);
+ }
+ fprintf(stderr, "bdb_create_queue: %s %s\n", queue_name, db_strerror(ret));
+ pthread_rwlock_unlock(&qlist_ht_lock);
+ return -1;
}
-int print_queue_db_list(char *buf, size_t buf_size){
- DBT dbkey, dbdata;
- int ret, res;
- DB_TXN *txn = NULL;
- DBC *cursorp = NULL;
- char queue_name[512];
- DB *queue_db = NULL;
- int remains = buf_size - 5;
-
- memset(queue_name, 0, 512);
- BDB_CLEANUP_DBT();
- dbkey.data = (void *)queue_name;
- dbkey.ulen = 512;
- dbkey.flags = DB_DBT_USERMEM;
- dbdata.data = (void *)&queue_db;
- dbdata.ulen = sizeof(queue_db);
- dbdata.flags = DB_DBT_USERMEM;
-
- ret = envp->txn_begin(envp, NULL, &txn, 0);
- if (ret != 0) {
- goto err;
- }
-
- /* Get a cursor */
- ret = qlist_dbp->cursor(qlist_dbp, txn, &cursorp, 0);
- if (ret != 0){
- goto err;
- }
-
- /* Iterate over the database, retrieving each record in turn. */
- while ((ret = cursorp->get(cursorp, &dbkey, &dbdata, DB_NEXT)) == 0) {
- queue_name[dbkey.size] = '\0';
- if (remains > strlen(queue_name) + 8){
- res = sprintf(buf, "STAT %s\r\n", queue_name);
- remains -= res;
- buf += res;
- } else {
- break;
- }
- }
- if (!(ret == DB_NOTFOUND || ret == 0)) {
- goto err;
- }
+int bdb_delete_queue(char *queue_name){
+ pthread_rwlock_wrlock(&qlist_ht_lock);
+ queue_t *q = hashtable_search(qlist_htp, (void *)queue_name);
+ /* NOT FOUND */
+ if (q == NULL) {
+ pthread_rwlock_unlock(&qlist_ht_lock);
+ return 1;
+ }
+ /* Found, just close and remove it. */
+ q->dbp->close(q->dbp, 0);
+ pthread_mutex_destroy(&(q->lock));
+ q = hashtable_remove(qlist_htp, (void *)queue_name);
+ assert(NULL != q);
+ free(q);
- if (cursorp != NULL){
- cursorp->close(cursorp);
- }
-
- ret = txn->commit(txn, 0);
- if (ret != 0) {
- goto err;
- }
- sprintf(buf, "END");
+ int ret;
+ DB_TXN *txnp = NULL;
+ ret = envp->txn_begin(envp, NULL, &txnp, 0);
+ CHECK_DB_RET(ret);
+ ret = envp->dbremove(envp, txnp, queue_name, NULL, 0);
+ CHECK_DB_RET(ret);
+ ret = txnp->commit(txnp, 0);
+ CHECK_DB_RET(ret);
+ pthread_rwlock_unlock(&qlist_ht_lock);
return 0;
-
-err:
- if (cursorp != NULL){
- cursorp->close(cursorp);
- }
- if (txn != NULL){
- txn->abort(txn);
- }
- if (settings.verbose > 1) {
- fprintf(stderr, "print_queue_db_list: %s\n", db_strerror(ret));
+dberr:
+ if (txnp != NULL){
+ txnp->abort(txnp);
}
+ fprintf(stderr, "bdb_delete_queue: %s %s\n", queue_name, db_strerror(ret));
+ pthread_rwlock_unlock(&qlist_ht_lock);
return -1;
}
-static void close_queue_db_list(void){
+static void dump_qstats(void) {
+ struct hashtable_itr *itr = NULL;
+
+ /* qstats hashtable */
+ char *kk;
+ qstats_t *s;
+ struct hashtable *qstats_htp = NULL;
+ qstats_htp = create_hashtable(64, hashfromkey, equalkeys);
+ assert(qstats_htp != NULL);
+
+ /* cp hashtable to stats table, this is very fast in-memory */
+ pthread_rwlock_rdlock(&qlist_ht_lock);
+ char *k;
+ queue_t *q;
+ itr = hashtable_iterator(qlist_htp);
+ assert(itr != NULL);
+ if (hashtable_count(qlist_htp) > 0)
+ {
+ do {
+ k = hashtable_iterator_key(itr);
+ q = hashtable_iterator_value(itr);
+ pthread_mutex_lock(&(q->lock));
+ if (q->old_set_hits == q->set_hits &&
+ q->old_get_hits == q->get_hits) {
+ pthread_mutex_unlock(&(q->lock));
+ continue;
+ }
+ q->old_set_hits = q->set_hits;
+ q->old_get_hits = q->get_hits;
+ pthread_mutex_unlock(&(q->lock));
+ kk = strdup(k);
+ assert(kk);
+ s = calloc(1, sizeof(qstats_t));
+ assert(s);
+ s->set_hits = q->old_set_hits;
+ s->get_hits = q->old_get_hits;
+ hashtable_insert(qstats_htp, (void *)kk, (void *)s);
+ } while (hashtable_iterator_advance(itr));
+ }
+ free(itr);
+ itr = NULL;
+ pthread_rwlock_unlock(&qlist_ht_lock);
+
+ /* dump stats hashtable to db */
DBT dbkey, dbdata;
int ret;
- DB_TXN *txn = NULL;
- DBC *cursorp = NULL;
- char queue_name[512];
- DB *queue_dbp = NULL;
-
- memset(queue_name, 0, 512);
- BDB_CLEANUP_DBT();
- dbkey.data = (void *)queue_name;
- dbkey.ulen = 512;
- dbkey.flags = DB_DBT_USERMEM;
- dbdata.data = (void *)&queue_dbp;
- dbdata.ulen = sizeof(queue_dbp);
- dbdata.flags = DB_DBT_USERMEM;
-
- ret = envp->txn_begin(envp, NULL, &txn, 0);
- if (ret != 0) {
- goto err;
- }
-
- /* Get a cursor */
- ret = qlist_dbp->cursor(qlist_dbp, txn, &cursorp, 0);
- if (ret != 0){
- goto err;
- }
-
- /* Iterate over the database, retrieving each record in turn. */
- while ((ret = cursorp->get(cursorp, &dbkey, &dbdata, DB_NEXT)) == 0) {
- ret = queue_dbp->close(queue_dbp, 0);
- if (settings.verbose > 1) {
- fprintf(stderr, "close_queue_db_list: %s %s\n", queue_name, db_strerror(ret));
- }
- }
- if (ret != DB_NOTFOUND) {
- goto err;
- }
-
- if (cursorp != NULL){
- cursorp->close(cursorp);
- }
-
- ret = txn->commit(txn, 0);
- if (ret != 0) {
- goto err;
- }
+ DB_TXN *txnp = NULL;
+ ret = envp->txn_begin(envp, NULL, &txnp, 0);
+ CHECK_DB_RET(ret);
+ itr = hashtable_iterator(qstats_htp);
+ assert(itr != NULL);
+ if (hashtable_count(qstats_htp) > 0)
+ {
+ do {
+ kk = hashtable_iterator_key(itr);
+ s = hashtable_iterator_value(itr);
+ dbkey.data = kk;
+ dbkey.size = strlen(kk) + 1;
+ dbdata.data = s;
+ dbdata.size = sizeof(qstats_t);
+ ret = qlist_dbp->put(qlist_dbp, txnp, &dbkey, &dbdata, 0);
+ CHECK_DB_RET(ret);
+ fprintf(stderr, "dump stats[%s], set_hits: %lld, get_hits: %lld \n",
+ kk, s->set_hits, s->get_hits);
+ } while (hashtable_iterator_advance(itr));
+ }
+ free(itr);
+ itr = NULL;
+ ret = txnp->commit(txnp, 0);
+ CHECK_DB_RET(ret);
+
+ hashtable_destroy(qstats_htp, 1);
+ qstats_htp = NULL;
return;
-
-err:
- if (cursorp != NULL){
- cursorp->close(cursorp);
- }
- if (txn != NULL){
- txn->abort(txn);
+dberr:
+ if (txnp != NULL){
+ txnp->abort(txnp);
}
if (settings.verbose > 1) {
- fprintf(stderr, "close_queue_db_list: %s\n", db_strerror(ret));
+ fprintf(stderr, "dump_qstats: %s\n", db_strerror(ret));
}
- return;
}
+
/* if return item is not NULL, free by caller */
-item *bdb_get(char *key, size_t nkey){
+item *bdb_get(char *key){
+ pthread_rwlock_rdlock(&qlist_ht_lock);
item *it = NULL;
- DBT dbkey, dbdata;
- DB_TXN *txn = NULL;
- DB *queue_dbp = NULL;
- db_recno_t recno;
+ DB_TXN *txnp = NULL;
int ret;
- /* first, alloc a fixed size */
- it = item_alloc2();
- if (it == 0) {
+ queue_t *q = (queue_t *)hashtable_search(qlist_htp, (void *)key);
+ /* queue not exsited */
+ if (q == NULL) {
+ pthread_rwlock_unlock(&qlist_ht_lock);
return NULL;
- }
+ } else {
+ DBT dbkey, dbdata;
+ db_recno_t recno;
+
+ /* first, alloc a fixed size */
+ it = item_alloc2();
+ if (it == 0) {
+ pthread_rwlock_unlock(&qlist_ht_lock);
+ return NULL;
+ }
- BDB_CLEANUP_DBT();
- dbkey.data = &recno;
- dbkey.ulen = sizeof(recno);
- dbkey.flags = DB_DBT_USERMEM;
- dbdata.ulen = bdb_settings.re_len;
- dbdata.data = it;
- dbdata.flags = DB_DBT_USERMEM;
-
- ret = envp->txn_begin(envp, NULL, &txn, 0);
- if (ret != 0) {
- goto err;
- }
-
- ret = get_queue_db_handle(txn, key, nkey, &queue_dbp);
- if (ret != 0 || queue_dbp == NULL){
- goto err;
- }
-
- ret = queue_dbp->get(queue_dbp, txn, &dbkey, &dbdata, DB_CONSUME);
- if (ret != 0){
- goto err;
- }
-
- ret = txn->commit(txn, 0);
- if (ret != 0) {
- goto err;
- }
+ BDB_CLEANUP_DBT();
+ dbkey.data = &recno;
+ dbkey.ulen = sizeof(recno);
+ dbkey.flags = DB_DBT_USERMEM;
+ dbdata.ulen = bdb_settings.re_len;
+ dbdata.data = it;
+ dbdata.flags = DB_DBT_USERMEM;
+
+ ret = envp->txn_begin(envp, NULL, &txnp, 0);
+ CHECK_DB_RET(ret);
+ ret = q->dbp->get(q->dbp, txnp, &dbkey, &dbdata, DB_CONSUME);
+ CHECK_DB_RET(ret);
+ ret = txnp->commit(txnp, 0);
+ CHECK_DB_RET(ret);
+ }
+ pthread_rwlock_unlock(&qlist_ht_lock);
return it;
-err:
+dberr:
item_free(it);
it = NULL;
- if (txn != NULL){
- txn->abort(txn);
+ if (txnp != NULL){
+ txnp->abort(txnp);
}
if (settings.verbose > 1) {
fprintf(stderr, "bdb_get: %s\n", db_strerror(ret));
}
+ pthread_rwlock_unlock(&qlist_ht_lock);
return NULL;
}
/* 0 for Success
-1 for SERVER_ERROR
*/
-int bdb_put(char *key, size_t nkey, item *it){
+int bdb_set(char *key, item *it){
+ pthread_rwlock_rdlock(&qlist_ht_lock);
+ queue_t *q = (queue_t *)hashtable_search(qlist_htp, (void *)key);
+ DB_TXN *txnp = NULL;
int ret;
- DBT dbkey, dbdata;
- DB_TXN *txn = NULL;
- DB *queue_dbp = NULL;
- db_recno_t recno;
- BDB_CLEANUP_DBT();
- dbkey.data = &recno;
- dbkey.ulen = sizeof(recno);
- dbkey.flags = DB_DBT_USERMEM;
- dbdata.data = it;
- dbdata.size = ITEM_ntotal(it);
-
- ret = envp->txn_begin(envp, NULL, &txn, 0);
- if (ret != 0) {
- goto err;
- }
-
- ret = get_queue_db_handle(txn, key, nkey, &queue_dbp);
- if (ret != 0){
- goto err;
- }
-
- if (queue_dbp == NULL) {
- ret = create_queue_db(txn, key, nkey, &queue_dbp);
- if (ret != 0){
- goto err;
+ if (NULL == q) {
+ pthread_rwlock_unlock(&qlist_ht_lock);
+ ret = bdb_create_queue(key);
+ if (0 != ret){
+ return -1;
}
- }
-
- ret = queue_dbp->put(queue_dbp, txn, &dbkey, &dbdata, DB_APPEND);
- if (ret != 0) {
- goto err;
- }
-
- ret = txn->commit(txn, 0);
- if (ret != 0) {
- goto err;
- }
-
+ /* search again */
+ pthread_rwlock_rdlock(&qlist_ht_lock);
+ q = (queue_t *)hashtable_search(qlist_htp, (void *)key);
+ }
+
+ if (NULL != q) {
+ db_recno_t recno;
+ DBT dbkey, dbdata;
+ BDB_CLEANUP_DBT();
+ dbkey.data = &recno;
+ dbkey.ulen = sizeof(recno);
+ dbkey.flags = DB_DBT_USERMEM;
+ dbdata.data = it;
+ dbdata.size = ITEM_ntotal(it);
+ ret = envp->txn_begin(envp, NULL, &txnp, 0);
+ CHECK_DB_RET(ret);
+ ret = q->dbp->put(q->dbp, txnp, &dbkey, &dbdata, DB_APPEND);
+ CHECK_DB_RET(ret);
+ ret = txnp->commit(txnp, 0);
+ CHECK_DB_RET(ret);
+ }
+ pthread_rwlock_unlock(&qlist_ht_lock);
return 0;
-err:
- if (txn != NULL){
- txn->abort(txn);
+dberr:
+ if (txnp != NULL){
+ txnp->abort(txnp);
}
if (settings.verbose > 1) {
- fprintf(stderr, "bdb_put: %s\n", db_strerror(ret));
+ fprintf(stderr, "bdb_set: %s\n", db_strerror(ret));
}
+ pthread_rwlock_unlock(&qlist_ht_lock);
return -1;
}
-void start_chkpoint_thread(void){
- if (bdb_settings.chkpoint_val > 0){
+void start_checkpoint_thread(void){
+ pthread_t tid;
+ if (bdb_settings.checkpoint_val > 0){
/* Start a checkpoint thread. */
if ((errno = pthread_create(
- &chk_ptid, NULL, bdb_chkpoint_thread, (void *)envp)) != 0) {
+ &tid, NULL, bdb_checkpoint_thread, (void *)envp)) != 0) {
fprintf(stderr,
"failed spawning checkpoint thread: %s\n",
strerror(errno));
@@ -699,11 +554,12 @@ void start_chkpoint_thread(void){
}
}
-void start_memp_trickle_thread(void){
- if (bdb_settings.memp_trickle_val > 0){
+void start_mempool_trickle_thread(void){
+ pthread_t tid;
+ if (bdb_settings.mempool_trickle_val > 0){
/* Start a memp_trickle thread. */
if ((errno = pthread_create(
- &mtri_ptid, NULL, bdb_memp_trickle_thread, (void *)envp)) != 0) {
+ &tid, NULL, bdb_mempool_trickle_thread, (void *)envp)) != 0) {
fprintf(stderr,
"failed spawning memp_trickle thread: %s\n",
strerror(errno));
@@ -712,11 +568,12 @@ void start_memp_trickle_thread(void){
}
}
-void start_dl_detect_thread(void){
- if (bdb_settings.dldetect_val > 0){
+void start_deadlock_detect_thread(void){
+ pthread_t tid;
+ if (bdb_settings.deadlock_detect_val > 0){
/* Start a deadlock detecting thread. */
if ((errno = pthread_create(
- &dld_ptid, NULL, bdb_dl_detect_thread, (void *)envp)) != 0) {
+ &tid, NULL, bdb_deadlock_detect_thread, (void *)envp)) != 0) {
fprintf(stderr,
"failed spawning deadlock thread: %s\n",
strerror(errno));
@@ -724,17 +581,26 @@ void start_dl_detect_thread(void){
}
}
}
+/* TODO: */
+void start_qstats_dump_thread(void){
+ pthread_t tid;
+ if (bdb_settings.qstats_dump_val > 0){
+ /* Start a queue stats dump thread. */
+ if ((errno = pthread_create(
+ &tid, NULL, bdb_qstats_dump_thread, (void *)envp)) != 0) {
+ fprintf(stderr,
+ "failed spawning qstats dump thread: %s\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+}
-static void *bdb_chkpoint_thread(void *arg)
-{
+static void *bdb_checkpoint_thread(void *arg){
DB_ENV *dbenv;
int ret;
dbenv = arg;
- if (settings.verbose > 1) {
- dbenv->errx(dbenv, "checkpoint thread created: %lu, every %d seconds",
- (u_long)pthread_self(), bdb_settings.chkpoint_val);
- }
- for (;; sleep(bdb_settings.chkpoint_val)) {
+ for (;; sleep(bdb_settings.checkpoint_val)) {
if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) {
dbenv->err(dbenv, ret, "checkpoint thread");
}
@@ -743,37 +609,26 @@ static void *bdb_chkpoint_thread(void *arg)
return (NULL);
}
-static void *bdb_memp_trickle_thread(void *arg)
-{
+static void *bdb_mempool_trickle_thread(void *arg){
DB_ENV *dbenv;
int ret, nwrotep;
dbenv = arg;
- if (settings.verbose > 1) {
- dbenv->errx(dbenv, "memp_trickle thread created: %lu, every %d seconds, %d%% pages should be clean.",
- (u_long)pthread_self(), bdb_settings.memp_trickle_val,
- bdb_settings.memp_trickle_percent);
- }
- for (;; sleep(bdb_settings.memp_trickle_val)) {
- if ((ret = dbenv->memp_trickle(dbenv, bdb_settings.memp_trickle_percent, &nwrotep)) != 0) {
- dbenv->err(dbenv, ret, "memp_trickle thread");
+ for (;; sleep(bdb_settings.mempool_trickle_val)) {
+ if ((ret = dbenv->memp_trickle(dbenv, bdb_settings.mempool_trickle_percent, &nwrotep)) != 0) {
+ dbenv->err(dbenv, ret, "mempool_trickle thread");
}
- dbenv->errx(dbenv, "memp_trickle thread: writing %d dirty pages", nwrotep);
+ dbenv->errx(dbenv, "mempool_trickle thread: writing %d dirty pages", nwrotep);
}
return (NULL);
}
-static void *bdb_dl_detect_thread(void *arg)
-{
+static void *bdb_deadlock_detect_thread(void *arg){
DB_ENV *dbenv;
struct timeval t;
dbenv = arg;
- if (settings.verbose > 1) {
- dbenv->errx(dbenv, "deadlock detecting thread created: %lu, every %d millisecond",
- (u_long)pthread_self(), bdb_settings.dldetect_val);
- }
while (!daemon_quit) {
t.tv_sec = 0;
- t.tv_usec = bdb_settings.dldetect_val;
+ t.tv_usec = bdb_settings.deadlock_detect_val;
(void)dbenv->lock_detect(dbenv, 0, DB_LOCK_YOUNGEST, NULL);
/* select is a more accurate sleep timer */
(void)select(0, NULL, NULL, NULL, &t);
@@ -781,18 +636,15 @@ static void *bdb_dl_detect_thread(void *arg)
return (NULL);
}
-static void bdb_event_callback(DB_ENV *env, u_int32_t which, void *info)
-{
- switch (which) {
- case DB_EVENT_PANIC:
- env->errx(env, "evnet: DB_EVENT_PANIC, we got panic, recovery should be run.");
- break;
- case DB_EVENT_WRITE_FAILED:
- env->errx(env, "event: DB_EVENT_WRITE_FAILED, I wrote to stable storage failed.");
- break;
- default:
- env->errx(env, "ignoring event %d", which);
+static void *bdb_qstats_dump_thread(void *arg){
+ DB_ENV *dbenv;
+ int ret;
+ dbenv = arg;
+ for (;; sleep(bdb_settings.qstats_dump_val)) {
+ dump_qstats();
+ dbenv->errx(dbenv, "qstats dump thread: a qstats is dump.");
}
+ return (NULL);
}
static void bdb_err_callback(const DB_ENV *dbenv, const char *errpfx, const char *msg){
@@ -810,8 +662,7 @@ static void bdb_msg_callback(const DB_ENV *dbenv, const char *msg){
}
/* for atexit cleanup */
-void bdb_chkpoint(void)
-{
+void bdb_chkpoint(void){
int ret = 0;
if (envp != NULL){
ret = envp->txn_checkpoint(envp, 0, 0, 0);
@@ -823,33 +674,4 @@ void bdb_chkpoint(void)
}
}
-/* for atexit cleanup */
-void bdb_db_close(void){
- int ret = 0;
-
- /* close the queue list db */
- if (qlist_dbp != NULL) {
- close_queue_db_list();
- ret = qlist_dbp->close(qlist_dbp, 0);
- if (0 != ret){
- fprintf(stderr, "qlist_dbp->close: %s\n", db_strerror(ret));
- }else{
- qlist_dbp = NULL;
- fprintf(stderr, "qlist_dbp->close: OK\n");
- }
- }
-}
-/* for atexit cleanup */
-void bdb_env_close(void){
- int ret = 0;
- if (envp != NULL) {
- ret = envp->close(envp, 0);
- if (0 != ret){
- fprintf(stderr, "envp->close: %s\n", db_strerror(ret));
- }else{
- envp = NULL;
- fprintf(stderr, "envp->close: OK\n");
- }
- }
-}
View
26 configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for memcacheq 0.1.1.
+# Generated by GNU Autoconf 2.61 for memcacheq 0.2.0.
#
# Report bugs to <stvchu@gmail.com>.
#
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='memcacheq'
PACKAGE_TARNAME='memcacheq'
-PACKAGE_VERSION='0.1.1'
-PACKAGE_STRING='memcacheq 0.1.1'
+PACKAGE_VERSION='0.2.0'
+PACKAGE_STRING='memcacheq 0.2.0'
PACKAGE_BUGREPORT='stvchu@gmail.com'
# Factoring default headers for most tests.
@@ -1206,7 +1206,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures memcacheq 0.1.1 to adapt to many kinds of systems.
+\`configure' configures memcacheq 0.2.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1272,7 +1272,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of memcacheq 0.1.1:";;
+ short | recursive ) echo "Configuration of memcacheq 0.2.0:";;
esac
cat <<\_ACEOF
@@ -1363,7 +1363,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-memcacheq configure 0.1.1
+memcacheq configure 0.2.0
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1377,7 +1377,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by memcacheq $as_me 0.1.1, which was
+It was created by memcacheq $as_me 0.2.0, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
@@ -2067,7 +2067,7 @@ fi
# Define the identity of the package.
PACKAGE='memcacheq'
- VERSION='0.1.1'
+ VERSION='0.2.0'
cat >>confdefs.h <<_ACEOF
@@ -3398,7 +3398,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
else
eval ac_cv_prog_cc_${ac_cc}_c_o=no
fi
-rm -f core conftest*
+rm -f -r core conftest*
fi
if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
@@ -4130,7 +4130,7 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
else
ac_cv_header_stdc=no
fi
-rm -f conftest*
+rm -f -r conftest*
fi
@@ -4151,7 +4151,7 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
else
ac_cv_header_stdc=no
fi
-rm -f conftest*
+rm -f -r conftest*
fi
@@ -5928,7 +5928,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by memcacheq $as_me 0.1.1, which was
+This file was extended by memcacheq $as_me 0.2.0, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -5981,7 +5981,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-memcacheq config.status 0.1.1
+memcacheq config.status 0.2.0
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
View
2  configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.61)
-AC_INIT([memcacheq], [0.1.1], [stvchu@gmail.com])
+AC_INIT([memcacheq], [0.2.0], [stvchu@gmail.com])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AM_PROG_CC_C_O
View
89 daemon.c
@@ -0,0 +1,89 @@
+/* $Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $ */
+/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined __SUNPRO_C || defined __DECC || defined __HP_cc
+# pragma ident "@(#)$Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $"
+# pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $"
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "memcacheq.h"
+
+int daemonize(int nochdir, int noclose)
+{
+ int fd;
+
+ switch (fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ _exit(EXIT_SUCCESS);
+ }
+
+ if (setsid() == -1)
+ return (-1);
+
+ if (nochdir == 0) {
+ if(chdir("/") != 0) {
+ perror("chdir");
+ return (-1);
+ }
+ }
+
+ if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
+ if(dup2(fd, STDIN_FILENO) < 0) {
+ perror("dup2 stdin");
+ return (-1);
+ }
+ if(dup2(fd, STDOUT_FILENO) < 0) {
+ perror("dup2 stdout");
+ return (-1);
+ }
+ if(dup2(fd, STDERR_FILENO) < 0) {
+ perror("dup2 stderr");
+ return (-1);
+ }
+
+ if (fd > STDERR_FILENO) {
+ if(close(fd) < 0) {
+ perror("close");
+ return (-1);
+ }
+ }
+ }
+ return (0);
+}
View
67 hash.c
@@ -0,0 +1,67 @@
+/*-----------------------------------------------------------------------------
+ * MurmurHash2, by Austin Appleby
+ *
+ * Note - This code makes a few assumptions about how your machine behaves -
+ *
+ * 1. We can read a 4-byte value from any address without crashing
+ * 2. sizeof(int) == 4
+ *
+ * And it has a few limitations -
+ *
+ * 1. It will not work incrementally.
+ * 2. It will not produce the same results on little-endian and big-endian
+ * machines.
+ */
+
+unsigned int murmurhash2 ( const void * key, int len, unsigned int seed )
+{
+ /* 'm' and 'r' are mixing constants generated offline.
+ * They're not really 'magic', they just happen to work well.
+ */
+
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ /* Initialize the hash to a 'random' value */
+
+ unsigned int h = seed ^ len;
+
+ /* Mix 4 bytes at a time into the hash */
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ while(len >= 4)
+ {
+ unsigned int k = *(unsigned int *)data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ /* Handle the last few bytes of the input array */
+
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ /* Do a few final mixes of the hash to ensure the last few
+ * bytes are well-incorporated.
+ */
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
View
26 hash.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * MemcacheQ - Simple Queue Service over Memcache
+ *
+ * http://memcacheq.googlecode.com
+ *
+ * The source code of MemcacheQ is most based on MemcachDB:
+ *
+ * http://memcachedb.googlecode.com
+ *
+ * Copyright 2008 Steve Chu. All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the LICENSE file for full text.
+ *
+ * Authors:
+ * Steve Chu <stvchu@gmail.com>
+ *
+ */
+
+#ifndef QLIST_H__
+#define QLIST_H__
+
+unsigned int murmurhash2( const void * key, int len, unsigned int seed );
+
+#endif /* QLIST_H__ */
View
422 hashtable.c
@@ -0,0 +1,422 @@
+/* Copyright (C) 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#include "hashtable.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+Credit for primes table: Aaron Krowne
+ http://br.endernet.org/~akrowne/
+ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+53, 97, 193, 389,
+769, 1543, 3079, 6151,
+12289, 24593, 49157, 98317,
+196613, 393241, 786433, 1572869,
+3145739, 6291469, 12582917, 25165843,
+50331653, 100663319, 201326611, 402653189,
+805306457, 1610612741
+};
+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
+const float max_load_factor = 0.65;
+
+/*****************************************************************************/
+struct hashtable *
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashf) (void*),
+ int (*eqf) (void*,void*))
+{
+ struct hashtable *h;
+ unsigned int pindex, size = primes[0];
+ /* Check requested hashtable isn't too large */
+ if (minsize > (1u << 30)) return NULL;
+ /* Enforce size as prime */
+ for (pindex=0; pindex < prime_table_length; pindex++) {
+ if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+ }
+ h = (struct hashtable *)malloc(sizeof(struct hashtable));
+ if (NULL == h) return NULL; /*oom*/
+ h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
+ if (NULL == h->table) { free(h); return NULL; } /*oom*/
+ memset(h->table, 0, size * sizeof(struct entry *));
+ h->tablelength = size;
+ h->primeindex = pindex;
+ h->entrycount = 0;
+ h->hashfn = hashf;
+ h->eqfn = eqf;
+ h->loadlimit = (unsigned int) ceil(size * max_load_factor);
+ return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+ /* Aim to protect against poor hash functions by adding logic here
+ * - logic taken from java 1.4 hashtable source */
+ unsigned int i = h->hashfn(k);
+ i += ~(i << 9);
+ i ^= ((i >> 14) | (i << 18)); /* >>> */
+ i += (i << 4);
+ i ^= ((i >> 10) | (i << 22)); /* >>> */
+ return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+ /* Double the size of the table to accomodate more entries */
+ struct entry **newtable;
+ struct entry *e;
+ struct entry **pE;
+ unsigned int newsize, i, index;
+ /* Check we're not hitting max capacity */
+ if (h->primeindex == (prime_table_length - 1)) return 0;
+ newsize = primes[++(h->primeindex)];
+
+ newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
+ if (NULL != newtable)
+ {
+ memset(newtable, 0, newsize * sizeof(struct entry *));
+ /* This algorithm is not 'stable'. ie. it reverses the list
+ * when it transfers entries between the tables */
+ for (i = 0; i < h->tablelength; i++) {
+ while (NULL != (e = h->table[i])) {
+ h->table[i] = e->next;
+ index = indexFor(newsize,e->h);
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ free(h->table);
+ h->table = newtable;
+ }
+ /* Plan B: realloc instead */
+ else
+ {
+ newtable = (struct entry **)
+ realloc(h->table, newsize * sizeof(struct entry *));
+ if (NULL == newtable) { (h->primeindex)--; return 0; }
+ h->table = newtable;
+ memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+ for (i = 0; i < h->tablelength; i++) {
+ for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+ index = indexFor(newsize,e->h);
+ if (index == i)
+ {
+ pE = &(e->next);
+ }
+ else
+ {
+ *pE = e->next;
+ e->next = newtable[index];
+ newtable[index] = e;
+ }
+ }
+ }
+ }
+ h->tablelength = newsize;
+ h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
+ return -1;
+}
+
+/*****************************************************************************/
+unsigned int
+hashtable_count(struct hashtable *h)
+{
+ return h->entrycount;
+}
+
+/*****************************************************************************/
+int
+hashtable_insert(struct hashtable *h, void *k, void *v)
+{
+ /* This method allows duplicate keys - but they shouldn't be used */
+ unsigned int index;
+ struct entry *e;
+ if (++(h->entrycount) > h->loadlimit)
+ {
+ /* Ignore the return value. If expand fails, we should
+ * still try cramming just this value into the existing table
+ * -- we may not have memory for a larger table, but one more
+ * element may be ok. Next time we insert, we'll try expanding again.*/
+ hashtable_expand(h);
+ }
+ e = (struct entry *)malloc(sizeof(struct entry));
+ if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+ e->h = hash(h,k);
+ index = indexFor(h->tablelength,e->h);
+ e->k = k;
+ e->v = v;
+ e->next = h->table[index];
+ h->table[index] = e;
+ return -1;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+ struct entry *e;
+ unsigned int hashvalue, index;
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+ e = h->table[index];
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+ /* TODO: consider compacting the table when the load factor drops enough,
+ * or provide a 'compact' method. */
+
+ struct entry *e;
+ struct entry **pE;
+ void *v;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hash(h,k));
+ pE = &(h->table[index]);
+ e = *pE;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ *pE = e->next;
+ h->entrycount--;
+ v = e->v;
+ freekey(e->k);
+ free(e);
+ return v;
+ }
+ pE = &(e->next);
+ e = e->next;
+ }
+ return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+void
+hashtable_destroy(struct hashtable *h, int free_values)
+{
+ unsigned int i;
+ struct entry *e, *f;
+ struct entry **table = h->table;
+ if (free_values)
+ {
+ for (i = 0; i < h->tablelength; i++)
+ {
+ e = table[i];
+ while (NULL != e)
+ { f = e; e = e->next; freekey(f->k); free(f->v); free(f); }
+ }
+ }
+ else
+ {
+ for (i = 0; i < h->tablelength; i++)
+ {
+ e = table[i];
+ while (NULL != e)
+ { f = e; e = e->next; freekey(f->k); free(f); }
+ }
+ }
+ free(h->table);
+ free(h);
+}
+
+/*****************************************************************************/
+/* hashtable_iterator - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+ unsigned int i, tablelength;
+ struct hashtable_itr *itr = (struct hashtable_itr *)
+ malloc(sizeof(struct hashtable_itr));
+ if (NULL == itr) return NULL;
+ itr->h = h;
+ itr->e = NULL;
+ itr->parent = NULL;
+ tablelength = h->tablelength;
+ itr->index = tablelength;
+ if (0 == h->entrycount) return itr;
+
+ for (i = 0; i < tablelength; i++)
+ {
+ if (NULL != h->table[i])
+ {
+ itr->e = h->table[i];
+ itr->index = i;
+ break;
+ }
+ }
+ return itr;
+}
+
+/*****************************************************************************/
+/* key - return the key of the (key,value) pair at the current position */
+/* value - return the value of the (key,value) pair at the current position */
+
+void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{ return i->e->k; }
+
+void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{ return i->e->v; }
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+ unsigned int j,tablelength;
+ struct entry **table;
+ struct entry *next;
+ if (NULL == itr->e) return 0; /* stupidity check */
+
+ next = itr->e->next;
+ if (NULL != next)
+ {
+ itr->parent = itr->e;
+ itr->e = next;
+ return -1;
+ }
+ tablelength = itr->h->tablelength;
+ itr->parent = NULL;
+ if (tablelength <= (j = ++(itr->index)))
+ {
+ itr->e = NULL;
+ return 0;
+ }
+ table = itr->h->table;
+ while (NULL == (next = table[j]))
+ {
+ if (++j >= tablelength)
+ {
+ itr->index = tablelength;
+ itr->e = NULL;
+ return 0;
+ }
+ }
+ itr->index = j;
+ itr->e = next;
+ return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ * and advance the iterator, if there is a successive
+ * element.
+ * If you want the value, read it before you remove:
+ * beware memory leaks if you don't.
+ * Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+ struct entry *remember_e, *remember_parent;
+ int ret;
+
+ /* Do the removal */
+ if (NULL == (itr->parent))
+ {
+ /* element is head of a chain */
+ itr->h->table[itr->index] = itr->e->next;
+ } else {
+ /* element is mid-chain */
+ itr->parent->next = itr->e->next;
+ }
+ /* itr->e is now outside the hashtable */
+ remember_e = itr->e;
+ itr->h->entrycount--;
+ freekey(remember_e->k);
+
+ /* Advance the iterator, correcting the parent */
+ remember_parent = itr->parent;
+ ret = hashtable_iterator_advance(itr);
+ if (itr->parent == remember_e) { itr->parent = remember_parent; }
+ free(remember_e);
+ return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k)
+{
+ struct entry *e, *parent;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h,k);
+ index = indexFor(h->tablelength,hashvalue);
+
+ e = h->table[index];
+ parent = NULL;
+ while (NULL != e)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ {
+ itr->index = index;
+ itr->e = e;
+ itr->parent = parent;
+ itr->h = h;
+ return -1;
+ }
+ parent = e;
+ e = e->next;
+ }
+ return 0;
+}
+
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
View
274 hashtable.h
@@ -0,0 +1,274 @@
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+
+/*****************************************************************************/
+struct entry
+{
+ void *k, *v;
+ unsigned int h;
+ struct entry *next;
+};
+
+struct hashtable {
+ unsigned int tablelength;
+ struct entry **table;
+ unsigned int entrycount;
+ unsigned int loadlimit;
+ unsigned int primeindex;
+ unsigned int (*hashfn) (void *k);
+ int (*eqfn) (void *k1, void *k2);
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static inline unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+ return (hashvalue % tablelength);
+};
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+
+/*****************************************************************************/
+
+/* Example of use:
+ *
+ * struct hashtable *h;
+ * struct some_key *k;
+ * struct some_value *v;
+ *
+ * static unsigned int hash_from_key_fn( void *k );
+ * static int keys_equal_fn ( void *key1, void *key2 );
+ *
+ * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ * k = (struct some_key *) malloc(sizeof(struct some_key));
+ * v = (struct some_value *) malloc(sizeof(struct some_value));
+ *
+ * (initialise k and v to suitable values)
+ *
+ * if (! hashtable_insert(h,k,v) )
+ * { exit(-1); }
+ *
+ * if (NULL == (found = hashtable_search(h,k) ))
+ * { printf("not found!"); }
+ *
+ * if (NULL == (found = hashtable_remove(h,k) ))
+ * { printf("Not found\n"); }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ *
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+
+ * @name create_hashtable
+ * @param minsize minimum initial size of hashtable
+ * @param hashfunction function for hashing keys
+ * @param key_eq_fn function for determining key equality
+ * @return newly created hashtable or NULL on failure
+ */
+
+struct hashtable *
+create_hashtable(unsigned int minsize,
+ unsigned int (*hashfunction) (void*),
+ int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+
+ * @name hashtable_insert
+ * @param h the hashtable to insert into
+ * @param k the key - hashtable claims ownership and will free on removal
+ * @param v the value - does not claim ownership
+ * @return non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+int
+hashtable_insert(struct hashtable *h, void *k, void *v);
+
+/*****************************************************************************
+ * hashtable_search
+
+ * @name hashtable_search
+ * @param h the hashtable to search
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+void *
+hashtable_search(struct hashtable *h, void *k);
+
+/*****************************************************************************
+ * hashtable_remove
+
+ * @name hashtable_remove
+ * @param h the hashtable to remove the item from
+ * @param k the key to search for - does not claim ownership
+ * @return the value associated with the key, or NULL if none found
+ */
+
+void * /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+/*****************************************************************************
+ * hashtable_count
+
+ * @name hashtable_count
+ * @param h the hashtable
+ * @return the number of items stored in the hashtable
+ */
+unsigned int
+hashtable_count(struct hashtable *h);
+
+/*****************************************************************************
+ * hashtable_destroy
+
+ * @name hashtable_destroy
+ * @param h the hashtable
+ * @param free_values whether to call 'free' on the remaining values
+ */
+
+void
+hashtable_destroy(struct hashtable *h, int free_values);
+
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+ struct hashtable *h;
+ struct entry *e;
+ struct entry *parent;
+ unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+
+extern inline void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+ return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+extern inline void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+ return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ * NB: if you need the value to free it, read it before
+ * removing. ie: beware memory leaks!
+ * returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ * matching the supplied key.
+ h points to the hashtable to be searched.
+ * returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+ struct hashtable *h, void *k);
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
View
175 memcacheq.c
@@ -101,12 +101,8 @@ static void conn_free(conn *c);
/** exported globals **/
struct stats stats;
struct settings settings;
-
struct bdb_settings bdb_settings;
-struct bdb_version bdb_version;
DB_ENV *envp = NULL;
-DB *qlist_dbp = NULL;
-
int daemon_quit = 0;
/** file scope variables **/
@@ -654,7 +650,7 @@ static void complete_nread(conn *c) {
if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) {
out_string(c, "CLIENT_ERROR bad data chunk");
} else {
- ret = bdb_put(key, nkey, it);
+ ret = bdb_set(key, it);
if (ret == 0){
STATS_LOCK();
stats.set_hits++;
@@ -768,21 +764,21 @@ static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
pid_t pid = getpid();
char *pos = temp;
-#ifndef WIN32
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
-#endif /* !WIN32 */
STATS_LOCK();
pos += sprintf(pos, "STAT pid %u\r\n", pid);
pos += sprintf(pos, "STAT uptime %ld\r\n", now - stats.started);
pos += sprintf(pos, "STAT time %ld\r\n", now);
pos += sprintf(pos, "STAT version " VERSION "\r\n");
- pos += sprintf(pos, "STAT pointer_size %d\r\n", 8 * sizeof(void *));
-#ifndef WIN32
- pos += sprintf(pos, "STAT rusage_user %ld.%06ld\r\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);
- pos += sprintf(pos, "STAT rusage_system %ld.%06ld\r\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);
-#endif /* !WIN32 */
+ pos += sprintf(pos, "STAT pointer_size %lu\r\n", (unsigned long)8 * sizeof(void *));
+ pos += sprintf(pos, "STAT rusage_user %lu.%06lu\r\n",
+ (unsigned long)usage.ru_utime.tv_sec,
+ (unsigned long)usage.ru_utime.tv_usec);
+ pos += sprintf(pos, "STAT rusage_system %lu.%06lu\r\n",
+ (unsigned long)usage.ru_stime.tv_sec,
+ (unsigned long)usage.ru_stime.tv_usec);
pos += sprintf(pos, "STAT curr_connections %u\r\n", stats.curr_conns - 1); /* ignore listening conn */
pos += sprintf(pos, "STAT total_connections %u\r\n", stats.total_conns);
pos += sprintf(pos, "STAT connection_structures %u\r\n", stats.conn_structs);
@@ -807,95 +803,16 @@ static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
return;
}
- if (strcmp(subcommand, "bdb") == 0) {
- char temp[512];
- char *pos = temp;
- int ret;
- pos += sprintf(pos, "STAT db_ver %d.%d.%d\r\n", bdb_version.majver, bdb_version.minver, bdb_version.patch);
- pos += sprintf(pos, "STAT cache_size %u\r\n", bdb_settings.cache_size);
- pos += sprintf(pos, "STAT page_size %u\r\n", bdb_settings.page_size);
- pos += sprintf(pos, "STAT txn_lg_bsize %u\r\n", bdb_settings.txn_lg_bsize);
- pos += sprintf(pos, "STAT txn_nosync %d\r\n", bdb_settings.txn_nosync);
- pos += sprintf(pos, "STAT dldetect_val %d\r\n", bdb_settings.dldetect_val);
- pos += sprintf(pos, "STAT chkpoint_val %d\r\n", bdb_settings.chkpoint_val);
- pos += sprintf(pos, "STAT memp_trickle_val %d\r\n", bdb_settings.memp_trickle_val);
- pos += sprintf(pos, "STAT memp_trickle_percent %d\r\n", bdb_settings.memp_trickle_percent);
- pos += sprintf(pos, "END");
- out_string(c, temp);
- return;
- }
-
- if (strcmp(subcommand, "queue") == 0) {
- char temp[512];
- int ret;
- ret = print_queue_db_list(temp, 512);
- if (ret == 0)
- out_string(c, temp);
- else
- out_string(c, "END");
- return;
- }
-
-#ifdef HAVE_MALLOC_H
-#ifdef HAVE_STRUCT_MALLINFO
- if (strcmp(subcommand, "malloc") == 0) {
- char temp[512];
- struct mallinfo info;
- char *pos = temp;
-
- info = mallinfo();
- pos += sprintf(pos, "STAT arena_size %d\r\n", info.arena);
- pos += sprintf(pos, "STAT free_chunks %d\r\n", info.ordblks);
- pos += sprintf(pos, "STAT fastbin_blocks %d\r\n", info.smblks);
- pos += sprintf(pos, "STAT mmapped_regions %d\r\n", info.hblks);
- pos += sprintf(pos, "STAT mmapped_space %d\r\n", info.hblkhd);
- pos += sprintf(pos, "STAT max_total_alloc %d\r\n", info.usmblks);
- pos += sprintf(pos, "STAT fastbin_space %d\r\n", info.fsmblks);
- pos += sprintf(pos, "STAT total_alloc %d\r\n", info.uordblks);
- pos += sprintf(pos, "STAT total_free %d\r\n", info.fordblks);
- pos += sprintf(pos, "STAT releasable_space %d\r\nEND", info.keepcost);
- out_string(c, temp);
- return;
- }
-#endif /* HAVE_STRUCT_MALLINFO */
-#endif /* HAVE_MALLOC_H */
-
-#if !defined(WIN32) || !defined(__APPLE__)
- if (strcmp(subcommand, "maps") == 0) {
- char *wbuf;
- int wsize = 8192; /* should be enough */
- int fd;
- int res;
-
- if ((wbuf = (char *)malloc(wsize)) == NULL) {
- out_string(c, "SERVER_ERROR out of memory writing stats maps");
- return;
- }
-
- fd = open("/proc/self/maps", O_RDONLY);
- if (fd == -1) {
- out_string(c, "SERVER_ERROR cannot open the maps file");
- free(wbuf);
- return;
- }
-
- res = read(fd, wbuf, wsize - 6); /* 6 = END\r\n\0 */
- if (res == wsize - 6) {
- out_string(c, "SERVER_ERROR buffer overflow");
- free(wbuf); close(fd);
- return;
- }
- if (res == 0 || res == -1) {
- out_string(c, "SERVER_ERROR can't read the maps file");