簡體   English   中英

RocksDB:迭代器上限未按預期工作

[英]RocksDB: iterator upper bound not working as expected

我需要使用以下格式的鍵在 RocksDB(使用 v6.20.3)中存儲一堆值: PREFIX_<INTEGER_ID> INTEGER_ID是從0N的連續數字序列。

我使用serialize_uint32_t function 將 integer ID 轉換為 lexographic 有序字符串(因為我需要按順序迭代整數)。 由於N可能很大,我想通過設置迭代器的iterate_upper_bound屬性來迭代 RocksDB 條目,直到更小的 integer 值K 但是,當我啟用此屬性時,不會發生迭代。

下面是一個小型的、完全可復制的程序。 當我注釋掉上限設置行時,迭代器工作並且值被正確打印。

更新:注意到另一個奇怪的事情:帶有上限的代碼片段在調試模式下工作正常,但在 -O2 發布時卻不行。

#include <iostream>
#include <rocksdb/db.h>
#include <rocksdb/options.h>

using namespace std;

static std::string serialize_uint32_t(uint32_t num) {
    unsigned char bytes[4];
    bytes[0] = (unsigned char) ((num >> 24) & 0xFF);
    bytes[1] = (unsigned char) ((num >> 16) & 0xFF);
    bytes[2] = (unsigned char) ((num >> 8) & 0xFF);
    bytes[3] = (unsigned char) ((num & 0xFF));

    return std::string(bytes, bytes+4);
}

int main() {
    const std::string state_dir_path = "/tmp/local-data";
    system("rm -rf /tmp/local-data && mkdir -p /tmp/local-data");

    rocksdb::DB *db;
    rocksdb::Options options;
    rocksdb::WriteOptions write_options;
    options.create_if_missing = true;

    rocksdb::Status s = rocksdb::DB::Open(options, state_dir_path, &db);
    if(!s.ok()) {
        std::cout << "Error while initializing store: " << s.ToString() << std::endl;
        return 1;
    }

    std::string key_prefix = "PREFIX_";

    for(size_t i = 0; i < 9; i++) {
        auto key_val = key_prefix + serialize_uint32_t(i);
        db->Put(write_options, key_val, "HELLO:"+std::to_string(i));
    }

    std::cout << "Wrote 9 entries." << std::endl;

    // Try to iterate only 6 entries
    rocksdb::ReadOptions read_opts;
    rocksdb::Slice upper_bound(key_prefix + serialize_uint32_t(6));
    read_opts.iterate_upper_bound = &upper_bound;   // does NOT work when set

    rocksdb::Iterator *iter = db->NewIterator(read_opts);
    iter->Seek(key_prefix + serialize_uint32_t(0));

    while(iter->Valid() && iter->key().starts_with(key_prefix)) {
        std::cout << iter->value().ToString() << std::endl;
        iter->Next();
    }

    delete iter;
    delete db;

    return 0;
}

我不確定這是否是根本原因,但代碼有錯誤。 Rocksdb::Slice 類似於 std::string_view。 它指向一個 char 數組,但不維護它。 構造upper_bound后, key_prefix + serialize_uint32_t(6)可能會被銷毀,所以read_opts.iterate_upper_bound指向一個被銷毀的memory。

iter->Seek() 的參數可能也不安全,因為 Seek() 也接受rocksdb::Slice,而不是std::string。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM