[英]RocksDB: iterator upper bound not working as expected
我需要使用以下格式的键在 RocksDB(使用 v6.20.3)中存储一堆值: PREFIX_<INTEGER_ID>
。 INTEGER_ID
是从0
到N
的连续数字序列。
我使用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.