diff --git a/db/repair.cc b/db/repair.cc index 9ed326032..b3862baab 100644 --- a/db/repair.cc +++ b/db/repair.cc @@ -254,14 +254,21 @@ class Repairer { } // search wal_dir if user uses a customize wal_dir - if (!db_options_.wal_dir.empty() && - db_options_.wal_dir != dbname_) { - to_search_paths.push_back(db_options_.wal_dir); + bool same = false; + Status status = env_->AreFilesSame(db_options_.wal_dir, dbname_, &same); + if (status.IsNotSupported()) { + same = db_options_.wal_dir == dbname_; + status = Status::OK(); + } else if (!status.ok()) { + return status; + } + + if (!same) { + to_search_paths.push_back(db_options_.wal_dir); } for (size_t path_id = 0; path_id < to_search_paths.size(); path_id++) { - Status status = - env_->GetChildren(to_search_paths[path_id], &filenames); + status = env_->GetChildren(to_search_paths[path_id], &filenames); if (!status.ok()) { return status; } diff --git a/db/repair_test.cc b/db/repair_test.cc index b267c6d16..1cc86664a 100644 --- a/db/repair_test.cc +++ b/db/repair_test.cc @@ -309,6 +309,25 @@ TEST_F(RepairTest, RepairColumnFamilyOptions) { } } +TEST_F(RepairTest, DbNameContainsTrailingSlash) { + { + bool tmp; + if (env_->AreFilesSame("", "", &tmp).IsNotSupported()) { + fprintf(stderr, + "skipping RepairTest.DbNameContainsTrailingSlash due to " + "unsupported Env::AreFilesSame\n"); + return; + } + } + + Put("key", "val"); + Flush(); + Close(); + + ASSERT_OK(RepairDB(dbname_ + "/", CurrentOptions())); + Reopen(CurrentOptions()); + ASSERT_EQ(Get("key"), "val"); +} #endif // ROCKSDB_LITE } // namespace rocksdb diff --git a/env/env_posix.cc b/env/env_posix.cc index 5a671d72f..a120f863e 100644 --- a/env/env_posix.cc +++ b/env/env_posix.cc @@ -23,6 +23,7 @@ #ifdef OS_LINUX #include #include +#include #endif #include #include @@ -592,6 +593,26 @@ class PosixEnv : public Env { return result; } + virtual Status AreFilesSame(const std::string& first, + const std::string& second, bool* res) override { + struct stat statbuf[2]; + if (stat(first.c_str(), &statbuf[0]) != 0) { + return IOError("stat file", first, errno); + } + if (stat(second.c_str(), &statbuf[1]) != 0) { + return IOError("stat file", second, errno); + } + + if (major(statbuf[0].st_dev) != major(statbuf[1].st_dev) || + minor(statbuf[0].st_dev) != minor(statbuf[1].st_dev) || + statbuf[0].st_ino != statbuf[1].st_ino) { + *res = false; + } else { + *res = true; + } + return Status::OK(); + } + virtual Status LockFile(const std::string& fname, FileLock** lock) override { *lock = nullptr; Status result; diff --git a/include/rocksdb/env.h b/include/rocksdb/env.h index 6b05c0d0b..eac97a496 100644 --- a/include/rocksdb/env.h +++ b/include/rocksdb/env.h @@ -261,6 +261,11 @@ class Env { return Status::NotSupported("LinkFile is not supported for this Env"); } + virtual Status AreFilesSame(const std::string& first, + const std::string& second, bool* res) { + return Status::NotSupported("AreFilesSame is not supported for this Env"); + } + // Lock the specified file. Used to prevent concurrent access to // the same db by multiple processes. On failure, stores nullptr in // *lock and returns non-OK. @@ -980,6 +985,11 @@ class EnvWrapper : public Env { return target_->LinkFile(s, t); } + Status AreFilesSame(const std::string& first, const std::string& second, + bool* res) override { + return target_->AreFilesSame(first, second, res); + } + Status LockFile(const std::string& f, FileLock** l) override { return target_->LockFile(f, l); }