mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
implement support for LMDB in ext/dba
don't abort txn if cursor is active fix typos
This commit is contained in:
parent
2058d8ed22
commit
16d7fd9d7f
7 changed files with 457 additions and 0 deletions
|
@ -100,6 +100,9 @@ PHP_ARG_WITH(dbm,,
|
|||
PHP_ARG_WITH(tcadb,,
|
||||
[ --with-tcadb[=DIR] DBA: Tokyo Cabinet abstract DB support], no, no)
|
||||
|
||||
PHP_ARG_WITH(lmdb,,
|
||||
[ --with-lmdb[=DIR] DBA: Lightning memory-mapped database support], no, no)
|
||||
|
||||
|
||||
dnl
|
||||
dnl Library checks
|
||||
|
@ -228,6 +231,37 @@ if test "$PHP_TCADB" != "no"; then
|
|||
fi
|
||||
PHP_DBA_STD_RESULT(tcadb)
|
||||
|
||||
dnl LMDB
|
||||
if test "$PHP_LMDB" != "no"; then
|
||||
PHP_DBA_STD_BEGIN
|
||||
for i in $PHP_LMDB /usr/local /usr; do
|
||||
if test -f "$i/include/lmdb.h"; then
|
||||
THIS_PREFIX=$i
|
||||
PHP_ADD_INCLUDE($THIS_PREFIX/include)
|
||||
THIS_INCLUDE=$i/include/lmdb.h
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -n "$THIS_INCLUDE"; then
|
||||
for LIB in lmdb; do
|
||||
PHP_CHECK_LIBRARY($LIB, mdb_open, [
|
||||
AC_DEFINE_UNQUOTED(LMDB_INCLUDE_FILE, "$THIS_INCLUDE", [ ])
|
||||
AC_DEFINE(DBA_LMDB, 1, [ ])
|
||||
THIS_LIBS=$LIB
|
||||
], [], [-L$THIS_PREFIX/$PHP_LIBDIR])
|
||||
if test -n "$THIS_LIBS"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
PHP_DBA_STD_ASSIGN
|
||||
PHP_DBA_STD_CHECK
|
||||
PHP_DBA_STD_ATTACH
|
||||
fi
|
||||
PHP_DBA_STD_RESULT(lmdb)
|
||||
|
||||
dnl Berkeley specific (library and version test)
|
||||
dnl parameters(version, library list, function)
|
||||
AC_DEFUN([PHP_DBA_DB_CHECK],[
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
ARG_WITH("dba", "DBA support", "no");
|
||||
ARG_WITH("qdbm", "DBA: QDBM support", "no");
|
||||
ARG_WITH("db", "DBA: Berkeley DB support", "no");
|
||||
ARG_WITH("lmdb", "DBA: Lightning memory-mapped database support", "no");
|
||||
|
||||
if (PHP_DBA != "no") {
|
||||
EXTENSION("dba", "dba.c dba_cdb.c dba_db1.c dba_db2.c dba_db3.c dba_dbm.c dba_flatfile.c dba_gdbm.c dba_ndbm.c dba_inifile.c");
|
||||
|
@ -32,4 +33,16 @@ if (PHP_DBA != "no") {
|
|||
WARNING("dba: qdbm handlers not enabled; libraries and headers not found");
|
||||
}
|
||||
}
|
||||
|
||||
if (PHP_QDBM != "no") {
|
||||
if (CHECK_LIB("liblmdb_a.lib", "dba", PHP_DBA) &&
|
||||
CHECK_HEADER_ADD_INCLUDE("lmdb.h", "CFLAGS_DBA") &&
|
||||
CHECK_LIB("ntdll.lib", "dba", PHP_DBA)) {
|
||||
ADD_SOURCES("ext/dba", "dba_lmdb.c", "dba");
|
||||
AC_DEFINE("LMDB_INCLUDE_FILE", "<lmdb.h>", "", false);
|
||||
AC_DEFINE("DBA_LMDB", 1, "");
|
||||
} else {
|
||||
WARNING("dba: lmdb handlers not enabled; libraries and headers not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "php_inifile.h"
|
||||
#include "php_qdbm.h"
|
||||
#include "php_tcadb.h"
|
||||
#include "php_lmdb.h"
|
||||
|
||||
/* {{{ arginfo */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_popen, 0, 0, 2)
|
||||
|
@ -362,6 +363,9 @@ static dba_handler handler[] = {
|
|||
#endif
|
||||
#if DBA_TCADB
|
||||
DBA_HND(tcadb, DBA_LOCK_ALL)
|
||||
#endif
|
||||
#if DBA_LMDB
|
||||
DBA_HND(lmdb, DBA_LOCK_EXT)
|
||||
#endif
|
||||
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
@ -387,6 +391,8 @@ static dba_handler handler[] = {
|
|||
#elif DBA_TCADB
|
||||
#define DBA_DEFAULT "tcadb"
|
||||
#else
|
||||
#define DBA_DEFAULT "lmdb"
|
||||
#else
|
||||
#define DBA_DEFAULT ""
|
||||
#endif
|
||||
/* cdb/cdb_make and ini are no option here */
|
||||
|
|
353
ext/dba/dba_lmdb.c
Normal file
353
ext/dba/dba_lmdb.c
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2017 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Anatol Belski <ab@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "php.h"
|
||||
|
||||
#if DBA_LMDB
|
||||
#include "php_lmdb.h"
|
||||
|
||||
#ifdef LMDB_INCLUDE_FILE
|
||||
#include LMDB_INCLUDE_FILE
|
||||
#endif
|
||||
|
||||
struct php_lmdb_info {
|
||||
MDB_env *env;
|
||||
MDB_txn *txn;
|
||||
MDB_dbi dbi;
|
||||
MDB_cursor *cur;
|
||||
};
|
||||
|
||||
#define LMDB_IT(it) (((struct php_lmdb_info *)info->dbf)->it)
|
||||
|
||||
DBA_OPEN_FUNC(lmdb)
|
||||
{
|
||||
MDB_env *env;
|
||||
MDB_txn *txn;
|
||||
int rc, mode = 0644, flags = MDB_NOSUBDIR;
|
||||
|
||||
if(info->argc > 0) {
|
||||
convert_to_long_ex(&info->argv[0]);
|
||||
mode = Z_LVAL(info->argv[0]);
|
||||
|
||||
/* TODO implement handling of the additional flags. */
|
||||
}
|
||||
|
||||
rc = mdb_env_create(&env);
|
||||
if (rc) {
|
||||
*error = mdb_strerror(rc);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
rc = mdb_env_open(env, info->path, flags, mode);
|
||||
if (rc) {
|
||||
*error = mdb_strerror(rc);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
rc = mdb_txn_begin(env, NULL, 0, &txn);
|
||||
if (rc) {
|
||||
mdb_env_close(env);
|
||||
*error = mdb_strerror(rc);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
info->dbf = pemalloc(sizeof(struct php_lmdb_info), info->flags & DBA_PERSISTENT);
|
||||
if (!info->dbf) {
|
||||
*error = "Failed to allocate php_lmdb_info.";
|
||||
return FAILURE;
|
||||
}
|
||||
memset(info->dbf, 0, sizeof(struct php_lmdb_info));
|
||||
|
||||
rc = mdb_dbi_open(txn, NULL, 0, &LMDB_IT(dbi));
|
||||
if (rc) {
|
||||
mdb_env_close(env);
|
||||
pefree(info->dbf, info->flags & DBA_PERSISTENT);
|
||||
*error = mdb_strerror(rc);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
LMDB_IT(env) = env;
|
||||
LMDB_IT(txn) = txn;
|
||||
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
DBA_CLOSE_FUNC(lmdb)
|
||||
{
|
||||
mdb_dbi_close(LMDB_IT(env), LMDB_IT(dbi));
|
||||
mdb_env_close(LMDB_IT(env));
|
||||
|
||||
pefree(info->dbf, info->flags & DBA_PERSISTENT);
|
||||
}
|
||||
|
||||
DBA_FETCH_FUNC(lmdb)
|
||||
{
|
||||
int rc;
|
||||
MDB_val k, v;
|
||||
char *ret = NULL;
|
||||
|
||||
if (LMDB_IT(cur)) {
|
||||
rc = mdb_txn_renew(LMDB_IT(txn));
|
||||
} else {
|
||||
rc = mdb_txn_begin(LMDB_IT(env), NULL, MDB_RDONLY, &LMDB_IT(txn));
|
||||
}
|
||||
if (rc) {
|
||||
php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k.mv_size = keylen;
|
||||
k.mv_data = key;
|
||||
|
||||
rc = mdb_get(LMDB_IT(txn), LMDB_IT(dbi), &k, &v);
|
||||
if (rc) {
|
||||
if (MDB_NOTFOUND != rc) {
|
||||
php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
|
||||
}
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (v.mv_data) {
|
||||
if(newlen) *newlen = v.mv_size;
|
||||
ret = estrndup(v.mv_data, v.mv_size);
|
||||
}
|
||||
|
||||
if (LMDB_IT(cur)) {
|
||||
mdb_txn_reset(LMDB_IT(txn));
|
||||
} else {
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBA_UPDATE_FUNC(lmdb)
|
||||
{
|
||||
int rc;
|
||||
MDB_val k, v;
|
||||
|
||||
rc = mdb_txn_begin(LMDB_IT(env), NULL, 0, &LMDB_IT(txn));
|
||||
if (rc) {
|
||||
php_error_docref2(NULL, key, val, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
k.mv_size = keylen;
|
||||
k.mv_data = key;
|
||||
v.mv_size = vallen;
|
||||
v.mv_data = val;
|
||||
|
||||
rc = mdb_put(LMDB_IT(txn), LMDB_IT(dbi), &k, &v, mode == 1 ? MDB_NOOVERWRITE : 0);
|
||||
if (rc) {
|
||||
if (MDB_KEYEXIST != rc) {
|
||||
php_error_docref2(NULL, key, val, E_WARNING, "%s", mdb_strerror(rc));
|
||||
}
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
rc = mdb_txn_commit(LMDB_IT(txn));
|
||||
if (rc) {
|
||||
php_error_docref2(NULL, key, val, E_WARNING, "%s", mdb_strerror(rc));
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
DBA_EXISTS_FUNC(lmdb)
|
||||
{
|
||||
int rc;
|
||||
MDB_val k, v;
|
||||
|
||||
if (LMDB_IT(cur)) {
|
||||
rc = mdb_txn_renew(LMDB_IT(txn));
|
||||
} else {
|
||||
rc = mdb_txn_begin(LMDB_IT(env), NULL, MDB_RDONLY, &LMDB_IT(txn));
|
||||
}
|
||||
if (rc) {
|
||||
php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
k.mv_size = keylen;
|
||||
k.mv_data = key;
|
||||
|
||||
rc = mdb_get(LMDB_IT(txn), LMDB_IT(dbi), &k, &v);
|
||||
if (rc) {
|
||||
if (MDB_NOTFOUND != rc) {
|
||||
php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
|
||||
}
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (LMDB_IT(cur)) {
|
||||
mdb_txn_reset(LMDB_IT(txn));
|
||||
} else {
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
DBA_DELETE_FUNC(lmdb)
|
||||
{
|
||||
int rc;
|
||||
MDB_val k;
|
||||
|
||||
rc = mdb_txn_begin(LMDB_IT(env), NULL, 0, &LMDB_IT(txn));
|
||||
if (rc) {
|
||||
php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
k.mv_size = keylen;
|
||||
k.mv_data = key;
|
||||
|
||||
rc = mdb_del(LMDB_IT(txn), LMDB_IT(dbi), &k, NULL);
|
||||
if (!rc) {
|
||||
rc = mdb_txn_commit(LMDB_IT(txn));
|
||||
if (rc) {
|
||||
php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
php_error_docref1(NULL, key, E_WARNING, "%s", mdb_strerror(rc));
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
DBA_FIRSTKEY_FUNC(lmdb)
|
||||
{
|
||||
int rc;
|
||||
MDB_val k, v;
|
||||
char *ret = NULL;
|
||||
|
||||
rc = mdb_txn_begin(LMDB_IT(env), NULL, MDB_RDONLY, &LMDB_IT(txn));
|
||||
if (rc) {
|
||||
php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = mdb_cursor_open(LMDB_IT(txn), LMDB_IT(dbi), &LMDB_IT(cur));
|
||||
if (rc) {
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = mdb_cursor_get(LMDB_IT(cur), &k, &v, MDB_FIRST);
|
||||
if (rc) {
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
mdb_cursor_close(LMDB_IT(cur));
|
||||
if (MDB_NOTFOUND != rc) {
|
||||
php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(k.mv_data) {
|
||||
if(newlen) *newlen = k.mv_size;
|
||||
ret = estrndup(k.mv_data, k.mv_size);
|
||||
}
|
||||
|
||||
mdb_txn_reset(LMDB_IT(txn));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBA_NEXTKEY_FUNC(lmdb)
|
||||
{
|
||||
int rc;
|
||||
MDB_val k, v;
|
||||
char *ret = NULL;
|
||||
|
||||
rc = mdb_txn_renew(LMDB_IT(txn));
|
||||
if (rc) {
|
||||
php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = mdb_cursor_get(LMDB_IT(cur), &k, &v, MDB_NEXT);
|
||||
if (rc) {
|
||||
mdb_txn_abort(LMDB_IT(txn));
|
||||
mdb_cursor_close(LMDB_IT(cur));
|
||||
LMDB_IT(cur) = NULL;
|
||||
if (MDB_NOTFOUND != rc) {
|
||||
php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(k.mv_data) {
|
||||
if(newlen) *newlen = k.mv_size;
|
||||
ret = estrndup(k.mv_data, k.mv_size);
|
||||
}
|
||||
|
||||
mdb_txn_reset(LMDB_IT(txn));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DBA_OPTIMIZE_FUNC(lmdb)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
DBA_SYNC_FUNC(lmdb)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = mdb_env_sync(LMDB_IT(env), 1);
|
||||
if (rc) {
|
||||
php_error_docref0(NULL, E_WARNING, "%s", mdb_strerror(rc));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
DBA_INFO_FUNC(lmdb)
|
||||
{
|
||||
return estrdup(MDB_VERSION_STRING);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: sw=4 ts=4 fdm=marker
|
||||
* vim<600: sw=4 ts=4
|
||||
*/
|
12
ext/dba/php_lmdb.h
Normal file
12
ext/dba/php_lmdb.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef PHP_LMDB_H
|
||||
#define PHP_LMDB_H
|
||||
|
||||
#if DBA_LMDB
|
||||
|
||||
#include "php_dba.h"
|
||||
|
||||
DBA_FUNCS(lmdb);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -2,4 +2,5 @@
|
|||
$db_filename = dirname(__FILE__) .'/test0.dbm'; // see test.inc
|
||||
@unlink($db_filename);
|
||||
@unlink($db_filename.'.lck');
|
||||
@unlink($db_filename.'-lock');
|
||||
?>
|
||||
|
|
38
ext/dba/tests/dba_lmdb.phpt
Normal file
38
ext/dba/tests/dba_lmdb.phpt
Normal file
|
@ -0,0 +1,38 @@
|
|||
--TEST--
|
||||
DBA LMDB handler test
|
||||
--SKIPIF--
|
||||
<?php
|
||||
$handler = 'lmdb';
|
||||
require_once dirname(__FILE__) .'/skipif.inc';
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$handler = 'lmdb';
|
||||
require_once dirname(__FILE__) .'/test.inc';
|
||||
$lock_flag = ''; // lock in library
|
||||
require_once dirname(__FILE__) .'/dba_handler.inc';
|
||||
?>
|
||||
===DONE===
|
||||
--CLEAN--
|
||||
<?php
|
||||
require_once dirname(__FILE__) .'/clean.inc';
|
||||
?>
|
||||
--EXPECTF--
|
||||
database handler: lmdb
|
||||
3NYNYY
|
||||
Content String 2
|
||||
Content 2 replaced
|
||||
Read during write:%sallowed
|
||||
"key number 6" written
|
||||
Failed to write "key number 6" 2nd time
|
||||
Content 2 replaced 2nd time
|
||||
The 6th value
|
||||
array(3) {
|
||||
["key number 6"]=>
|
||||
string(13) "The 6th value"
|
||||
["key2"]=>
|
||||
string(27) "Content 2 replaced 2nd time"
|
||||
["key5"]=>
|
||||
string(23) "The last content string"
|
||||
}
|
||||
===DONE===
|
Loading…
Add table
Add a link
Reference in a new issue