Fix false NotFound from batched MultiGet with kHashSearch (#6821)

Summary:
The error is assigning KeyContext::s to NotFound status in a
table reader for a "not found in this table" case, which skips searching
in later tables, like only a delete should. (The hash search index iterator
is the only one that can return status NotFound even if Valid() == false.)

This was detected by intermittent failure in
MultiThreadedDBTest.MultiThreaded/5, a kHashSearch configuration.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6821

Test Plan: modified existing unit test to reproduce problem

Reviewed By: anand1976

Differential Revision: D21450469

Pulled By: pdillinger

fbshipit-source-id: 7478003684d637dbd491cdac81468041a791be2c
main
Peter Dillinger 4 years ago committed by Facebook GitHub Bot
parent e9ba4ba348
commit b27a1448b6
  1. 1
      HISTORY.md
  2. 8
      db/db_basic_test.cc
  3. 7
      table/block_based/block_based_table_reader.cc

@ -2,6 +2,7 @@
## Unreleased ## Unreleased
### Bug Fixes ### Bug Fixes
* Fix consistency checking error swallowing in some cases when options.force_consistency_checks = true. * Fix consistency checking error swallowing in some cases when options.force_consistency_checks = true.
* Fix possible false NotFound status from batched MultiGet using index type kHashSearch.
### Public API Change ### Public API Change
* Flush(..., column_family) may return Status::ColumnFamilyDropped() instead of Status::InvalidArgument() if column_family is dropped while processing the flush request. * Flush(..., column_family) may return Status::ColumnFamilyDropped() instead of Status::InvalidArgument() if column_family is dropped while processing the flush request.

@ -1295,14 +1295,18 @@ TEST_F(DBBasicTest, MultiGetBatchedSimpleUnsorted) {
} while (ChangeCompactOptions()); } while (ChangeCompactOptions());
} }
TEST_F(DBBasicTest, MultiGetBatchedSimpleSorted) { TEST_F(DBBasicTest, MultiGetBatchedSortedMultiFile) {
do { do {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
SetPerfLevel(kEnableCount); SetPerfLevel(kEnableCount);
// To expand the power of this test, generate > 1 table file and
// mix with memtable
ASSERT_OK(Put(1, "k1", "v1")); ASSERT_OK(Put(1, "k1", "v1"));
ASSERT_OK(Put(1, "k2", "v2")); ASSERT_OK(Put(1, "k2", "v2"));
Flush(1);
ASSERT_OK(Put(1, "k3", "v3")); ASSERT_OK(Put(1, "k3", "v3"));
ASSERT_OK(Put(1, "k4", "v4")); ASSERT_OK(Put(1, "k4", "v4"));
Flush(1);
ASSERT_OK(Delete(1, "k4")); ASSERT_OK(Delete(1, "k4"));
ASSERT_OK(Put(1, "k5", "v5")); ASSERT_OK(Put(1, "k5", "v5"));
ASSERT_OK(Delete(1, "no_key")); ASSERT_OK(Delete(1, "no_key"));
@ -1333,7 +1337,7 @@ TEST_F(DBBasicTest, MultiGetBatchedSimpleSorted) {
ASSERT_TRUE(s[5].IsNotFound()); ASSERT_TRUE(s[5].IsNotFound());
SetPerfLevel(kDisable); SetPerfLevel(kDisable);
} while (ChangeCompactOptions()); } while (ChangeOptions());
} }
TEST_F(DBBasicTest, MultiGetBatchedMultiLevel) { TEST_F(DBBasicTest, MultiGetBatchedMultiLevel) {

@ -2461,13 +2461,16 @@ void BlockBasedTable::MultiGet(const ReadOptions& read_options,
ExtractUserKey(v.first_internal_key)) < 0)) { ExtractUserKey(v.first_internal_key)) < 0)) {
// The requested key falls between highest key in previous block and // The requested key falls between highest key in previous block and
// lowest key in current block. // lowest key in current block.
*(miter->s) = iiter->status(); if (!iiter->status().IsNotFound()) {
*(miter->s) = iiter->status();
}
data_block_range.SkipKey(miter); data_block_range.SkipKey(miter);
sst_file_range.SkipKey(miter); sst_file_range.SkipKey(miter);
continue; continue;
} }
if (!uncompression_dict_status.ok()) { if (!uncompression_dict_status.ok()) {
assert(!uncompression_dict_status.IsNotFound());
*(miter->s) = uncompression_dict_status; *(miter->s) = uncompression_dict_status;
data_block_range.SkipKey(miter); data_block_range.SkipKey(miter);
sst_file_range.SkipKey(miter); sst_file_range.SkipKey(miter);
@ -2680,7 +2683,7 @@ void BlockBasedTable::MultiGet(const ReadOptions& read_options,
PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_full_true_positive, 1, PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_full_true_positive, 1,
rep_->level); rep_->level);
} }
if (s.ok()) { if (s.ok() && !iiter->status().IsNotFound()) {
s = iiter->status(); s = iiter->status();
} }
*(miter->s) = s; *(miter->s) = s;

Loading…
Cancel
Save