おぎろぐはてブロ

なんだかんだエンジニアになって10年以上

現在trunkにあるTokyoCabinetのdbaハンドラをPHP5.3で使ってみる

dba関数というのを知っていますか?dbm形式のデータベースの抽象化レイヤとなる関数を提供するモジュールで、PHPソースコードに同梱されています。

例えば、dbm や qdbm といったものを利用できる他、inifile という php.ini 形式のようなファイルをDBMのように読み書きできるハンドラが用意されています。

で、現在、PHPソースコードのtrunkには、TokyoCabinetのハンドラがコミットされています。

いつ、これが提供されるようになるかは不明ですが、現時点でもbackportすれば利用はできるので、使ってみました。手元ではPHP5.2.8、5.3.1で確認しています。

パッチを適用

TokyoCabinet用のドライバである php_tcadb.h と tcadb.c をそのままコピーと、dba.c と config.m4 のTokyoCabinetに関する部分の追加分をパッチで適用します。
ほとんどファイル追加なので長ったらしいパッチは以下。

PHP5.3のソースコードの、ext/dba ディレクトリで patch -p0 -d . < PATCH_FILE してください。

$ patch -p0 -d . < ../php53-dba-tcadb.patch 
patching file config.m4
patching file dba.c
patching file dba_tcadb.c
patching file php_tcadb.h
1点修正を加えてます

うまく動かなかったので、TokyoCabinetのマニュアルを見ながらオープン周りを確認してみたところ、
http://1978th.net/tokyocabinet/spex-ja.html

bool tcadbopen(TCADB *adb, const char *name);
.. snip ..
If successful, the return value is true, else, it is false.

とあるのに、オープン処理で if (tcadbopen(...)) { return FAILURE; } になっていたので、失敗したときに成功とみなし操作できない、成功したときにオープン失敗とエラーが出るという状態になっていたので、上のパッチではその箇所も修正しています。

--- dba_tcadb.c	2010-01-17 14:10:39.000000000 +0900
+++ dba_tcadb.c.new	2010-01-17 16:50:04.000000000 +0900
@@ -65,7 +65,7 @@
 				return FAILURE;
 		}
 
-		if (tcadbopen(tcadb, path_string)) {
+		if (!tcadbopen(tcadb, path_string)) {
 			efree(path_string);
 			return FAILURE;
 		}

さすがに初っ端で動かないので、この状態でコミットされているのが謎ですが、他にも問題あるかもしれません。

ビルド

PHP本体はすでにビルドされていて、dbaモジュールは組み込んでない場合として、動的モジュールとしてビルドしてみます。
当然ながら、tokyocabinetがインストールされている必要があります。Ubuntuで試したので sudo apt-get install libtokyocabinet-dev で導入しました。

まずはphpize

$ phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519

configureで、--with-tcadb。必要に応じて、パスを指定します。

$ ./configure --with-tcadb

そして、make

$ make

成功すると、modules/下に dba.so ができるので、extension_dir の下に配置して、php.iniに、

extension=dba.so

と設定して、読み込ませます。

動作させてみる

こんな感じですね。

<?php

sleep(1);
$id = dba_open("test.tch", "n", "tcadb");

if (!$id) {
    echo "dba_open failed\n";
    exit;
}

dba_replace("key", "This is an example!", $id);

if (dba_exists("key", $id)) {
    echo dba_fetch("key", $id);
    dba_delete("key", $id);
}

dba_close($id);
?>