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