Tuesday, July 20, 2010

tdb を 64bit 対応にする

tdb(Trivial Database) は、dbm の一種で、key/value の形でデータを保存できる。 install の仕方は、以下のとおり

以下から download する
http://sourceforge.net/projects/tdb/

$ wget "http://downloads.sourceforge.net/project/tdb/tdb/1.0.6/tdb-1.0.6.tar.gz?use_mirror=jaist&ts=1279553081"
$ tar zxvf tdb-1.0.6.tar.gz
$ cd tdb-1.0.6
$ ./configure --prefix=$HOME/local --host="i860-linux-gnu" --enable-shared
$ perl -pi -e 's/$/\\n\\/ if( $.>=172 && $.<=187)' tdbtool.c
$ perl -pi -e 's/#define u32 unsigned/#define u32 unsigned long long/' tdb.h
$ make
$ make install

tdb は、ファイル1つに対しデータベースを作っており、offset と size でデータを取り出したり、 保存したりしている。 offset の指定が unsigned int になっているので、4GB を超えるあたりで、動かなくなる問題があったので、 改善方法を考えてみた。

offset は u32 型で定義しているので、以下のようにmacroを書き換えればよい

$ perl -pi -e 's/#define u32 unsigned/#define u32 unsigned long long/' tdb.h

正常に動くかどうかは、以下のプログラムを動かして確認した。

$ cat tdb_overflow.cc
#include 
#include 
#include "tdb.h"
#include 
#include 

using namespace std;

#define TDB_DB "tdb.db"
#define TDB_HASH_SIZE 2000*10000

void log(TDB_CONTEXT *tdb, int Num, const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}

void get_tdb_val(TDB_CONTEXT *tdb, int num, TDB_DATA *tkey, TDB_DATA *tvalue){
    static string pre_key = "";
    static string pre_value = "";
    if( "" == pre_key ){
        pre_key = "key";
    }
    if( "" == pre_value ){
        for(int i=0;i<100*5000;++i){
            pre_value += "0123456789";
        }
    }
    char numStr[1024];
    snprintf(numStr, 1024, "%d", num);

    static string key;
    key = pre_key + numStr;
    tkey->dptr = (char *)key.c_str();
    tkey->dsize = key.length() + 1;

    static string value;
    value = pre_value + numStr;
    tvalue->dptr = (char *)value.c_str();
    tvalue->dsize = value.length() + 1;
}
int main(){
    printf("tdb file:%s\n", TDB_DB);
    printf("hash size:%u\n", TDB_HASH_SIZE);

    TDB_CONTEXT *tdb;
    tdb = tdb_open_ex(TDB_DB, TDB_HASH_SIZE, TDB_CLEAR_IF_FIRST|TDB_NOMMAP, O_RDWR|O_CREAT, S_IRWXU, &log);
    if(NULL == tdb){
        fprintf(stderr, "can't open tdb\n");
        return -1;
    }

    // set
    TDB_DATA tkey;
    TDB_DATA tvalue;
    for(int i=0;i<1000;++i){
        get_tdb_val(tdb, i, &tkey, &tvalue);
        if(0 != tdb_store(tdb, tkey, tvalue, TDB_INSERT)){
            printf("fault. key:%s val:%s\n", tkey.dptr, tvalue.dptr);
            continue;
        }
        printf("success set %d\n", i);
    }

    // get
    for(int i=0;i<1000;++i){
        TDB_DATA tret;
        get_tdb_val(tdb, i, &tkey, &tvalue);

        tret = tdb_fetch(tdb, tkey);
        if( strcmp(tvalue.dptr, tret.dptr) ){
            printf("fault. key:%s val:%s ret:%s\n", tkey.dptr, tvalue.dptr, tret.dptr);
            continue;
        }
        delete tret.dptr;
        printf("success. get %d\n", i);
    }
    tdb_close(tdb);
    printf("success end.\n");
}
$ cat Makefile
INCDIR=/home/sikaku/local/include
LIBDIR=/home/sikaku/local/lib

default: all

tdb_overflow:tdb_overflow.cc
    g++ -g -I$(INCDIR) -L$(LIBDIR) -ltdb tdb_overflow.cc -o $@

all:tdb_overflow

clean:
    rm ./tdb_overflow

test:
    LD_LIBRARY_PATH=$(LIBDIR) ./tdb_overflow

5160394752byte の tdb.db が作成されて、正常に終了した。

No comments:

Post a Comment