Symfoware

Symfowareについての考察blog

Lux IO のPythonバインディングを作成する

Lux IOのインストールと、動作確認は行えました。
Debianに高速データベースマネージャ(DBM) Lux IOをインストールする

・・・実は、C++書いたことがないんですよね。
普段、Pythonを愛用しているのですが、残念ながらLux IOの
Pythonバインディングはまだないようです。

Lux IO の言語バインディングとか

ないものは作ればよい。
ということで、がんばって作成してみようと思います。

以前、VS2008でPython拡張の作成方法を調べたことがあるので、
これを参考にまずはDebianで動作する拡張モジュールを作成してみます。

以前調べた内容はこちら。
Visual Studio 2008 Express EditionでPythonのC言語拡張を作成する


Pythonから呼び出す部分は、
Lux IO(ラックス アイオー)をPHPから使ってみる
こちらを参考に書いてみました。

■luxio.cpp


#include <Python.h>
#include <luxio/btree.h>
#include <iostream>

static PyObject * luxio_btree_ctor(PyObject *self, PyObject *args) {
    Lux::IO::Btree *bt = new Lux::IO::Btree(Lux::IO::CLUSTER);
    return (PyObject *)bt;
}

static PyObject * luxio_btree_open(PyObject *self, PyObject *args) {

    Lux::IO::Btree *bt;
    char *file_name = NULL;
    int create_type;
    if (!PyArg_ParseTuple(args, "Osi", &bt, &file_name, &create_type)) {
        return NULL;
    }
    
    if (bt->open(file_name, create_type)) {
        Py_RETURN_TRUE;
    }
    Py_RETURN_FALSE;
}

static PyObject * luxio_btree_put(PyObject *self, PyObject *args) {
    Lux::IO::Btree *bt;
    char *key = NULL;
    char *val = NULL;
    int key_len = 0;
    int val_len = 0;
    if (!PyArg_ParseTuple(args, "Os#s#", &bt, &key, &key_len, &val, &val_len)) {
        return NULL;
    }
    
    Lux::IO::data_t lux_key = {key, key_len};
    Lux::IO::data_t lux_val = {val, val_len};
    if (bt->put(&lux_key, &lux_val)) {
        Py_RETURN_TRUE;
    }
    Py_RETURN_FALSE;
}


static PyObject * luxio_btree_get(PyObject *self, PyObject *args) {
    Lux::IO::Btree *bt;
    char *key = NULL;
    int key_len = 0;
    char *value = NULL;
    if (!PyArg_ParseTuple(args, "Os#", &bt, &key, &key_len)) {
            return NULL;
    }
    Lux::IO::data_t lux_key = {key, key_len};
    Lux::IO::data_t *lux_val = bt->get(&lux_key);
    if (!lux_val) {
        Py_RETURN_FALSE;
    }
    return Py_BuildValue("s", lux_val->data);
}

static PyObject * luxio_btree_del(PyObject *self, PyObject *args) {
    Lux::IO::Btree *bt;
    char *key = NULL;
    int key_len = 0;
    
    if (!PyArg_ParseTuple(args, "Os#", &bt, &key, &key_len)) {
            return NULL;
    }
    Lux::IO::data_t lux_key = {key, key_len};
    if (bt->del(&lux_key)) {
        Py_RETURN_TRUE;
    }
    Py_RETURN_FALSE;
}

static PyObject * luxio_btree_close(PyObject *self, PyObject *args) {
    Lux::IO::Btree *bt;
    
    if (!PyArg_ParseTuple(args, "O", &bt)) {
            return NULL;
    }
    if (bt->close()) {
        Py_RETURN_TRUE;
    }
    Py_RETURN_FALSE;
}

static PyMethodDef def[] = {
        {"luxiobtree", luxio_btree_ctor, METH_VARARGS, NULL},
        {"open", luxio_btree_open, METH_VARARGS, NULL},
        {"put", luxio_btree_put, METH_VARARGS, NULL},
        {"get", luxio_btree_get, METH_VARARGS, NULL},
        {"delete", luxio_btree_del, METH_VARARGS, NULL},
        {"close", luxio_btree_close, METH_VARARGS, NULL},
        {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC initluxio(void) {
        PyObject* m;
        m = Py_InitModule("luxio", def);
        PyModule_AddIntConstant(m, "LUX_DB_RDONLY", Lux::IO::DB_RDONLY);
        PyModule_AddIntConstant(m, "LUX_DB_RDWR", Lux::IO::DB_RDWR);
        PyModule_AddIntConstant(m, "LUX_DB_CREAT", Lux::IO::DB_CREAT);
        PyModule_AddIntConstant(m, "LUX_DB_TRUNC", Lux::IO::DB_TRUNC);
}



※delはPythonの予約語なので、deleteにしてます。

ビルド、インストールするためのsetup.pyはこんな感じ。


■setup.py


from distutils.core import setup
from distutils.extension import Extension
setup(name='luxio',
     version='0.0.1',
     ext_modules=[Extension('luxio', ['luxio.cpp'], libraries=['luxio'])],
)



librariesにluxioと指定しておかないと、一見ビルドが通ったように見えても、
Pythonから呼び出したとき落ちます。

名前を一緒にしてしまったので紛らわしいですが、librariesでしていしている
luxioはluxio.aライブラリのこと。


これで、python setup.py installとすればモジュールがビルドされるのですが、
C++の関数を外に追い出しただけなので、ちょっと扱いづらい。

Pythonでアクセス用のモジュールを書いて使うことにしました。

■luxio_dbm.py


#!/usr/bin/env python
#-*- coding:utf-8 -*-
import luxio

class LuxIOBtree(object):
    
    RDONLY = luxio.LUX_DB_RDONLY
    RDWR = luxio.LUX_DB_RDWR
    CREAT = luxio.LUX_DB_CREAT
    TRUNC = luxio.LUX_DB_TRUNC
    
    def __init__(self):
        self.dbm = luxio.luxiobtree()
        
    def open(self, path, mode):
        return luxio.open(self.dbm, path, mode)
    
    def put(self, key, value):
        return luxio.put(self.dbm, key, value)
    
    def get(self, key):
        return luxio.get(self.dbm, key)
    
    def delete(self, key):
        return luxio.delete(self.dbm, key)
    
    def close(self):
        ret = luxio.close(self.dbm)
        self.dbm = None
        return ret
    
    def __del__(self):
        if self.dbm:
            luxio.close(self.dbm)





使い方はこんな感じ。


#!/usr/bin/env python
#-*- coding:utf-8 -*-

from luxio_dbm import LuxIOBtree

luxiobtree = LuxIOBtree()

luxiobtree.open('/var/tmp/test', LuxIOBtree.CREAT);

ret = luxiobtree.put('key', 'value');
# True

ret = luxiobtree.get('key');
# value

ret = luxiobtree.delete('key');
# True

ret = luxiobtree.close()
# True




・・・もっと勉強して拡張モジュールだけで完結するようにします。
あと、日本語の登録がうまくいかないので、そこも修正する必要アリです。



【参考URL】
setup.pyの記載方法
拡張モジュールについて記述する

Python拡張の書き方
Python/C API リファレンスマニュアル
Python インタプリタの拡張と埋め込み




関連記事
  1. 2009/09/18(金) 12:28:49|
  2. Python
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<Jettyのインストールと、Eclipseプラグインの設定 | ホーム | Debianに高速データベースマネージャ(DBM) Lux IOをインストールする>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/144-43c40844
この記事にトラックバックする(FC2ブログユーザー)