mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-07 11:32:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2df3e90028 | ||
|
|
6a23aaf86e | ||
|
|
bd39be1859 | ||
|
|
62cf055775 | ||
|
|
97bf78721b | ||
|
|
0bda0e3dfa |
No files matched your search
@@ -1,4 +1,13 @@
|
||||
# Rocksdb Change Log
|
||||
## 6.13.4 (11/15/2020)
|
||||
### Bug Fixes
|
||||
* Fixed a bug of encoding and parsing BlockBasedTableOptions::read_amp_bytes_per_bit as a 64-bit integer.
|
||||
* Fixed the logic of populating native data structure for `read_amp_bytes_per_bit` during OPTIONS file parsing on big-endian architecture. Without this fix, original code introduced in PR7659, when running on big-endian machine, can mistakenly store read_amp_bytes_per_bit (an uint32) in little endian format. Future access to `read_amp_bytes_per_bit` will give wrong values. Little endian architecture is not affected.
|
||||
|
||||
## 6.13.3 (10/14/2020)
|
||||
### Bug Fixes
|
||||
* Fix a bug that could cause a stalled write to crash with mixed of slowdown and no_slowdown writes (`WriteOptions.no_slowdown=true`).
|
||||
|
||||
## 6.13.2 (10/13/2020)
|
||||
### Bug Fixes
|
||||
* Fix false positive flush/compaction `Status::Corruption` failure when `paranoid_file_checks == true` and range tombstones were written to the compaction output files.
|
||||
|
||||
@@ -470,6 +470,7 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
|
||||
WriteThread::Writer w(write_options, my_batch, callback, log_ref,
|
||||
disable_memtable);
|
||||
write_thread_.JoinBatchGroup(&w);
|
||||
TEST_SYNC_POINT("DBImplWrite::PipelinedWriteImpl:AfterJoinBatchGroup");
|
||||
if (w.state == WriteThread::STATE_GROUP_LEADER) {
|
||||
WriteThread::WriteGroup wal_write_group;
|
||||
if (w.callback && !w.callback->AllowWriteBatching()) {
|
||||
|
||||
@@ -42,6 +42,125 @@ TEST_P(DBWriteTest, SyncAndDisableWAL) {
|
||||
ASSERT_TRUE(dbfull()->Write(write_options, &batch).IsInvalidArgument());
|
||||
}
|
||||
|
||||
TEST_P(DBWriteTest, WriteStallRemoveNoSlowdownWrite) {
|
||||
Options options = GetOptions();
|
||||
options.level0_stop_writes_trigger = options.level0_slowdown_writes_trigger =
|
||||
4;
|
||||
std::vector<port::Thread> threads;
|
||||
std::atomic<int> thread_num(0);
|
||||
port::Mutex mutex;
|
||||
port::CondVar cv(&mutex);
|
||||
// Guarded by mutex
|
||||
int writers = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
std::function<void()> write_slowdown_func = [&]() {
|
||||
int a = thread_num.fetch_add(1);
|
||||
std::string key = "foo" + std::to_string(a);
|
||||
WriteOptions wo;
|
||||
wo.no_slowdown = false;
|
||||
dbfull()->Put(wo, key, "bar");
|
||||
};
|
||||
std::function<void()> write_no_slowdown_func = [&]() {
|
||||
int a = thread_num.fetch_add(1);
|
||||
std::string key = "foo" + std::to_string(a);
|
||||
WriteOptions wo;
|
||||
wo.no_slowdown = true;
|
||||
dbfull()->Put(wo, key, "bar");
|
||||
};
|
||||
std::function<void(void*)> unblock_main_thread_func = [&](void*) {
|
||||
mutex.Lock();
|
||||
++writers;
|
||||
cv.SignalAll();
|
||||
mutex.Unlock();
|
||||
};
|
||||
|
||||
// Create 3 L0 files and schedule 4th without waiting
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteThread::JoinBatchGroup:Start", unblock_main_thread_func);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBWriteTest::WriteStallRemoveNoSlowdownWrite:1",
|
||||
"DBImpl::BackgroundCallFlush:start"},
|
||||
{"DBWriteTest::WriteStallRemoveNoSlowdownWrite:2",
|
||||
"DBImplWrite::PipelinedWriteImpl:AfterJoinBatchGroup"},
|
||||
// Make compaction start wait for the write stall to be detected and
|
||||
// implemented by a write group leader
|
||||
{"DBWriteTest::WriteStallRemoveNoSlowdownWrite:3",
|
||||
"BackgroundCallCompaction:0"}});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Schedule creation of 4th L0 file without waiting. This will seal the
|
||||
// memtable and then wait for a sync point before writing the file. We need
|
||||
// to do it this way because SwitchMemtable() needs to enter the
|
||||
// write_thread
|
||||
FlushOptions fopt;
|
||||
fopt.wait = false;
|
||||
dbfull()->Flush(fopt);
|
||||
|
||||
// Create a mix of slowdown/no_slowdown write threads
|
||||
mutex.Lock();
|
||||
// First leader
|
||||
threads.emplace_back(write_slowdown_func);
|
||||
while (writers != 1) {
|
||||
cv.Wait();
|
||||
}
|
||||
|
||||
// Second leader. Will stall writes
|
||||
// Build a writers list with no slowdown in the middle:
|
||||
// +-------------+
|
||||
// | slowdown +<----+ newest
|
||||
// +--+----------+
|
||||
// |
|
||||
// v
|
||||
// +--+----------+
|
||||
// | no slowdown |
|
||||
// +--+----------+
|
||||
// |
|
||||
// v
|
||||
// +--+----------+
|
||||
// | slowdown +
|
||||
// +-------------+
|
||||
threads.emplace_back(write_slowdown_func);
|
||||
while (writers != 2) {
|
||||
cv.Wait();
|
||||
}
|
||||
threads.emplace_back(write_no_slowdown_func);
|
||||
while (writers != 3) {
|
||||
cv.Wait();
|
||||
}
|
||||
threads.emplace_back(write_slowdown_func);
|
||||
while (writers != 4) {
|
||||
cv.Wait();
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
|
||||
TEST_SYNC_POINT("DBWriteTest::WriteStallRemoveNoSlowdownWrite:1");
|
||||
dbfull()->TEST_WaitForFlushMemTable(nullptr);
|
||||
// This would have triggered a write stall. Unblock the write group leader
|
||||
TEST_SYNC_POINT("DBWriteTest::WriteStallRemoveNoSlowdownWrite:2");
|
||||
// The leader is going to create missing newer links. When the leader
|
||||
// finishes, the next leader is going to delay writes and fail writers with
|
||||
// no_slowdown
|
||||
|
||||
TEST_SYNC_POINT("DBWriteTest::WriteStallRemoveNoSlowdownWrite:3");
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_P(DBWriteTest, WriteThreadHangOnWriteStall) {
|
||||
Options options = GetOptions();
|
||||
options.level0_stop_writes_trigger = options.level0_slowdown_writes_trigger = 4;
|
||||
|
||||
+7
-1
@@ -344,7 +344,13 @@ void WriteThread::BeginWriteStall() {
|
||||
prev->link_older = w->link_older;
|
||||
w->status = Status::Incomplete("Write stall");
|
||||
SetState(w, STATE_COMPLETED);
|
||||
if (prev->link_older) {
|
||||
// Only update `link_newer` if it's already set.
|
||||
// `CreateMissingNewerLinks()` will update the nullptr `link_newer` later,
|
||||
// which assumes the the first non-nullptr `link_newer` is the last
|
||||
// nullptr link in the writer list.
|
||||
// If `link_newer` is set here, `CreateMissingNewerLinks()` may stop
|
||||
// updating the whole list when it sees the first non nullptr link.
|
||||
if (prev->link_older && prev->link_older->link_newer) {
|
||||
prev->link_older->link_newer = prev;
|
||||
}
|
||||
w = prev->link_older;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define ROCKSDB_MAJOR 6
|
||||
#define ROCKSDB_MINOR 13
|
||||
#define ROCKSDB_PATCH 2
|
||||
#define ROCKSDB_PATCH 4
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
@@ -821,7 +821,12 @@ TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
|
||||
"block_cache=1M;block_cache_compressed=1k;block_size=1024;"
|
||||
"block_size_deviation=8;block_restart_interval=4;"
|
||||
"format_version=5;whole_key_filtering=1;"
|
||||
"filter_policy=bloomfilter:4.567:false;",
|
||||
"filter_policy=bloomfilter:4.567:false;"
|
||||
// A bug caused read_amp_bytes_per_bit to be a large integer in OPTIONS
|
||||
// file generated by 6.10 to 6.14. Though bug is fixed in these releases,
|
||||
// we need to handle the case of loading OPTIONS file generated before the
|
||||
// fix.
|
||||
"read_amp_bytes_per_bit=17179869185;",
|
||||
&new_opt));
|
||||
ASSERT_TRUE(new_opt.cache_index_and_filter_blocks);
|
||||
ASSERT_EQ(new_opt.index_type, BlockBasedTableOptions::kHashSearch);
|
||||
@@ -842,6 +847,9 @@ TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
|
||||
dynamic_cast<const BloomFilterPolicy&>(*new_opt.filter_policy);
|
||||
EXPECT_EQ(bfp.GetMillibitsPerKey(), 4567);
|
||||
EXPECT_EQ(bfp.GetWholeBitsPerKey(), 5);
|
||||
// Verify that only the lower 32bits are stored in
|
||||
// new_opt.read_amp_bytes_per_bit.
|
||||
EXPECT_EQ(1U, new_opt.read_amp_bytes_per_bit);
|
||||
|
||||
// unknown option
|
||||
ASSERT_NOK(GetBlockBasedTableOptionsFromString(
|
||||
|
||||
@@ -331,8 +331,24 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
OptionTypeFlags::kNone, 0}},
|
||||
{"read_amp_bytes_per_bit",
|
||||
{offsetof(struct BlockBasedTableOptions, read_amp_bytes_per_bit),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone, 0}},
|
||||
OptionType::kUInt32T, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone, 0,
|
||||
[](const ConfigOptions& /*opts*/, const std::string& /*name*/,
|
||||
const std::string& value, char* addr) {
|
||||
// A workaround to fix a bug in 6.10, 6.11, 6.12, 6.13
|
||||
// and 6.14. The bug will write out 8 bytes to OPTIONS file from the
|
||||
// starting address of BlockBasedTableOptions.read_amp_bytes_per_bit
|
||||
// which is actually a uint32. Consequently, the value of
|
||||
// read_amp_bytes_per_bit written in the OPTIONS file is wrong.
|
||||
// From 6.15, RocksDB will try to parse the read_amp_bytes_per_bit
|
||||
// from OPTIONS file as a uint32. To be able to load OPTIONS file
|
||||
// generated by affected releases before the fix, we need to
|
||||
// manually parse read_amp_bytes_per_bit with this special hack.
|
||||
uint64_t read_amp_bytes_per_bit = ParseUint64(value);
|
||||
*(reinterpret_cast<uint32_t*>(addr)) =
|
||||
static_cast<uint32_t>(read_amp_bytes_per_bit);
|
||||
return Status::OK();
|
||||
}}},
|
||||
{"enable_index_compression",
|
||||
{offsetof(struct BlockBasedTableOptions, enable_index_compression),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal,
|
||||
|
||||
Reference in new issue
Block a user