Skip to content

Commit c062d4e

Browse files
committed
Add ticker stats for read corruption retries (#12923)
Summary: Add a couple of ticker stats for corruption retry count and successful retries. This PR also eliminates an extra read attempt when there's a checksum mismatch in a block read from the prefetch buffer. Pull Request resolved: #12923 Test Plan: Update existing tests Reviewed By: jowlyzhang Differential Revision: D61024687 Pulled By: anand1976 fbshipit-source-id: 3a08403580ab244000e0d480b7ee0f5a03d76b06
1 parent dec94ec commit c062d4e

File tree

10 files changed

+81
-2
lines changed

10 files changed

+81
-2
lines changed

db/db_impl/db_impl_open.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,12 @@ Status DBImpl::Recover(
530530
/*no_error_if_files_missing=*/false, is_retry,
531531
&desc_status);
532532
desc_status.PermitUncheckedError();
533+
if (is_retry) {
534+
RecordTick(stats_, FILE_READ_CORRUPTION_RETRY_COUNT);
535+
if (desc_status.ok()) {
536+
RecordTick(stats_, FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT);
537+
}
538+
}
533539
if (can_retry) {
534540
// If we're opening for the first time and the failure is likely due to
535541
// a corrupt MANIFEST file (could result in either the log::Reader

db/db_io_failure_test.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,7 @@ class DBIOCorruptionTest
705705
DBIOCorruptionTest() : DBIOFailureTest() {
706706
BlockBasedTableOptions bbto;
707707
options_ = CurrentOptions();
708+
options_.statistics = CreateDBStatistics();
708709

709710
base_env_ = env_;
710711
EXPECT_NE(base_env_, nullptr);
@@ -727,6 +728,8 @@ class DBIOCorruptionTest
727728

728729
Status ReopenDB() { return TryReopen(options_); }
729730

731+
Statistics* stats() { return options_.statistics.get(); }
732+
730733
protected:
731734
std::unique_ptr<Env> env_guard_;
732735
std::shared_ptr<CorruptionFS> fs_;
@@ -749,8 +752,12 @@ TEST_P(DBIOCorruptionTest, GetReadCorruptionRetry) {
749752
if (std::get<2>(GetParam())) {
750753
ASSERT_OK(s);
751754
ASSERT_EQ(val, "val1");
755+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 1);
756+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT),
757+
1);
752758
} else {
753759
ASSERT_TRUE(s.IsCorruption());
760+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 0);
754761
}
755762
}
756763

@@ -773,8 +780,12 @@ TEST_P(DBIOCorruptionTest, IterReadCorruptionRetry) {
773780
}
774781
if (std::get<2>(GetParam())) {
775782
ASSERT_OK(iter->status());
783+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 1);
784+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT),
785+
1);
776786
} else {
777787
ASSERT_TRUE(iter->status().IsCorruption());
788+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 0);
778789
}
779790
delete iter;
780791
}
@@ -799,9 +810,13 @@ TEST_P(DBIOCorruptionTest, MultiGetReadCorruptionRetry) {
799810
if (std::get<2>(GetParam())) {
800811
ASSERT_EQ(values[0].ToString(), "val1");
801812
ASSERT_EQ(values[1].ToString(), "val2");
813+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 1);
814+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT),
815+
1);
802816
} else {
803817
ASSERT_TRUE(statuses[0].IsCorruption());
804818
ASSERT_TRUE(statuses[1].IsCorruption());
819+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 0);
805820
}
806821
}
807822

@@ -818,6 +833,9 @@ TEST_P(DBIOCorruptionTest, CompactionReadCorruptionRetry) {
818833
Status s = dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
819834
if (std::get<2>(GetParam())) {
820835
ASSERT_OK(s);
836+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 1);
837+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT),
838+
1);
821839

822840
std::string val;
823841
ReadOptions ro;
@@ -826,6 +844,7 @@ TEST_P(DBIOCorruptionTest, CompactionReadCorruptionRetry) {
826844
ASSERT_EQ(val, "val1");
827845
} else {
828846
ASSERT_TRUE(s.IsCorruption());
847+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 0);
829848
}
830849
}
831850

