Cache session/[{cursor, config}] for reuse and spawn threads when needed. #9
3 changed files with 33 additions and 18 deletions
|
@ -34,9 +34,9 @@ extern "C" {
|
||||||
#define UNUSED(v) ((void)(v))
|
#define UNUSED(v) ((void)(v))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ASYNC_NIF_MAX_WORKERS 512
|
#define ASYNC_NIF_MAX_WORKERS 1024
|
||||||
#define ASYNC_NIF_WORKER_QUEUE_SIZE 500
|
#define ASYNC_NIF_WORKER_QUEUE_SIZE 500
|
||||||
#define ASYNC_NIF_MAX_QUEUED_REQS 1000 * ASYNC_NIF_MAX_WORKERS
|
#define ASYNC_NIF_MAX_QUEUED_REQS ASYNC_NIF_WORKER_QUEUE_SIZE * ASYNC_NIF_MAX_WORKERS
|
||||||
|
|
||||||
STAT_DECL(qwait, 1000);
|
STAT_DECL(qwait, 1000);
|
||||||
|
|
||||||
|
@ -104,12 +104,12 @@ struct async_nif_state {
|
||||||
return enif_make_tuple2(env, enif_make_atom(env, "error"), \
|
return enif_make_tuple2(env, enif_make_atom(env, "error"), \
|
||||||
enif_make_atom(env, "shutdown")); \
|
enif_make_atom(env, "shutdown")); \
|
||||||
req = async_nif_reuse_req(async_nif); \
|
req = async_nif_reuse_req(async_nif); \
|
||||||
new_env = req->env; \
|
|
||||||
if (!req) { \
|
if (!req) { \
|
||||||
async_nif_recycle_req(req, async_nif); \
|
async_nif_recycle_req(req, async_nif); \
|
||||||
return enif_make_tuple2(env, enif_make_atom(env, "error"), \
|
return enif_make_tuple2(env, enif_make_atom(env, "error"), \
|
||||||
enif_make_atom(env, "eagain")); \
|
enif_make_atom(env, "eagain")); \
|
||||||
} \
|
} \
|
||||||
|
new_env = req->env; \
|
||||||
do pre_block while(0); \
|
do pre_block while(0); \
|
||||||
copy_of_args = (struct decl ## _args *)enif_alloc(sizeof(struct decl ## _args)); \
|
copy_of_args = (struct decl ## _args *)enif_alloc(sizeof(struct decl ## _args)); \
|
||||||
if (!copy_of_args) { \
|
if (!copy_of_args) { \
|
||||||
|
@ -267,17 +267,17 @@ async_nif_enqueue_req(struct async_nif_state* async_nif, struct async_nif_req_en
|
||||||
enif_mutex_unlock(q->reqs_mutex);
|
enif_mutex_unlock(q->reqs_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (fifo_q_size(reqs, q->reqs) > async_nif->num_queues) {
|
if (!fifo_q_full(reqs, q->reqs)) {
|
||||||
double await = STAT_MEAN_LOG2_SAMPLE(async_nif, qwait);
|
double await = STAT_MEAN_LOG2_SAMPLE(async_nif, qwait);
|
||||||
double await_inthisq = STAT_MEAN_LOG2_SAMPLE(q, qwait);
|
double await_inthisq = STAT_MEAN_LOG2_SAMPLE(q, qwait);
|
||||||
if (fifo_q_full(reqs, q->reqs) || await_inthisq > await) {
|
if (await_inthisq > await) {
|
||||||
enif_mutex_unlock(q->reqs_mutex);
|
enif_mutex_unlock(q->reqs_mutex);
|
||||||
qid = (qid + 1) % async_nif->num_queues;
|
qid = (qid + 1) % async_nif->num_queues;
|
||||||
q = &async_nif->queues[qid];
|
q = &async_nif->queues[qid];
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// TODO: at some point add in work sheading/stealing
|
// TODO: at some point add in work sheading/stealing
|
||||||
} while(n-- > 0);
|
} while(n-- > 0);
|
||||||
|
|
||||||
|
@ -467,7 +467,7 @@ async_nif_load()
|
||||||
sizeof(struct async_nif_work_queue) * num_queues);
|
sizeof(struct async_nif_work_queue) * num_queues);
|
||||||
|
|
||||||
async_nif->num_queues = num_queues;
|
async_nif->num_queues = num_queues;
|
||||||
async_nif->num_workers = 2 * num_queues;
|
async_nif->num_workers = ASYNC_NIF_MAX_WORKERS;
|
||||||
async_nif->next_q = 0;
|
async_nif->next_q = 0;
|
||||||
async_nif->shutdown = 0;
|
async_nif->shutdown = 0;
|
||||||
async_nif->recycled_reqs = fifo_q_new(reqs, ASYNC_NIF_MAX_QUEUED_REQS);
|
async_nif->recycled_reqs = fifo_q_new(reqs, ASYNC_NIF_MAX_QUEUED_REQS);
|
||||||
|
|
|
@ -33,7 +33,7 @@ extern "C" {
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#define DPRINTF(fmt, ...) \
|
#define DPRINTF(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, __VA_ARGS__); \
|
fprintf(stderr, "%s:%d (%s) " fmt "\n", __FILE__, __LINE__, __func__, __VA_ARGS__); \
|
||||||
fflush(stderr); \
|
fflush(stderr); \
|
||||||
} while(0)
|
} while(0)
|
||||||
#define DPUTS(arg) DPRINTF("%s", arg)
|
#define DPUTS(arg) DPRINTF("%s", arg)
|
||||||
|
|
|
@ -336,7 +336,7 @@ __retain_ctx(WterlConnHandle *conn_handle, uint32_t worker_id,
|
||||||
struct wterl_ctx **ctx,
|
struct wterl_ctx **ctx,
|
||||||
int count, const char *session_config, ...)
|
int count, const char *session_config, ...)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 3;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
uint64_t sig;
|
uint64_t sig;
|
||||||
const char *arg;
|
const char *arg;
|
||||||
|
@ -347,33 +347,37 @@ __retain_ctx(WterlConnHandle *conn_handle, uint32_t worker_id,
|
||||||
sig = __ctx_cache_sig(session_config, ap, count);
|
sig = __ctx_cache_sig(session_config, ap, count);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
*ctx = NULL;
|
||||||
do {
|
do {
|
||||||
c = conn_handle->mru_ctx[worker_id];
|
c = conn_handle->mru_ctx[worker_id];
|
||||||
if (CASPO(&conn_handle->mru_ctx[worker_id], c, NULL) == c) {
|
if (CASPO(&conn_handle->mru_ctx[worker_id], c, NULL) == c) {
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
// mru miss:
|
// mru miss:
|
||||||
|
DPRINTF("[%.4u] mru miss: %llu != NULL", worker_id, PRIuint64(sig));
|
||||||
*ctx = NULL;
|
*ctx = NULL;
|
||||||
} else {
|
} else {
|
||||||
if (c->sig == sig) {
|
if (c->sig == sig) {
|
||||||
// mru hit:
|
// mru hit:
|
||||||
|
DPRINTF("[%.4u] mru hit: %llu", worker_id, PRIuint64(sig));
|
||||||
*ctx = c;
|
*ctx = c;
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
// mru missmatch:
|
// mru missmatch:
|
||||||
|
DPRINTF("[%.4u] mru missmatch: %llu != %llu", worker_id, PRIuint64(sig), PRIuint64(c->sig));
|
||||||
__ctx_cache_add(conn_handle, c);
|
__ctx_cache_add(conn_handle, c);
|
||||||
*ctx = NULL;
|
*ctx = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// CAS failed, retry...
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} while(0);
|
// CAS failed, retry up to 3 times
|
||||||
|
} while(i--);
|
||||||
|
|
||||||
if (*ctx == NULL) {
|
if (*ctx == NULL) {
|
||||||
// check the cache
|
// check the cache
|
||||||
(*ctx) = __ctx_cache_find(conn_handle, sig);
|
(*ctx) = __ctx_cache_find(conn_handle, sig);
|
||||||
if ((*ctx) == NULL) {
|
if ((*ctx) == NULL) {
|
||||||
// cache miss:
|
// cache miss:
|
||||||
|
DPRINTF("[%.4u] cache miss: %llu [%d]", worker_id, PRIuint64(sig), conn_handle->cache_size);
|
||||||
WT_CONNECTION *conn = conn_handle->conn;
|
WT_CONNECTION *conn = conn_handle->conn;
|
||||||
WT_SESSION *session = NULL;
|
WT_SESSION *session = NULL;
|
||||||
int rc = conn->open_session(conn, NULL, session_config, &session);
|
int rc = conn->open_session(conn, NULL, session_config, &session);
|
||||||
|
@ -402,7 +406,10 @@ __retain_ctx(WterlConnHandle *conn_handle, uint32_t worker_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
} // else { cache hit }
|
} else {
|
||||||
|
// cache hit:
|
||||||
|
DPRINTF("[%.4u] cache hit: %llu [%d]", worker_id, PRIuint64(sig), conn_handle->cache_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -423,9 +430,14 @@ __release_ctx(WterlConnHandle *conn_handle, uint32_t worker_id, struct wterl_ctx
|
||||||
cursor->reset(cursor);
|
cursor->reset(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
|
||||||
c = conn_handle->mru_ctx[worker_id];
|
c = conn_handle->mru_ctx[worker_id];
|
||||||
} while(CASPO(&conn_handle->mru_ctx[worker_id], c, ctx) != c);
|
if (CASPO(&conn_handle->mru_ctx[worker_id], c, ctx) != c) {
|
||||||
|
__ctx_cache_add(conn_handle, ctx);
|
||||||
|
} else {
|
||||||
|
if (c != NULL) {
|
||||||
|
__ctx_cache_add(conn_handle, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1462,15 +1474,18 @@ ASYNC_NIF_DECL(
|
||||||
cursor->set_key(cursor, &item_key);
|
cursor->set_key(cursor, &item_key);
|
||||||
rc = cursor->search(cursor);
|
rc = cursor->search(cursor);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
|
__release_ctx(args->conn_handle, worker_id, ctx);
|
||||||
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cursor->get_value(cursor, &item_value);
|
rc = cursor->get_value(cursor, &item_value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
|
__release_ctx(args->conn_handle, worker_id, ctx);
|
||||||
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ERL_NIF_TERM value;
|
ERL_NIF_TERM value;
|
||||||
unsigned char *bin = enif_make_new_binary(env, item_value.size, &value);
|
unsigned char *bin = enif_make_new_binary(env, item_value.size, &value);
|
||||||
memcpy(bin, item_value.data, item_value.size);
|
memcpy(bin, item_value.data, item_value.size);
|
||||||
|
|
Loading…
Reference in a new issue