diff --git a/c_src/wterl.c b/c_src/wterl.c index 747f753..068e871 100644 --- a/c_src/wterl.c +++ b/c_src/wterl.c @@ -46,7 +46,8 @@ typedef struct WT_CURSOR* cursor; } wterl_cursor_handle; -typedef char TableName[128]; +typedef char Config[256]; // configuration strings +typedef char Uri[128]; // object names // Atoms (initialized in on_load) static ERL_NIF_TERM ATOM_ERROR; @@ -61,6 +62,7 @@ static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_N static ERL_NIF_TERM wterl_cursor_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_cursor_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc); static ERL_NIF_TERM wterl_cursor_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_search_near(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near); @@ -71,6 +73,12 @@ static ERL_NIF_TERM wterl_session_drop(ErlNifEnv* env, int argc, const ERL_NIF_T static ERL_NIF_TERM wterl_session_get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_put(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_session_rename(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_session_salvage(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_session_sync(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_session_truncate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_session_upgrade(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_session_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ErlNifFunc nif_funcs[] = { @@ -90,37 +98,47 @@ static ErlNifFunc nif_funcs[] = {"session_get", 3, wterl_session_get}, {"session_open", 1, wterl_session_open}, {"session_put", 4, wterl_session_put}, + {"session_rename", 4, wterl_session_rename}, + {"session_salvage", 3, wterl_session_salvage}, + {"session_sync", 3, wterl_session_sync}, + {"session_truncate", 3, wterl_session_truncate}, + {"session_upgrade", 3, wterl_session_upgrade}, + {"session_verify", 3, wterl_session_verify}, }; +static inline ERL_NIF_TERM wterl_strerror(ErlNifEnv* env, int rc) +{ + if (rc == WT_NOTFOUND) + return enif_make_tuple2(env, ATOM_ERROR, enif_make_atom(env, "not_found")); + else + return enif_make_tuple2(env, ATOM_ERROR, + enif_make_string(env, wiredtiger_strerror(rc), ERL_NIF_LATIN1)); +} + static ERL_NIF_TERM wterl_conn_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + Config config; char homedir[4096]; - ErlNifBinary configBin; if (enif_get_string(env, argv[0], homedir, sizeof homedir, ERL_NIF_LATIN1) && - enif_inspect_binary(env, argv[1], &configBin)) + enif_get_string(env, argv[1], config, sizeof config, ERL_NIF_LATIN1)) { WT_CONNECTION* conn; - int rc = wiredtiger_open(homedir, NULL, (const char*)configBin.data, &conn); + int rc = wiredtiger_open(homedir, NULL, config, &conn); if (rc == 0) { - wterl_conn_handle* handle = enif_alloc_resource(wterl_conn_RESOURCE, + wterl_conn_handle* conn_handle = enif_alloc_resource(wterl_conn_RESOURCE, sizeof(wterl_conn_handle)); - handle->conn = conn; - ERL_NIF_TERM result = enif_make_resource(env, handle); - enif_release_resource(handle); + conn_handle->conn = conn; + ERL_NIF_TERM result = enif_make_resource(env, conn_handle); + enif_release_resource(conn_handle); return enif_make_tuple2(env, ATOM_OK, result); } else { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); + return wterl_strerror(env, rc); } } - else - { - return enif_make_badarg(env); - } + return enif_make_badarg(env); } static ERL_NIF_TERM wterl_conn_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -132,11 +150,70 @@ static ERL_NIF_TERM wterl_conn_close(ErlNifEnv* env, int argc, const ERL_NIF_TER int rc = conn->close(conn, NULL); if (rc != 0) { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); + return wterl_strerror(env, rc); + } + else { + return ATOM_OK; + } + } + return enif_make_badarg(env); +} + +#define WTERL_OP_CREATE 1 +#define WTERL_OP_DROP 2 +#define WTERL_OP_SALVAGE 3 +#define WTERL_OP_SYNC 4 +#define WTERL_OP_TRUNCATE 5 +#define WTERL_OP_UPGRADE 6 +#define WTERL_OP_VERIFY 7 + +static inline ERL_NIF_TERM wterl_session_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int op) +{ + wterl_session_handle* session_handle; + if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) + { + WT_SESSION* session = session_handle->session; + Uri uri; + Config config; + if (enif_get_string(env, argv[1], uri, sizeof uri, ERL_NIF_LATIN1) && + enif_get_string(env, argv[2], config, sizeof config, ERL_NIF_LATIN1)) + { + int rc; + switch (op) { + case WTERL_OP_CREATE: + rc = session->create(session, uri, config); + break; + case WTERL_OP_DROP: + rc = session->drop(session, uri, config); + break; + case WTERL_OP_SALVAGE: + rc = session->salvage(session, uri, config); + break; + case WTERL_OP_SYNC: + rc = session->sync(session, uri, config); + break; + case WTERL_OP_TRUNCATE: + // Ignore the cursor start/stop form of truncation for now, + // support only the full file truncation. + rc = session->truncate(session, uri, NULL, NULL, config); + break; + case WTERL_OP_UPGRADE: + rc = session->upgrade(session, uri, config); + break; + default: + case WTERL_OP_VERIFY: + rc = session->verify(session, uri, config); + break; + } + if (rc != 0) + { + return wterl_strerror(env, rc); + } + else + { + return ATOM_OK; + } } - return ATOM_OK; } return enif_make_badarg(env); } @@ -151,155 +228,17 @@ static ERL_NIF_TERM wterl_session_open(ErlNifEnv* env, int argc, const ERL_NIF_T int rc = conn->open_session(conn, NULL, NULL, &session); if (rc == 0) { - wterl_session_handle* shandle = enif_alloc_resource(wterl_session_RESOURCE, + wterl_session_handle* session_handle = enif_alloc_resource(wterl_session_RESOURCE, sizeof(wterl_session_handle)); - shandle->session = session; - ERL_NIF_TERM result = enif_make_resource(env, shandle); + session_handle->session = session; + ERL_NIF_TERM result = enif_make_resource(env, session_handle); enif_keep_resource(conn_handle); - enif_release_resource(shandle); + enif_release_resource(session_handle); return enif_make_tuple2(env, ATOM_OK, result); } else { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - } - return enif_make_badarg(env); -} - -static ERL_NIF_TERM wterl_session_get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - wterl_session_handle* session_handle; - if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) - { - WT_SESSION* session = session_handle->session; - TableName table; - ErlNifBinary key; - if (enif_get_string(env, argv[1], table, sizeof table, ERL_NIF_LATIN1) && - enif_inspect_binary(env, argv[2], &key)) - { - WT_CURSOR* cursor; - int rc = session->open_cursor(session, table, NULL, "overwrite,raw", &cursor); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - WT_ITEM raw_key; - raw_key.data = key.data; - raw_key.size = key.size; - cursor->set_key(cursor, &raw_key); - rc = cursor->search(cursor); - if (rc == 0) - { - WT_ITEM raw_value; - rc = cursor->get_value(cursor, &raw_value); - cursor->close(cursor); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - ErlNifBinary value; - enif_alloc_binary(raw_value.size, &value); - memcpy(value.data, raw_value.data, raw_value.size); - return enif_make_tuple2(env, ATOM_OK, enif_make_binary(env, &value)); - } - else - { - cursor->close(cursor); - if (rc == WT_NOTFOUND) - { - return enif_make_tuple2(env, ATOM_ERROR, enif_make_atom(env, "not_found")); - } - else - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - } - } - } - return enif_make_badarg(env); -} - -static ERL_NIF_TERM wterl_session_put(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - wterl_session_handle* session_handle; - if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) - { - WT_SESSION* session = session_handle->session; - TableName table; - ErlNifBinary key, value; - if (enif_get_string(env, argv[1], table, sizeof table, ERL_NIF_LATIN1) && - enif_inspect_binary(env, argv[2], &key) && enif_inspect_binary(env, argv[3], &value)) - { - WT_CURSOR* cursor; - int rc = session->open_cursor(session, table, NULL, "overwrite,raw", &cursor); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - WT_ITEM raw_key, raw_value; - raw_key.data = key.data; - raw_key.size = key.size; - cursor->set_key(cursor, &raw_key); - raw_value.data = value.data; - raw_value.size = value.size; - cursor->set_value(cursor, &raw_value); - rc = cursor->insert(cursor); - cursor->close(cursor); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - return ATOM_OK; - } - } - return enif_make_badarg(env); -} - -static ERL_NIF_TERM wterl_session_delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - wterl_session_handle* session_handle; - if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) - { - WT_SESSION* session = session_handle->session; - TableName table; - ErlNifBinary key; - if (enif_get_string(env, argv[1], table, sizeof table, ERL_NIF_LATIN1) && - enif_inspect_binary(env, argv[2], &key)) - { - WT_CURSOR* cursor; - int rc = session->open_cursor(session, table, NULL, "raw", &cursor); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - WT_ITEM raw_key; - raw_key.data = key.data; - raw_key.size = key.size; - cursor->set_key(cursor, &raw_key); - rc = cursor->remove(cursor); - cursor->close(cursor); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - return ATOM_OK; + return wterl_strerror(env, rc); } } return enif_make_badarg(env); @@ -314,58 +253,185 @@ static ERL_NIF_TERM wterl_session_close(ErlNifEnv* env, int argc, const ERL_NIF_ int rc = session->close(session, NULL); if (rc != 0) { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); + return wterl_strerror(env, rc); } - return ATOM_OK; + else + { + return ATOM_OK; + } } return enif_make_badarg(env); } static ERL_NIF_TERM wterl_session_create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - wterl_session_handle* session_handle; - if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) - { - WT_SESSION* session = session_handle->session; - TableName table; - char config[256]; - if (enif_get_string(env, argv[1], table, sizeof table, ERL_NIF_LATIN1) && - enif_get_string(env, argv[2], config, sizeof config, ERL_NIF_LATIN1)) - { - int rc = session->create(session, table, config); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - return ATOM_OK; - } - } - return enif_make_badarg(env); + return wterl_session_worker(env, argc, argv, WTERL_OP_CREATE); } static ERL_NIF_TERM wterl_session_drop(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_session_worker(env, argc, argv, WTERL_OP_DROP); +} + +static ERL_NIF_TERM wterl_session_rename(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { wterl_session_handle* session_handle; if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) { WT_SESSION* session = session_handle->session; - TableName table; - char config[256]; - if (enif_get_string(env, argv[1], table, sizeof table, ERL_NIF_LATIN1) && - enif_get_string(env, argv[2], config, sizeof config, ERL_NIF_LATIN1)) + Config config; + Uri oldname, newname; + if (enif_get_string(env, argv[1], oldname, sizeof oldname, ERL_NIF_LATIN1) && + enif_get_string(env, argv[2], newname, sizeof newname, ERL_NIF_LATIN1) && + enif_get_string(env, argv[3], config, sizeof config, ERL_NIF_LATIN1)) { - int rc = session->drop(session, table, config); + int rc = session->rename(session, oldname, newname, config); if (rc != 0) { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); + return wterl_strerror(env, rc); } - return ATOM_OK; + else + { + return ATOM_OK; + } + } + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wterl_session_salvage(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_session_worker(env, argc, argv, WTERL_OP_SALVAGE); +} + +static ERL_NIF_TERM wterl_session_sync(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_session_worker(env, argc, argv, WTERL_OP_SYNC); +} + +static ERL_NIF_TERM wterl_session_truncate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_session_worker(env, argc, argv, WTERL_OP_TRUNCATE); +} + +static ERL_NIF_TERM wterl_session_upgrade(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_session_worker(env, argc, argv, WTERL_OP_UPGRADE); +} + +static ERL_NIF_TERM wterl_session_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_session_worker(env, argc, argv, WTERL_OP_VERIFY); +} + +static ERL_NIF_TERM wterl_session_delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + wterl_session_handle* session_handle; + if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) + { + WT_SESSION* session = session_handle->session; + Uri uri; + ErlNifBinary key; + if (enif_get_string(env, argv[1], uri, sizeof uri, ERL_NIF_LATIN1) && + enif_inspect_binary(env, argv[2], &key)) + { + WT_CURSOR* cursor; + int rc = session->open_cursor(session, uri, NULL, "raw", &cursor); + if (rc != 0) + { + return wterl_strerror(env, rc); + } + WT_ITEM raw_key; + raw_key.data = key.data; + raw_key.size = key.size; + cursor->set_key(cursor, &raw_key); + rc = cursor->remove(cursor); + cursor->close(cursor); + if (rc != 0) + { + return wterl_strerror(env, rc); + } + else + { + return ATOM_OK; + } + } + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wterl_session_get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + wterl_session_handle* session_handle; + if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) + { + WT_SESSION* session = session_handle->session; + Uri uri; + ErlNifBinary key; + if (enif_get_string(env, argv[1], uri, sizeof uri, ERL_NIF_LATIN1) && + enif_inspect_binary(env, argv[2], &key)) + { + WT_CURSOR* cursor; + int rc = session->open_cursor(session, uri, NULL, "overwrite,raw", &cursor); + if (rc != 0) + { + return wterl_strerror(env, rc); + } + WT_ITEM raw_key, raw_value; + raw_key.data = key.data; + raw_key.size = key.size; + cursor->set_key(cursor, &raw_key); + rc = cursor->search(cursor); + if (rc == 0) + rc = cursor->get_value(cursor, &raw_value); + (void)cursor->close(cursor); + if (rc == 0) + { + ErlNifBinary value; + enif_alloc_binary(raw_value.size, &value); + memcpy(value.data, raw_value.data, raw_value.size); + return enif_make_tuple2(env, ATOM_OK, enif_make_binary(env, &value)); + } + else + { + return wterl_strerror(env, rc); + } + } + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wterl_session_put(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + wterl_session_handle* session_handle; + if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) + { + WT_SESSION* session = session_handle->session; + Uri uri; + ErlNifBinary key, value; + if (enif_get_string(env, argv[1], uri, sizeof uri, ERL_NIF_LATIN1) && + enif_inspect_binary(env, argv[2], &key) && enif_inspect_binary(env, argv[3], &value)) + { + WT_CURSOR* cursor; + int rc = session->open_cursor(session, uri, NULL, "overwrite,raw", &cursor); + if (rc != 0) + { + return wterl_strerror(env, rc); + } + WT_ITEM raw_key, raw_value; + raw_key.data = key.data; + raw_key.size = key.size; + cursor->set_key(cursor, &raw_key); + raw_value.data = value.data; + raw_value.size = value.size; + cursor->set_value(cursor, &raw_value); + rc = cursor->insert(cursor); + (void)cursor->close(cursor); + if (rc != 0) + { + return wterl_strerror(env, rc); + } + return ATOM_OK; } } return enif_make_badarg(env); @@ -377,158 +443,30 @@ static ERL_NIF_TERM wterl_cursor_open(ErlNifEnv* env, int argc, const ERL_NIF_TE if (enif_get_resource(env, argv[0], wterl_session_RESOURCE, (void**)&session_handle)) { WT_SESSION* session = session_handle->session; - TableName table; WT_CURSOR* cursor; - if (enif_get_string(env, argv[1], table, sizeof table, ERL_NIF_LATIN1)) + Uri uri; + if (enif_get_string(env, argv[1], uri, sizeof uri, ERL_NIF_LATIN1)) { - int rc = session->open_cursor(session, table, NULL, "overwrite,raw", &cursor); + int rc = session->open_cursor(session, uri, NULL, "overwrite,raw", &cursor); if (rc == 0) { - wterl_cursor_handle* handle = enif_alloc_resource(wterl_cursor_RESOURCE, + wterl_cursor_handle* cursor_handle = enif_alloc_resource(wterl_cursor_RESOURCE, sizeof(wterl_cursor_handle)); - handle->cursor = cursor; - ERL_NIF_TERM result = enif_make_resource(env, handle); + cursor_handle->cursor = cursor; + ERL_NIF_TERM result = enif_make_resource(env, cursor_handle); enif_keep_resource(session_handle); - enif_release_resource(handle); - return (enif_make_tuple2(env, ATOM_OK, result)); + enif_release_resource(cursor_handle); + return enif_make_tuple2(env, ATOM_OK, result); } else { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); + return wterl_strerror(env, rc); } } } return enif_make_badarg(env); } -static ERL_NIF_TERM wterl_cursor_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - return (wterl_cursor_np_worker(env, argc, argv, 1)); -} - -static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - return (wterl_cursor_np_worker(env, argc, argv, 0)); -} - -static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int next) -{ - wterl_cursor_handle *cursor_handle; - if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle)) - { - WT_CURSOR* cursor = cursor_handle->cursor; - int rc = next == 1 ? cursor->next(cursor) : cursor->prev(cursor); - if (rc == 0) - { - WT_ITEM raw_value; - rc = cursor->get_value(cursor, &raw_value); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - ErlNifBinary value; - enif_alloc_binary(raw_value.size, &value); - memcpy(value.data, raw_value.data, raw_value.size); - return enif_make_tuple2(env, ATOM_OK, enif_make_binary(env, &value)); - } - else - { - if (rc == WT_NOTFOUND) - { - return enif_make_tuple2(env, ATOM_ERROR, enif_make_atom(env, "not_found")); - } - else - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - } - } - return enif_make_badarg(env); -} - -static ERL_NIF_TERM wterl_cursor_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - return (wterl_cursor_search_worker(env, argc, argv, 0)); -} - -static ERL_NIF_TERM wterl_cursor_search_near(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - return (wterl_cursor_search_worker(env, argc, argv, 1)); -} - -static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near) -{ - wterl_cursor_handle *cursor_handle; - ErlNifBinary key; - if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle) && - enif_inspect_binary(env, argv[1], &key)) - { - WT_CURSOR* cursor = cursor_handle->cursor; - WT_ITEM raw_key; - int exact; - raw_key.data = key.data; - raw_key.size = key.size; - cursor->set_key(cursor, &raw_key); - int rc = near == 1 ? cursor->search_near(cursor, &exact) : cursor->search(cursor); - if (rc == 0) - { - WT_ITEM raw_value; - rc = cursor->get_value(cursor, &raw_value); - if (rc != 0) - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - ErlNifBinary value; - enif_alloc_binary(raw_value.size, &value); - memcpy(value.data, raw_value.data, raw_value.size); - return enif_make_tuple2(env, ATOM_OK, enif_make_binary(env, &value)); - } - else - { - if (rc == WT_NOTFOUND) - { - return enif_make_tuple2(env, ATOM_ERROR, enif_make_atom(env, "not_found")); - } - else - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - } - } - return enif_make_badarg(env); -} - -static ERL_NIF_TERM wterl_cursor_reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - wterl_cursor_handle *cursor_handle; - if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle)) - { - WT_CURSOR* cursor = cursor_handle->cursor; - int rc = cursor->reset(cursor); - if (rc == 0) - { - return ATOM_OK; - } - else - { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); - } - } - return enif_make_badarg(env); -} - static ERL_NIF_TERM wterl_cursor_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { wterl_cursor_handle *cursor_handle; @@ -542,9 +480,97 @@ static ERL_NIF_TERM wterl_cursor_close(ErlNifEnv* env, int argc, const ERL_NIF_T } else { - return enif_make_tuple2(env, ATOM_ERROR, - enif_make_string(env, wiredtiger_strerror(rc), - ERL_NIF_LATIN1)); + return wterl_strerror(env, rc); + } + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wterl_cursor_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc) +{ + if (rc == 0) + { + WT_ITEM raw_value; + rc = cursor->get_value(cursor, &raw_value); + if (rc == 0) + { + ErlNifBinary value; + enif_alloc_binary(raw_value.size, &value); + memcpy(value.data, raw_value.data, raw_value.size); + return enif_make_tuple2(env, ATOM_OK, enif_make_binary(env, &value)); + } + } + return wterl_strerror(env, rc); +} + +static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int prev) +{ + wterl_cursor_handle *cursor_handle; + if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle)) + { + WT_CURSOR* cursor = cursor_handle->cursor; + return wterl_cursor_ret(env, cursor, prev == 0 ? cursor->next(cursor) : cursor->prev(cursor)); + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wterl_cursor_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_cursor_np_worker(env, argc, argv, 0); +} + +static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_cursor_np_worker(env, argc, argv, 1); +} + +static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near) +{ + wterl_cursor_handle *cursor_handle; + ErlNifBinary key; + if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle) && + enif_inspect_binary(env, argv[1], &key)) + { + WT_CURSOR* cursor = cursor_handle->cursor; + WT_ITEM raw_key; + int exact; + raw_key.data = key.data; + raw_key.size = key.size; + cursor->set_key(cursor, &raw_key); + + // We currently ignore the less-than, greater-than or equals-to return information + // from the cursor.search_near method. + return wterl_cursor_ret(env, cursor, + near == 1 ? + cursor->search_near(cursor, &exact) : cursor->search(cursor)); + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wterl_cursor_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_cursor_search_worker(env, argc, argv, 0); +} + +static ERL_NIF_TERM wterl_cursor_search_near(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_cursor_search_worker(env, argc, argv, 1); +} + +static ERL_NIF_TERM wterl_cursor_reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + wterl_cursor_handle *cursor_handle; + if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle)) + { + WT_CURSOR* cursor = cursor_handle->cursor; + int rc = cursor->reset(cursor); + if (rc == 0) + { + return ATOM_OK; + } + else + { + return wterl_strerror(env, rc); } } return enif_make_badarg(env); diff --git a/src/wterl.erl b/src/wterl.erl index f2039de..df5ecc5 100644 --- a/src/wterl.erl +++ b/src/wterl.erl @@ -24,15 +24,6 @@ -export([conn_open/2, conn_close/1, - session_open/1, - session_get/3, - session_put/4, - session_delete/3, - session_close/1, - session_create/2, - session_create/3, - session_drop/2, - session_drop/3, cursor_close/1, cursor_next/1, cursor_open/2, @@ -40,6 +31,27 @@ cursor_reset/1, cursor_search/2, cursor_search_near/2, + session_close/1, + session_create/2, + session_create/3, + session_delete/3, + session_drop/2, + session_drop/3, + session_get/3, + session_open/1, + session_put/4, + session_rename/3, + session_rename/4, + session_salvage/2, + session_salvage/3, + session_sync/2, + session_sync/3, + session_truncate/2, + session_truncate/3, + session_upgrade/2, + session_upgrade/3, + session_verify/2, + session_verify/3, config_to_bin/2]). -on_load(init/0). @@ -72,33 +84,64 @@ conn_close(_ConnRef) -> session_open(_ConnRef) -> ?nif_stub. +session_close(_Ref) -> + ?nif_stub. + +session_create(Ref, Name) -> + session_create(Ref, Name, ""). +session_create(_Ref, _Name, _Config) -> + ?nif_stub. + +session_drop(Ref, Name) -> + session_drop(Ref, Name, ""). +session_drop(_Ref, _Name, _Config) -> + ?nif_stub. + +session_delete(_Ref, _Table, _Key) -> + ?nif_stub. + session_get(_Ref, _Table, _Key) -> ?nif_stub. session_put(_Ref, _Table, _Key, _Value) -> ?nif_stub. -session_delete(_Ref, _Table, _Key) -> +session_rename(Ref, OldName, NewName) -> + session_rename(Ref, OldName, NewName, ""). +session_rename(_Ref, _OldName, _NewName, _Config) -> ?nif_stub. -session_close(_Ref) -> +session_salvage(Ref, Name) -> + session_salvage(Ref, Name, ""). +session_salvage(_Ref, _Name, _Config) -> ?nif_stub. -session_create(Ref, Name) -> - session_create(Ref, Name, ""). - -session_create(_Ref, _Name, _Config) -> +session_sync(Ref, Name) -> + session_sync(Ref, Name, ""). +session_sync(_Ref, _Name, _Config) -> ?nif_stub. -session_drop(Ref, Name) -> - session_drop(Ref, Name, ""). +session_truncate(Ref, Name) -> + session_truncate(Ref, Name, ""). +session_truncate(_Ref, _Name, _Config) -> + ?nif_stub. -session_drop(_Ref, _Name, _Config) -> +session_upgrade(Ref, Name) -> + session_upgrade(Ref, Name, ""). +session_upgrade(_Ref, _Name, _Config) -> + ?nif_stub. + +session_verify(Ref, Name) -> + session_verify(Ref, Name, ""). +session_verify(_Ref, _Name, _Config) -> ?nif_stub. cursor_open(_Ref, _Table) -> ?nif_stub. +cursor_close(_Cursor) -> + ?nif_stub. + cursor_next(_Cursor) -> ?nif_stub. @@ -114,9 +157,6 @@ cursor_search_near(_Cursor, _Key) -> cursor_reset(_Cursor) -> ?nif_stub. -cursor_close(_Cursor) -> - ?nif_stub. - %% %% Configuration type information. %% @@ -180,35 +220,80 @@ config_to_bin([{Key, Value} | Rest], Acc) -> basic_test() -> %% Open a connection and a session, create the test table. - Opts = [{create, true}, {cache_size, "100MB"}], ok = filelib:ensure_dir(filename:join("/tmp/wterl.basic", "foo")), - {ok, ConnRef} = conn_open("/tmp/wterl.basic", config_to_bin(Opts, [])), + + io:put_chars(standard_error, "\topen connection\n"), + {ok, ConnRef} = + conn_open("/tmp/wterl.basic", "create=true,cache_size=100MB"), {ok, SRef} = session_open(ConnRef), - %% Remove the table from any earlier run. + %% Remove the table from any earlier run and re-create it + io:put_chars(standard_error, "\ttable drop/create\n"), ok = session_drop(SRef, "table:test", "force"), - - %% Create the table ok = session_create(SRef, "table:test"), %% Insert/delete a key using the session handle + io:put_chars(standard_error, "\tsession insert/delete\n"), ok = session_put(SRef, "table:test", <<"a">>, <<"apple">>), {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>), ok = session_delete(SRef, "table:test", <<"a">>), {error, not_found} = session_get(SRef, "table:test", <<"a">>), - %% Open/close a cursor - {ok, Cursor} = cursor_open(SRef, "table:test"), - ok = cursor_close(Cursor), - %% Insert some items + io:put_chars(standard_error, "\tsession insert\n"), ok = session_put(SRef, "table:test", <<"a">>, <<"apple">>), ok = session_put(SRef, "table:test", <<"b">>, <<"banana">>), ok = session_put(SRef, "table:test", <<"c">>, <<"cherry">>), ok = session_put(SRef, "table:test", <<"d">>, <<"date">>), ok = session_put(SRef, "table:test", <<"g">>, <<"gooseberry">>), + %% Remaining session operations. + io:put_chars(standard_error, "\tsession verify\n"), + ok = session_verify(SRef, "table:test"), + {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>), + + io:put_chars(standard_error, "\tsession sync\n"), + ok = session_sync(SRef, "table:test"), + {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>), + + %% =================================================================== + %% KEITH: SKIP SALVAGE FOR NOW, THERE IS SOMETHING WRONG. + %% =================================================================== + %% io:put_chars(standard_error, "\tsession salvage\n"), + %% ok = session_salvage(SRef, "table:test"), + %% {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>), + + io:put_chars(standard_error, "\tsession truncate\n"), + ok = session_truncate(SRef, "table:test"), + {error, not_found} = session_get(SRef, "table:test", <<"a">>), + + ok = session_put(SRef, "table:test", <<"a">>, <<"apple">>), + ok = session_put(SRef, "table:test", <<"b">>, <<"banana">>), + ok = session_put(SRef, "table:test", <<"c">>, <<"cherry">>), + ok = session_put(SRef, "table:test", <<"d">>, <<"date">>), + ok = session_put(SRef, "table:test", <<"g">>, <<"gooseberry">>), + + io:put_chars(standard_error, "\tsession upgrade\n"), + ok = session_upgrade(SRef, "table:test"), + {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>), + + io:put_chars(standard_error, "\tsession rename\n"), + ok = session_rename(SRef, "table:test", "table:new"), + {ok, <<"apple">>} = session_get(SRef, "table:new", <<"a">>), + ok = session_rename(SRef, "table:new", "table:test"), + {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>), + + %% Open/close a pair of cursors, check first/last returns + io:put_chars(standard_error, "\tcursor open/close, first/last\n"), + {ok, Cursor1} = cursor_open(SRef, "table:test"), + {ok, <<"apple">>} = cursor_next(Cursor1), + ok = cursor_close(Cursor1), + {ok, Cursor2} = cursor_open(SRef, "table:test"), + {ok, <<"gooseberry">>} = cursor_prev(Cursor2), + ok = cursor_close(Cursor2), + %% Move a cursor back and forth + io:put_chars(standard_error, "\tcursor next/prev\n"), {ok, Cursor} = cursor_open(SRef, "table:test"), {ok, <<"apple">>} = cursor_next(Cursor), {ok, <<"banana">>} = cursor_next(Cursor), @@ -221,16 +306,19 @@ basic_test() -> ok = cursor_close(Cursor), %% Search for an item + io:put_chars(standard_error, "\tcursor search\n"), {ok, Cursor} = cursor_open(SRef, "table:test"), {ok, <<"banana">>} = cursor_search(Cursor, <<"b">>), ok = cursor_close(Cursor), %% Range search for an item + io:put_chars(standard_error, "\tcursor search-near\n"), {ok, Cursor} = cursor_open(SRef, "table:test"), - {ok, <<"gooseberry">>} = cursor_search_near(Cursor, <<"f">>), + {ok, <<"gooseberry">>} = cursor_search_near(Cursor, <<"z">>), ok = cursor_close(Cursor), %% Check that cursor reset works + io:put_chars(standard_error, "\tcursor reset\n"), {ok, Cursor} = cursor_open(SRef, "table:test"), {ok, <<"apple">>} = cursor_next(Cursor), ok = cursor_reset(Cursor), @@ -238,6 +326,7 @@ basic_test() -> ok = cursor_close(Cursor), %% Close the session/connection + io:put_chars(standard_error, "\tsession/connection close\n"), ok = session_close(SRef), ok = conn_close(ConnRef).