@@ -838,6 +857,9 @@ TEST_P(DBIOCorruptionTest, FlushReadCorruptionRetry) {
838857
Status s = Flush();
839858
if (std::get<2>(GetParam())) {
840859
ASSERT_OK(s);
860+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 1);
861+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT),
862+
1);
841863

842864
std::string val;
843865
ReadOptions ro;
@@ -846,6 +868,7 @@ TEST_P(DBIOCorruptionTest, FlushReadCorruptionRetry) {
846868
ASSERT_EQ(val, "val1");
847869
} else {
848870
ASSERT_NOK(s);
871+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 0);
849872
}
850873
}
851874

@@ -862,8 +885,12 @@ TEST_P(DBIOCorruptionTest, ManifestCorruptionRetry) {
862885

863886
if (std::get<2>(GetParam())) {
864887
ASSERT_OK(ReopenDB());
888+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 1);
889+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT),
890+
1);
865891
} else {
866892
ASSERT_EQ(ReopenDB(), Status::Corruption());
893+
ASSERT_EQ(stats()->getTickerCount(FILE_READ_CORRUPTION_RETRY_COUNT), 0);
867894
}
868895
SyncPoint::GetInstance()->DisableProcessing();
869896
}

include/rocksdb/statistics.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,11 @@ enum Tickers : uint32_t {
529529
// Footer corruption detected when opening an SST file for reading
530530
SST_FOOTER_CORRUPTION_COUNT,
531531

532+
// Counters for file read retries with the verify_and_reconstruct_read
533+
// file system option after detecting a checksum mismatch
534+
FILE_READ_CORRUPTION_RETRY_COUNT,
535+
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT,
536+
532537
TICKER_ENUM_MAX
533538
};
534539

