cruppstahl / upscaledb

A very fast lightweight embedded database engine with a built-in query language.
https://upscaledb.com
Apache License 2.0
568 stars 69 forks source link

ups_cursor_find won't return #103

Closed Amadeszueusz closed 6 years ago

Amadeszueusz commented 6 years ago

Please check the following sample:

void fillWithRandom(ups_db_t* db, size_t item_count)
{
    srand(0);

    std::set<unsigned int> unique_keys;

    while(unique_keys.size() != item_count)
    {
        unsigned int v = rand() % 100000;
        if(unique_keys.insert(v).second)
        {
            ups_key_t key = ups_make_key(&v, sizeof(v));
            ups_record_t record = {0};

            ups_db_insert(db, 0, &key, &record, 0);
        }
    }
}

const unsigned int bulk_size = 100;

int main()
{
    ups_env_t* env;
    ups_env_create(&env, "test.db", UPS_ENABLE_TRANSACTIONS, 0664, 0);

    ups_parameter_t params[] = {
    {UPS_PARAM_KEY_TYPE, UPS_TYPE_UINT32},
    {0, }
    };

    ups_db_t* db_1;
    ups_env_create_db(env, &db_1, 1, 0, &params[0]);
    ups_db_t* db_2;
    ups_env_create_db(env, &db_2, 2, 0, &params[0]);

    size_t db_size = bulk_size * 2;

    fillWithRandom(db_1, db_size);

    ups_status_t st;

    do
    {
        ups_cursor_t* cur;
        if(UPS_SUCCESS != (st =ups_cursor_create(&cur, db_1, 0, 0)))
        {
            std::cout << "Cursor create error " << st;
        }
        unsigned int query = 0;

        ups_key_t key_find = ups_make_key(&query, sizeof(query));

        if((st = ups_cursor_find(cur, &key_find, 0, UPS_FIND_GEQ_MATCH)) != UPS_SUCCESS) // won't return in second iteration
        {
            std::cout << "Find error " << st;
        }

        ups_key_t key_move = {0};

        size_t insertions = 0;

        while(UPS_SUCCESS == (st = ups_cursor_move(cur, &key_move, 0, UPS_CURSOR_NEXT)) && (insertions++ <= bulk_size))
        {
            ups_record_t record = {0};

            if(UPS_SUCCESS != (st = ups_db_insert(db_2, 0, &key_move, &record, 0)))
            {
                std::cout << "Insert error " << st;
            }

            if(UPS_SUCCESS != (st = ups_db_erase(db_1, 0, &key_move, 0)))
            {
                std::cout << "Erase error " << st;
            }
        }

        if(UPS_SUCCESS != (st = ups_cursor_close(cur)))
        {
            std::cout << "Cursor close error " << st;
        }

    }while((db_size -= bulk_size) > 0);

    return 0;
}

What I tried here was to transfer data between databases in chunks. During second iteration ups_cursor_find won't return. With transactions disabled this issue doesn't occur.

_Remark: In app where I'm using upscaledb this function may also returned UPS_KEY_NOT_FOUND on non-empty database where key to look for is the lowest possible value from key-values range. (Ex.: 0 in range <0; 6555000>). In some cases ups_cursor_find would also not return depending on how many items was stored in db.