Skip to content

Commit bbde32d

Browse files
author
wulei
committed
rwlock: protect khash-map
1 parent 762a2c8 commit bbde32d

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

c_src/elmdb_nif.c

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <errno.h>
22
#include <string.h>
3+
#include <stdbool.h>
34

45
#include "erl_nif.h"
56
#include <erl_driver.h>
@@ -29,6 +30,8 @@ static ErlNifResourceType *lmdbEnvResType;
2930

3031
typedef struct lmdb_env_s {
3132
MDB_env *env;
33+
34+
ErlNifRWLock* layers_rwlock;
3235
khash_t(layer) *layers;
3336
} lmdb_env_t;
3437

@@ -39,19 +42,24 @@ static void lmdb_close(lmdb_env_t* lmdb) {
3942
DBG("\tfree dbnames & destroy kh");
4043
const char* dbname = NULL;
4144
MDB_dbi dbi;
45+
enif_rwlock_rwlock(lmdb->layers_rwlock);
4246
kh_foreach(lmdb->layers, dbname, dbi, {
4347
DBG("\tfree dbi: %s", dbname);
4448
//mdb_dbi_close(lmdb->env, dbi);
4549
free((void*)dbname);
4650
});
4751
kh_destroy(layer, lmdb->layers);
52+
enif_rwlock_rwunlock(lmdb->layers_rwlock);
4853
lmdb->layers = NULL;
4954
}
5055
if (lmdb->env) {
5156
DBG("\tclose env!");
5257
mdb_env_close(lmdb->env);
5358
lmdb->env = NULL;
5459
}
60+
61+
enif_rwlock_destroy(lmdb->layers_rwlock);
62+
lmdb->layers_rwlock = NULL;
5563
}
5664
}
5765

@@ -187,6 +195,7 @@ static ERL_NIF_TERM elmdb_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
187195

