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
107
db_del(BMCTX * ctx,const IWKV_val * key,bool sync)108 static bool db_del(BMCTX *ctx, const IWKV_val *key, bool sync) {
109 BM_BDB *bmdb = ctx->db;
110 DBT bkey = {.data = key->data, .size = key->size};
111 int ret = bmdb->dbp->del(bmdb->dbp, 0, &bkey, 0);
112 if (ret == DB_NOTFOUND) {
113 ret = 0;
114 } else if (ret) {
115 fprintf(stderr, "db_del: %s\n", db_strerror(ret));
116 return false;
117 }
118 if (sync) {
119 ret = bmdb->dbp->sync(bmdb->dbp, 0);
120 if (ret) {
121 fprintf(stderr, "db_del: %s\n", db_strerror(ret));
122 return false;
123 }
124 }
125 return true;
126 }
127
db_read_seq(BMCTX * ctx,bool reverse)128 static bool db_read_seq(BMCTX *ctx, bool reverse) {
129 BM_BDB *bmdb = ctx->db;
130 DBC *curp;
131 DBT bkey = {.flags = DB_DBT_MALLOC};
132 DBT bval = {.flags = DB_DBT_MALLOC};
133 int ret = bmdb->dbp->cursor(bmdb->dbp, 0, &curp, 0);
134 if (ret) {
135 fprintf(stderr, "db_read_seq: %s\n", db_strerror(ret));
136 return false;
137 }
138 ret = curp->get(curp, &bkey, &bval, reverse ? DB_LAST : DB_FIRST);
139 if (ret == DB_NOTFOUND) {
140 ret = 0;
141 }
142 if (bkey.data) free(bkey.data);
143 if (bval.data) free(bval.data);
144
145 for (int i = 0; i < bm.param_num - 1 && !ret; ++i) {
146 bkey.data = 0;
147 bval.data = 0;
148 ret = curp->get(curp, &bkey, &bval, reverse ? DB_PREV : DB_NEXT);
149 if (ret == DB_NOTFOUND) {
150 ret = 0;
151 break;
152 } else if (ret) {
153 fprintf(stderr, "db_read_seq: %s\n", db_strerror(ret));
154 }
155 if (bkey.data) free(bkey.data);
156 if (bval.data) free(bval.data);
157 }
158
159 curp->close(curp);
160 return ret == 0;
161 }
162
db_cursor_to_key(BMCTX * ctx,const IWKV_val * key,IWKV_val * val,bool * found)163 static bool db_cursor_to_key(BMCTX *ctx, const IWKV_val *key, IWKV_val *val, bool *found) {
164 BM_BDB *bmdb = ctx->db;
165 DBC *curp;
166 DBT bkey = {.data = key->data, .size = key->size};
167 DBT bval = {.flags = DB_DBT_MALLOC};
168 int ret = bmdb->dbp->cursor(bmdb->dbp, 0, &curp, 0);
169 if (ret) {
170 fprintf(stderr, "db_cursor_to_key: %s\n", db_strerror(ret));
171 return false;
172 }
173 ret = curp->get(curp, &bkey, &bval, DB_SET);
174 if (ret == DB_NOTFOUND) {
175 *found = false;
176 ret = 0;
177 } else if (ret) {
178 *found = false;
179 fprintf(stderr, "db_cursor_to_key: %s\n", db_strerror(ret));
180 } else {
181 *found = true;
182 val->data = bval.data;
183 val->size = bval.size;
184 }
185 curp->close(curp);
186 return ret == 0;
187 }
188
main(int argc,char ** argv)189 int main(int argc, char **argv) {
190 if (argc < 1) return -1;
191 g_program = argv[0];
192 bm.env_setup = env_setup;
193 bm.db_size_bytes = db_size_bytes;
194 bm.val_free = val_free;
195 bm.db_open = db_open;
196 bm.db_close = db_close;
197 bm.db_put = db_put;
198 bm.db_get = db_get;
199 bm.db_del = db_del;
200 bm.db_read_seq = db_read_seq;
201 bm.db_cursor_to_key = db_cursor_to_key;
202 if (!bm_bench_run(argc, argv)) {
203 return 1;
204 }
205 return 0;
206 }
207