Pollute buffer before calling Read() (#8955)

Summary:
Add a paranoid check where in case FileSystem layer doesn't fill the buffer but returns succeed, checksum is unlikely to match even if buffer contains a previous block. The byte modified is not useful anyway, so it isn't expect to change any behavior.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/8955

Test Plan: See existing CI to pass.

Reviewed By: pdillinger

Differential Revision: D31183966

fbshipit-source-id: dcc4de429e18131873f783b90d3be55d7eb44a1f
This commit is contained in:
sdong 2021-09-27 21:28:24 -07:00 committed by Facebook GitHub Bot
parent 345f4c9462
commit b88109db19
3 changed files with 32 additions and 0 deletions

View File

@ -48,6 +48,9 @@
* Extended parameter `output_file_names` of `CompactFiles` API to also include paths of the blob files generated by the compaction in Integrated BlobDB. * Extended parameter `output_file_names` of `CompactFiles` API to also include paths of the blob files generated by the compaction in Integrated BlobDB.
* Most `BackupEngine` functions now return `IOStatus` instead of `Status`. Most existing code should be compatible with this change but some calls might need to be updated. * Most `BackupEngine` functions now return `IOStatus` instead of `Status`. Most existing code should be compatible with this change but some calls might need to be updated.
### Miscellaneous
* Add a paranoid check where in case FileSystem layer doesn't fill the buffer but returns succeed, checksum is unlikely to match even if buffer contains a previous block. The byte modified is not useful anyway, so it isn't expected to change any behavior when FileSystem is satisfying its contract.
## 6.24.0 (2021-08-20) ## 6.24.0 (2021-08-20)
### Bug Fixes ### Bug Fixes
* If the primary's CURRENT file is missing or inaccessible, the secondary instance should not hang repeatedly trying to switch to a new MANIFEST. It should instead return the error code encountered while accessing the file. * If the primary's CURRENT file is missing or inaccessible, the secondary instance should not hang repeatedly trying to switch to a new MANIFEST. It should instead return the error code encountered while accessing the file.

View File

@ -41,6 +41,15 @@ IOStatus RandomAccessFileReader::Read(const IOOptions& opts, uint64_t offset,
(void)aligned_buf; (void)aligned_buf;
TEST_SYNC_POINT_CALLBACK("RandomAccessFileReader::Read", nullptr); TEST_SYNC_POINT_CALLBACK("RandomAccessFileReader::Read", nullptr);
// To be paranoid: modify scratch a little bit, so in case underlying
// FileSystem doesn't fill the buffer but return success and `scratch` returns
// contains a previous block, returned value will not pass checksum.
if (n > 0 && scratch != nullptr) {
// This byte might not change anything for direct I/O case, but it's OK.
scratch[0]++;
}
IOStatus io_s; IOStatus io_s;
uint64_t elapsed = 0; uint64_t elapsed = 0;
{ {
@ -214,6 +223,18 @@ IOStatus RandomAccessFileReader::MultiRead(const IOOptions& opts,
AlignedBuf* aligned_buf) const { AlignedBuf* aligned_buf) const {
(void)aligned_buf; // suppress warning of unused variable in LITE mode (void)aligned_buf; // suppress warning of unused variable in LITE mode
assert(num_reqs > 0); assert(num_reqs > 0);
// To be paranoid modify scratch a little bit, so in case underlying
// FileSystem doesn't fill the buffer but return succee and `scratch` returns
// contains a previous block, returned value will not pass checksum.
// This byte might not change anything for direct I/O case, but it's OK.
for (size_t i = 0; i < num_reqs; i++) {
FSReadRequest& r = read_reqs[i];
if (r.len > 0 && r.scratch != nullptr) {
r.scratch[0]++;
}
}
IOStatus io_s; IOStatus io_s;
uint64_t elapsed = 0; uint64_t elapsed = 0;
{ {

View File

@ -58,6 +58,14 @@ IOStatus SequentialFileReader::Read(size_t n, Slice* result, char* scratch) {
*result = Slice(scratch, r); *result = Slice(scratch, r);
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
} else { } else {
// To be paranoid, modify scratch a little bit, so in case underlying
// FileSystem doesn't fill the buffer but return succee and `scratch`
// returns contains a previous block, returned value will not pass
// checksum.
// It's hard to find useful byte for direct I/O case, so we skip it.
if (n > 0 && scratch != nullptr) {
scratch[0]++;
}
io_s = file_->Read(n, IOOptions(), result, scratch, nullptr); io_s = file_->Read(n, IOOptions(), result, scratch, nullptr);
} }
IOSTATS_ADD(bytes_read, result->size()); IOSTATS_ADD(bytes_read, result->size());