Arhn - архитектура программирования

Итератор указателя на функцию в Berkeley DB

Я реализую итератор для просмотра записей из базы данных Беркли. Однако, похоже, мне нужно установить флаг DB_DBT_USERMEM перед вызовом cursor->get с DB_NEXT.

Такой подход сделал бы мой итератор менее связным, и мне пришлось бы реализовывать несколько итераторов для каждого типа данных, которые я хочу получить.

Есть ли способ иметь общий итератор, который может перемещаться по структурам без указателей и базовых типов данных? Вот чего я пытаюсь добиться.

#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, хотя бы для того, чтобы избежать вызова malloc() внутри BDB для DB_DBT_MALLOC/REALLOC. Когда вы используете его, вы должны передать в свою собственную память достаточно большой объем, чтобы вместить самый большой элемент в вашей базе данных. Это справедливо и для ключевого DBT, так как вы можете использовать его там.

В вашем примере, поскольку ключ и данные настолько малы, я бы просто поместил массивы символов в стек в вашей функции «итератор», а затем инициализировал ключ и данные после вызова memset(). То, что у вас выше, неверно, потому что вы устанавливаете USERMEM после вызова c_get().

Вот переработанный пример, который дает 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;
}

Чтобы обрабатывать различные структуры внутри вашего итератора, каким-то образом включите тип данных как часть ключа. Например, вместо простого целого числа для ключа используйте структуру, и пусть первый символ определяет, к какому типу он относится. Затем внутри вашей функции итератора вы можете включить это.

27.03.2014
  • Спасибо за ваш ответ. Есть ли способ, которым итератор может перемещаться по структурам без указателей и базовых типов и позволять функции, на которую указывает указатель, обрабатывать тип? в отличие от нескольких итераторов для каждого типа данных. Я обновил пример. 27.03.2014
  • Типичный способ обработки — каким-то образом включить тип данных как часть ключа. Например, вместо простого целого числа для ключа используйте структуру, и пусть первый символ определяет, к какому типу он относится. Затем внутри вашей функции итератора вы можете включить это. 27.03.2014
  • Спасибо, кажется, это то, что я ищу. 28.03.2014
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..