44#include "erl_nif.h"
55#include <erl_driver.h>
66
7+ #include "khash.h"
78#include "common.h"
89#include "liblmdb/lmdb.h"
910#include "mylog.h"
2223 goto label; \
2324 } while(0)
2425
26+ KHASH_MAP_INIT_STR (layer , MDB_dbi )
2527
2628static ErlNifResourceType * lmdbEnvResType ;
27- static ErlNifResourceType * lmdbDbiResType ;
2829
2930typedef struct lmdb_env_s {
3031 MDB_env * env ;
32+ khash_t (layer ) * layers ;
3133} lmdb_env_t ;
3234
33- typedef struct lmdb_dbi_s {
34- char name [64 ];
35- lmdb_env_t * lmdb_env ;
36- MDB_txn * txn ;
37- MDB_cursor * cursor ;
38- MDB_dbi dbi ;
39- } lmdb_dbi_t ;
40-
4135static void lmdb_dtor (ErlNifEnv * __attribute__((unused )) env , void * obj ) {
4236 INFO_LOG ("destroy...... lmdb.env -> %p" , obj );
4337 lmdb_env_t * lmdb = (lmdb_env_t * )obj ;
@@ -46,20 +40,13 @@ static void lmdb_dtor(ErlNifEnv* __attribute__((unused)) env, void* obj) {
4640 mdb_env_close (lmdb -> env );
4741 lmdb -> env = NULL ;
4842 }
43+ if (lmdb -> layers ) {
44+ kh_destroy (layer , lmdb -> layers );
45+ lmdb -> layers = NULL ;
46+ }
4947 }
5048}
5149
52- static void lmdb_dbi_dtor (ErlNifEnv * env , void * obj ) {
53- INFO_LOG ("destroy...... lmdb.dbi -> %p" , obj );
54- __UNUSED (env );
55- lmdb_dbi_t * f = (lmdb_dbi_t * )obj ;
56- if (f ) {
57- DBG ("dbi: %u, name: %s" , f -> dbi , f -> name );
58- mdb_dbi_close (f -> lmdb_env -> env , f -> dbi );
59- enif_release_resource (f -> lmdb_env );
60- }
61- }
62-
6350static int loads = 0 ;
6451
6552static int load (ErlNifEnv * env , void * * priv_data , ERL_NIF_TERM load_info )
@@ -73,6 +60,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
7360 ATOM_ERROR = enif_make_atom (env , "error" );
7461 ATOM_OK = enif_make_atom (env , "ok" );
7562 ATOM_NOT_FOUND = enif_make_atom (env , "not_found" );
63+ ATOM_DBI_NOT_FOUND = enif_make_atom (env , "dbi_not_found" );
7664 ATOM_EXISTS = enif_make_atom (env , "exists" );
7765
7866 ATOM_KEYEXIST = enif_make_atom (env , "key_exist" );
@@ -96,8 +84,6 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
9684
9785 lmdbEnvResType = enif_open_resource_type (env , NULL , "lmdb_res" , lmdb_dtor ,
9886 ERL_NIF_RT_CREATE |ERL_NIF_RT_TAKEOVER , NULL );
99- lmdbDbiResType = enif_open_resource_type (env , NULL , "lmdb_dbi_res" , lmdb_dbi_dtor ,
100- ERL_NIF_RT_CREATE |ERL_NIF_RT_TAKEOVER , NULL );
10187
10288 return 0 ;
10389}
@@ -144,84 +130,113 @@ static ERL_NIF_TERM elmdb_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
144130 // The MDB_NOTLS flag changes this for read-only transactions
145131// CHECK(mdb_env_set_flags(handle->env, MDB_NOTLS, 1), err2);
146132
133+ MDB_txn * txn = NULL ;
134+ CHECK (mdb_txn_begin (ctx , NULL , MDB_RDONLY , & txn ), err2 );
135+ MDB_dbi dbi ;
136+ CHECK (mdb_dbi_open (txn , NULL , 0 , & dbi ), err1 );
137+ MDB_cursor * cursor ;
138+ CHECK (mdb_cursor_open (txn , dbi , & cursor ), err2 );
139+
140+ khash_t (layer ) * layers = kh_init (layer );
141+ MDB_val key , val ;
142+ while (mdb_cursor_get (cursor , & key , NULL , MDB_NEXT_NODUP ) == 0 ) {
143+ if (memchr (key .mv_data , '\0' , key .mv_size ))
144+ continue ;
145+ char * str = malloc (key .mv_size + 1 );
146+ memcpy (str , key .mv_data , key .mv_size );
147+ DBG ("key: sz=%d, len=%d" , key .mv_size , strlen (key .mv_data ));
148+ str [key .mv_size ] = '\0' ;
149+ MDB_dbi db2 ;
150+ if (mdb_dbi_open (txn , str , 0 , & db2 ) == MDB_SUCCESS ) {
151+ INFO_LOG ("dbi --> %s => %d" , str , db2 );
152+ int absent = 0 ;
153+ khiter_t k = kh_put (layer , layers , str , & absent );
154+ if (absent ) {
155+ kh_key (layers , k ) = str ;
156+ }
157+ else {
158+ free (str );
159+ }
160+ kh_value (layers , k ) = 0 ; // TODO: some value for each layer
161+ mdb_dbi_close (ctx , db2 );
162+ }
163+ else {
164+ WARN_LOG ("not a dbi: %s" , str );
165+ }
166+ }
167+ mdb_cursor_close (cursor );
168+ mdb_txn_abort (txn );
169+
147170 lmdb_env_t * handle = enif_alloc_resource (lmdbEnvResType , sizeof (* handle ));
148- if (handle == NULL ) FAIL_ERR (ENOMEM , err3 );
171+ if (handle == NULL ) FAIL_ERR (ENOMEM , err1 );
149172
150173 handle -> env = ctx ;
174+ handle -> layers = layers ;
151175 ERL_NIF_TERM term = enif_make_resource (env , handle );
152176 enif_release_resource (handle );
153177 return term ;
154178
179+ err1 :
180+ kh_destroy (layer , layers );
155181err2 :
156182 mdb_env_close (ctx );
157183err3 :
158184 return err ;
159185}
160186
161- static ERL_NIF_TERM elmdb_open (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
187+ static ERL_NIF_TERM elmdb_put (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
162188 lmdb_env_t * handle = NULL ;
163189 if (!enif_get_resource (env , argv [0 ], lmdbEnvResType , (void * * )& handle )) {
164190 return enif_make_badarg (env );
165191 }
166-
167- char dbname [128 ];
168- if (!enif_get_string (env , argv [1 ], dbname , sizeof (dbname ), ERL_NIF_LATIN1 )) {
192+
193+ const ERL_NIF_TERM * laykey = NULL ;
194+ int arity = 0 ;
195+ if (!enif_get_tuple (env , argv [1 ], & arity , & laykey )) {
196+ return enif_make_badarg (env );
197+ }
198+ ErlNifBinary layBin ;
199+ ErlNifBinary keyBin ;
200+ if (arity != 2 ||
201+ !enif_inspect_iolist_as_binary (env , laykey [0 ], & layBin ) ||
202+ !enif_inspect_binary (env , laykey [1 ], & keyBin )) {
169203 return enif_make_badarg (env );
170204 }
171205
172206 int ret ;
173207 ERL_NIF_TERM err ;
174208
175- MDB_dbi dbi ;
176209 MDB_txn * txn = NULL ;
177- CHECK (mdb_txn_begin (handle -> env , NULL , 0 , & txn ), err2 );
178- unsigned int dbFlags = MDB_CREATE ;
179- CHECK (mdb_dbi_open (txn , dbname , dbFlags , & dbi ), err1 );
180- CHECK (mdb_txn_commit (txn ), err1 );
181- lmdb_dbi_t * family = enif_alloc_resource (lmdbDbiResType , sizeof (* family ));
182- if (family == NULL ) FAIL_ERR (ENOMEM , err2 );
183- * family = (lmdb_dbi_t ) {
184- .lmdb_env = handle ,
185- .dbi = dbi
186- };
187- strncpy (family -> name , dbname , strlen (dbname ) + 1 );
188- ERL_NIF_TERM res = enif_make_resource (env , family );
189- enif_release_resource (family );
190- enif_keep_resource (handle );
191-
192- return res ;
193-
194- err1 :
195- mdb_txn_abort (txn );
196- err2 :
197- return err ;
198- }
210+ CHECK (mdb_txn_begin (handle -> env , NULL , 0 , & txn ), err1 );
199211
200- static ERL_NIF_TERM elmdb_put (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
201- lmdb_dbi_t * dbihandle = NULL ;
202- if (!enif_get_resource (env , argv [0 ], lmdbDbiResType , (void * * )& dbihandle )) {
203- return enif_make_badarg (env );
212+ MDB_dbi dbi ;
213+ char dbname [128 ] = {};
214+ memcpy (dbname , layBin .data , layBin .size );
215+ dbname [layBin .size ] = '\0' ;
216+ if (kh_get (layer ,handle -> layers , dbname ) == kh_end (handle -> layers )) {
217+ DBG ("the layer(%s) not found, create one" , dbname );
218+ CHECK (mdb_dbi_open (txn , dbname , MDB_CREATE , & dbi ), err1 );
219+ int absent = 0 ;
220+ khiter_t k = kh_put (layer , handle -> layers , dbname , & absent );
221+ if (absent ) kh_key (handle -> layers , k ) = strndup (dbname , sizeof (dbname ));
222+ kh_value (handle -> layers , k ) = dbi ;
204223 }
205- ErlNifBinary keyTerm ;
224+ else {
225+ CHECK (mdb_dbi_open (txn , dbname , 0 , & dbi ), err1 );
226+ }
227+
206228 ErlNifBinary valTerm ;
207- if (!enif_inspect_binary (env , argv [1 ], & keyTerm ) ||
208- !enif_inspect_binary (env , argv [2 ], & valTerm )) {
229+ if (!enif_inspect_binary (env , argv [2 ], & valTerm )) {
209230 return enif_make_badarg (env );
210231 }
211232
212- int ret ;
213- ERL_NIF_TERM err ;
214-
215- MDB_txn * txn = NULL ;
216- CHECK (mdb_txn_begin (dbihandle -> lmdb_env -> env , NULL , 0 , & txn ), err1 );
217-
218233 MDB_val key , val ;
219- key .mv_size = keyTerm .size ;
220- key .mv_data = keyTerm .data ;
234+ key .mv_size = keyBin .size ;
235+ key .mv_data = keyBin .data ;
221236 val .mv_size = valTerm .size ;
222237 val .mv_data = valTerm .data ;
223238
224- mdb_put (txn , dbihandle -> dbi , & key , & val , MDB_NOOVERWRITE );
239+ mdb_put (txn , dbi , & key , & val , MDB_NOOVERWRITE );
225240 CHECK (mdb_txn_commit (txn ), err2 );
226241 return argv [0 ];
227242
@@ -232,26 +247,45 @@ static ERL_NIF_TERM elmdb_put(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
232247}
233248
234249static ERL_NIF_TERM elmdb_get (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
235- lmdb_dbi_t * dbihandle = NULL ;
236- if (!enif_get_resource (env , argv [0 ], lmdbDbiResType , (void * * )& dbihandle )) {
250+ lmdb_env_t * handle = NULL ;
251+ if (!enif_get_resource (env , argv [0 ], lmdbEnvResType , (void * * )& handle )) {
237252 return enif_make_badarg (env );
238253 }
239254
240- ErlNifBinary keyTerm ;
241- if (!enif_inspect_binary (env , argv [1 ], & keyTerm )) {
255+ const ERL_NIF_TERM * laykey = NULL ;
256+ int arity = 0 ;
257+ if (!enif_get_tuple (env , argv [1 ], & arity , & laykey )) {
258+ return enif_make_badarg (env );
259+ }
260+ ErlNifBinary layBin ;
261+ ErlNifBinary keyBin ;
262+ if (arity != 2 ||
263+ !enif_inspect_iolist_as_binary (env , laykey [0 ], & layBin ) ||
264+ !enif_inspect_binary (env , laykey [1 ], & keyBin )) {
242265 return enif_make_badarg (env );
243266 }
244267
268+ char dbname [128 ] = {};
269+ memcpy (dbname , layBin .data , layBin .size );
270+ dbname [layBin .size ] = '\0' ;
271+ if (kh_get (layer ,handle -> layers , dbname ) == kh_end (handle -> layers )) {
272+ ERR_LOG ("no layer found for %s" , dbname );
273+ return enif_raise_exception (env ,
274+ enif_make_tuple2 (env , ATOM_DBI_NOT_FOUND , laykey [0 ]));
275+ }
276+
245277 int ret ;
246278 ERL_NIF_TERM err ;
247279
248280 MDB_txn * txn = NULL ;
249- CHECK (mdb_txn_begin (dbihandle -> lmdb_env -> env , NULL , MDB_RDONLY , & txn ), err1 );
281+ CHECK (mdb_txn_begin (handle -> env , NULL , MDB_RDONLY , & txn ), err1 );
282+ MDB_dbi dbi ;
283+ CHECK (mdb_dbi_open (txn , dbname , 0 , & dbi ), err1 );
250284
251285 MDB_val key , val ;
252- key .mv_size = keyTerm .size ;
253- key .mv_data = keyTerm .data ;
254- CHECK ( mdb_get (txn , dbihandle -> dbi , & key , & val ), err1 );
286+ key .mv_size = keyBin .size ;
287+ key .mv_data = keyBin .data ;
288+ CHECK ( mdb_get (txn , dbi , & key , & val ), err1 );
255289 mdb_txn_abort (txn );
256290
257291 ERL_NIF_TERM res ;
@@ -265,20 +299,51 @@ static ERL_NIF_TERM elmdb_get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
265299}
266300
267301static ERL_NIF_TERM hello (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
268- if (enif_is_atom (env , argv [0 ])) {
269- return enif_make_tuple2 (env ,
270- enif_make_atom (env , "hello" ),
271- argv [0 ]);
302+ lmdb_env_t * handle = NULL ;
303+ if (!enif_get_resource (env , argv [0 ], lmdbEnvResType , (void * * )& handle )) {
304+ return enif_make_badarg (env );
305+ }
306+
307+ int ret ;
308+ ERL_NIF_TERM err ;
309+
310+ MDB_txn * txn = NULL ;
311+ CHECK (mdb_txn_begin (handle -> env , NULL , MDB_RDONLY , & txn ), err2 );
312+ for (khiter_t k = kh_begin (handle -> layers ); k < kh_end (handle -> layers ); ++ k ) {
313+ if (kh_exist (handle -> layers , k )) {
314+ const char * dbname = kh_key (handle -> layers , k );
315+ INFO_LOG ("dbi: [%s] -> " , dbname );
316+ MDB_dbi dbi ;
317+ CHECK (mdb_dbi_open (txn , dbname , 0 , & dbi ), err1 );
318+ MDB_cursor * cursor = NULL ;
319+ mdb_cursor_open (txn , dbi , & cursor );
320+ MDB_val key , value ;
321+ int rc = 0 ;
322+ while ((rc = mdb_cursor_get (cursor , & key , & value , MDB_NEXT )) == 0 ) {
323+ DBG ("key: %.*s => value: %.*s" , (int )key .mv_size , (char * )key .mv_data , (int )value .mv_size , (char * )value .mv_data );
324+ }
325+ if (rc == MDB_NOTFOUND ) {
326+ INFO_LOG ("Gotcha you, last one" );
327+ }
328+ else ERR_LOG ("found one ret: %T" , __strerror_term (env , rc ));
329+ mdb_cursor_close (cursor );
330+ mdb_dbi_close (handle -> env , dbi );
331+ }
272332 }
333+ mdb_txn_abort (txn );
273334
274335 return enif_make_tuple2 (env ,
275336 enif_make_atom (env , "error" ),
276337 enif_make_atom (env , "badarg" ));
338+
339+ err1 :
340+ mdb_txn_abort (txn );
341+ err2 :
342+ return err ;
277343}
278344
279345static ErlNifFunc nif_funcs [] = {
280346 {"init" , 1 , elmdb_init },
281- {"open" , 2 , elmdb_open },
282347 {"put" , 3 , elmdb_put },
283348 {"get" , 2 , elmdb_get },
284349 {"hello" , 1 , hello }
0 commit comments