xref: /PHP-7.2/ext/dba/dba_lmdb.c (revision 902d39a3)
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