java/rocksjni/portal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5269,6 +5269,10 @@ class TickerTypeJni {
52695269
return -0x53;
52705270
case ROCKSDB_NAMESPACE::Tickers::SST_FOOTER_CORRUPTION_COUNT:
52715271
return -0x55;
5272+
case ROCKSDB_NAMESPACE::Tickers::FILE_READ_CORRUPTION_RETRY_COUNT:
5273+
return -0x56;
5274+
case ROCKSDB_NAMESPACE::Tickers::FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT:
5275+
return -0x57;
52725276
case ROCKSDB_NAMESPACE::Tickers::TICKER_ENUM_MAX:
52735277
// -0x54 is the max value at this time. Since these values are exposed
52745278
// directly to Java clients, we'll keep the value the same till the next
@@ -5726,6 +5730,11 @@ class TickerTypeJni {
57265730
return ROCKSDB_NAMESPACE::Tickers::PREFETCH_HITS;
57275731
case -0x55:
57285732
return ROCKSDB_NAMESPACE::Tickers::SST_FOOTER_CORRUPTION_COUNT;
5733+
case -0x56:
5734+
return ROCKSDB_NAMESPACE::Tickers::FILE_READ_CORRUPTION_RETRY_COUNT;
5735+
case -0x57:
5736+
return ROCKSDB_NAMESPACE::Tickers::
5737+
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT;
57295738
case -0x54:
57305739
// -0x54 is the max value at this time. Since these values are exposed
57315740
// directly to Java clients, we'll keep the value the same till the next

java/src/main/java/org/rocksdb/TickerType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,10 @@ public enum TickerType {
878878

879879
SST_FOOTER_CORRUPTION_COUNT((byte) -0x55),
880880

881+
FILE_READ_CORRUPTION_RETRY_COUNT((byte) -0x56),
882+
883+
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT((byte) -0x57),
884+
881885
TICKER_ENUM_MAX((byte) -0x54);
882886

883887
private final byte value;

monitoring/statistics.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
266266
{PREFETCH_BYTES_USEFUL, "rocksdb.prefetch.bytes.useful"},
267267
{PREFETCH_HITS, "rocksdb.prefetch.hits"},
268268
{SST_FOOTER_CORRUPTION_COUNT, "rocksdb.footer.corruption.count"},
269+
{FILE_READ_CORRUPTION_RETRY_COUNT,
270+
"rocksdb.file.read.corruption.retry.count"},
271+
{FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT,
272+
"rocksdb.file.read.corruption.retry.success.count"},
269273
};
270274

271275
const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {

table/block_based/block_based_table_reader.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,10 @@ Status BlockBasedTable::Open(
693693
s = ReadFooterFromFile(retry_opts, file.get(), *ioptions.fs,
694694
prefetch_buffer.get(), file_size, &footer,
695695
kBlockBasedTableMagicNumber);
696+
RecordTick(ioptions.stats, FILE_READ_CORRUPTION_RETRY_COUNT);
697+
if (s.ok()) {
698+
RecordTick(ioptions.stats, FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT);
699+
}
696700
}
697701
}
698702
if (!s.ok()) {

table/block_based/block_based_table_reader_sync_and_async.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,16 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
223223
s = VerifyBlockChecksum(footer, data, handle.size(),
224224
rep_->file->file_name(), handle.offset());
225225
RecordTick(ioptions.stats, BLOCK_CHECKSUM_COMPUTE_COUNT);
226+
if (!s.ok()) {
227+
RecordTick(ioptions.stats, BLOCK_CHECKSUM_MISMATCH_COUNT);
228+
}
226229
TEST_SYNC_POINT_CALLBACK("RetrieveMultipleBlocks:VerifyChecksum", &s);
227230
if (!s.ok() &&
228231
CheckFSFeatureSupport(ioptions.fs.get(),
229232
FSSupportedOps::kVerifyAndReconstructRead)) {
230233
assert(s.IsCorruption());
231234
assert(!ioptions.allow_mmap_reads);
232-
RecordTick(ioptions.stats, BLOCK_CHECKSUM_MISMATCH_COUNT);
235+
RecordTick(ioptions.stats, FILE_READ_CORRUPTION_RETRY_COUNT);
233236

234237
// Repeat the read for this particular block using the regular
235238
// synchronous Read API. We can use the same chunk of memory
@@ -246,6 +249,10 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
246249
assert(result.size() == BlockSizeWithTrailer(handle));
247250
s = VerifyBlockChecksum(footer, data, handle.size(),
248251
rep_->file->file_name(), handle.offset());
252+
if (s.ok()) {
253+
RecordTick(ioptions.stats,
254+
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT);
255+
}
249256
} else {
250257
s = io_s;
251258
}

table/block_fetcher.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ inline bool BlockFetcher::TryGetFromPrefetchBuffer() {
8484
if (io_status_.ok()) {
8585
got_from_prefetch_buffer_ = true;
8686
used_buf_ = const_cast<char*>(slice_.data());
87-
} else if (!(io_status_.IsCorruption() && retry_corrupt_read_)) {
87+
} else if (io_status_.IsCorruption()) {
88+
// Returning true apparently indicates we either got some data from
89+
// the prefetch buffer, or we tried and encountered an error.
8890
return true;
8991
}
9092
}
@@ -334,9 +336,15 @@ void BlockFetcher::ReadBlock(bool retry) {
334336
ProcessTrailerIfPresent();
335337
}
336338

339+
if (retry) {
340+
RecordTick(ioptions_.stats, FILE_READ_CORRUPTION_RETRY_COUNT);
341+
}
337342
if (io_status_.ok()) {
338343
InsertCompressedBlockToPersistentCacheIfNeeded();
339344
fs_buf_ = std::move(read_req.fs_scratch);
345+
if (retry) {
346+
RecordTick(ioptions_.stats, FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT);
347+
}
340348
} else {
341349
ReleaseFileSystemProvidedBuffer(&read_req);
342350
direct_io_buf_.reset();
@@ -355,7 +363,11 @@ IOStatus BlockFetcher::ReadBlockContents() {
355363
return IOStatus::OK();
356364
}
357365
if (TryGetFromPrefetchBuffer()) {
366+
if (io_status_.IsCorruption() && retry_corrupt_read_) {
367+
ReadBlock(/*retry=*/true);
368+
}
358369
if (!io_status_.ok()) {
370+
assert(!fs_buf_);
359371
return io_status_;
360372
}
361373
} else if (!TryGetSerializedBlockFromPersistentCache()) {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add ticker stats to count file read retries due to checksum mismatch

0 commit comments

Comments
 (0)