1 #include "bmbase.c"
2 #include <db.h>
3 
4 #define DEFAULT_DB "bdb_bench.db"
5 
6 
7 typedef struct BM_BDB {
8   DB *dbp;
9 } BM_BDB;
10 
env_setup()11 static void env_setup() {
12   fprintf(stderr, " engine: %s\n", DB_VERSION_STRING);
13 }
14 
db_size_bytes(BMCTX * ctx)15 static uint64_t db_size_bytes(BMCTX *ctx) {
16   const char *path = bm.param_db ? bm.param_db : DEFAULT_DB;
17   IWP_FILE_STAT fst;
18   iwrc rc = iwp_fstat(path, &fst);
19   if (rc) {
20     iwlog_ecode_error3(rc);
21     return 0;
22   }
23   return fst.size;
24 }
25 
val_free(void * data)26 static void val_free(void *data) {
27   free(data);
28 }
29 
db_open(BMCTX * ctx)30 static void *db_open(BMCTX *ctx) {
31   if (ctx->db) {
32     return 0; // db is not closed properly
33   }
34   const char *path = bm.param_db ? bm.param_db : DEFAULT_DB;
35   BM_BDB *bmdb = malloc(sizeof(*bmdb));
36   int ret = db_create(&bmdb->dbp, 0, 0);
37   if (ret) {
38     fprintf(stderr, "db_create: %s\n", db_strerror(ret));
39     free(bmdb);
40     return 0;
41   }
42   int32_t mode = DB_CREATE;
43   if (ctx->freshdb) {
44     mode |= DB_TRUNCATE;
45   }
46   ret = bmdb->dbp->open(bmdb->dbp, 0, path, 0, DB_BTREE, mode, 0664);
47   if (ret) {
48     fprintf(stderr, "db_open: %s\n", db_strerror(ret));
49     free(bmdb);
50     return 0;
51   }
52   return bmdb;
53 }
54 
db_close(BMCTX * ctx)55 static bool db_close(BMCTX *ctx) {
56   if (!ctx->db) {
57     return false;
58   }
59   BM_BDB *bmdb = ctx->db;
60   int ret = bmdb->dbp->close(bmdb->dbp, 0);
61   if (ret) {
62     fprintf(stderr, "db_close: %s\n", db_strerror(ret));
63     return false;
64   }
65   free(bmdb);
66   return true;
67 }
68 
db_put(BMCTX * ctx,const IWKV_val * key,const IWKV_val * val,bool sync)69 static bool db_put(BMCTX *ctx, const IWKV_val *key, const IWKV_val *val, bool sync) {
70   BM_BDB *bmdb = ctx->db;
71   DBT bkey = { .data = key->data, .size = key->size };
72   DBT bval = { .data = val->data, .size = val->size };
73   int ret = bmdb->dbp->put(bmdb->dbp, 0, &bkey, &bval, 0);
74   if (ret) {
75     fprintf(stderr, "db_put: %s\n", db_strerror(ret));
76     return false;
77   }
78   if (sync) {
79     ret = bmdb->dbp->sync(bmdb->dbp, 0);
80     if (ret) {
81       fprintf(stderr, "db_sync: %s\n", db_strerror(ret));
82       return false;
83     }
84   }
85   return true;
86 }
87 
db_get(BMCTX * ctx,const IWKV_val * key,IWKV_val * val,bool * found)88 static bool db_get(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found) {
89   BM_BDB *bmdb = ctx->db;
90   DBT bkey = { .data = key->data, .size = key->size };
91   DBT bval = { .flags = DB_DBT_MALLOC };
92   int ret = bmdb->dbp->get(bmdb->dbp, 0, &bkey, &bval, 0);
93   val->data = bval.data;
94   val->size = bval.size;
95   if (ret == DB_NOTFOUND) {
96     *found = false;
97     ret = 0;
98   } else if (ret) {
99     *found = false;
100     fprintf(stderr, "db_get: %s\n", db_strerror(ret));
101   } else {
102     *found = true;
103   }
104   return ret == 0;
105 }
106 
db_del(BMCTX * ctx,const IWKV_val * key,bool sync)107 static bool db_del(BMCTX *ctx, const IWKV_val *key, bool sync) {
108   BM_BDB *bmdb = ctx->db;
109   DBT bkey = { .data = key->data, .size = key->size };
110   int ret = bmdb->dbp->del(bmdb->dbp, 0, &bkey, 0);
111   if (ret == DB_NOTFOUND) {
112     ret = 0;
113   } else if (ret) {
114     fprintf(stderr, "db_del: %s\n", db_strerror(ret));
115     return false;
116   }
117   if (sync) {
118     ret = bmdb->dbp->sync(bmdb->dbp, 0);
119     if (ret) {
120       fprintf(stderr, "db_del: %s\n", db_strerror(ret));
121       return false;
122     }
123   }
124   return true;
125 }
126 
db_read_seq(BMCTX * ctx,bool reverse)127 static bool db_read_seq(BMCTX *ctx, bool reverse) {
128   BM_BDB *bmdb = ctx->db;
129   DBC *curp;
130   DBT bkey = { .flags = DB_DBT_MALLOC };
131   DBT bval = { .flags = DB_DBT_MALLOC };
132   int ret = bmdb->dbp->cursor(bmdb->dbp, 0, &curp, 0);
133   if (ret) {
134     fprintf(stderr, "db_read_seq: %s\n", db_strerror(ret));
135     return false;
136   }
137   ret = curp->get(curp, &bkey, &bval, reverse ? DB_LAST : DB_FIRST);
138   if (ret == DB_NOTFOUND) {
139     ret = 0;
140   }
141   if (bkey.data) {
142     free(bkey.data);
143   }
144   if (bval.data) {
145     free(bval.data);
146   }
147 
148   for (int i = 0; i < bm.param_num - 1 && !ret; ++i) {
149     bkey.data = 0;
150     bval.data = 0;
151     ret = curp->get(curp, &bkey, &bval, reverse ? DB_PREV : DB_NEXT);
152     if (ret == DB_NOTFOUND) {
153       ret = 0;
154       break;
155     } else if (ret) {
156       fprintf(stderr, "db_read_seq: %s\n", db_strerror(ret));
157     }
158     if (bkey.data) {
159       free(bkey.data);
160     }
161     if (bval.data) {
162       free(bval.data);
163     }
164   }
165 
166   curp->close(curp);
167   return ret == 0;
168 }
169 
db_cursor_to_key(BMCTX * ctx,const IWKV_val * key,IWKV_val * val,bool * found)170 static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found) {
171   BM_BDB *bmdb = ctx->db;
172   DBC *curp;
173   DBT bkey = { .data = key->data, .size = key->size };
174   DBT bval = { .flags = DB_DBT_MALLOC };
175   int ret = bmdb->dbp->cursor(bmdb->dbp, 0, &curp, 0);
176   if (ret) {
177     fprintf(stderr, "db_cursor_to_key: %s\n", db_strerror(ret));
178     return false;
179   }
180   ret = curp->get(curp, &bkey, &bval, DB_SET);
181   if (ret == DB_NOTFOUND) {
182     *found = false;
183     ret = 0;
184   } else if (ret) {
185     *found = false;
186     fprintf(stderr, "db_cursor_to_key: %s\n", db_strerror(ret));
187   } else {
188     *found = true;
189     val->data = bval.data;
190     val->size = bval.size;
191   }
192   curp->close(curp);
193   return ret == 0;
194 }
195 
main(int argc,char ** argv)196 int main(int argc, char **argv) {
197   if (argc < 1) {
198     return -1;
199   }
200   g_program = argv[0];
201   bm.env_setup = env_setup;
202   bm.db_size_bytes = db_size_bytes;
203   bm.val_free = val_free;
204   bm.db_open = db_open;
205   bm.db_close = db_close;
206   bm.db_put = db_put;
207   bm.db_get = db_get;
208   bm.db_del = db_del;
209   bm.db_read_seq = db_read_seq;
210   bm.db_cursor_to_key = db_cursor_to_key;
211   if (!bm_bench_run(argc, argv)) {
212     return 1;
213   }
214   return 0;
215 }
216