facebook / facebook/rocksdb

DeleteRange causes put then iterate to fail on WBWI

Open
#5,260 7 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
32.1k
Forks
6.9k
Avg merge
32m
Merged PRs (30d)
1

Description

Putting the following 3 key/value pairs into a `WBWI` (`WriteBatchWithIndex`), i.e.:

```c++
batch.Put(&cf1, "a1", "some value");
batch.Put(&cf1, "a2", "some value");
batch.Put(&cf1, "a3", "some value");
```

With respect to `batch.NewIteratorWithBase`, iterating returns just those 3 key/value pairs correctly. So far so good!

---

However, if I call `batch.DeleteRange("a", "b")` before putting the values into the WBWI, then subsequently iterating the WBWI incorrectly returns 4 key/value pairs and not 3, i.e. the following code appears to cause false data to appear:

```c++
batch.DeleteRange("a", "b")

batch.Put(&cf1, "a1", "some value");
batch.Put(&cf1, "a2", "some value");
batch.Put(&cf1, "a3", "some value");
```

The first key/value pair returned by `NewIteratorWithBase` seems to be an error as its key has the value `a`, yet we never stored any such key!

I have created a reproducible test case showing the problem that fits into `utilities/write_batch_with_index/write_batch_with_index_test.cc`:

```c++
TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBaseDeleteRange) {
ColumnFamilyHandleImplDummy cf1(6, BytewiseComparator());
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);

std::string key1("a1");
std::string key2("a2");
std::string key3("a3");

const std::string fixed_value("some value");

// delete a range (NOTE: the line below erroneously causes the test to fail!!!)
batch.DeleteRange(&cf1, "a", "b");

// put keys in the range we just deleted
batch.Put(&cf1, key1, fixed_value);
batch.Put(&cf1, key2, fixed_value);
batch.Put(&cf1, key3, fixed_value);

// retrieve keys using iterator
KVMap empty_map;
std::unique_ptr iter(
batch.NewIteratorWithBase(&cf1, new KVIter(&empty_map)));

iter->Seek("a");

// check key1
ASSERT_OK(iter->status());
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(key1, iter->key().ToString());
ASSERT_EQ(fixed_value, iter->value().ToString());

iter->Next();

// check key2
ASSERT_OK(iter->status());
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(key2, iter->key().ToString());
ASSERT_EQ(fixed_value, iter->value().ToString());

iter->Next();

// check key3
ASSERT_OK(iter->status());
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(key3, iter->key().ToString());
ASSERT_EQ(fixed_value, iter->value().ToString());

// should have reached the end of iterator
iter->Next();
ASSERT_OK(iter->status());
ASSERT_FALSE(iter->Valid());
}
```

Commenting out the `batch.DeleteRange(&cf1, "a", "b");` above causes the test to pass, but I don't think it should actually have an impact on the iterator produced from `WriteBatchWithIndex::NewIteratorWithBase`.

Can someone please confirm that this is indeed an issue... and that I am not doing something blindly stupid ;-)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.