Summary:
From HISTORY.md: Added a subcode of `Status::Corruption`, `Status::SubCode::kMergeOperatorFailed`, for users to identify corruption failures originating in the merge operator, as opposed to RocksDB's internally identified data corruptions.
This is a followup to https://github.com/facebook/rocksdb/issues/11092, where we gave users the ability to keep running a DB despite merge operator failing. Now that the DB keeps running despite such failures, they want to be able to distinguish such failures from real corruptions.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/11231
Test Plan: updated unit test
Reviewed By: akankshamahajan15
Differential Revision:
D43396607
Pulled By: ajkr
fbshipit-source-id:
17fbcc779ad724dafada8abd73efd38e1c5208b9
* Completely removed the following deprecated/obsolete statistics: the tickers `BLOCK_CACHE_INDEX_BYTES_EVICT`, `BLOCK_CACHE_FILTER_BYTES_EVICT`, `BLOOM_FILTER_MICROS`, `NO_FILE_CLOSES`, `STALL_L0_SLOWDOWN_MICROS`, `STALL_MEMTABLE_COMPACTION_MICROS`, `STALL_L0_NUM_FILES_MICROS`, `RATE_LIMIT_DELAY_MILLIS`, `NO_ITERATORS`, `NUMBER_FILTERED_DELETES`, `WRITE_TIMEDOUT`, `BLOB_DB_GC_NUM_KEYS_OVERWRITTEN`, `BLOB_DB_GC_NUM_KEYS_EXPIRED`, `BLOB_DB_GC_BYTES_OVERWRITTEN`, `BLOB_DB_GC_BYTES_EXPIRED`, `BLOCK_CACHE_COMPRESSION_DICT_BYTES_EVICT` as well as the histograms `STALL_L0_SLOWDOWN_COUNT`, `STALL_MEMTABLE_COMPACTION_COUNT`, `STALL_L0_NUM_FILES_COUNT`, `HARD_RATE_LIMIT_DELAY_COUNT`, `SOFT_RATE_LIMIT_DELAY_COUNT`, `BLOB_DB_GC_MICROS`, and `NUM_DATA_BLOCKS_READ_PER_LEVEL`. Note that as a result, the C++ enum values of the still supported statistics have changed. Developers are advised to not rely on the actual numeric values.
* Deprecated IngestExternalFileOptions::write_global_seqno and change default to false. This option only needs to be set to true to generate a DB compatible with RocksDB versions before 5.16.0.
* Remove deprecated APIs `GetColumnFamilyOptionsFrom{Map|String}(const ColumnFamilyOptions&, ..)`, `GetDBOptionsFrom{Map|String}(const DBOptions&, ..)`, `GetBlockBasedTableOptionsFrom{Map|String}(const BlockBasedTableOptions& table_options, ..)` and ` GetPlainTableOptionsFrom{Map|String}(const PlainTableOptions& table_options,..)`.
+* Added a subcode of `Status::Corruption`, `Status::SubCode::kMergeOperatorFailed`, for users to identify corruption failures originating in the merge operator, as opposed to RocksDB's internally identified data corruptions
### Build Changes
* The `make` build now builds a shared library by default instead of a static library. Use `LIB_MODE=static` to override.
{
std::string value;
ASSERT_OK(db_->Get(ReadOptions(), "k0", &value));
- ASSERT_TRUE(db_->Get(ReadOptions(), "k1", &value).IsCorruption());
+ Status s = db_->Get(ReadOptions(), "k1", &value);
+ ASSERT_TRUE(s.IsCorruption());
+ ASSERT_EQ(Status::SubCode::kMergeOperatorFailed, s.subcode());
ASSERT_OK(db_->Get(ReadOptions(), "k2", &value));
}
ASSERT_EQ("k0", iter->key());
iter->Next();
ASSERT_TRUE(iter->status().IsCorruption());
+ ASSERT_EQ(Status::SubCode::kMergeOperatorFailed,
+ iter->status().subcode());
iter->SeekToLast();
ASSERT_TRUE(iter->Valid());
if (!success) {
RecordTick(statistics, NUMBER_MERGE_FAILURES);
- return Status::Corruption("Error: Could not perform merge.");
+ return Status::Corruption(Status::SubCode::kMergeOperatorFailed);
}
return Status::OK();
"Encounter unexpected blob index. Please open DB with "
"ROCKSDB_NAMESPACE::blob_db::BlobDB instead.");
return;
+ case GetContext::kMergeOperatorFailed:
+ *status = Status::Corruption(Status::SubCode::kMergeOperatorFailed);
+ return;
}
f = fp.GetNextFile();
}
"ROCKSDB_NAMESPACE::blob_db::BlobDB instead.");
file_range.MarkKeyDone(iter);
continue;
+ case GetContext::kMergeOperatorFailed:
+ *status = Status::Corruption(Status::SubCode::kMergeOperatorFailed);
+ file_range.MarkKeyDone(iter);
+ continue;
}
}
kOverwritten = 12,
kTxnNotPrepared = 13,
kIOFenced = 14,
+ kMergeOperatorFailed = 15,
kMaxSubCode
};
/* update_num_ops_stats */ true,
/* op_failure_scope */ nullptr);
if (!s.ok()) {
- state_ = kCorrupt;
+ if (s.subcode() == Status::SubCode::kMergeOperatorFailed) {
+ state_ = kMergeOperatorFailed;
+ } else {
+ state_ = kCorrupt;
+ }
return;
}
/* update_num_ops_stats */ true,
/* op_failure_scope */ nullptr);
if (!s.ok()) {
- state_ = kCorrupt;
+ if (s.subcode() == Status::SubCode::kMergeOperatorFailed) {
+ state_ = kMergeOperatorFailed;
+ } else {
+ state_ = kCorrupt;
+ }
return;
}
}
&result, logger_, statistics_, clock_, /* update_num_ops_stats */ true,
/* op_failure_scope */ nullptr);
if (!s.ok()) {
- state_ = kCorrupt;
+ if (s.subcode() == Status::SubCode::kMergeOperatorFailed) {
+ state_ = kMergeOperatorFailed;
+ } else {
+ state_ = kCorrupt;
+ }
return;
}
}
kCorrupt,
kMerge, // saver contains the current merge result (the operands)
kUnexpectedBlobIndex,
+ kMergeOperatorFailed,
};
GetContextStats get_context_stats_;
"Insufficient capacity for merge operands",
// kManualCompactionPaused
"Manual compaction paused",
- " (overwritten)", // kOverwritten, subcode of OK
- "Txn not prepared", // kTxnNotPrepared
- "IO fenced off", // kIOFenced
+ " (overwritten)", // kOverwritten, subcode of OK
+ "Txn not prepared", // kTxnNotPrepared
+ "IO fenced off", // kIOFenced
+ "Merge operator failed", // kMergeOperatorFailed
};
Status::Status(Code _code, SubCode _subcode, const Slice& msg,