Berkeley DB中的函数指针迭代器

时间:2014-03-26 22:00:25

标签: c iterator function-pointers berkeley-db

我实现了一个迭代器来检查Berkeley DB中的记录。但是,我似乎需要在调用cursor-> get with DB_NEXT之前设置DB_DBT_USERMEM标志。

这样做会使我的迭代器不那么有凝聚力,并且必须为我想要检索的每种数据类型实现多个迭代器。

有没有办法让一个通用的迭代器可以遍历没有指针和基本数据类型的结构?这就是我想要实现的目标。

#include <stdio.h>
#include <string.h>
#include <db.h>

// let this function handle integers and use DB_DBT_USERMEM for memory alignment
void integer_items(DBT key, DBT data) {
        int number = 0;
        data.data = &number;
        data.flags = DB_DBT_USERMEM;
        data.ulen = sizeof(int);
        printf("key is: %s, data is: %d\n", (char *) key.data,number);
}

// let this function handle pointer structs. No need for DB_DBT_USERMEM
void ptr_struct_items(DBT key, DBT data) {
        // MY_STRUCT user;
        // marshall struct...
        // buffsize = sizeof(int) +(strlen(user.familiar_name) + strlen(user.surname) + 2);
        // databuff = malloc(buffsize);
        // memset(databuff, 0, buffsize);  
        // ...
        // printf("key is: %s, data is: %d\n", (char *) key.data,number);
}

int iterator(DB *database, void(*function)(DBT key, DBT data)) {
        DBT key, data;
        DBC *cursor;

        memset(&key, 0, sizeof(DBT));
        memset(&data, 0, sizeof(DBT));
        database->cursor(database, NULL, &cursor, 0);
        while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
                (*function)(key, data);
        }
        cursor->c_close(cursor);
        return 0;
}

int main() {
        DB_ENV *myEnv;
        DB *dbp;
        DBT key, data;
        int r, v = 10;
        char *k = "Test";

        db_env_create(&myEnv, 0);
        myEnv->open(myEnv, "./", DB_CREATE | DB_INIT_MPOOL, 0);

        db_create(&dbp, myEnv, 0);
        dbp->open(dbp, NULL, "test.db", NULL, DB_HASH, DB_CREATE, 0664);

        memset(&key, 0, sizeof(key));
        memset(&data, 0, sizeof(data));

        key.data = k;
        key.size = strlen(k) +1;
        data.data = &v;
        data.size = sizeof(int);

        if((r=dbp->put(dbp, NULL, &key, &data, 0)!=0))
                fprintf(stderr, "%s\n", db_strerror(r));

        iterator(dbp, integer_items);
        iterator(dbp, ptr_struct_items);

        return 0;
}

1 个答案:

答案 0 :(得分:0)

你几乎总是想要使用DB_DBT_USERMEM,如果只是为了避免来自BDB内部的DB_DBT_MALLOC / REALLOC的malloc()。使用它时,必须传入足够大的内存以容纳数据库中最大的项目。这也适用于关键的DBT,因为你可能想在那里使用它。

在您的示例中,由于密钥和数据非常小,我只是将字符数组放在您的&#34; iterator&#34;中。函数,然后在调用memset()后初始化键和数据。你上面提到的是错误的,因为你在调用c_get()之后设置了USERMEM。

这是一个重写的示例,它为BDB提供256字节的密钥和数据。

void integer_items(DBT key, DBT data) {
        int number = 0;

        if (data.size == sizeof number) {
            number = *(int *)data.data;
            printf("key is: %s, data is: %d\n", (char *) key.data, number);
        }
}

int iterator(DB *database, void(*function)(DBT key, DBT data)) {
        DBT key, data;
        DBC *cursor;
        char kmem[256];
        char dmem[256];

        memset(&key, 0, sizeof(DBT));
        memset(&data, 0, sizeof(DBT));

        key.flags  = DB_DBT_USERMEM;
        key.data   = kmem;
        key.ulen   = sizeof kmem;

        data.flags = DB_DBT_USERMEM;
        data.data  = dmem;
        data.ulen  = sizeof dmem;

        database->cursor(database, NULL, &cursor, 0);
        while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
                (*function)(key, data);
        }
        cursor->c_close(cursor);
        return 0;
}

要处理迭代器内部的不同结构,请以某种方式将数据类型包含在键的一部分中。例如,代替键的裸整数,使用结构,并使第一个字符定义它是哪种类型。然后,在你的迭代器函数中,你可以打开它。