Do not attempt to rename non-existent info log (#8622)
Summary: Previously we attempted to rename "LOG" to "LOG.old.*" without checking its existence first. "LOG" had no reason to exist in a new DB. Errors in renaming a non-existent "LOG" were swallowed via `PermitUncheckedError()` so things worked. However the storage service's error monitoring was detecting all these benign rename failures. So it is better to fix it. Also with this PR we can now distinguish rename failure for other reasons and return them. Pull Request resolved: https://github.com/facebook/rocksdb/pull/8622 Test Plan: new unit test Reviewed By: akankshamahajan15 Differential Revision: D30115189 Pulled By: ajkr fbshipit-source-id: e2f337ffb2bd171be0203172abc8e16e7809b170
This commit is contained in:
parent
2898067de8
commit
60f5a22cff
@ -1,4 +1,8 @@
|
|||||||
# Rocksdb Change Log
|
# Rocksdb Change Log
|
||||||
|
## Unreleased
|
||||||
|
### Bug Fixes
|
||||||
|
* Removed a call to `RenameFile()` on a non-existent info log file ("LOG") when opening a new DB. Such a call was guaranteed to fail though did not impact applications since we swallowed the error. Now we also stopped swallowing errors in renaming "LOG" file.
|
||||||
|
|
||||||
## 6.23.2 (2021-08-04)
|
## 6.23.2 (2021-08-04)
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
* Fixed a race related to the destruction of `ColumnFamilyData` objects. The earlier logic unlocked the DB mutex before destroying the thread-local `SuperVersion` pointers, which could result in a process crash if another thread managed to get a reference to the `ColumnFamilyData` object.
|
* Fixed a race related to the destruction of `ColumnFamilyData` objects. The earlier logic unlocked the DB mutex before destroying the thread-local `SuperVersion` pointers, which could result in a process crash if another thread managed to get a reference to the `ColumnFamilyData` object.
|
||||||
|
@ -675,6 +675,14 @@ class SpecialEnv : public EnvWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status RenameFile(const std::string& src, const std::string& dest) override {
|
||||||
|
rename_count_.fetch_add(1);
|
||||||
|
if (rename_error_.load(std::memory_order_acquire)) {
|
||||||
|
return Status::NotSupported("Simulated `RenameFile()` error.");
|
||||||
|
}
|
||||||
|
return target()->RenameFile(src, dest);
|
||||||
|
}
|
||||||
|
|
||||||
// Something to return when mocking current time
|
// Something to return when mocking current time
|
||||||
const int64_t maybe_starting_time_;
|
const int64_t maybe_starting_time_;
|
||||||
|
|
||||||
@ -702,6 +710,9 @@ class SpecialEnv : public EnvWrapper {
|
|||||||
// Force write to log files to fail while this pointer is non-nullptr
|
// Force write to log files to fail while this pointer is non-nullptr
|
||||||
std::atomic<bool> log_write_error_;
|
std::atomic<bool> log_write_error_;
|
||||||
|
|
||||||
|
// Force `RenameFile()` to fail while this pointer is non-nullptr
|
||||||
|
std::atomic<bool> rename_error_{false};
|
||||||
|
|
||||||
// Slow down every log write, in micro-seconds.
|
// Slow down every log write, in micro-seconds.
|
||||||
std::atomic<int> log_write_slowdown_;
|
std::atomic<int> log_write_slowdown_;
|
||||||
|
|
||||||
@ -745,6 +756,8 @@ class SpecialEnv : public EnvWrapper {
|
|||||||
|
|
||||||
std::atomic<int> delete_count_;
|
std::atomic<int> delete_count_;
|
||||||
|
|
||||||
|
std::atomic<int> rename_count_{0};
|
||||||
|
|
||||||
std::atomic<bool> is_wal_sync_thread_safe_{true};
|
std::atomic<bool> is_wal_sync_thread_safe_{true};
|
||||||
|
|
||||||
std::atomic<size_t> compaction_readahead_size_{};
|
std::atomic<size_t> compaction_readahead_size_{};
|
||||||
|
@ -296,12 +296,19 @@ Status CreateLoggerFromOptions(const std::string& dbname,
|
|||||||
}
|
}
|
||||||
#endif // !ROCKSDB_LITE
|
#endif // !ROCKSDB_LITE
|
||||||
// Open a log file in the same directory as the db
|
// Open a log file in the same directory as the db
|
||||||
env->RenameFile(
|
s = env->FileExists(fname);
|
||||||
fname, OldInfoLogFileName(dbname, clock->NowMicros(), db_absolute_path,
|
if (s.ok()) {
|
||||||
options.db_log_dir))
|
s = env->RenameFile(
|
||||||
.PermitUncheckedError();
|
fname, OldInfoLogFileName(dbname, clock->NowMicros(), db_absolute_path,
|
||||||
s = env->NewLogger(fname, logger);
|
options.db_log_dir));
|
||||||
if (logger->get() != nullptr) {
|
} else if (s.IsNotFound()) {
|
||||||
|
// "LOG" is not required to exist since this could be a new DB.
|
||||||
|
s = Status::OK();
|
||||||
|
}
|
||||||
|
if (s.ok()) {
|
||||||
|
s = env->NewLogger(fname, logger);
|
||||||
|
}
|
||||||
|
if (s.ok() && logger->get() != nullptr) {
|
||||||
(*logger)->SetInfoLogLevel(options.info_log_level);
|
(*logger)->SetInfoLogLevel(options.info_log_level);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "db/db_test_util.h"
|
||||||
#include "logging/logging.h"
|
#include "logging/logging.h"
|
||||||
#include "port/port.h"
|
#include "port/port.h"
|
||||||
#include "rocksdb/db.h"
|
#include "rocksdb/db.h"
|
||||||
@ -686,6 +687,50 @@ TEST_F(AutoRollLoggerTest, FileCreateFailure) {
|
|||||||
ASSERT_NOK(CreateLoggerFromOptions("", options, &logger));
|
ASSERT_NOK(CreateLoggerFromOptions("", options, &logger));
|
||||||
ASSERT_TRUE(!logger);
|
ASSERT_TRUE(!logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(AutoRollLoggerTest, RenameOnlyWhenExists) {
|
||||||
|
InitTestDb();
|
||||||
|
SpecialEnv env(Env::Default());
|
||||||
|
Options options;
|
||||||
|
options.env = &env;
|
||||||
|
|
||||||
|
// Originally no LOG exists. Should not see a rename.
|
||||||
|
{
|
||||||
|
std::shared_ptr<Logger> logger;
|
||||||
|
ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
|
||||||
|
ASSERT_EQ(0, env.rename_count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now a LOG exists. Create a new one should see a rename.
|
||||||
|
{
|
||||||
|
std::shared_ptr<Logger> logger;
|
||||||
|
ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
|
||||||
|
ASSERT_EQ(1, env.rename_count_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AutoRollLoggerTest, RenameError) {
|
||||||
|
InitTestDb();
|
||||||
|
SpecialEnv env(Env::Default());
|
||||||
|
env.rename_error_ = true;
|
||||||
|
Options options;
|
||||||
|
options.env = &env;
|
||||||
|
|
||||||
|
// Originally no LOG exists. Should not be impacted by rename error.
|
||||||
|
{
|
||||||
|
std::shared_ptr<Logger> logger;
|
||||||
|
ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
|
||||||
|
ASSERT_TRUE(logger != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now a LOG exists. Rename error should cause failure.
|
||||||
|
{
|
||||||
|
std::shared_ptr<Logger> logger;
|
||||||
|
ASSERT_NOK(CreateLoggerFromOptions(kTestDir, options, &logger));
|
||||||
|
ASSERT_TRUE(logger == nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ROCKSDB_NAMESPACE
|
} // namespace ROCKSDB_NAMESPACE
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
Loading…
Reference in New Issue
Block a user