Improve Status message for block checksum mismatches

Summary:
We've got some DBs where iterators return Status with message "Corruption: block checksum mismatch" all the time. That's not very informative. It would be much easier to investigate if the error message contained the file name - then we would know e.g. how old the corrupted file is, which would be very useful for finding the root cause. This PR adds file name, offset and other stuff to some block corruption-related status messages.

It doesn't improve all the error messages, just a few that were easy to improve. I'm mostly interested in "block checksum mismatch" and "Bad table magic number" since they're the only corruption errors that I've ever seen in the wild.
Closes https://github.com/facebook/rocksdb/pull/2507

Differential Revision: D5345702

Pulled By: al13n321

fbshipit-source-id: fc8023d43f1935ad927cef1b9c55481ab3cb1339
main
Mike Kolupaev 8 years ago committed by Facebook Github Bot
parent 18c63af6ef
commit 397ab11152
  1. 3
      db/external_sst_file_ingestion_job.cc
  2. 2
      db/table_cache.cc
  3. 12
      db/version_set.cc
  4. 2
      table/cuckoo_table_builder_test.cc
  5. 10
      table/cuckoo_table_reader_test.cc
  6. 31
      table/format.cc
  7. 2
      table/table_reader_bench.cc
  8. 4
      tools/sst_dump_tool.cc
  9. 5
      util/file_reader_writer.h
  10. 3
      util/testutil.cc
  11. 2
      utilities/blob_db/blob_dump_tool.cc
  12. 3
      utilities/blob_db/blob_file.cc
  13. 2
      utilities/column_aware_encoding_util.cc
  14. 2
      utilities/persistent_cache/block_cache_tier_file.cc

@ -286,7 +286,8 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
if (!status.ok()) { if (!status.ok()) {
return status; return status;
} }
sst_file_reader.reset(new RandomAccessFileReader(std::move(sst_file))); sst_file_reader.reset(new RandomAccessFileReader(std::move(sst_file),
external_file));
status = cfd_->ioptions()->table_factory->NewTableReader( status = cfd_->ioptions()->table_factory->NewTableReader(
TableReaderOptions(*cfd_->ioptions(), env_options_, TableReaderOptions(*cfd_->ioptions(), env_options_,

@ -108,7 +108,7 @@ Status TableCache::GetTableReader(
} }
StopWatch sw(ioptions_.env, ioptions_.statistics, TABLE_OPEN_IO_MICROS); StopWatch sw(ioptions_.env, ioptions_.statistics, TABLE_OPEN_IO_MICROS);
std::unique_ptr<RandomAccessFileReader> file_reader( std::unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(file), ioptions_.env, new RandomAccessFileReader(std::move(file), fname, ioptions_.env,
ioptions_.statistics, record_read_stats, ioptions_.statistics, record_read_stats,
file_read_hist, ioptions_.rate_limiter, file_read_hist, ioptions_.rate_limiter,
for_compaction)); for_compaction));

@ -598,15 +598,15 @@ Status Version::GetTableProperties(std::shared_ptr<const TableProperties>* tp,
// 2. Table is not present in table cache, we'll read the table properties // 2. Table is not present in table cache, we'll read the table properties
// directly from the properties block in the file. // directly from the properties block in the file.
std::unique_ptr<RandomAccessFile> file; std::unique_ptr<RandomAccessFile> file;
std::string file_name;
if (fname != nullptr) { if (fname != nullptr) {
s = ioptions->env->NewRandomAccessFile( file_name = *fname;
*fname, &file, vset_->env_options_);
} else { } else {
s = ioptions->env->NewRandomAccessFile( file_name =
TableFileName(vset_->db_options_->db_paths, file_meta->fd.GetNumber(), TableFileName(vset_->db_options_->db_paths, file_meta->fd.GetNumber(),
file_meta->fd.GetPathId()), file_meta->fd.GetPathId());
&file, vset_->env_options_);
} }
s = ioptions->env->NewRandomAccessFile(file_name, &file, vset_->env_options_);
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
@ -615,7 +615,7 @@ Status Version::GetTableProperties(std::shared_ptr<const TableProperties>* tp,
// By setting the magic number to kInvalidTableMagicNumber, we can by // By setting the magic number to kInvalidTableMagicNumber, we can by
// pass the magic number check in the footer. // pass the magic number check in the footer.
std::unique_ptr<RandomAccessFileReader> file_reader( std::unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(file))); new RandomAccessFileReader(std::move(file), file_name));
s = ReadTableProperties( s = ReadTableProperties(
file_reader.get(), file_meta->fd.GetFileSize(), file_reader.get(), file_meta->fd.GetFileSize(),
Footer::kInvalidTableMagicNumber /* table's magic number */, *ioptions, &raw_table_properties); Footer::kInvalidTableMagicNumber /* table's magic number */, *ioptions, &raw_table_properties);

@ -56,7 +56,7 @@ class CuckooBuilderTest : public testing::Test {
// Assert Table Properties. // Assert Table Properties.
TableProperties* props = nullptr; TableProperties* props = nullptr;
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(read_file))); new RandomAccessFileReader(std::move(read_file), fname));
ASSERT_OK(ReadTableProperties(file_reader.get(), read_file_size, ASSERT_OK(ReadTableProperties(file_reader.get(), read_file_size,
kCuckooTableMagicNumber, ioptions, kCuckooTableMagicNumber, ioptions,
&props)); &props));

