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
3031typedef 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+
346418static 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
0 commit comments