• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "bmbase.c"
2 #include <lmdb.h>
3 #include <unistd.h>
4 #include <errno.h>
5 
6 static_assert(sizeof(size_t) == 8, "sizeof(size_t) == 8 bytes");
7 
8 #define E(expr_, ret_) \
9   if ((rc = (expr_)) != MDB_SUCCESS) { \
10     fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, mdb_strerror(rc)); \
11     return ret_; \
12   }
13 
14 #define B(expr_) E(expr_, 0)
15 
16 #define DEFAULT_DB "lmdb_bench.db"
17 
18 typedef struct BM_LEVELDB {
19   MDB_env *env;
20   MDB_dbi  dbi;
21 } BM_LMDB;
22 
env_setup()23 static void env_setup() {
24   int major, minor, patch;
25   mdb_version(&major, &minor, &patch);
26   fprintf(stderr, " engine: LMDB %d.%d.%d\n", major, minor, patch);
27 }
28 
db_size_bytes(BMCTX * ctx)29 uint64_t db_size_bytes(BMCTX *ctx) {
30   const char *path = bm.param_db ? bm.param_db : DEFAULT_DB;
31   IWP_FILE_STAT fst;
32   iwrc rc = iwp_fstat(path, &fst);
33   if (rc) {
34     iwlog_ecode_error3(rc);
35     return 0;
36   }
37   return fst.size;
38 }
39 
db_open(BMCTX * ctx)40 static void *db_open(BMCTX *ctx) {
41   int rc;
42   if (ctx->db) {
43     return 0; // db is not closed properly
44   }
45   const char *path = bm.param_db ? bm.param_db : DEFAULT_DB;
46   if (ctx->freshdb) { // completely remove db folder
47     rc = unlink(path);
48     if (rc && (errno != ENOENT)) {
49       E(errno, 0);
50     }
51   }
52   MDB_txn *txn;
53   BM_LMDB *bmdb = malloc(sizeof(*bmdb));
54   E(mdb_env_create(&bmdb->env), 0);
55   E(mdb_env_set_maxreaders(bmdb->env, 1), 0);
56   E(mdb_env_set_mapsize(bmdb->env, 1024ULL * 1024 * 1024 * 100), 0); // 100 GB
57   E(mdb_env_open(bmdb->env, path, MDB_FIXEDMAP | MDB_NOSUBDIR | MDB_NOSYNC, 0664), 0);
58   E(mdb_txn_begin(bmdb->env, NULL, 0, &txn), 0);
59   E(mdb_dbi_open(txn, NULL, 0, &bmdb->dbi), 0);
60   E(mdb_txn_commit(txn), 0);
61   return bmdb;
62 }
63 
db_close(BMCTX * ctx)64 static bool db_close(BMCTX *ctx) {
65   int rc;
66   if (!ctx->db) {
67     return false;
68   }
69   BM_LMDB *bmdb = ctx->db;
70   B(mdb_env_sync(bmdb->env, 1));
71   mdb_dbi_close(bmdb->env, bmdb->dbi);
72   mdb_env_close(bmdb->env);
73   free(bmdb);
74   return true;
75 }
76 
db_put(BMCTX * ctx,const IWKV_val * key,const IWKV_val * val,bool sync)77 static bool db_put(BMCTX *ctx, const IWKV_val *key, const IWKV_val *val, bool sync) {
78   int rc;
79   BM_LMDB *bmdb = ctx->db;
80   MDB_txn *txn;
81   MDB_val mkey, mval;
82   mkey.mv_data = key->data;
83   mkey.mv_size = key->size;
84   mval.mv_data = val->data;
85   mval.mv_size = val->size;
86   B(mdb_txn_begin(bmdb->env, NULL, 0, &txn));
87   B(mdb_put(txn, bmdb->dbi, &mkey, &mval, 0));
88   B(mdb_txn_commit(txn));
89   if (sync) {
90     B(mdb_env_sync(bmdb->env, 1));
91   }
92   return true;
93 }
94 
db_get(BMCTX * ctx,const IWKV_val * key,IWKV_val * val,bool * found)95 static bool db_get(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found) {
96   int rc;
97   MDB_txn *txn;
98   MDB_val mkey, mval;
99   BM_LMDB *bmdb = ctx->db;
100   mkey.mv_data = key->data;
101   mkey.mv_size = key->size;
102   B(mdb_txn_begin(bmdb->env, NULL, MDB_RDONLY, &txn));
103   rc = mdb_get(txn, bmdb->dbi, &mkey, &mval);
104   if (!rc) {
105     *found = true;
106     val->size = mval.mv_size;
107     val->data = malloc(val->size);
108     memcpy(val->data, mval.mv_data, mval.mv_size);
109   } else if (rc == MDB_NOTFOUND) {
110     *found = false;
111     rc = 0;
112   }
113   mdb_txn_abort(txn);
114   B(rc);
115   return true;
116 }
117 
db_del(BMCTX * ctx,const IWKV_val * key,bool sync)118 static bool db_del(BMCTX *ctx, const IWKV_val *key, bool sync) {
119   int rc;
120   MDB_txn *txn;
121   MDB_val mkey;
122   BM_LMDB *bmdb = ctx->db;
123   mkey.mv_data = key->data;
124   mkey.mv_size = key->size;
125   B(mdb_txn_begin(bmdb->env, NULL, 0, &txn));
126   rc = mdb_del(txn, bmdb->dbi, &mkey, 0);
127   if (rc == MDB_NOTFOUND) {
128     rc = 0;
129   }
130   B(mdb_txn_commit(txn));
131   if (sync) {
132     B(mdb_env_sync(bmdb->env, 1));
133   }
134   return true;
135 }
136 
db_read_seq(BMCTX * ctx,bool reverse)137 static bool db_read_seq(BMCTX *ctx, bool reverse) {
138   int rc = 0;
139   MDB_txn *txn;
140   MDB_cursor *cur;
141   MDB_val mkey, mval;
142   BM_LMDB *bmdb = ctx->db;
143   B(mdb_txn_begin(bmdb->env, NULL, MDB_RDONLY, &txn));
144   B(mdb_cursor_open(txn, bmdb->dbi, &cur));
145   B(mdb_cursor_get(cur, &mkey, &mval, reverse ? MDB_LAST : MDB_FIRST));
146   for (int i = 0; i < bm.param_num - 1 && !rc; ++i) {
147     rc = mdb_cursor_get(cur, &mkey, &mval, reverse ? MDB_PREV : MDB_NEXT);
148   }
149   if (rc == MDB_NOTFOUND) {
150     rc = 0;
151   }
152   mdb_cursor_close(cur);
153   mdb_txn_abort(txn);
154   B(rc);
155   return true;
156 }
157 
db_cursor_to_key(BMCTX * ctx,const IWKV_val * key,IWKV_val * val,bool * found)158 static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found) {
159   int rc = 0;
160   MDB_txn *txn;
161   MDB_cursor *cur;
162   MDB_val mkey, mval;
163   BM_LMDB *bmdb = ctx->db;
164   mkey.mv_data = key->data;
165   mkey.mv_size = key->size;
166   B(mdb_txn_begin(bmdb->env, NULL, MDB_RDONLY, &txn));
167   B(mdb_cursor_open(txn, bmdb->dbi, &cur));
168   rc = mdb_cursor_get(cur, &mkey, &mval, MDB_SET);
169   if (rc == MDB_NOTFOUND) {
170     *found = false;
171     val->data = 0;
172     val->size = 0;
173     rc = 0;
174   } else if (!rc) {
175     *found = true;
176     val->data = malloc(mval.mv_size);
177     ;
178     memcpy(val->data, mval.mv_data, mval.mv_size);
179   }
180   mdb_cursor_close(cur);
181   mdb_txn_abort(txn);
182   B(rc);
183   return true;
184 }
185 
main(int argc,char ** argv)186 int main(int argc, char **argv) {
187   if (argc < 1) {
188     return -1;
189   }
190   g_program = argv[0];
191   bm.env_setup = env_setup;
192   bm.db_size_bytes = db_size_bytes;
193   bm.db_open = db_open;
194   bm.db_close = db_close;
195   bm.db_put = db_put;
196   bm.db_get = db_get;
197   bm.db_del = db_del;
198   bm.db_read_seq = db_read_seq;
199   bm.db_cursor_to_key = db_cursor_to_key;
200   if (!bm_bench_run(argc, argv)) {
201     return 1;
202   }
203   return 0;
204 }
205