summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/dba/config.m434
-rw-r--r--ext/dba/config.w3213
-rw-r--r--ext/dba/dba.c6
-rw-r--r--ext/dba/dba_lmdb.c353
-rw-r--r--ext/dba/php_lmdb.h12
-rw-r--r--ext/dba/tests/clean.inc1
-rw-r--r--ext/dba/tests/dba_lmdb.phpt38
7 files changed, 457 insertions, 0 deletions
diff --git a/ext/dba/config.m4 b/ext/dba/config.m4
index 740cf14e39..a8bd561c50 100644
--- a/ext/dba/config.m4
+++ b/ext/dba/config.m4
@@ -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],[
diff --git a/ext/dba/config.w32 b/ext/dba/config.w32
index d521e6ad62..5eb542d986 100644
--- a/ext/dba/config.w32
+++ b/ext/dba/config.w32
@@ -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");
+ }
+ }
}
diff --git a/ext/dba/dba.c b/ext/dba/dba.c
index 072f84b784..a8470d9d59 100644
--- a/ext/dba/dba.c
+++ b/ext/dba/dba.c
@@ -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)
@@ -363,6 +364,9 @@ static dba_handler handler[] = {
#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 */
diff --git a/ext/dba/dba_lmdb.c b/ext/dba/dba_lmdb.c
new file mode 100644
index 0000000000..91f42e1a76
--- /dev/null
+++ b/ext/dba/dba_lmdb.c
@@ -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
+ */
diff --git a/ext/dba/php_lmdb.h b/ext/dba/php_lmdb.h
new file mode 100644
index 0000000000..1b4928f49b
--- /dev/null
+++ b/ext/dba/php_lmdb.h
@@ -0,0 +1,12 @@
+#ifndef PHP_LMDB_H
+#define PHP_LMDB_H
+
+#if DBA_LMDB
+
+#include "php_dba.h"
+
+DBA_FUNCS(lmdb);
+
+#endif
+
+#endif
diff --git a/ext/dba/tests/clean.inc b/ext/dba/tests/clean.inc
index 7c53e7e61f..9f6d539a19 100644
--- a/ext/dba/tests/clean.inc
+++ b/ext/dba/tests/clean.inc
@@ -2,4 +2,5 @@
$db_filename = dirname(__FILE__) .'/test0.dbm'; // see test.inc
@unlink($db_filename);
@unlink($db_filename.'.lck');
+ @unlink($db_filename.'-lock');
?>
diff --git a/ext/dba/tests/dba_lmdb.phpt b/ext/dba/tests/dba_lmdb.phpt
new file mode 100644
index 0000000000..b32cd58bbd
--- /dev/null
+++ b/ext/dba/tests/dba_lmdb.phpt
@@ -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===