Skip to content

Commit d8c6ee6

Browse files
author
wulei
committed
layer as dbi: use {layer,key}, instead of key
1 parent 1695fe1 commit d8c6ee6

File tree

5 files changed

+776
-85
lines changed

5 files changed

+776
-85
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ PROJECT_DESCRIPTION = New project
33
PROJECT_VERSION = 0.1.0
44

55
#CFLAGS +=-DMYDEBUG
6+
CFLAGS += -pthread
7+
CFLAGS += -DMDB_DEBUG
68

79
include erlang.mk

c_src/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
static ERL_NIF_TERM ATOM_ERROR;
1111
static ERL_NIF_TERM ATOM_OK;
1212
static ERL_NIF_TERM ATOM_NOT_FOUND;
13+
static ERL_NIF_TERM ATOM_DBI_NOT_FOUND;
1314
static ERL_NIF_TERM ATOM_EXISTS;
1415
static ERL_NIF_TERM ATOM_KEYEXIST;
1516
static ERL_NIF_TERM ATOM_NOTFOUND;

c_src/elmdb_nif.c

Lines changed: 144 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
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"
@@ -22,22 +23,15 @@
2223
goto label; \
2324
} while(0)
2425

26+
KHASH_MAP_INIT_STR(layer, MDB_dbi)
2527

2628
static ErlNifResourceType *lmdbEnvResType;
27-
static ErlNifResourceType *lmdbDbiResType;
2829

2930
typedef 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-
4135
static 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-
6350
static int loads = 0;
6451

6552
static 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);
155181
err2:
156182
mdb_env_close(ctx);
157183
err3:
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

234249
static 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

267301
static 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

279345
static 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

Comments
 (0)