@ -116,7 +116,7 @@ class CuckooReaderTest : public testing::Test {
std::unique_ptr<RandomAccessFile> read_file; std::unique_ptr<RandomAccessFile> read_file;
ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options)); ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options));
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(read_file))); new RandomAccessFileReader(std::move(read_file), fname));
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucomp, CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucomp,
GetSliceHash); GetSliceHash);
@ -144,7 +144,7 @@ class CuckooReaderTest : public testing::Test {
std::unique_ptr<RandomAccessFile> read_file; std::unique_ptr<RandomAccessFile> read_file;
ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options)); ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options));
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(read_file))); new RandomAccessFileReader(std::move(read_file), fname));
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucomp, CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucomp,
GetSliceHash); GetSliceHash);
@ -322,7 +322,7 @@ TEST_F(CuckooReaderTest, WhenKeyNotFound) {
std::unique_ptr<RandomAccessFile> read_file; std::unique_ptr<RandomAccessFile> read_file;
ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options)); ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options));
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(read_file))); new RandomAccessFileReader(std::move(read_file), fname));
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucmp, CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucmp,
GetSliceHash); GetSliceHash);
@ -428,7 +428,7 @@ void WriteFile(const std::vector<std::string>& keys,
std::unique_ptr<RandomAccessFile> read_file; std::unique_ptr<RandomAccessFile> read_file;
ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options)); ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options));
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(read_file))); new RandomAccessFileReader(std::move(read_file), fname));
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
CuckooTableReader reader(ioptions, std::move(file_reader), file_size, CuckooTableReader reader(ioptions, std::move(file_reader), file_size,
@ -460,7 +460,7 @@ void ReadKeys(uint64_t num, uint32_t batch_size) {
std::unique_ptr<RandomAccessFile> read_file; std::unique_ptr<RandomAccessFile> read_file;
ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options)); ASSERT_OK(env->NewRandomAccessFile(fname, &read_file, env_options));
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(read_file))); new RandomAccessFileReader(std::move(read_file), fname));
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
CuckooTableReader reader(ioptions, std::move(file_reader), file_size, CuckooTableReader reader(ioptions, std::move(file_reader), file_size,

@ -221,7 +221,9 @@ std::string Footer::ToString() const {
Status ReadFooterFromFile(RandomAccessFileReader* file, uint64_t file_size, Status ReadFooterFromFile(RandomAccessFileReader* file, uint64_t file_size,
Footer* footer, uint64_t enforce_table_magic_number) { Footer* footer, uint64_t enforce_table_magic_number) {
if (file_size < Footer::kMinEncodedLength) { if (file_size < Footer::kMinEncodedLength) {
return Status::Corruption("file is too short to be an sstable"); return Status::Corruption(
"file is too short (" + ToString(file_size) + " bytes) to be an "
"sstable: " + file->file_name());
} }
char footer_space[Footer::kMaxEncodedLength]; char footer_space[Footer::kMaxEncodedLength];
@ -237,7 +239,9 @@ Status ReadFooterFromFile(RandomAccessFileReader* file, uint64_t file_size,
// Check that we actually read the whole footer from the file. It may be // Check that we actually read the whole footer from the file. It may be
// that size isn't correct. // that size isn't correct.
if (footer_input.size() < Footer::kMinEncodedLength) { if (footer_input.size() < Footer::kMinEncodedLength) {
return Status::Corruption("file is too short to be an sstable"); return Status::Corruption(
"file is too short (" + ToString(file_size) + " bytes) to be an "
"sstable" + file->file_name());
} }
s = footer->DecodeFrom(&footer_input); s = footer->DecodeFrom(&footer_input);
@ -246,7 +250,11 @@ Status ReadFooterFromFile(RandomAccessFileReader* file, uint64_t file_size,
} }
if (enforce_table_magic_number != 0 && if (enforce_table_magic_number != 0 &&
enforce_table_magic_number != footer->table_magic_number()) { enforce_table_magic_number != footer->table_magic_number()) {
return Status::Corruption("Bad table magic number"); return Status::Corruption(
"Bad table magic number: expected "
+ ToString(enforce_table_magic_number) + ", found "
+ ToString(footer->table_magic_number())
+ " in " + file->file_name());
} }
return Status::OK(); return Status::OK();
} }
@ -275,7 +283,11 @@ Status ReadBlock(RandomAccessFileReader* file, const Footer& footer,
return s; return s;
} }
if (contents->size() != n + kBlockTrailerSize) { if (contents->size() != n + kBlockTrailerSize) {
return Status::Corruption("truncated block read"); return Status::Corruption(
"truncated block read from " + file->file_name() + " offset "
+ ToString(handle.offset()) + ", expected "
+ ToString(n + kBlockTrailerSize) + " bytes, got "
+ ToString(contents->size()));
} }
// Check the crc of the type and the block contents // Check the crc of the type and the block contents
@ -293,10 +305,17 @@ Status ReadBlock(RandomAccessFileReader* file, const Footer& footer,
actual = XXH32(data, static_cast<int>(n) + 1, 0); actual = XXH32(data, static_cast<int>(n) + 1, 0);
break; break;
default: default:
s = Status::Corruption("unknown checksum type"); s = Status::Corruption(
"unknown checksum type " + ToString(footer.checksum())
+ " in " + file->file_name() + " offset "
+ ToString(handle.offset()) + " size " + ToString(n));
} }
if (s.ok() && actual != value) { if (s.ok() && actual != value) {
s = Status::Corruption("block checksum mismatch"); s = Status::Corruption(
"block checksum mismatch: expected " + ToString(actual)
+ ", got " + ToString(value) + " in " + file->file_name()
+ " offset " + ToString(handle.offset())
+ " size " + ToString(n));
} }
if (!s.ok()) { if (!s.ok()) {
return s; return s;

@ -139,7 +139,7 @@ void TableReaderBenchmark(Options& opts, EnvOptions& env_options,
uint64_t file_size; uint64_t file_size;
env->GetFileSize(file_name, &file_size); env->GetFileSize(file_name, &file_size);
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(raf))); new RandomAccessFileReader(std::move(raf), file_name));
s = opts.table_factory->NewTableReader( s = opts.table_factory->NewTableReader(
TableReaderOptions(ioptions, env_options, ikc), std::move(file_reader), TableReaderOptions(ioptions, env_options, ikc), std::move(file_reader),
file_size, &table_reader); file_size, &table_reader);

@ -79,7 +79,7 @@ Status SstFileReader::GetTableReader(const std::string& file_path) {
s = options_.env->GetFileSize(file_path, &file_size); s = options_.env->GetFileSize(file_path, &file_size);
} }
file_.reset(new RandomAccessFileReader(std::move(file))); file_.reset(new RandomAccessFileReader(std::move(file), file_path));
if (s.ok()) { if (s.ok()) {
s = ReadFooterFromFile(file_.get(), file_size, &footer); s = ReadFooterFromFile(file_.get(), file_size, &footer);
@ -93,7 +93,7 @@ Status SstFileReader::GetTableReader(const std::string& file_path) {
magic_number == kLegacyPlainTableMagicNumber) { magic_number == kLegacyPlainTableMagicNumber) {
soptions_.use_mmap_reads = true; soptions_.use_mmap_reads = true;
options_.env->NewRandomAccessFile(file_path, &file, soptions_); options_.env->NewRandomAccessFile(file_path, &file, soptions_);
file_.reset(new RandomAccessFileReader(std::move(file))); file_.reset(new RandomAccessFileReader(std::move(file), file_path));
} }
options_.comparator = &internal_comparator_; options_.comparator = &internal_comparator_;
// For old sst format, ReadTableProperties might fail but file can be read // For old sst format, ReadTableProperties might fail but file can be read

@ -59,6 +59,7 @@ class SequentialFileReader {
class RandomAccessFileReader { class RandomAccessFileReader {
private: private:
std::unique_ptr<RandomAccessFile> file_; std::unique_ptr<RandomAccessFile> file_;
std::string file_name_;
Env* env_; Env* env_;
Statistics* stats_; Statistics* stats_;
uint32_t hist_type_; uint32_t hist_type_;
@ -68,6 +69,7 @@ class RandomAccessFileReader {
public: public:
explicit RandomAccessFileReader(std::unique_ptr<RandomAccessFile>&& raf, explicit RandomAccessFileReader(std::unique_ptr<RandomAccessFile>&& raf,
std::string _file_name,
Env* env = nullptr, Env* env = nullptr,
Statistics* stats = nullptr, Statistics* stats = nullptr,
uint32_t hist_type = 0, uint32_t hist_type = 0,
@ -75,6 +77,7 @@ class RandomAccessFileReader {
RateLimiter* rate_limiter = nullptr, RateLimiter* rate_limiter = nullptr,
bool for_compaction = false) bool for_compaction = false)
: file_(std::move(raf)), : file_(std::move(raf)),
file_name_(std::move(_file_name)),
env_(env), env_(env),
stats_(stats), stats_(stats),
hist_type_(hist_type), hist_type_(hist_type),
@ -109,6 +112,8 @@ class RandomAccessFileReader {
RandomAccessFile* file() { return file_.get(); } RandomAccessFile* file() { return file_.get(); }
std::string file_name() const { return file_name_; }
bool use_direct_io() const { return file_->use_direct_io(); } bool use_direct_io() const { return file_->use_direct_io(); }
}; };

@ -139,7 +139,8 @@ WritableFileWriter* GetWritableFileWriter(WritableFile* wf) {
RandomAccessFileReader* GetRandomAccessFileReader(RandomAccessFile* raf) { RandomAccessFileReader* GetRandomAccessFileReader(RandomAccessFile* raf) {
unique_ptr<RandomAccessFile> file(raf); unique_ptr<RandomAccessFile> file(raf);
return new RandomAccessFileReader(std::move(file)); return new RandomAccessFileReader(std::move(file),
"[test RandomAccessFileReader]");
} }
SequentialFileReader* GetSequentialFileReader(SequentialFile* se) { SequentialFileReader* GetSequentialFileReader(SequentialFile* se) {

@ -50,7 +50,7 @@ Status BlobDumpTool::Run(const std::string& filename, DisplayType show_key,
if (file_size == 0) { if (file_size == 0) {
return Status::Corruption("File is empty."); return Status::Corruption("File is empty.");
} }
reader_.reset(new RandomAccessFileReader(std::move(file))); reader_.reset(new RandomAccessFileReader(std::move(file), filename));
uint64_t offset = 0; uint64_t offset = 0;
uint64_t footer_offset = 0; uint64_t footer_offset = 0;
s = DumpBlobLogHeader(&offset); s = DumpBlobLogHeader(&offset);

@ -212,7 +212,8 @@ std::shared_ptr<RandomAccessFileReader> BlobFile::GetOrOpenRandomAccessReader(
return nullptr; return nullptr;
} }
ra_file_reader_ = std::make_shared<RandomAccessFileReader>(std::move(rfile)); ra_file_reader_ = std::make_shared<RandomAccessFileReader>(std::move(rfile),
PathName());
*fresh_open = true; *fresh_open = true;
return ra_file_reader_; return ra_file_reader_;
} }

@ -49,7 +49,7 @@ void ColumnAwareEncodingReader::InitTableReader(const std::string& file_path) {
options_.env->NewRandomAccessFile(file_path, &file, soptions_); options_.env->NewRandomAccessFile(file_path, &file, soptions_);
options_.env->GetFileSize(file_path, &file_size); options_.env->GetFileSize(file_path, &file_size);
file_.reset(new RandomAccessFileReader(std::move(file))); file_.reset(new RandomAccessFileReader(std::move(file), file_path));
options_.comparator = &internal_comparator_; options_.comparator = &internal_comparator_;
options_.table_factory = std::make_shared<BlockBasedTableFactory>(); options_.table_factory = std::make_shared<BlockBasedTableFactory>();

@ -214,7 +214,7 @@ bool RandomAccessCacheFile::OpenImpl(const bool enable_direct_reads) {
status.ToString().c_str()); status.ToString().c_str());
return false; return false;
} }
freader_.reset(new RandomAccessFileReader(std::move(file), env_)); freader_.reset(new RandomAccessFileReader(std::move(file), Path(), env_));
return true; return true;
} }

Loading…
Cancel
Save