I was noticing an issue with database compaction causing some values that had been deleted to mysteriously reappear. I've included an example below.
The example creates two (interspersed) ranges of keys and then deletes the second one. When the compaction is done, some of the deleted keys are still seen in the database. When the compaction line is commented out, the example works correctly.
This seems to be related to the size of the database (keys + values), with the bug only showing up after a large number of keys is used. Also, I'm only seeing the problem when doing batch deletes.
Sincerely,
Kevin Regan
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
namespace {
const std::string DB_PATH = "/tmp/my_test_db";
size_t NUM_KEYS = 1100000;
void
check_status(const leveldb::Status& status, const std::string& error_msg)
{
if (!status.ok()) {
std::cerr << "ERROR: " << error_msg << ": " <<
status.ToString() << std::endl;
std::exit(1);
}
}
std::string
create_key_1(size_t i)
{
std::ostringstream out;
out << "my_key_" << i;
return out.str();
}
std::string
create_key_2(size_t i)
{
return create_key_1(i) + "_xxx";
}
} // namespace
int
main (int argc, char** argv)
{
// open database
leveldb::DB* db;
leveldb::Options db_options;
db_options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(db_options, DB_PATH, &db);
check_status(status, "Could not open database");
// create first key range
std::cout << "Creating first key range" << std::endl;
leveldb::WriteBatch batch;
for (size_t i = 0; i < NUM_KEYS; i++) {
batch.Put(create_key_1(i), "value for range 1 key");
}
status = db->Write(leveldb::WriteOptions(), &batch);
check_status(status, "Could not create keys for first range");
// create second key range
std::cout << "Creating second key range" << std::endl;
batch.Clear();
for (size_t i = 0; i < NUM_KEYS; i++) {
batch.Put(create_key_2(i), "value for range 2 key");
}
status = db->Write(leveldb::WriteOptions(), &batch);
check_status(status, "Could not create keys for second range");
// delete second key range
std::cout << "Deleting second key range" << std::endl;
batch.Clear();
for (size_t i = 0; i < NUM_KEYS; i++) {
batch.Delete(create_key_2(i));
}
status = db->Write(leveldb::WriteOptions(), &batch);
check_status(status, "Could not delete keys");
// compact database
std::cout << "Compacting database" << std::endl;
std::string start_key = create_key_1(0);
std::string end_key = create_key_1(NUM_KEYS - 1);
leveldb::Slice least(start_key.data(), start_key.size());
leveldb::Slice greatest(end_key.data(), end_key.size());
// commenting out the line below causes the example to work correctly
db->CompactRange(&least, &greatest);
// count the keys
std::cout << "Counting number of keys left" << std::endl;
leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions());;
size_t num_keys = 0;
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
num_keys++;
}
delete iter;
std::cout << "Found " << num_keys << " keys" << std::endl;
// close database
delete db;
}
--
You received this message because you are subscribed to the Google Groups "leveldb" group.
To unsubscribe from this group and stop receiving emails from it, send an email to leveldb+unsubscribe <at> googlegroups.com.
For more options, visit
https://groups.google.com/groups/opt_out.