2013-04-05 22:09:54 +00:00
|
|
|
/*
|
|
|
|
* wterl: an Erlang NIF for WiredTiger
|
|
|
|
*
|
|
|
|
* Copyright (c) 2012-2013 Basho Technologies, Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* This file is provided to you under the Apache License, Version 2.0 (the
|
|
|
|
* "License"); you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
|
|
|
*
|
|
|
|
*/
|
2011-12-22 04:46:35 +00:00
|
|
|
#include "erl_nif.h"
|
|
|
|
#include "erl_driver.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2012-02-15 14:59:28 +00:00
|
|
|
#include <string.h>
|
2013-04-11 15:57:41 +00:00
|
|
|
#include <errno.h>
|
2011-12-22 04:46:35 +00:00
|
|
|
|
|
|
|
#include "wiredtiger.h"
|
2013-03-25 01:00:48 +00:00
|
|
|
#include "async_nif.h"
|
2013-04-06 15:05:41 +00:00
|
|
|
#include "khash.h"
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2013-04-11 15:57:41 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
void debugf(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
|
|
fprintf(stderr, "\r\n");
|
|
|
|
fflush(stderr);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
# define debugf(X, ...) {}
|
|
|
|
#endif
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
static ErlNifResourceType *wterl_conn_RESOURCE;
|
|
|
|
static ErlNifResourceType *wterl_cursor_RESOURCE;
|
|
|
|
|
2013-04-11 15:57:41 +00:00
|
|
|
KHASH_INIT(cursors, char*, WT_CURSOR*, 1, kh_str_hash_func, kh_str_hash_equal);
|
2013-04-06 15:05:41 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* We will have exactly one (1) WterlCtx for each async worker thread. As
|
|
|
|
* requests arrive we will reuse the same WterlConnHandle->contexts[worker_id]
|
|
|
|
* WterlCtx in the work block ensuring that each async worker thread a) has
|
|
|
|
* a separate WT_SESSION (because they are not thread safe) and b) when
|
|
|
|
* possible we avoid opening new cursors by first looking for one in the
|
|
|
|
* cursors hash table. In practice this means we could have (num_workers
|
|
|
|
* * num_tables) of cursors open which we need to account for when setting
|
|
|
|
* session_max in the configuration of WiredTiger so that it creates enough
|
2013-04-06 15:05:41 +00:00
|
|
|
* hazard pointers for this extreme case.
|
|
|
|
*
|
|
|
|
* Note: We don't protect access to this struct with a mutex because it will
|
|
|
|
* only be accessed by the same worker thread.
|
2013-04-05 22:09:54 +00:00
|
|
|
*/
|
2012-04-02 20:59:13 +00:00
|
|
|
typedef struct {
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_SESSION *session;
|
2013-04-06 15:05:41 +00:00
|
|
|
khash_t(cursors) *cursors;
|
2013-04-05 22:09:54 +00:00
|
|
|
} WterlCtx;
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2012-04-02 20:59:13 +00:00
|
|
|
typedef struct {
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_CONNECTION *conn;
|
|
|
|
const char *session_config;
|
|
|
|
ErlNifMutex *context_mutex;
|
2013-04-06 15:05:41 +00:00
|
|
|
unsigned int num_contexts;
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlCtx contexts[ASYNC_NIF_MAX_WORKERS];
|
|
|
|
} WterlConnHandle;
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2012-04-02 20:59:13 +00:00
|
|
|
typedef struct {
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_CURSOR *cursor;
|
|
|
|
WT_SESSION *session;
|
2012-04-02 20:59:13 +00:00
|
|
|
} WterlCursorHandle;
|
2012-02-16 18:22:03 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/* WiredTiger object names*/
|
|
|
|
typedef char Uri[128];
|
2012-02-08 22:31:16 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/* Atoms (initialized in on_load) */
|
2011-12-22 04:46:35 +00:00
|
|
|
static ERL_NIF_TERM ATOM_ERROR;
|
2012-02-08 22:31:16 +00:00
|
|
|
static ERL_NIF_TERM ATOM_OK;
|
2013-04-05 22:09:54 +00:00
|
|
|
static ERL_NIF_TERM ATOM_NOT_FOUND;
|
2013-04-11 15:57:41 +00:00
|
|
|
static ERL_NIF_TERM ATOM_FIRST;
|
|
|
|
static ERL_NIF_TERM ATOM_LAST;
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the per-worker reusable WT_SESSION for a worker_id.
|
|
|
|
*/
|
|
|
|
static int
|
2013-04-06 15:05:41 +00:00
|
|
|
__session_for(WterlConnHandle *conn_handle, unsigned int worker_id, WT_SESSION **session)
|
2013-04-05 22:09:54 +00:00
|
|
|
{
|
2013-04-06 15:05:41 +00:00
|
|
|
WterlCtx *ctx = &conn_handle->contexts[worker_id];
|
|
|
|
*session = ctx->session;
|
2013-04-05 22:09:54 +00:00
|
|
|
if (*session == NULL) {
|
|
|
|
/* Create a context for this worker thread to reuse. */
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_lock(conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_CONNECTION *conn = conn_handle->conn;
|
|
|
|
int rc = conn->open_session(conn, NULL, conn_handle->session_config, session);
|
2013-04-11 15:57:41 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
enif_mutex_unlock(conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return rc;
|
2013-04-11 15:57:41 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
ctx->session = *session;
|
2013-04-06 15:05:41 +00:00
|
|
|
ctx->cursors = kh_init(cursors);
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-08 21:21:48 +00:00
|
|
|
void
|
|
|
|
__close_all_sessions(WterlConnHandle *conn_handle)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < conn_handle->num_contexts; i++) {
|
|
|
|
WterlCtx *ctx = &conn_handle->contexts[i];
|
2013-04-11 15:57:41 +00:00
|
|
|
WT_SESSION *session = ctx->session;
|
|
|
|
khash_t(cursors) *h = ctx->cursors;
|
|
|
|
khiter_t itr;
|
|
|
|
for (itr = kh_begin(h); itr != kh_end(h); ++itr) {
|
|
|
|
if (kh_exist(h, itr)) {
|
|
|
|
WT_CURSOR *cursor = kh_val(h, itr);
|
|
|
|
enif_free(kh_key(h, itr));
|
|
|
|
cursor->close(cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kh_destroy(cursors, h);
|
|
|
|
session->close(session, NULL);
|
2013-04-08 21:21:48 +00:00
|
|
|
ctx->session = NULL;
|
|
|
|
ctx->cursors = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
/**
|
|
|
|
* Close cursors open on 'uri' object.
|
|
|
|
*
|
|
|
|
* Note: always call within enif_mutex_lock/unlock(conn_handle->context_mutex)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
__close_cursors_on(WterlConnHandle *conn_handle, const char *uri) // TODO: race?
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < conn_handle->num_contexts; i++) {
|
|
|
|
WterlCtx *ctx = &conn_handle->contexts[i];
|
|
|
|
khash_t(cursors) *h = ctx->cursors;
|
2013-04-11 15:57:41 +00:00
|
|
|
khiter_t itr = kh_get(cursors, h, (char *)uri);
|
2013-04-08 02:16:44 +00:00
|
|
|
if (itr != kh_end(h)) {
|
2013-04-11 15:57:41 +00:00
|
|
|
WT_CURSOR *cursor = kh_value(h, itr);
|
|
|
|
char *key = kh_key(h, itr);
|
2013-04-08 02:16:44 +00:00
|
|
|
kh_del(cursors, h, itr);
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_free(key);
|
2013-04-08 02:16:44 +00:00
|
|
|
cursor->close(cursor);
|
2013-04-11 15:57:41 +00:00
|
|
|
debugf("closing worker_id: %d 0x%p %s", i, cursor, uri);
|
2013-04-08 02:16:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Get a reusable cursor that was opened for a particular worker within its
|
|
|
|
* session.
|
|
|
|
*/
|
|
|
|
static int
|
2013-04-08 02:16:44 +00:00
|
|
|
__retain_cursor(WterlConnHandle *conn_handle, unsigned int worker_id, const char *uri, WT_CURSOR **cursor)
|
2013-04-05 22:09:54 +00:00
|
|
|
{
|
2013-04-08 02:16:44 +00:00
|
|
|
/* Check to see if we have a cursor open for this uri and if so reuse it. */
|
2013-04-06 15:05:41 +00:00
|
|
|
WterlCtx *ctx = &conn_handle->contexts[worker_id];
|
|
|
|
khash_t(cursors) *h = ctx->cursors;
|
2013-04-11 15:57:41 +00:00
|
|
|
khiter_t itr = kh_get(cursors, h, (char *)uri);
|
2013-04-06 15:05:41 +00:00
|
|
|
if (itr != kh_end(h)) {
|
|
|
|
// key exists in hash table, retrieve it
|
|
|
|
*cursor = (WT_CURSOR*)kh_value(h, itr);
|
|
|
|
} else {
|
|
|
|
// key does not exist in hash table, create and insert one
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_lock(conn_handle->context_mutex);
|
2013-04-06 15:05:41 +00:00
|
|
|
WT_SESSION *session = conn_handle->contexts[worker_id].session;
|
2013-04-05 22:09:54 +00:00
|
|
|
int rc = session->open_cursor(session, uri, NULL, "overwrite,raw", cursor);
|
2013-04-11 15:57:41 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
enif_mutex_unlock(conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return rc;
|
2013-04-11 15:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char *key = enif_alloc(sizeof(Uri));
|
|
|
|
if (!key) {
|
|
|
|
session->close(session, NULL);
|
|
|
|
enif_mutex_unlock(conn_handle->context_mutex);
|
|
|
|
return ENOMEM;
|
|
|
|
}
|
|
|
|
memcpy(key, uri, 128);
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
int itr_status;
|
2013-04-11 15:57:41 +00:00
|
|
|
itr = kh_put(cursors, h, key, &itr_status);
|
2013-04-06 15:05:41 +00:00
|
|
|
kh_value(h, itr) = *cursor;
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
static void
|
|
|
|
__release_cursor(WterlConnHandle *conn_handle, unsigned int worker_id, const char *uri, WT_CURSOR *cursor)
|
|
|
|
{
|
|
|
|
cursor->reset(cursor);
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
2013-04-08 21:21:48 +00:00
|
|
|
* Convenience function to generate {error, {errno, Reason}} or 'not_found'
|
2013-04-05 22:09:54 +00:00
|
|
|
* Erlang terms to return to callers.
|
|
|
|
*
|
|
|
|
* env NIF environment
|
|
|
|
* rc code returned by WiredTiger
|
|
|
|
*/
|
|
|
|
static ERL_NIF_TERM
|
|
|
|
__strerror_term(ErlNifEnv* env, int rc)
|
2012-02-16 23:44:28 +00:00
|
|
|
{
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc == WT_NOTFOUND) {
|
|
|
|
return ATOM_NOT_FOUND;
|
|
|
|
} else {
|
2013-04-08 21:21:48 +00:00
|
|
|
/* TODO: The string for the error message provided by strerror() for
|
|
|
|
any given errno value may be different across platforms, return
|
|
|
|
{atom, string} and may have been localized too. */
|
2013-04-06 15:05:41 +00:00
|
|
|
return enif_make_tuple2(env, ATOM_ERROR,
|
2013-04-08 21:21:48 +00:00
|
|
|
enif_make_tuple2(env,
|
|
|
|
enif_make_atom(env, erl_errno_id(rc)),
|
|
|
|
enif_make_string(env, wiredtiger_strerror(rc), ERL_NIF_LATIN1)));
|
2013-04-05 22:09:54 +00:00
|
|
|
}
|
2012-02-16 23:44:28 +00:00
|
|
|
}
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Opens a WiredTiger WT_CONNECTION object.
|
|
|
|
*
|
|
|
|
* argv[0] path to directory for the database files
|
|
|
|
* argv[1] WiredTiger connection config string as an Erlang binary
|
|
|
|
* argv[2] WiredTiger session config string as an Erlang binary
|
|
|
|
*/
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_conn_open,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
ERL_NIF_TERM config;
|
2013-04-05 22:09:54 +00:00
|
|
|
ERL_NIF_TERM session_config;
|
2011-12-22 04:46:35 +00:00
|
|
|
char homedir[4096];
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
if (!(argc == 3 &&
|
2013-03-25 01:00:48 +00:00
|
|
|
enif_get_string(env, argv[0], args->homedir, sizeof args->homedir, ERL_NIF_LATIN1) &&
|
2013-04-07 13:21:47 +00:00
|
|
|
enif_is_binary(env, argv[1]) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
2013-04-07 13:21:47 +00:00
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[1]);
|
|
|
|
args->session_config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_CONNECTION *conn;
|
2013-03-25 01:00:48 +00:00
|
|
|
ErlNifBinary config;
|
2013-04-05 22:09:54 +00:00
|
|
|
ErlNifBinary session_config;
|
2013-04-07 13:21:47 +00:00
|
|
|
|
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
2013-03-25 01:00:48 +00:00
|
|
|
}
|
2013-04-07 13:21:47 +00:00
|
|
|
if (!enif_inspect_binary(env, args->session_config, &session_config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
2013-04-05 22:09:54 +00:00
|
|
|
}
|
2013-04-11 15:57:41 +00:00
|
|
|
//debugf("c: %d // %s\ns: %d // %s", config.size, (char *)config.data, (char *)session_config.data, session_config.size);
|
2013-04-07 13:21:47 +00:00
|
|
|
int rc = wiredtiger_open(args->homedir, NULL, config.data[0] != 0 ? (const char*)config.data : NULL, &conn);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
WterlConnHandle *conn_handle = enif_alloc_resource(wterl_conn_RESOURCE, sizeof(WterlConnHandle));
|
2013-04-11 15:57:41 +00:00
|
|
|
if (session_config.size > 1) {
|
|
|
|
char *sc = enif_alloc(session_config.size);
|
|
|
|
if (!sc) {
|
|
|
|
enif_release_resource(conn_handle);
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, ENOMEM));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memcpy(sc, session_config.data, session_config.size);
|
|
|
|
|
|
|
|
conn_handle->session_config = (const char *)sc;
|
|
|
|
} else {
|
2013-04-06 21:19:59 +00:00
|
|
|
conn_handle->session_config = NULL;
|
2013-04-11 15:57:41 +00:00
|
|
|
}
|
|
|
|
conn_handle->conn = conn;
|
2013-04-05 22:09:54 +00:00
|
|
|
conn_handle->num_contexts = 0;
|
|
|
|
bzero(conn_handle->contexts, sizeof(WterlCtx) * ASYNC_NIF_MAX_WORKERS);
|
|
|
|
conn_handle->context_mutex = enif_mutex_create(NULL);
|
2013-04-02 13:42:07 +00:00
|
|
|
ERL_NIF_TERM result = enif_make_resource(env, conn_handle);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource(conn_handle); // When GC'ed the BEAM calls __resource_conn_dtor()
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_REPLY(enif_make_tuple2(env, ATOM_OK, result));
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2013-03-25 01:00:48 +00:00
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Closes a WiredTiger WT_CONNECTION object.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
*/
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_conn_close,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlConnHandle* conn_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CONNECTION* conn = args->conn_handle->conn;
|
|
|
|
int rc = conn->close(conn, NULL);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->conn_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Create a WiredTiger table, column group, index or file.
|
|
|
|
*
|
|
|
|
* We create, use and discard a WT_SESSION here because table creation is not
|
|
|
|
* too performance sensitive.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] config string as an Erlang binary
|
|
|
|
*/
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_create,
|
2013-03-25 01:00:48 +00:00
|
|
|
{ // struct
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
|
|
|
Uri uri;
|
2013-03-25 01:00:48 +00:00
|
|
|
ERL_NIF_TERM config;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
if (!(argc == 3 &&
|
2013-04-06 15:05:41 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-03-25 01:00:48 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
ErlNifBinary config;
|
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2012-02-16 23:44:28 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/* We create, use and discard a WT_SESSION here because a) we don't need a
|
|
|
|
cursor and b) we don't anticipate doing this operation frequently enough
|
|
|
|
to impact performance. */
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
2012-02-08 22:31:16 +00:00
|
|
|
}
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->create(session, args->uri, (const char*)config.data);
|
|
|
|
(void)session->close(session, NULL);
|
2013-04-08 21:21:48 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-03-25 01:00:48 +00:00
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Drop (remove) a WiredTiger table, column group, index or file.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] config string as an Erlang binary
|
|
|
|
*/
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_drop,
|
2013-03-25 01:00:48 +00:00
|
|
|
{ // struct
|
|
|
|
|
|
|
|
Uri uri;
|
|
|
|
ERL_NIF_TERM config;
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 3 &&
|
2013-04-06 15:05:41 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-03-25 01:00:48 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
/* This call requires that there be no open cursors referencing the object. */
|
|
|
|
enif_mutex_lock(args->conn_handle->context_mutex);
|
|
|
|
__close_cursors_on(args->conn_handle, args->uri);
|
|
|
|
|
2013-03-08 01:31:42 +00:00
|
|
|
ErlNifBinary config;
|
2013-03-25 01:00:48 +00:00
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-03-25 01:00:48 +00:00
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/* We create, use and discard a WT_SESSION here because a) we don't need a
|
|
|
|
cursor and b) we don't anticipate doing this operation frequently enough
|
|
|
|
to impact performance. */
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
/* Note: we must first close all cursors referencing this object or this
|
|
|
|
operation will fail with EBUSY(16) "Device or resource busy". */
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
// TODO: add a condition for this object name, test for that in cursor
|
|
|
|
// create, pause the async nif layer's workers, find and close open cursors
|
|
|
|
// on this table, restart worker threads, do the drop, remove the condition
|
|
|
|
// variable (read: punt for now, expect a lot of EBUSYs)
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->drop(session, args->uri, (const char*)config.data);
|
|
|
|
(void)session->close(session, NULL);
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2012-02-16 23:44:28 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Rename a WiredTiger table, column group, index or file.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] old object name URI string
|
|
|
|
* argv[2] new object name URI string
|
|
|
|
* argv[3] config string as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_rename,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
|
|
|
|
2013-03-25 01:00:48 +00:00
|
|
|
Uri oldname;
|
|
|
|
Uri newname;
|
2013-04-05 22:09:54 +00:00
|
|
|
ERL_NIF_TERM config;
|
|
|
|
WterlConnHandle *conn_handle;
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 4 &&
|
2013-04-06 15:05:41 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-03-25 01:00:48 +00:00
|
|
|
enif_get_string(env, argv[1], args->oldname, sizeof args->oldname, ERL_NIF_LATIN1) &&
|
|
|
|
enif_get_string(env, argv[2], args->newname, sizeof args->newname, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[3]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
2012-02-08 22:31:16 +00:00
|
|
|
}
|
2013-03-25 01:00:48 +00:00
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[3]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // work
|
2011-12-22 04:46:35 +00:00
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
/* This call requires that there be no open cursors referencing the object. */
|
|
|
|
enif_mutex_lock(args->conn_handle->context_mutex);
|
|
|
|
__close_cursors_on(args->conn_handle, args->oldname);
|
|
|
|
|
2013-04-02 13:42:07 +00:00
|
|
|
ErlNifBinary config;
|
2013-03-25 01:00:48 +00:00
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/* We create, use and discard a WT_SESSION here because a) we don't need a
|
|
|
|
cursor and b) we don't anticipate doing this operation frequently enough
|
|
|
|
to impact performance. */
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note: we must first close all cursors referencing this object or this
|
|
|
|
operation will fail with EBUSY(16) "Device or resource busy". */
|
|
|
|
// TODO: see drop's note, same goes here.
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->rename(session, args->oldname, args->newname, (const char*)config.data);
|
2013-04-05 22:09:54 +00:00
|
|
|
(void)session->close(session, NULL);
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-03-25 01:00:48 +00:00
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Salvage rebuilds the file, or files of which a table is comprised,
|
|
|
|
* discarding any corrupted file blocks. Use this as a fallback if
|
|
|
|
* an attempt to open a WiredTiger database object fails.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] config string as an Erlang binary
|
|
|
|
*/
|
2013-03-25 01:00:48 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_salvage,
|
2013-03-25 01:00:48 +00:00
|
|
|
{ // struct
|
2012-02-16 23:44:28 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-03-25 01:00:48 +00:00
|
|
|
Uri uri;
|
|
|
|
ERL_NIF_TERM config;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 3 &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-03-25 01:00:48 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-03-25 01:00:48 +00:00
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
/* This call requires that there be no open cursors referencing the object. */
|
|
|
|
enif_mutex_lock(args->conn_handle->context_mutex);
|
|
|
|
__close_cursors_on(args->conn_handle, args->uri);
|
|
|
|
|
2012-09-17 14:58:48 +00:00
|
|
|
ErlNifBinary config;
|
2013-03-25 01:00:48 +00:00
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/* We create, use and discard a WT_SESSION here because a) we don't need a
|
|
|
|
cursor and b) we don't anticipate doing this operation frequently enough
|
|
|
|
to impact performance. */
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->salvage(session, args->uri, (const char*)config.data);
|
2013-04-05 22:09:54 +00:00
|
|
|
(void)session->close(session, NULL);
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2012-02-16 23:44:28 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Checkpoint writes a transactionally consistent snapshot of a database or set
|
|
|
|
* of objects specified.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] config string as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_checkpoint,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
2012-02-16 23:44:28 +00:00
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
ERL_NIF_TERM config;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 2 &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-02 13:42:07 +00:00
|
|
|
enif_is_binary(env, argv[1]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
2013-03-25 01:00:48 +00:00
|
|
|
}
|
2013-04-02 13:42:07 +00:00
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[1]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-02 13:42:07 +00:00
|
|
|
ErlNifBinary config;
|
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_SESSION *session = NULL;
|
2013-04-06 15:05:41 +00:00
|
|
|
int rc = __session_for(args->conn_handle, worker_id, &session);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->checkpoint(session, (const char*)config.data);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
2012-02-16 23:44:28 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Truncate a file, table or cursor range.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] start key as an Erlang binary
|
|
|
|
* argv[3] stop key as an Erlang binary
|
|
|
|
* argv[4] config string as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_truncate,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
Uri uri;
|
2013-04-11 15:57:41 +00:00
|
|
|
int start_first;
|
|
|
|
int stop_last;
|
2013-04-05 22:09:54 +00:00
|
|
|
ERL_NIF_TERM start;
|
|
|
|
ERL_NIF_TERM stop;
|
2013-04-02 13:42:07 +00:00
|
|
|
ERL_NIF_TERM config;
|
|
|
|
},
|
|
|
|
{ // pre
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
if (!(argc == 5 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-02 13:42:07 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_is_binary(env, argv[4]))) {
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
2013-03-25 01:00:48 +00:00
|
|
|
}
|
2013-04-11 15:57:41 +00:00
|
|
|
if (enif_is_binary(env, argv[2])) {
|
|
|
|
args->start_first = 0;
|
2013-04-05 22:09:54 +00:00
|
|
|
args->start = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-11 15:57:41 +00:00
|
|
|
} else if (enif_is_atom(env, argv[2]) && argv[2] == ATOM_FIRST) {
|
|
|
|
args->start_first = 1;
|
|
|
|
} else {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
if (enif_is_binary(env, argv[3])) {
|
|
|
|
args->stop_last = 0;
|
2013-04-05 22:09:54 +00:00
|
|
|
args->stop = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[3]);
|
2013-04-11 15:57:41 +00:00
|
|
|
} else if (enif_is_atom(env, argv[3]) && argv[3] == ATOM_LAST) {
|
|
|
|
args->stop_last = 1;
|
|
|
|
} else {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[4]);
|
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
/* This call requires that there be no open cursors referencing the object. */
|
|
|
|
enif_mutex_lock(args->conn_handle->context_mutex);
|
|
|
|
__close_cursors_on(args->conn_handle, args->uri);
|
|
|
|
|
2013-04-02 13:42:07 +00:00
|
|
|
ErlNifBinary config;
|
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-02 13:42:07 +00:00
|
|
|
return;
|
2013-03-25 01:00:48 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/* We create, use and discard a WT_SESSION and up to two WT_CURSORS here because
|
|
|
|
a) we'll have to close out other, shared cursors on this table first and b) we
|
|
|
|
don't anticipate doing this operation frequently enough to impact performance. */
|
|
|
|
// TODO: see drop's note, same goes here.
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErlNifBinary start_key;
|
|
|
|
WT_CURSOR *start = NULL;
|
2013-04-11 15:57:41 +00:00
|
|
|
if (!args->start_first) {
|
2013-04-08 21:21:48 +00:00
|
|
|
if (!enif_inspect_binary(env, args->start, &start_key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
rc = session->open_cursor(session, args->uri, NULL, "raw", &start);
|
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-06 15:05:41 +00:00
|
|
|
session->close(session, NULL);
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
WT_ITEM item_start;
|
|
|
|
item_start.data = start_key.data;
|
|
|
|
item_start.size = start_key.size;
|
|
|
|
start->set_key(start, item_start);
|
|
|
|
}
|
|
|
|
|
|
|
|
ErlNifBinary stop_key;
|
|
|
|
WT_CURSOR *stop = NULL;
|
2013-04-11 15:57:41 +00:00
|
|
|
if (!args->stop_last) {
|
2013-04-08 21:21:48 +00:00
|
|
|
if (!enif_inspect_binary(env, args->stop, &stop_key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
rc = session->open_cursor(session, args->uri, NULL, "raw", &stop);
|
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-06 15:05:41 +00:00
|
|
|
session->close(session, NULL);
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
WT_ITEM item_stop;
|
|
|
|
item_stop.data = stop_key.data;
|
|
|
|
item_stop.size = stop_key.size;
|
|
|
|
stop->set_key(stop, item_stop);
|
|
|
|
}
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->truncate(session, args->uri, start, stop, (const char*)config.data);
|
2013-04-11 15:57:41 +00:00
|
|
|
if (start) start->close(start);
|
|
|
|
if (stop) stop->close(stop);
|
2013-04-08 21:21:48 +00:00
|
|
|
(void)session->close(session, NULL);
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Upgrade upgrades a file or table, if upgrade is required.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] config string as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-06 15:05:41 +00:00
|
|
|
wterl_upgrade,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
Uri uri;
|
|
|
|
ERL_NIF_TERM config;
|
|
|
|
},
|
|
|
|
{ // pre
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-02 13:42:07 +00:00
|
|
|
if (!(argc == 3 &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-02 13:42:07 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
2012-02-20 01:20:38 +00:00
|
|
|
}
|
2013-04-02 13:42:07 +00:00
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
/* This call requires that there be no open cursors referencing the object. */
|
|
|
|
enif_mutex_lock(args->conn_handle->context_mutex);
|
|
|
|
__close_cursors_on(args->conn_handle, args->uri);
|
|
|
|
|
2013-04-02 13:42:07 +00:00
|
|
|
ErlNifBinary config;
|
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-02 13:42:07 +00:00
|
|
|
return;
|
2013-03-25 01:00:48 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/* We create, use and discard a WT_SESSION here because a) we don't need a
|
|
|
|
cursor and b) we don't anticipate doing this operation frequently enough
|
|
|
|
to impact performance. */
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->upgrade(session, args->uri, (const char*)config.data);
|
2013-04-05 22:09:54 +00:00
|
|
|
(void)session->close(session, NULL);
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Verify reports if a file, or the files of which a table is comprised, have
|
|
|
|
* been corrupted.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] config string as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_verify,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
Uri uri;
|
|
|
|
ERL_NIF_TERM config;
|
|
|
|
},
|
|
|
|
{ // pre
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-02 13:42:07 +00:00
|
|
|
if (!(argc == 3 &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-02 13:42:07 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-08 02:16:44 +00:00
|
|
|
/* This call requires that there be no open cursors referencing the object. */
|
|
|
|
enif_mutex_lock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
__close_all_sessions(args->conn_handle);
|
2013-04-08 02:16:44 +00:00
|
|
|
|
2013-04-02 13:42:07 +00:00
|
|
|
ErlNifBinary config;
|
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-02 13:42:07 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/* We create, use and discard a WT_SESSION here because a) we don't need a
|
|
|
|
cursor and b) we don't anticipate doing this operation frequently enough
|
|
|
|
to impact performance. */
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
rc = session->verify(session, args->uri, (const char*)config.data);
|
|
|
|
(void)session->close(session, NULL);
|
2013-04-08 02:16:44 +00:00
|
|
|
enif_mutex_unlock(args->conn_handle->context_mutex);
|
2013-04-08 21:21:48 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2012-02-20 01:20:38 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
2012-02-20 01:20:38 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Delete a key's value from the specified table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] key as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-06 15:05:41 +00:00
|
|
|
wterl_delete,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
2012-02-16 23:44:28 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
Uri uri;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 3 &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-02 13:42:07 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
2013-03-25 01:00:48 +00:00
|
|
|
ErlNifBinary key;
|
2013-04-02 13:42:07 +00:00
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
WT_SESSION *session = NULL;
|
2013-04-06 15:05:41 +00:00
|
|
|
int rc = __session_for(args->conn_handle, worker_id, &session);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WT_CURSOR *cursor = NULL;
|
2013-04-08 02:16:44 +00:00
|
|
|
rc = __retain_cursor(args->conn_handle, worker_id, args->uri, &cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
WT_ITEM item_key;
|
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
2013-04-02 13:42:07 +00:00
|
|
|
rc = cursor->remove(cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-08 02:16:44 +00:00
|
|
|
__release_cursor(args->conn_handle, worker_id, args->uri, cursor);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Get the value for the key's value from the specified table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] key as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_get,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
Uri uri;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 3 &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-02 13:42:07 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
ErlNifBinary key;
|
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
WT_SESSION *session = NULL;
|
2013-04-06 15:05:41 +00:00
|
|
|
int rc = __session_for(args->conn_handle, worker_id, &session);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WT_CURSOR *cursor = NULL;
|
2013-04-08 02:16:44 +00:00
|
|
|
rc = __retain_cursor(args->conn_handle, worker_id, args->uri, &cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
2013-03-25 01:00:48 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
WT_ITEM item_key;
|
|
|
|
WT_ITEM item_value;
|
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
2013-04-02 13:42:07 +00:00
|
|
|
rc = cursor->search(cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = cursor->get_value(cursor, &item_value);
|
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ERL_NIF_TERM value;
|
|
|
|
unsigned char *bin = enif_make_new_binary(env, item_value.size, &value);
|
|
|
|
memcpy(bin, item_value.data, item_value.size);
|
|
|
|
ASYNC_NIF_REPLY(enif_make_tuple2(env, ATOM_OK, value));
|
2013-04-08 02:16:44 +00:00
|
|
|
__release_cursor(args->conn_handle, worker_id, args->uri, cursor);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Store a value for the key's value from the specified table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] key as an Erlang binary
|
|
|
|
* argv[3] value as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_put,
|
2013-04-02 13:42:07 +00:00
|
|
|
{ // struct
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
Uri uri;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
ERL_NIF_TERM value;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 4 &&
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
2013-04-02 13:42:07 +00:00
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]) &&
|
|
|
|
enif_is_binary(env, argv[3]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
|
|
|
args->value = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[3]);
|
2013-04-06 15:05:41 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
ErlNifBinary key;
|
|
|
|
ErlNifBinary value;
|
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!enif_inspect_binary(env, args->value, &value)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
WT_SESSION *session = NULL;
|
2013-04-06 15:05:41 +00:00
|
|
|
int rc = __session_for(args->conn_handle, worker_id, &session);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WT_CURSOR *cursor = NULL;
|
2013-04-08 02:16:44 +00:00
|
|
|
rc = __retain_cursor(args->conn_handle, worker_id, args->uri, &cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
WT_ITEM item_key;
|
|
|
|
WT_ITEM item_value;
|
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
|
|
|
item_value.data = value.data;
|
|
|
|
item_value.size = value.size;
|
|
|
|
cursor->set_value(cursor, &item_value);
|
2013-04-02 13:42:07 +00:00
|
|
|
rc = cursor->insert(cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-08 02:16:44 +00:00
|
|
|
__release_cursor(args->conn_handle, worker_id, args->uri, cursor);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Open a cursor on a table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlConnHandle resource
|
|
|
|
* argv[1] object name URI string
|
|
|
|
* argv[2] config string as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_open,
|
|
|
|
{ // struct
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle;
|
2013-04-02 13:42:07 +00:00
|
|
|
Uri uri;
|
2013-04-05 22:09:54 +00:00
|
|
|
ERL_NIF_TERM config;
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
if (!(argc == 3 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_conn_RESOURCE, (void**)&args->conn_handle) &&
|
|
|
|
enif_get_string(env, argv[1], args->uri, sizeof args->uri, ERL_NIF_LATIN1) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
2013-04-07 13:21:47 +00:00
|
|
|
args->config = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_keep_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
ErlNifBinary config;
|
2013-04-07 13:21:47 +00:00
|
|
|
if (!enif_inspect_binary(env, args->config, &config)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
|
|
|
/* We create a separate session here to ensure that operations are thread safe. */
|
|
|
|
WT_CONNECTION *conn = args->conn_handle->conn;
|
|
|
|
WT_SESSION *session = NULL;
|
2013-04-11 15:57:41 +00:00
|
|
|
//debugf("cursor open: %s", (char *)args->conn_handle->session_config);
|
2013-04-05 22:09:54 +00:00
|
|
|
int rc = conn->open_session(conn, NULL, args->conn_handle->session_config, &session);
|
|
|
|
if (rc != 0) {
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
2013-04-05 22:09:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WT_CURSOR* cursor;
|
2013-04-07 13:21:47 +00:00
|
|
|
rc = session->open_cursor(session, args->uri, NULL, (config.data[0] != 0) ? (char *)config.data : "overwrite,raw", &cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
ASYNC_NIF_REPLY(__strerror_term(env, rc));
|
|
|
|
return;
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
|
2013-04-08 21:21:48 +00:00
|
|
|
WterlCursorHandle* cursor_handle = enif_alloc_resource(wterl_cursor_RESOURCE, sizeof(WterlCursorHandle));
|
2013-04-05 22:09:54 +00:00
|
|
|
cursor_handle->session = session;
|
|
|
|
cursor_handle->cursor = cursor;
|
|
|
|
ERL_NIF_TERM result = enif_make_resource(env, cursor_handle);
|
|
|
|
enif_release_resource(cursor_handle); // When GC'ed the BEAM calls __resource_cursor_dtor()
|
|
|
|
ASYNC_NIF_REPLY(enif_make_tuple2(env, ATOM_OK, result));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_release_resource((void*)args->conn_handle);
|
2013-04-02 13:42:07 +00:00
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Close a cursor releasing resources it held.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_close,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
2013-04-08 21:21:48 +00:00
|
|
|
WT_CURSOR *cursor = args->cursor_handle->cursor;
|
|
|
|
WT_SESSION *session = args->cursor_handle->session;
|
2013-04-05 22:09:54 +00:00
|
|
|
/* Note: session->close() will cause all open cursors in the session to be
|
|
|
|
closed first, so we don't have explicitly to do that here. */
|
2013-04-08 21:21:48 +00:00
|
|
|
int rc = cursor->close(cursor);
|
|
|
|
(void)session->close(session, NULL);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
static ERL_NIF_TERM
|
|
|
|
__cursor_key_ret(ErlNifEnv *env, WT_CURSOR *cursor, int rc)
|
2012-02-17 00:06:56 +00:00
|
|
|
{
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
WT_ITEM item_key;
|
|
|
|
rc = cursor->get_key(cursor, &item_key);
|
|
|
|
if (rc == 0) {
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
memcpy(enif_make_new_binary(env, item_key.size, &key), item_key.data, item_key.size);
|
|
|
|
return enif_make_tuple2(env, ATOM_OK, key);
|
|
|
|
}
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
return __strerror_term(env, rc);
|
2012-02-17 00:06:56 +00:00
|
|
|
}
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
static ERL_NIF_TERM
|
|
|
|
__cursor_kv_ret(ErlNifEnv *env, WT_CURSOR *cursor, int rc)
|
2012-02-17 00:06:56 +00:00
|
|
|
{
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
WT_ITEM item_key, item_value;
|
|
|
|
rc = cursor->get_key(cursor, &item_key);
|
|
|
|
if (rc == 0) {
|
|
|
|
rc = cursor->get_value(cursor, &item_value);
|
|
|
|
if (rc == 0) {
|
2013-04-02 13:42:07 +00:00
|
|
|
ERL_NIF_TERM key, value;
|
2013-04-05 22:09:54 +00:00
|
|
|
memcpy(enif_make_new_binary(env, item_key.size, &key), item_key.data, item_key.size);
|
|
|
|
memcpy(enif_make_new_binary(env, item_value.size, &value), item_value.data, item_value.size);
|
2013-04-02 13:42:07 +00:00
|
|
|
return enif_make_tuple3(env, ATOM_OK, key, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
return __strerror_term(env, rc);
|
2012-02-17 00:06:56 +00:00
|
|
|
}
|
2013-03-25 01:00:48 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
static ERL_NIF_TERM
|
|
|
|
__cursor_value_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc)
|
2012-02-17 00:06:56 +00:00
|
|
|
{
|
2013-04-05 22:09:54 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
WT_ITEM item_value;
|
|
|
|
rc = cursor->get_value(cursor, &item_value);
|
|
|
|
if (rc == 0) {
|
2013-04-02 13:42:07 +00:00
|
|
|
ERL_NIF_TERM value;
|
2013-04-05 22:09:54 +00:00
|
|
|
memcpy(enif_make_new_binary(env, item_value.size, &value), item_value.data, item_value.size);
|
2013-04-02 13:42:07 +00:00
|
|
|
return enif_make_tuple2(env, ATOM_OK, value);
|
|
|
|
}
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
return __strerror_term(env, rc);
|
2012-02-17 00:06:56 +00:00
|
|
|
}
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Use a cursor to fetch the next key/value pair from the table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_next,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__cursor_kv_ret(env, cursor, cursor->next(cursor)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Use a cursor to fetch the next key from the table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_next_key,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__cursor_key_ret(env, cursor, cursor->next(cursor)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Use a cursor to fetch the next value from the table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_next_value,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__cursor_value_ret(env, cursor, cursor->next(cursor)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Use a cursor to fetch the previous key/value pair from the table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_prev,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__cursor_kv_ret(env, cursor, cursor->prev(cursor)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Use a cursor to fetch the previous key from the table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_prev_key,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__cursor_key_ret(env, cursor, cursor->prev(cursor)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Use a cursor to fetch the previous value from the table or index.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_prev_value,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__cursor_value_ret(env, cursor, cursor->prev(cursor)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Position the cursor at the record matching the key.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_search,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 2 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle) &&
|
|
|
|
enif_is_binary(env, argv[1]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[1]);
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
|
|
|
ErlNifBinary key;
|
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_ITEM item_key;
|
2013-04-02 13:42:07 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
2013-04-02 13:42:07 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(__cursor_value_ret(env, cursor, cursor->search(cursor)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Position the cursor at the record matching the key if it exists, or a record
|
|
|
|
* that would be adjacent.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_search_near,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 2 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle) &&
|
|
|
|
enif_is_binary(env, argv[1]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[1]);
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
|
|
|
ErlNifBinary key;
|
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_ITEM item_key;
|
2013-04-02 13:42:07 +00:00
|
|
|
int exact;
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
2013-04-02 13:42:07 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
// TODO: We currently ignore the less-than, greater-than or equals-to
|
|
|
|
// return information from the cursor.search_near method.
|
|
|
|
ASYNC_NIF_REPLY(__cursor_value_ret(env, cursor, cursor->search_near(cursor, &exact)));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Reset the position of the cursor.
|
|
|
|
*
|
|
|
|
* Any resources held by the cursor are released, and the cursor's key and
|
|
|
|
* position are no longer valid. A subsequent iteration with wterl_cursor_next
|
|
|
|
* will move to the first record, or with wterl_cursor_prev will move to the
|
|
|
|
* last record.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_reset,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 1 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
|
|
|
int rc = cursor->reset(cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Insert, or overwrite, a record using a cursor.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
* argv[1] key as an Erlang binary
|
|
|
|
* argv[2] value as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_insert,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
ERL_NIF_TERM value;
|
|
|
|
int rc;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 3 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle) &&
|
|
|
|
enif_is_binary(env, argv[1]) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[1]);
|
|
|
|
args->value = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
|
|
|
ErlNifBinary key;
|
|
|
|
ErlNifBinary value;
|
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!enif_inspect_binary(env, args->value, &value)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_ITEM item_key;
|
|
|
|
WT_ITEM item_value;
|
|
|
|
|
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
|
|
|
item_value.data = value.data;
|
|
|
|
item_value.size = value.size;
|
|
|
|
cursor->set_value(cursor, &item_value);
|
2013-04-02 13:42:07 +00:00
|
|
|
int rc = cursor->insert(cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Update an existing record using a cursor.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
* argv[1] key as an Erlang binary
|
|
|
|
* argv[2] value as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_update,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
ERL_NIF_TERM value;
|
|
|
|
int rc;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 3 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle) &&
|
|
|
|
enif_is_binary(env, argv[1]) &&
|
|
|
|
enif_is_binary(env, argv[2]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[1]);
|
|
|
|
args->value = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[2]);
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
|
|
|
ErlNifBinary key;
|
|
|
|
ErlNifBinary value;
|
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!enif_inspect_binary(env, args->value, &value)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_ITEM item_key;
|
|
|
|
WT_ITEM item_value;
|
|
|
|
|
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
|
|
|
item_value.data = value.data;
|
|
|
|
item_value.size = value.size;
|
|
|
|
cursor->set_value(cursor, &item_value);
|
2013-04-02 13:42:07 +00:00
|
|
|
int rc = cursor->update(cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Remove a record using a cursor.
|
|
|
|
*
|
|
|
|
* argv[0] WterlCursorHandle resource
|
|
|
|
* argv[1] key as an Erlang binary
|
|
|
|
*/
|
2013-04-02 13:42:07 +00:00
|
|
|
ASYNC_NIF_DECL(
|
|
|
|
wterl_cursor_remove,
|
|
|
|
{ // struct
|
|
|
|
|
|
|
|
WterlCursorHandle *cursor_handle;
|
|
|
|
ERL_NIF_TERM key;
|
|
|
|
int rc;
|
|
|
|
},
|
|
|
|
{ // pre
|
|
|
|
|
|
|
|
if (!(argc == 2 &&
|
|
|
|
enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&args->cursor_handle) &&
|
|
|
|
enif_is_binary(env, argv[1]))) {
|
|
|
|
ASYNC_NIF_RETURN_BADARG();
|
|
|
|
}
|
|
|
|
args->key = enif_make_copy(ASYNC_NIF_WORK_ENV, argv[1]);
|
|
|
|
enif_keep_resource((void*)args->cursor_handle);
|
|
|
|
},
|
|
|
|
{ // work
|
|
|
|
|
|
|
|
WT_CURSOR* cursor = args->cursor_handle->cursor;
|
|
|
|
ErlNifBinary key;
|
|
|
|
if (!enif_inspect_binary(env, args->key, &key)) {
|
|
|
|
ASYNC_NIF_REPLY(enif_make_badarg(env));
|
|
|
|
return;
|
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
WT_ITEM item_key;
|
2013-04-02 13:42:07 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
item_key.data = key.data;
|
|
|
|
item_key.size = key.size;
|
|
|
|
cursor->set_key(cursor, &item_key);
|
2013-04-02 13:42:07 +00:00
|
|
|
int rc = cursor->remove(cursor);
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_REPLY(rc == 0 ? ATOM_OK : __strerror_term(env, rc));
|
2013-04-02 13:42:07 +00:00
|
|
|
},
|
|
|
|
{ // post
|
|
|
|
|
|
|
|
enif_release_resource((void*)args->cursor_handle);
|
|
|
|
});
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
/**
|
|
|
|
* Called when the resource handle is about to be garbage collected.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
__resource_conn_dtor(ErlNifEnv *env, void *obj)
|
|
|
|
{
|
2013-04-08 02:16:44 +00:00
|
|
|
int i;
|
2013-04-05 22:09:54 +00:00
|
|
|
WterlConnHandle *conn_handle = (WterlConnHandle *)obj;
|
|
|
|
/* Free up the shared sessions and cursors. */
|
|
|
|
enif_mutex_lock(conn_handle->context_mutex);
|
2013-04-06 15:14:23 +00:00
|
|
|
for (i = 0; i < conn_handle->num_contexts; i++) {
|
2013-04-06 15:05:41 +00:00
|
|
|
WterlCtx *ctx = &conn_handle->contexts[i];
|
2013-04-11 15:57:41 +00:00
|
|
|
WT_SESSION *session = ctx->session;
|
|
|
|
khash_t(cursors) *h = ctx->cursors;
|
|
|
|
khiter_t itr;
|
|
|
|
for (itr = kh_begin(h); itr != kh_end(h); ++itr) {
|
|
|
|
if (kh_exist(h, itr)) {
|
|
|
|
WT_CURSOR *cursor = kh_val(h, itr);
|
|
|
|
enif_free(kh_key(h, itr));
|
|
|
|
cursor->close(cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kh_destroy(cursors, h);
|
|
|
|
session->close(session, NULL);
|
2013-04-06 15:05:41 +00:00
|
|
|
}
|
2013-04-05 22:09:54 +00:00
|
|
|
enif_mutex_unlock(conn_handle->context_mutex);
|
|
|
|
enif_mutex_destroy(conn_handle->context_mutex);
|
2013-04-06 21:19:59 +00:00
|
|
|
if (conn_handle->session_config)
|
2013-04-11 15:57:41 +00:00
|
|
|
enif_free((void *)conn_handle->session_config);
|
2013-04-05 22:09:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called as this driver is loaded by the Erlang BEAM runtime triggered by the
|
|
|
|
* module's on_load directive.
|
|
|
|
*
|
|
|
|
* env the NIF environment
|
|
|
|
* priv_data used to hold the state for this NIF rather than global variables
|
|
|
|
* load_info an Erlang term, in this case a list with two two-tuples of the
|
|
|
|
* form: [{wterl, ""}, {wiredtiger, ""}] where the strings contain
|
|
|
|
* the git hash of the last commit for this code. This is used
|
|
|
|
* to determin if a rolling upgrade is possible or not.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
on_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info)
|
2011-12-22 04:46:35 +00:00
|
|
|
{
|
|
|
|
ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
|
2013-04-05 22:09:54 +00:00
|
|
|
wterl_conn_RESOURCE = enif_open_resource_type(env, NULL, "wterl_conn_resource",
|
|
|
|
__resource_conn_dtor, flags, NULL);
|
|
|
|
wterl_cursor_RESOURCE = enif_open_resource_type(env, NULL, "wterl_cursor_resource",
|
|
|
|
NULL, flags, NULL);
|
|
|
|
|
2011-12-22 04:46:35 +00:00
|
|
|
ATOM_ERROR = enif_make_atom(env, "error");
|
2012-02-08 22:31:16 +00:00
|
|
|
ATOM_OK = enif_make_atom(env, "ok");
|
2013-04-05 22:09:54 +00:00
|
|
|
ATOM_NOT_FOUND = enif_make_atom(env, "not_found");
|
2013-04-11 15:57:41 +00:00
|
|
|
ATOM_FIRST = enif_make_atom(env, "first");
|
|
|
|
ATOM_LAST = enif_make_atom(env, "last");
|
2013-04-02 13:42:07 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
*priv_data = ASYNC_NIF_LOAD();
|
2013-04-02 13:42:07 +00:00
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
return *priv_data ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
static int
|
|
|
|
on_reload(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info)
|
2013-04-05 22:09:54 +00:00
|
|
|
{
|
2013-04-06 15:05:41 +00:00
|
|
|
return 0; // TODO: determine what should be done here, if anything...
|
2011-12-22 04:46:35 +00:00
|
|
|
}
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
static void
|
|
|
|
on_unload(ErlNifEnv *env, void *priv_data)
|
2013-04-02 13:42:07 +00:00
|
|
|
{
|
2013-04-05 22:09:54 +00:00
|
|
|
ASYNC_NIF_UNLOAD(env);
|
2013-04-02 13:42:07 +00:00
|
|
|
}
|
|
|
|
|
2013-04-06 15:05:41 +00:00
|
|
|
static int
|
|
|
|
on_upgrade(ErlNifEnv *env, void **priv_data, void **old_priv_data, ERL_NIF_TERM load_info)
|
2013-04-02 13:42:07 +00:00
|
|
|
{
|
2013-04-06 15:05:41 +00:00
|
|
|
ASYNC_NIF_UPGRADE(env);
|
2013-04-02 13:42:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ErlNifFunc nif_funcs[] =
|
|
|
|
{
|
2013-04-05 22:09:54 +00:00
|
|
|
{"checkpoint_nif", 3, wterl_checkpoint},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"conn_close_nif", 2, wterl_conn_close},
|
2013-04-06 21:19:59 +00:00
|
|
|
{"conn_open_nif", 4, wterl_conn_open},
|
2013-04-07 13:21:47 +00:00
|
|
|
{"create_nif", 4, wterl_create},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"delete_nif", 4, wterl_delete},
|
|
|
|
{"drop_nif", 4, wterl_drop},
|
|
|
|
{"get_nif", 4, wterl_get},
|
|
|
|
{"put_nif", 5, wterl_put},
|
|
|
|
{"rename_nif", 5, wterl_rename},
|
|
|
|
{"salvage_nif", 4, wterl_salvage},
|
2013-04-08 02:16:44 +00:00
|
|
|
// TODO: {"txn_begin", 3, wterl_txn_begin},
|
|
|
|
// TODO: {"txn_commit", 3, wterl_txn_commit},
|
|
|
|
// TODO: {"txn_abort", 3, wterl_txn_abort},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"truncate_nif", 6, wterl_truncate},
|
|
|
|
{"upgrade_nif", 4, wterl_upgrade},
|
|
|
|
{"verify_nif", 4, wterl_verify},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"cursor_close_nif", 2, wterl_cursor_close},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"cursor_insert_nif", 4, wterl_cursor_insert},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"cursor_next_key_nif", 2, wterl_cursor_next_key},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"cursor_next_nif", 2, wterl_cursor_next},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"cursor_next_value_nif", 2, wterl_cursor_next_value},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"cursor_open_nif", 4, wterl_cursor_open},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"cursor_prev_key_nif", 2, wterl_cursor_prev_key},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"cursor_prev_nif", 2, wterl_cursor_prev},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"cursor_prev_value_nif", 2, wterl_cursor_prev_value},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"cursor_remove_nif", 3, wterl_cursor_remove},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"cursor_reset_nif", 2, wterl_cursor_reset},
|
2013-04-05 22:09:54 +00:00
|
|
|
{"cursor_search_near_nif", 3, wterl_cursor_search_near},
|
|
|
|
{"cursor_search_nif", 3, wterl_cursor_search},
|
2013-04-02 13:42:07 +00:00
|
|
|
{"cursor_update_nif", 4, wterl_cursor_update},
|
|
|
|
};
|
|
|
|
|
2013-04-05 22:09:54 +00:00
|
|
|
ERL_NIF_INIT(wterl, nif_funcs, &on_load, &on_reload, &on_upgrade, &on_unload);
|