1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2017-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Anatol Belski <ab@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26
27 #if DBA_LMDB
28 #include "php_lmdb.h"
29
30 #ifdef LMDB_INCLUDE_FILE
31 #include LMDB_INCLUDE_FILE
32 #endif
33
34 struct php_lmdb_info {
35 MDB_env *env;
36 MDB_txn *txn;
37 MDB_dbi dbi;
38 MDB_cursor *cur;
39 };
40
41 #define LMDB_IT(it) (((struct php_lmdb_info *)info->dbf)->it)
42
DBA_OPEN_FUNC(lmdb)43 DBA_OPEN_FUNC(lmdb)
44 {
45 MDB_env *env;
46 MDB_txn *txn;
47 int rc, mode = 0644, flags = MDB_NOSUBDIR;
48
49 if(info->argc > 0) {
50 convert_to_long_ex(&info->argv[0]);
51 mode = Z_LVAL(info->argv[0]);
52
53 /* TODO implement handling of the additional flags. */
54 }
55
56 rc = mdb_env_create(&env);
57 if (rc) {
58 *error = mdb_strerror(rc);
59 return FAILURE;
60 }
61
62 rc = mdb_env_open(env, info->path, flags, mode);
63 if (rc) {
64 *error = mdb_strerror(rc);
65 return FAILURE;
66 }
67
68 rc = mdb_txn_begin(env, NULL, 0, &txn);
69 if (rc) {
70 mdb_env_close(env);
71 *error = mdb_strerror(rc);
72 return FAILURE;
73 }
74
75 info->dbf = pemalloc(sizeof(struct php_lmdb_info), info->flags & DBA_PERSISTENT);
76 if (!info->dbf) {
77 *error = "Failed to allocate php_lmdb_info.";
78 return FAILURE;
79 }
80 memset(info->dbf, 0, sizeof(struct php_lmdb_info));
81
82 rc = mdb_dbi_open(txn, NULL, 0, &LMDB_IT(dbi));
83 if (rc) {
84 mdb_env_close(env);
85 pefree(info->dbf, info->flags & DBA_PERSISTENT);
86 *error = mdb_strerror(rc);
87 return FAILURE;
88 }
89
90 LMDB_IT(env) = env;
91 LMDB_IT(txn) = txn;
92
93 mdb_txn_abort(LMDB_IT(txn));
94
95 return SUCCESS;
96 }
97
DBA_CLOSE_FUNC(lmdb)98 DBA_CLOSE_FUNC(lmdb)
99 {
100 mdb_dbi_close(LMDB_IT(env), LMDB_IT(dbi));
101 mdb_env_close(LMDB_IT(env));
102
103 pefree(info->dbf, info->flags & DBA_PERSISTENT);
104 }
105
DBA_FETCH_FUNC(lmdb)106 DBA_FETCH_FUNC(lmdb)
107 {
108 int rc;
109 MDB_val k, v;
110 char *ret = NULL;
111
112 if (LMDB_IT(cur)) {
113 rc = mdb_txn_renew(LMDB_IT(txn));
114 } else {
115 rc = mdb_txn_begin(LMDB_IT(env), NULL, MDB_RDONLY, &LMDB_IT(txn));
116 }
117 if (rc) {
118 php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
119 return NULL;
120 }
121
122 k.mv_size = keylen;
123 k.mv_data = key;
124
125 rc = mdb_get(LMDB_IT(txn), LMDB_IT(dbi), &k, &v);
126 if (rc) {
127 if (MDB_NOTFOUND != rc) {
128 php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
129 }
130 mdb_txn_abort(LMDB_IT(txn));
131 return NULL;
132 }
133
134 if (v.mv_data) {
135 if(newlen) *newlen = v.mv_size;
136 ret = estrndup(v.mv_data, v.mv_size);
137 }
138
139 if (LMDB_IT(cur)) {
140 mdb_txn_reset(LMDB_IT(txn));
141 } else {
142 mdb_txn_abort(LMDB_IT(txn));
143 }
144
145 return ret;
146 }
147
DBA_UPDATE_FUNC(lmdb)148 DBA_UPDATE_FUNC(lmdb)
149 {
150 int rc;
151 MDB_val k, v;
152
153 rc = mdb_txn_begin(LMDB_IT(env), NULL, 0, &LMDB_IT(txn));
154 if (rc) {
155 php_error_docref2(NULL, key, val, E_WARNING, "%s", mdb_strerror(rc));
156 return FAILURE;
157 }
158
159 k.mv_size = keylen;
160 k.mv_data = key;
161 v.mv_size = vallen;
162 v.mv_data = val;
163
164 rc = mdb_put(LMDB_IT(txn), LMDB_IT(dbi), &k, &v, mode == 1 ? MDB_NOOVERWRITE : 0);
165 if (rc) {
166 if (MDB_KEYEXIST != rc) {
167 php_error_docref2(NULL, key, val, E_WARNING, "%s", mdb_strerror(rc));
168 }
169 mdb_txn_abort(LMDB_IT(txn));
170 return FAILURE;
171 }
172
173 rc = mdb_txn_commit(LMDB_IT(txn));
174 if (rc) {
175 php_error_docref2(NULL, key, val, E_WARNING, "%s", mdb_strerror(rc));
176 mdb_txn_abort(LMDB_IT(txn));
177 return FAILURE;
178 }
179
180 return SUCCESS;
181 }
182
DBA_EXISTS_FUNC(lmdb)183 DBA_EXISTS_FUNC(lmdb)
184 {
185 int rc;
186 MDB_val k, v;
187
188 if (LMDB_IT(cur)) {
189 rc = mdb_txn_renew(LMDB_IT(txn));
190 } else {
191 rc = mdb_txn_begin(LMDB_IT(env), NULL, MDB_RDONLY, &LMDB_IT(txn));
192 }
193 if (rc) {
194 php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
195 return FAILURE;
196 }
197
198 k.mv_size = keylen;
199 k.mv_data = key;
200
201 rc = mdb_get(LMDB_IT(txn), LMDB_IT(dbi), &k, &v);
202 if (rc) {
203 if (MDB_NOTFOUND != rc) {
204 php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
205 }
206 mdb_txn_abort(LMDB_IT(txn));
207 return FAILURE;
208 }
209
210 if (LMDB_IT(cur)) {
211 mdb_txn_reset(LMDB_IT(txn));
212 } else {
213 mdb_txn_abort(LMDB_IT(txn));
214 }
215
216 return SUCCESS;
217 }
218
DBA_DELETE_FUNC(lmdb)219 DBA_DELETE_FUNC(lmdb)
220 {
221 int rc;
222 MDB_val k;
223
224 rc = mdb_txn_begin(LMDB_IT(env), NULL, 0, &LMDB_IT(txn));
225 if (rc) {
226 php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
227 return FAILURE;
228 }
229
230 k.mv_size = keylen;
231 k.mv_data = key;
232
233 rc = mdb_del(LMDB_IT(txn), LMDB_IT(dbi), &k, NULL);
234 if (!rc) {
235 rc = mdb_txn_commit(LMDB_IT(txn));
236 if (rc) {
237 php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
238 mdb_txn_abort(LMDB_IT(txn));
239 return FAILURE;
240 }
241 return SUCCESS;
242 }
243
244 php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
245
246 return FAILURE;
247 }
248
DBA_FIRSTKEY_FUNC(lmdb)249 DBA_FIRSTKEY_FUNC(lmdb)
250 {
251 int rc;
252 MDB_val k, v;
253 char *ret = NULL;
254
255 rc = mdb_txn_begin(LMDB_IT(env), NULL, MDB_RDONLY, &LMDB_IT(txn));
256 if (rc) {
257 php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
258 return NULL;
259 }
260
261 rc = mdb_cursor_open(LMDB_IT(txn), LMDB_IT(dbi), &LMDB_IT(cur));
262 if (rc) {
263 mdb_txn_abort(LMDB_IT(txn));
264 php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
265 return NULL;
266 }
267
268 rc = mdb_cursor_get(LMDB_IT(cur), &k, &v, MDB_FIRST);
269 if (rc) {
270 mdb_txn_abort(LMDB_IT(txn));
271 mdb_cursor_close(LMDB_IT(cur));
272 LMDB_IT(cur) = NULL;
273 if (MDB_NOTFOUND != rc) {
274 php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
275 }
276 return NULL;
277 }
278
279 if(k.mv_data) {
280 if(newlen) *newlen = k.mv_size;
281 ret = estrndup(k.mv_data, k.mv_size);
282 }
283
284 mdb_txn_reset(LMDB_IT(txn));
285
286 return ret;
287 }
288
DBA_NEXTKEY_FUNC(lmdb)289 DBA_NEXTKEY_FUNC(lmdb)
290 {
291 int rc;
292 MDB_val k, v;
293 char *ret = NULL;
294
295 rc = mdb_txn_renew(LMDB_IT(txn));
296 if (rc) {
297 php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
298 return NULL;
299 }
300
301 rc = mdb_cursor_get(LMDB_IT(cur), &k, &v, MDB_NEXT);
302 if (rc) {
303 mdb_txn_abort(LMDB_IT(txn));
304 mdb_cursor_close(LMDB_IT(cur));
305 LMDB_IT(cur) = NULL;
306 if (MDB_NOTFOUND != rc) {
307 php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
308 }
309 return NULL;
310 }
311
312 if(k.mv_data) {
313 if(newlen) *newlen = k.mv_size;
314 ret = estrndup(k.mv_data, k.mv_size);
315 }
316
317 mdb_txn_reset(LMDB_IT(txn));
318
319 return ret;
320 }
321
DBA_OPTIMIZE_FUNC(lmdb)322 DBA_OPTIMIZE_FUNC(lmdb)
323 {
324 return SUCCESS;
325 }
326
DBA_SYNC_FUNC(lmdb)327 DBA_SYNC_FUNC(lmdb)
328 {
329 int rc;
330
331 rc = mdb_env_sync(LMDB_IT(env), 1);
332 if (rc) {
333 php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
334 return FAILURE;
335 }
336
337 return SUCCESS;
338 }
339
DBA_INFO_FUNC(lmdb)340 DBA_INFO_FUNC(lmdb)
341 {
342 return estrdup(MDB_VERSION_STRING);
343 }
344
345 #endif
346
347 /*
348 * Local variables:
349 * tab-width: 4
350 * c-basic-offset: 4
351 * End:
352 * vim600: sw=4 ts=4 fdm=marker
353 * vim<600: sw=4 ts=4
354 */
355