2016-02-10 00:12:00 +01:00
|
|
|
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
2017-07-16 01:03:42 +02:00
|
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
|
|
// (found in the LICENSE.Apache file in the root directory).
|
2013-10-16 23:59:46 +02:00
|
|
|
//
|
2011-03-18 23:37:00 +01:00
|
|
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
|
|
|
|
|
|
#include "db/log_writer.h"
|
|
|
|
|
|
|
|
#include <stdint.h>
|
2019-09-16 19:31:27 +02:00
|
|
|
#include "file/writable_file_writer.h"
|
2013-08-23 17:38:13 +02:00
|
|
|
#include "rocksdb/env.h"
|
2011-03-18 23:37:00 +01:00
|
|
|
#include "util/coding.h"
|
|
|
|
#include "util/crc32c.h"
|
|
|
|
|
2020-02-20 21:07:53 +01:00
|
|
|
namespace ROCKSDB_NAMESPACE {
|
2011-03-18 23:37:00 +01:00
|
|
|
namespace log {
|
|
|
|
|
2019-03-27 18:18:56 +01:00
|
|
|
Writer::Writer(std::unique_ptr<WritableFileWriter>&& dest, uint64_t log_number,
|
2022-02-18 01:18:01 +01:00
|
|
|
bool recycle_log_files, bool manual_flush,
|
|
|
|
CompressionType compression_type)
|
2015-10-08 19:07:15 +02:00
|
|
|
: dest_(std::move(dest)),
|
|
|
|
block_offset_(0),
|
|
|
|
log_number_(log_number),
|
2017-06-24 23:06:43 +02:00
|
|
|
recycle_log_files_(recycle_log_files),
|
2022-02-18 01:18:01 +01:00
|
|
|
manual_flush_(manual_flush),
|
|
|
|
compression_type_(compression_type) {
|
2011-03-18 23:37:00 +01:00
|
|
|
for (int i = 0; i <= kMaxRecordType; i++) {
|
|
|
|
char t = static_cast<char>(i);
|
|
|
|
type_crc_[i] = crc32c::Value(&t, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-25 19:04:57 +02:00
|
|
|
Writer::~Writer() {
|
|
|
|
if (dest_) {
|
2020-12-24 01:54:05 +01:00
|
|
|
WriteBuffer().PermitUncheckedError();
|
2019-04-25 19:04:57 +02:00
|
|
|
}
|
|
|
|
}
|
2017-06-24 23:06:43 +02:00
|
|
|
|
Pass IOStatus to write path and set retryable IO Error as hard error in BG jobs (#6487)
Summary:
In the current code base, we use Status to get and store the returned status from the call. Specifically, for IO related functions, the current Status cannot reflect the IO Error details such as error scope, error retryable attribute, and others. With the implementation of https://github.com/facebook/rocksdb/issues/5761, we have the new Wrapper for IO, which returns IOStatus instead of Status. However, the IOStatus is purged at the lower level of write path and transferred to Status.
The first job of this PR is to pass the IOStatus to the write path (flush, WAL write, and Compaction). The second job is to identify the Retryable IO Error as HardError, and set the bg_error_ as HardError. In this case, the DB Instance becomes read only. User is informed of the Status and need to take actions to deal with it (e.g., call db->Resume()).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6487
Test Plan: Added the testing case to error_handler_fs_test. Pass make asan_check
Reviewed By: anand1976
Differential Revision: D20685017
Pulled By: zhichao-cao
fbshipit-source-id: ff85f042896243abcd6ef37877834e26f36b6eb0
2020-03-28 00:03:05 +01:00
|
|
|
IOStatus Writer::WriteBuffer() { return dest_->Flush(); }
|
2011-03-18 23:37:00 +01:00
|
|
|
|
Pass IOStatus to write path and set retryable IO Error as hard error in BG jobs (#6487)
Summary:
In the current code base, we use Status to get and store the returned status from the call. Specifically, for IO related functions, the current Status cannot reflect the IO Error details such as error scope, error retryable attribute, and others. With the implementation of https://github.com/facebook/rocksdb/issues/5761, we have the new Wrapper for IO, which returns IOStatus instead of Status. However, the IOStatus is purged at the lower level of write path and transferred to Status.
The first job of this PR is to pass the IOStatus to the write path (flush, WAL write, and Compaction). The second job is to identify the Retryable IO Error as HardError, and set the bg_error_ as HardError. In this case, the DB Instance becomes read only. User is informed of the Status and need to take actions to deal with it (e.g., call db->Resume()).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6487
Test Plan: Added the testing case to error_handler_fs_test. Pass make asan_check
Reviewed By: anand1976
Differential Revision: D20685017
Pulled By: zhichao-cao
fbshipit-source-id: ff85f042896243abcd6ef37877834e26f36b6eb0
2020-03-28 00:03:05 +01:00
|
|
|
IOStatus Writer::Close() {
|
|
|
|
IOStatus s;
|
2019-04-25 19:04:57 +02:00
|
|
|
if (dest_) {
|
|
|
|
s = dest_->Close();
|
|
|
|
dest_.reset();
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
Pass IOStatus to write path and set retryable IO Error as hard error in BG jobs (#6487)
Summary:
In the current code base, we use Status to get and store the returned status from the call. Specifically, for IO related functions, the current Status cannot reflect the IO Error details such as error scope, error retryable attribute, and others. With the implementation of https://github.com/facebook/rocksdb/issues/5761, we have the new Wrapper for IO, which returns IOStatus instead of Status. However, the IOStatus is purged at the lower level of write path and transferred to Status.
The first job of this PR is to pass the IOStatus to the write path (flush, WAL write, and Compaction). The second job is to identify the Retryable IO Error as HardError, and set the bg_error_ as HardError. In this case, the DB Instance becomes read only. User is informed of the Status and need to take actions to deal with it (e.g., call db->Resume()).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6487
Test Plan: Added the testing case to error_handler_fs_test. Pass make asan_check
Reviewed By: anand1976
Differential Revision: D20685017
Pulled By: zhichao-cao
fbshipit-source-id: ff85f042896243abcd6ef37877834e26f36b6eb0
2020-03-28 00:03:05 +01:00
|
|
|
IOStatus Writer::AddRecord(const Slice& slice) {
|
2011-03-18 23:37:00 +01:00
|
|
|
const char* ptr = slice.data();
|
|
|
|
size_t left = slice.size();
|
|
|
|
|
2015-10-19 23:24:05 +02:00
|
|
|
// Header size varies depending on whether we are recycling or not.
|
|
|
|
const int header_size =
|
|
|
|
recycle_log_files_ ? kRecyclableHeaderSize : kHeaderSize;
|
|
|
|
|
2011-03-18 23:37:00 +01:00
|
|
|
// Fragment the record if necessary and emit it. Note that if slice
|
|
|
|
// is empty, we still want to iterate once to emit a single
|
|
|
|
// zero-length record
|
Pass IOStatus to write path and set retryable IO Error as hard error in BG jobs (#6487)
Summary:
In the current code base, we use Status to get and store the returned status from the call. Specifically, for IO related functions, the current Status cannot reflect the IO Error details such as error scope, error retryable attribute, and others. With the implementation of https://github.com/facebook/rocksdb/issues/5761, we have the new Wrapper for IO, which returns IOStatus instead of Status. However, the IOStatus is purged at the lower level of write path and transferred to Status.
The first job of this PR is to pass the IOStatus to the write path (flush, WAL write, and Compaction). The second job is to identify the Retryable IO Error as HardError, and set the bg_error_ as HardError. In this case, the DB Instance becomes read only. User is informed of the Status and need to take actions to deal with it (e.g., call db->Resume()).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6487
Test Plan: Added the testing case to error_handler_fs_test. Pass make asan_check
Reviewed By: anand1976
Differential Revision: D20685017
Pulled By: zhichao-cao
fbshipit-source-id: ff85f042896243abcd6ef37877834e26f36b6eb0
2020-03-28 00:03:05 +01:00
|
|
|
IOStatus s;
|
2011-05-21 04:17:43 +02:00
|
|
|
bool begin = true;
|
2011-03-18 23:37:00 +01:00
|
|
|
do {
|
2015-11-15 19:49:14 +01:00
|
|
|
const int64_t leftover = kBlockSize - block_offset_;
|
2011-03-18 23:37:00 +01:00
|
|
|
assert(leftover >= 0);
|
2015-10-19 23:24:05 +02:00
|
|
|
if (leftover < header_size) {
|
2011-03-18 23:37:00 +01:00
|
|
|
// Switch to a new block
|
|
|
|
if (leftover > 0) {
|
2015-10-19 23:24:05 +02:00
|
|
|
// Fill the trailer (literal below relies on kHeaderSize and
|
|
|
|
// kRecyclableHeaderSize being <= 11)
|
|
|
|
assert(header_size <= 11);
|
2018-04-19 23:00:52 +02:00
|
|
|
s = dest_->Append(Slice("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
|
|
|
static_cast<size_t>(leftover)));
|
|
|
|
if (!s.ok()) {
|
|
|
|
break;
|
|
|
|
}
|
2011-03-18 23:37:00 +01:00
|
|
|
}
|
|
|
|
block_offset_ = 0;
|
|
|
|
}
|
|
|
|
|
2015-10-19 23:24:05 +02:00
|
|
|
// Invariant: we never leave < header_size bytes in a block.
|
2015-11-15 19:49:14 +01:00
|
|
|
assert(static_cast<int64_t>(kBlockSize - block_offset_) >= header_size);
|
2011-03-18 23:37:00 +01:00
|
|
|
|
2015-10-19 23:24:05 +02:00
|
|
|
const size_t avail = kBlockSize - block_offset_ - header_size;
|
2011-03-18 23:37:00 +01:00
|
|
|
const size_t fragment_length = (left < avail) ? left : avail;
|
|
|
|
|
|
|
|
RecordType type;
|
|
|
|
const bool end = (left == fragment_length);
|
|
|
|
if (begin && end) {
|
2015-10-19 23:24:05 +02:00
|
|
|
type = recycle_log_files_ ? kRecyclableFullType : kFullType;
|
2011-03-18 23:37:00 +01:00
|
|
|
} else if (begin) {
|
2015-10-19 23:24:05 +02:00
|
|
|
type = recycle_log_files_ ? kRecyclableFirstType : kFirstType;
|
2011-03-18 23:37:00 +01:00
|
|
|
} else if (end) {
|
2015-10-19 23:24:05 +02:00
|
|
|
type = recycle_log_files_ ? kRecyclableLastType : kLastType;
|
2011-03-18 23:37:00 +01:00
|
|
|
} else {
|
2015-10-19 23:24:05 +02:00
|
|
|
type = recycle_log_files_ ? kRecyclableMiddleType : kMiddleType;
|
2011-03-18 23:37:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
s = EmitPhysicalRecord(type, ptr, fragment_length);
|
|
|
|
ptr += fragment_length;
|
|
|
|
left -= fragment_length;
|
2011-05-21 04:17:43 +02:00
|
|
|
begin = false;
|
2011-03-18 23:37:00 +01:00
|
|
|
} while (s.ok() && left > 0);
|
2019-05-21 21:17:15 +02:00
|
|
|
|
|
|
|
if (s.ok()) {
|
|
|
|
if (!manual_flush_) {
|
|
|
|
s = dest_->Flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-18 23:37:00 +01:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2022-02-18 01:18:01 +01:00
|
|
|
IOStatus Writer::AddCompressionTypeRecord() {
|
|
|
|
// Should be the first record
|
|
|
|
assert(block_offset_ == 0);
|
|
|
|
|
|
|
|
if (compression_type_ == kNoCompression) {
|
|
|
|
// No need to add a record
|
|
|
|
return IOStatus::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
CompressionTypeRecord record(compression_type_);
|
|
|
|
std::string encode;
|
|
|
|
record.EncodeTo(&encode);
|
|
|
|
IOStatus s =
|
|
|
|
EmitPhysicalRecord(kSetCompressionType, encode.data(), encode.size());
|
|
|
|
if (s.ok()) {
|
|
|
|
if (!manual_flush_) {
|
|
|
|
s = dest_->Flush();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Disable compression if the record could not be added.
|
|
|
|
compression_type_ = kNoCompression;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2018-05-14 19:53:32 +02:00
|
|
|
bool Writer::TEST_BufferIsEmpty() { return dest_->TEST_BufferIsEmpty(); }
|
|
|
|
|
Pass IOStatus to write path and set retryable IO Error as hard error in BG jobs (#6487)
Summary:
In the current code base, we use Status to get and store the returned status from the call. Specifically, for IO related functions, the current Status cannot reflect the IO Error details such as error scope, error retryable attribute, and others. With the implementation of https://github.com/facebook/rocksdb/issues/5761, we have the new Wrapper for IO, which returns IOStatus instead of Status. However, the IOStatus is purged at the lower level of write path and transferred to Status.
The first job of this PR is to pass the IOStatus to the write path (flush, WAL write, and Compaction). The second job is to identify the Retryable IO Error as HardError, and set the bg_error_ as HardError. In this case, the DB Instance becomes read only. User is informed of the Status and need to take actions to deal with it (e.g., call db->Resume()).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6487
Test Plan: Added the testing case to error_handler_fs_test. Pass make asan_check
Reviewed By: anand1976
Differential Revision: D20685017
Pulled By: zhichao-cao
fbshipit-source-id: ff85f042896243abcd6ef37877834e26f36b6eb0
2020-03-28 00:03:05 +01:00
|
|
|
IOStatus Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) {
|
2011-03-18 23:37:00 +01:00
|
|
|
assert(n <= 0xffff); // Must fit in two bytes
|
2015-10-19 23:24:05 +02:00
|
|
|
|
|
|
|
size_t header_size;
|
|
|
|
char buf[kRecyclableHeaderSize];
|
2011-03-18 23:37:00 +01:00
|
|
|
|
|
|
|
// Format the header
|
|
|
|
buf[4] = static_cast<char>(n & 0xff);
|
|
|
|
buf[5] = static_cast<char>(n >> 8);
|
|
|
|
buf[6] = static_cast<char>(t);
|
|
|
|
|
2015-10-19 23:24:05 +02:00
|
|
|
uint32_t crc = type_crc_[t];
|
2022-02-18 01:18:01 +01:00
|
|
|
if (t < kRecyclableFullType || t == kSetCompressionType) {
|
2015-10-19 23:24:05 +02:00
|
|
|
// Legacy record format
|
|
|
|
assert(block_offset_ + kHeaderSize + n <= kBlockSize);
|
|
|
|
header_size = kHeaderSize;
|
|
|
|
} else {
|
|
|
|
// Recyclable record format
|
|
|
|
assert(block_offset_ + kRecyclableHeaderSize + n <= kBlockSize);
|
|
|
|
header_size = kRecyclableHeaderSize;
|
|
|
|
|
|
|
|
// Only encode low 32-bits of the 64-bit log number. This means
|
|
|
|
// we will fail to detect an old record if we recycled a log from
|
|
|
|
// ~4 billion logs ago, but that is effectively impossible, and
|
|
|
|
// even if it were we'dbe far more likely to see a false positive
|
|
|
|
// on the 32-bit CRC.
|
|
|
|
EncodeFixed32(buf + 7, static_cast<uint32_t>(log_number_));
|
|
|
|
crc = crc32c::Extend(crc, buf + 7, 4);
|
|
|
|
}
|
|
|
|
|
2011-03-18 23:37:00 +01:00
|
|
|
// Compute the crc of the record type and the payload.
|
Using existing crc32c checksum in checksum handoff for Manifest and WAL (#8412)
Summary:
In PR https://github.com/facebook/rocksdb/issues/7523 , checksum handoff is introduced in RocksDB for WAL, Manifest, and SST files. When user enable checksum handoff for a certain type of file, before the data is written to the lower layer storage system, we calculate the checksum (crc32c) of each piece of data and pass the checksum down with the data, such that data verification can be down by the lower layer storage system if it has the capability. However, it cannot cover the whole lifetime of the data in the memory and also it potentially introduces extra checksum calculation overhead.
In this PR, we introduce a new interface in WritableFileWriter::Append, which allows the caller be able to pass the data and the checksum (crc32c) together. In this way, WritableFileWriter can directly use the pass-in checksum (crc32c) to generate the checksum of data being passed down to the storage system. It saves the calculation overhead and achieves higher protection coverage. When a new checksum is added with the data, we use Crc32cCombine https://github.com/facebook/rocksdb/issues/8305 to combine the existing checksum and the new checksum. To avoid the segmenting of data by rate-limiter before it is stored, rate-limiter is called enough times to accumulate enough credits for a certain write. This design only support Manifest and WAL which use log_writer in the current stage.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8412
Test Plan: make check, add new testing cases.
Reviewed By: anand1976
Differential Revision: D29151545
Pulled By: zhichao-cao
fbshipit-source-id: 75e2278c5126cfd58393c67b1efd18dcc7a30772
2021-06-25 09:46:33 +02:00
|
|
|
uint32_t payload_crc = crc32c::Value(ptr, n);
|
|
|
|
crc = crc32c::Crc32cCombine(crc, payload_crc, n);
|
2015-10-19 23:24:05 +02:00
|
|
|
crc = crc32c::Mask(crc); // Adjust for storage
|
2020-06-18 19:07:42 +02:00
|
|
|
TEST_SYNC_POINT_CALLBACK("LogWriter::EmitPhysicalRecord:BeforeEncodeChecksum",
|
|
|
|
&crc);
|
2011-03-18 23:37:00 +01:00
|
|
|
EncodeFixed32(buf, crc);
|
|
|
|
|
|
|
|
// Write the header and the payload
|
Pass IOStatus to write path and set retryable IO Error as hard error in BG jobs (#6487)
Summary:
In the current code base, we use Status to get and store the returned status from the call. Specifically, for IO related functions, the current Status cannot reflect the IO Error details such as error scope, error retryable attribute, and others. With the implementation of https://github.com/facebook/rocksdb/issues/5761, we have the new Wrapper for IO, which returns IOStatus instead of Status. However, the IOStatus is purged at the lower level of write path and transferred to Status.
The first job of this PR is to pass the IOStatus to the write path (flush, WAL write, and Compaction). The second job is to identify the Retryable IO Error as HardError, and set the bg_error_ as HardError. In this case, the DB Instance becomes read only. User is informed of the Status and need to take actions to deal with it (e.g., call db->Resume()).
Pull Request resolved: https://github.com/facebook/rocksdb/pull/6487
Test Plan: Added the testing case to error_handler_fs_test. Pass make asan_check
Reviewed By: anand1976
Differential Revision: D20685017
Pulled By: zhichao-cao
fbshipit-source-id: ff85f042896243abcd6ef37877834e26f36b6eb0
2020-03-28 00:03:05 +01:00
|
|
|
IOStatus s = dest_->Append(Slice(buf, header_size));
|
2011-03-18 23:37:00 +01:00
|
|
|
if (s.ok()) {
|
Using existing crc32c checksum in checksum handoff for Manifest and WAL (#8412)
Summary:
In PR https://github.com/facebook/rocksdb/issues/7523 , checksum handoff is introduced in RocksDB for WAL, Manifest, and SST files. When user enable checksum handoff for a certain type of file, before the data is written to the lower layer storage system, we calculate the checksum (crc32c) of each piece of data and pass the checksum down with the data, such that data verification can be down by the lower layer storage system if it has the capability. However, it cannot cover the whole lifetime of the data in the memory and also it potentially introduces extra checksum calculation overhead.
In this PR, we introduce a new interface in WritableFileWriter::Append, which allows the caller be able to pass the data and the checksum (crc32c) together. In this way, WritableFileWriter can directly use the pass-in checksum (crc32c) to generate the checksum of data being passed down to the storage system. It saves the calculation overhead and achieves higher protection coverage. When a new checksum is added with the data, we use Crc32cCombine https://github.com/facebook/rocksdb/issues/8305 to combine the existing checksum and the new checksum. To avoid the segmenting of data by rate-limiter before it is stored, rate-limiter is called enough times to accumulate enough credits for a certain write. This design only support Manifest and WAL which use log_writer in the current stage.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/8412
Test Plan: make check, add new testing cases.
Reviewed By: anand1976
Differential Revision: D29151545
Pulled By: zhichao-cao
fbshipit-source-id: 75e2278c5126cfd58393c67b1efd18dcc7a30772
2021-06-25 09:46:33 +02:00
|
|
|
s = dest_->Append(Slice(ptr, n), payload_crc);
|
2011-03-18 23:37:00 +01:00
|
|
|
}
|
2015-10-19 23:24:05 +02:00
|
|
|
block_offset_ += header_size + n;
|
2011-03-18 23:37:00 +01:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2011-10-31 18:22:06 +01:00
|
|
|
} // namespace log
|
2020-02-20 21:07:53 +01:00
|
|
|
} // namespace ROCKSDB_NAMESPACE
|