public
Description: Erlang -> Berkeley DB Sample
Homepage:
Clone URL: git://github.com/dawsdesign/erl_bdb_sample.git
Matt Williamson (author)
Tue May 26 07:48:34 -0700 2009
erl_bdb_sample / priv / bdb_drv.c
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 1 #include "bdb_drv.h"
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 2
3 static ErlDrvEntry basic_driver_entry = {
4 NULL, /* init */
5 start, /* startup */
6 stop, /* shutdown */
7 NULL, /* output */
8 NULL, /* ready_input */
9 NULL, /* ready_output */
10 "bdb_drv", /* the name of the driver */
11 NULL, /* finish */
12 NULL, /* handle */
13 NULL, /* control */
14 NULL, /* timeout */
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 15 outputv, /* outputv */
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 16 NULL, /* ready_async */
17 NULL, /* flush */
18 NULL, /* call */
19 NULL, /* event */
20 ERL_DRV_EXTENDED_MARKER, /* ERL_DRV_EXTENDED_MARKER */
21 ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MAJOR_VERSION */
22 ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MINOR_VERSION */
23 ERL_DRV_FLAG_USE_PORT_LOCKING /* ERL_DRV_FLAGs */
24 };
25
26 DRIVER_INIT(basic_driver) {
27 return &basic_driver_entry;
28 }
29
30 static ErlDrvData start(ErlDrvPort port, char* cmd) {
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 31 bdb_drv_t* retval = (bdb_drv_t*) driver_alloc(sizeof(bdb_drv_t));
ff218941 » Matt Williamson 2009-05-22 Added delete 32 u_int32_t open_flags = DB_CREATE | DB_THREAD;
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 33 DB *db;
f70d9a31 » Matt Williamson 2009-05-22 Put and GET now working. 34 int status;
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 35
36 db_create(&db, NULL, 0);
f300711b » Matt Williamson 2009-05-26 "" 37 status = db->open(db, NULL, DB_PATH, NULL, DB_BTREE, open_flags, 0);
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 38
f6c097bf » Matt Williamson 2009-05-26 Fixed makefile. 39 if(status != 0) {
40 char *error_reason;
41
42 switch(status){
43 case DB_OLD_VERSION:
44 error_reason = "the file was created with a different version.";
45 break;
46
47 case EINVAL:
48 error_reason = "the file was opened with incorrect flags. Perhaps the system does not support the DB_THREAD flag?";
49 break;
50
51 case DB_RUNRECOVERY:
52 error_reason = "the file needs to be recovered, it may be corrupt.";
53 break;
54 default:
55 error_reason = "of an unkown reason.";
56 }
57
58 fprintf(stderr, "Unabled to open file: %s because %s\n\n", DB_PATH, error_reason);
59 }
60
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 61 retval->port = port;
62 retval->db = db;
63
64 return (ErlDrvData) retval;
65 }
66
67 static void stop(ErlDrvData handle) {
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 68 bdb_drv_t* driver_data = (bdb_drv_t*) handle;
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 69
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 70 driver_data->db->close(driver_data->db, 0);
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 71 driver_free(driver_data);
72 }
73
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 74 static void outputv(ErlDrvData handle, ErlIOVec *ev) {
75 bdb_drv_t* driver_data = (bdb_drv_t*) handle;
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 76 ErlDrvBinary* data = ev->binv[1];
77 int command = data->orig_bytes[0];
78
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 79 switch(command) {
80 case CMD_PUT:
81 put(driver_data, ev);
82 break;
83
84 case CMD_GET:
85 get(driver_data, ev);
86 break;
87
ff218941 » Matt Williamson 2009-05-22 Added delete 88 case CMD_DEL:
89 del(driver_data, ev);
90 break;
91
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 92 default:
93 unkown(driver_data, ev);
94 }
95 }
96
97 static void put(bdb_drv_t *bdb_drv, ErlIOVec *ev) {
f70d9a31 » Matt Williamson 2009-05-22 Put and GET now working. 98 ErlDrvBinary* input = ev->binv[1];
99 char *bytes = input->orig_bytes;
f300711b » Matt Williamson 2009-05-26 "" 100 char *key_bytes = bytes+1;
101 char *value_bytes = bytes+1+KEY_SIZE;
102 int value_size = input->orig_size - 1 - KEY_SIZE;
ff218941 » Matt Williamson 2009-05-22 Added delete 103
f300711b » Matt Williamson 2009-05-26 "" 104 DB *db = bdb_drv->db;
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 105 DBT key;
f300711b » Matt Williamson 2009-05-26 "" 106 DBT value;
107 int status;
108
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 109 bzero(&key, sizeof(DBT));
f300711b » Matt Williamson 2009-05-26 "" 110 bzero(&value, sizeof(DBT));
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 111
f300711b » Matt Williamson 2009-05-26 "" 112 key.data = key_bytes;
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 113 key.size = KEY_SIZE;
114
f300711b » Matt Williamson 2009-05-26 "" 115 value.data = value_bytes;
116 value.size = value_size;
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 117
f300711b » Matt Williamson 2009-05-26 "" 118 status = db->put(db, NULL, &key, &value, 0);
f70d9a31 » Matt Williamson 2009-05-22 Put and GET now working. 119 db->sync(db, 0);
f300711b » Matt Williamson 2009-05-26 "" 120
121 if(status == 0) {
122 ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("ok")};
123
124 driver_output_term(bdb_drv->port, spec, sizeof(spec) / sizeof(spec[0]));
125 } else {
126 char * error_reason;
127
128 switch(status) {
129 case DB_LOCK_DEADLOCK:
130 error_reason = "deadlock";
131 break;
132 case EACCES:
133 error_reason = "readonly";
134 break;
135 case EINVAL:
136 error_reason = "badflag";
137 break;
138 case ENOSPC:
139 error_reason = "btree_max";
140 break;
141 case DB_RUNRECOVERY:
142 error_reason = "run_recovery";
143 break;
144 default:
145 error_reason = "unkown";
146 }
147
148 ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("error"),
149 ERL_DRV_ATOM, driver_mk_atom(error_reason),
150 ERL_DRV_TUPLE, 2};
151
152 driver_output_term(bdb_drv->port, spec, sizeof(spec) / sizeof(spec[0]));
153 }
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 154 }
155
f300711b » Matt Williamson 2009-05-26 "" 156 static void get(bdb_drv_t *bdb_drv, ErlIOVec *ev) {
157 ErlDrvBinary* input = ev->binv[1];
158 ErlDrvBinary *output_bytes;
159 char *bytes = input->orig_bytes;
160 char *key_bytes = bytes+1;
161
162 DB *db = bdb_drv->db;
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 163 DBT key;
f300711b » Matt Williamson 2009-05-26 "" 164 DBT value;
165 int status;
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 166
167 bzero(&key, sizeof(DBT));
f300711b » Matt Williamson 2009-05-26 "" 168 bzero(&value, sizeof(DBT));
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 169
f300711b » Matt Williamson 2009-05-26 "" 170 key.data = key_bytes;
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 171 key.size = KEY_SIZE;
172
f300711b » Matt Williamson 2009-05-26 "" 173 value.flags = DB_DBT_MALLOC; // Don't forget to free
8045eea9 » Matt Williamson 2009-05-22 Checkpoint. 174
f300711b » Matt Williamson 2009-05-26 "" 175 status = db->get(db, NULL, &key, &value, 0);
f70d9a31 » Matt Williamson 2009-05-22 Put and GET now working. 176
f300711b » Matt Williamson 2009-05-26 "" 177 if(status == 0) {
178 output_bytes = driver_alloc_binary(value.size);
179 output_bytes->orig_size = value.size;
180 // TODO:Figure out if we can somehow use this original memory
181 //binary->orig_bytes = (char *)&data.data;
182 memcpy(output_bytes->orig_bytes, value.data, value.size);
183 free(value.data);
184
185 ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("ok"),
186 ERL_DRV_BINARY, (ErlDrvTermData) output_bytes, output_bytes->orig_size, 0,
187 ERL_DRV_TUPLE, 2};
188
189 driver_output_term(bdb_drv->port, spec, sizeof(spec) / sizeof(spec[0]));
190 driver_free_binary(output_bytes);
191 } else {
192 char *error_reason;
f70d9a31 » Matt Williamson 2009-05-22 Put and GET now working. 193
f300711b » Matt Williamson 2009-05-26 "" 194 switch(status) {
195 case DB_LOCK_DEADLOCK:
196 error_reason = "deadlock";
197 break;
198 case DB_SECONDARY_BAD:
199 error_reason = "bad_secondary_index";
200 break;
201 case ENOMEM:
202 error_reason = "insufficient_memory";
203 break;
204 case EINVAL:
205 error_reason = "bad_flag";
206 break;
207 case DB_RUNRECOVERY:
208 error_reason = "run_recovery";
209 break;
210 default:
211 error_reason = "unknown";
212 }
213
214 ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("error"),
215 ERL_DRV_ATOM, driver_mk_atom(error_reason),
216 ERL_DRV_TUPLE, 2};
217 driver_output_term(bdb_drv->port, spec, sizeof(spec) / sizeof(spec[0]));
218 }
f7d2dcc4 » Matt Williamson 2009-05-19 first commit 219 }
ff218941 » Matt Williamson 2009-05-22 Added delete 220
f300711b » Matt Williamson 2009-05-26 "" 221 static void del(bdb_drv_t *bdb_drv, ErlIOVec *ev) {
222 ErlDrvBinary* data = ev->binv[1];
223 char *bytes = data->orig_bytes;
224 char *key_bytes = bytes+1;
225
226 DB *db = bdb_drv->db;
ff218941 » Matt Williamson 2009-05-22 Added delete 227 DBT key;
f300711b » Matt Williamson 2009-05-26 "" 228 int status;
ff218941 » Matt Williamson 2009-05-22 Added delete 229
230 bzero(&key, sizeof(DBT));
231
f300711b » Matt Williamson 2009-05-26 "" 232 key.data = key_bytes;
ff218941 » Matt Williamson 2009-05-22 Added delete 233 key.size = KEY_SIZE;
234
235 status = db->del(db, NULL, &key, 0);
f300711b » Matt Williamson 2009-05-26 "" 236 db->sync(db, 0);
237
238 if(status == 0) {
239 ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("ok")};
240
241 driver_output_term(bdb_drv->port, spec, sizeof(spec) / sizeof(spec[0]));
242
243 } else {
244 char *error_reason;
245
246 switch(status) {
247 case DB_NOTFOUND:
248 error_reason = "not_found";
249 break;
250 case DB_LOCK_DEADLOCK:
251 error_reason = "deadlock";
252 break;
253 case DB_SECONDARY_BAD:
254 error_reason = "bad_secondary_index";
255 break;
256 case EINVAL:
257 error_reason = "bad_flag";
258 break;
259 case EACCES:
260 error_reason = "readonly";
261 break;
262 case DB_RUNRECOVERY:
263 error_reason = "run_recovery";
264 break;
265 default:
266 error_reason = "unknown";
267 }
268
269 ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("error"),
270 ERL_DRV_ATOM, driver_mk_atom(error_reason),
271 ERL_DRV_TUPLE, 2};
272
273 driver_output_term(bdb_drv->port, spec, sizeof(spec) / sizeof(spec[0]));
274 }
275 }
276
277 static void unkown(bdb_drv_t *bdb_drv, ErlIOVec *ev) {
278 ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("error"),
279 ERL_DRV_ATOM, driver_mk_atom("uknown_command"),
280 ERL_DRV_TUPLE, 2};
281 driver_output_term(bdb_drv->port, spec, sizeof(spec) / sizeof(spec[0]));
ff218941 » Matt Williamson 2009-05-22 Added delete 282 }