188196
handle->env = ctx;
189197
handle->layers = layers;
198+
handle->layers_rwlock = enif_rwlock_create("khash-lock");
190199
ERL_NIF_TERM term = enif_make_resource(env, handle);
191200
enif_release_resource(handle);
192201
return term;
@@ -239,6 +248,8 @@ static ERL_NIF_TERM elmdb_put(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
239248
MDB_dbi dbi;
240249
char dbname[128] = {0};
241250
memcpy(dbname, layBin.data, layBin.size);
251+
252+
enif_rwlock_rwlock(handle->layers_rwlock);
242253
if (kh_get(layer,handle->layers, dbname) == kh_end(handle->layers)) {
243254
CHECK(mdb_dbi_open(txn, dbname, MDB_CREATE, &dbi), err1);
244255
DBG("the layer(%s) not found, create one(dbi=%d)", dbname, dbi);
@@ -250,6 +261,7 @@ static ERL_NIF_TERM elmdb_put(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
250261
else {
251262
CHECK(mdb_dbi_open(txn, dbname, 0, &dbi), err1);
252263
}
264+
enif_rwlock_rwunlock(handle->layers_rwlock);
253265

254266
ErlNifBinary valTerm;
255267
if (!enif_inspect_binary(env, argv[2], &valTerm)) {
@@ -292,11 +304,13 @@ static ERL_NIF_TERM elmdb_get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
292304
return enif_make_badarg(env);
293305
}
294306

295-
char dbname[128] = {};
307+
char dbname[128] = {0};
296308
memcpy(dbname, layBin.data, layBin.size);
297-
dbname[layBin.size] = '\0';
298-
if (kh_get(layer,handle->layers, dbname) == kh_end(handle->layers)) {
299-
ERR_LOG("no layer found for %s", dbname);
309+
enif_rwlock_rlock(handle->layers_rwlock);
310+
bool created = (kh_get(layer,handle->layers, dbname) != kh_end(handle->layers));
311+
enif_rwlock_runlock(handle->layers_rwlock);
312+
if (!created) {
313+
ERR_LOG("no layer created for %s", dbname);
300314
return enif_raise_exception(env,
301315
enif_make_tuple2(env, ATOM_DBI_NOT_FOUND, laykey[0]));
302316
}
@@ -336,13 +350,71 @@ static ERL_NIF_TERM elmdb_list_layers(ErlNifEnv* env, int argc, const ERL_NIF_TE
336350
ERL_NIF_TERM list = enif_make_list(env, 0);
337351
const char* dbname = NULL;
338352
MDB_dbi dbi;
353+
enif_rwlock_rlock(handle->layers_rwlock);
339354
kh_foreach(handle->layers, dbname, dbi, {
340355
ERL_NIF_TERM hd = enif_make_string(env, dbname, ERL_NIF_LATIN1);
341356
list = enif_make_list_cell(env, hd, list);
342357
});
358+
enif_rwlock_runlock(handle->layers_rwlock);
343359
return list;
344360
}
345361

362+
static ERL_NIF_TERM elmdb_to_map(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
363+
lmdb_env_t *handle = NULL;
364+
if (!enif_get_resource(env, argv[0], lmdbEnvResType, (void**)&handle)) {
365+
return enif_make_badarg(env);
366+
}
367+
if (handle->env == NULL) return enif_raise_exception(env, enif_make_string(env, "closed lmdb", ERL_NIF_LATIN1));
368+
369+
ErlNifBinary layBin;
370+
if (!enif_inspect_iolist_as_binary(env, argv[1], &layBin)) {
371+
return enif_make_badarg(env);
372+
}
373+
char dbname[128] = {0};
374+
memcpy(dbname, layBin.data, layBin.size);
375+
376+
enif_rwlock_rlock(handle->layers_rwlock);
377+
khiter_t k = kh_get(layer, handle->layers, dbname);
378+
enif_rwlock_runlock(handle->layers_rwlock);
379+
380+
int ret;
381+
ERL_NIF_TERM err;
382+
383+
MDB_txn *txn = NULL;
384+
CHECK(mdb_txn_begin(handle->env, NULL, MDB_RDONLY, &txn), err2);
385+
MDB_dbi dbi;
386+
CHECK(mdb_dbi_open(txn, dbname, 0, &dbi), err2);
387+
DBG("open dbi: %d", dbi);
388+
MDB_cursor *cur;
389+
CHECK(mdb_cursor_open(txn, dbi, &cur), err1);
390+
391+
ERL_NIF_TERM map = enif_make_new_map(env);
392+
MDB_val key, val;
393+
MDB_cursor_op op = MDB_FIRST;
394+
int rc;
395+
do {
396+
rc = mdb_cursor_get(cur, &key, &val, op);
397+
ERL_NIF_TERM keyTerm;
398+
unsigned char* ptr = enif_make_new_binary(env, key.mv_size, &keyTerm);
399+
memcpy(ptr, key.mv_data, key.mv_size);
400+
ERL_NIF_TERM valTerm;
401+
ptr = enif_make_new_binary(env, val.mv_size, &valTerm);
402+
memcpy(ptr, val.mv_data, val.mv_size);
403+
enif_make_map_put(env, map, keyTerm, valTerm, &map);
404+
op = MDB_NEXT;
405+
} while (rc != MDB_NOTFOUND);
406+
mdb_cursor_close(cur);
407+
mdb_dbi_close(handle->env, dbi);
408+
mdb_txn_abort(txn);
409+
return map;
410+
411+
err1:
412+
mdb_dbi_close(handle->env, dbi);
413+
err2:
414+
mdb_txn_abort(txn);
415+
return err;
416+
}
417+
346418
static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
347419
lmdb_env_t *handle = NULL;
348420
if (!enif_get_resource(env, argv[0], lmdbEnvResType, (void**)&handle)) {
@@ -395,6 +467,7 @@ static ErlNifFunc nif_funcs[] = {
395467
{"put", 3, elmdb_put},
396468
{"get", 2, elmdb_get},
397469
{"list_layers", 1, elmdb_list_layers},
470+
{"to_map", 2, elmdb_to_map},
398471
{"hello", 1, hello}
399472
};
400473

src/elmdb.erl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
-module(elmdb).
22

33
-export([hello/1]).
4+
-export([to_map/2]).
45
-export([init/1]).
56
-export([close/1]).
67
-export([put/3]).
@@ -21,6 +22,9 @@ on_load() ->
2122
hello(_) ->
2223
erlang:nif_error({not_loaded, ?MODULE}).
2324

25+
to_map(_Reference, _Layer) ->
26+
erlang:nif_error({not_loaded, ?MODULE}).
27+
2428
-spec init(filelib:dirname()) -> reference().
2529
init(_) ->
2630
erlang:nif_error({not_loaded, ?MODULE}).

0 commit comments

Comments
 (0)