Berkeley DB 中的函数指针迭代器

Posted

技术标签:

【中文标题】Berkeley DB 中的函数指针迭代器【英文标题】:Function pointer iterator in Berkeley DB 【发布时间】:2014-03-26 22:00:25 【问题描述】:

我正在实现一个迭代器来遍历伯克利数据库中的记录。但是,似乎我需要在调用 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】:

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

在您的示例中,由于键和数据非常小,我只需将字符数组放在“迭代器”函数的堆栈中,然后在调用 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;

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

【讨论】:

感谢您的回复。有没有一种方法可以让迭代器遍历没有指针的结构和基本类型,并让指向的函数处理类型?与每种数据类型的多个迭代器相反。我已经更新了示例。 处理该问题的典型方法是以某种方式将数据类型作为键的一部分包含在内。例如,不要使用裸整数作为键,而是使用结构,并让第一个字符定义它是哪种类型。然后,在你的迭代器函数中,你可以打开它。 谢谢,这似乎就是我要找的。​​span>

以上是关于Berkeley DB 中的函数指针迭代器的主要内容,如果未能解决你的问题,请参考以下文章

返回指向向量中项目的指针(来自迭代器)

Berkeley Db db_map 迭代器没有以正确的顺序循环

5.条款二十八:在class内切勿让public成员函数返回private成员的引用或指针或迭代器

STL迭代器

无论传递了迭代器类型/指针,指向元素的地址

是迭代器的指针类型转换吗?