when using custom comparator (https://github.com/facebook/rocksdb/wiki/Basic-Operations#user-content-comparators) ,
iterator->SeekToFirst() is wrong after DeleteRange.
class MyComparator : public rocksdb::Comparator {
public:
// Three-way comparison function:
// if a < b: negative result
// if a > b: positive result
// else: zero result
int Compare(const rocksdb::Slice& a, const rocksdb::Slice& b) const override {
int a_int = 0, b_int = 0;
std::stringstream s;
s << a.data();
s >> a_int;
s.str("");
s << b.data();
s >> b_int;
s.clear();
if (a_int < b_int) return -1;
if (a_int > b_int) return 1;
return 0;
}
// Ignore the following methods for now:
const char* Name() const override { return "MyComparator"; }
void FindShortestSeparator(std::string*, const rocksdb::Slice&) const override { }
void FindShortSuccessor(std::string*) const override { }
};
int main() {
MyComparator cmp;
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
options.comparator = &cmp;
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
rocksdb::WriteOptions write_options;
db->Put(write_options, "1", "v1");
db->Put(write_options, "10", "v10");
db->Put(write_options, "2", "v2");
db->Put(write_options, "3", "v3");
std::cout << "before delete:" << std::endl;
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << ": " << it->value().ToString() << std::endl;
}
assert(it->status().ok());
delete it;
db->DeleteRange(write_options, db->DefaultColumnFamily(), "1", "3");
std::cout << "after delete:" << std::endl;
it = db->NewIterator(rocksdb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << ": " << it->value().ToString() << std::endl;
}
assert(it->status().ok());
delete it;
return 0;
}
the result is:
before delete:
1: v1
2: v2
3: v3
10: v10
after delete:
it should be:
before delete:
1: v1
2: v2
3: v3
10: v10
after delete:
3: v3
10: v10
You can鈥檛 convert a.data() to int this way. A slice data() method needs to be used together with size(), since data() does not return a null-terminated string version of a slice.
Using
int a_int = std::stoi(a.ToString());
int b_int = std::stoi(b.ToString());
should work fine.
For better performance use fixed size keys (sizeof(int)) converted to BigEndian. This allows to compare numbers using default comparator.
Thanks @Devernua. Did you verify that it fixes the expected results?
@ajkr, yes
Most helpful comment
You can鈥檛 convert a.data() to int this way. A slice data() method needs to be used together with size(), since data() does not return a null-terminated string version of a slice.
Using
should work fine.
For better performance use fixed size keys (sizeof(int)) converted to BigEndian. This allows to compare numbers using default comparator.