fault_injection_env.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright 2014 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. // This test uses a custom Env to keep track of the state of a filesystem as of
  10. // the last "sync". It then checks for data loss errors by purposely dropping
  11. // file data (or entire files) not protected by a "sync".
  12. #pragma once
  13. #include <map>
  14. #include <set>
  15. #include <string>
  16. #include "file/filename.h"
  17. #include "rocksdb/env.h"
  18. #include "util/mutexlock.h"
  19. namespace ROCKSDB_NAMESPACE {
  20. class Random;
  21. class TestWritableFile;
  22. class FaultInjectionTestEnv;
  23. struct FileState {
  24. std::string filename_;
  25. ssize_t pos_;
  26. ssize_t pos_at_last_sync_;
  27. ssize_t pos_at_last_flush_;
  28. explicit FileState(const std::string& filename)
  29. : filename_(filename),
  30. pos_(-1),
  31. pos_at_last_sync_(-1),
  32. pos_at_last_flush_(-1) {}
  33. FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {}
  34. bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; }
  35. Status DropUnsyncedData(Env* env) const;
  36. Status DropRandomUnsyncedData(Env* env, Random* rand) const;
  37. };
  38. class TestRandomAccessFile : public RandomAccessFile {
  39. public:
  40. TestRandomAccessFile(std::unique_ptr<RandomAccessFile>&& target,
  41. FaultInjectionTestEnv* env);
  42. Status Read(uint64_t offset, size_t n, Slice* result,
  43. char* scratch) const override;
  44. Status Prefetch(uint64_t offset, size_t n) override;
  45. Status MultiRead(ReadRequest* reqs, size_t num_reqs) override;
  46. Status GetFileSize(uint64_t* file_size) override;
  47. private:
  48. std::unique_ptr<RandomAccessFile> target_;
  49. FaultInjectionTestEnv* env_;
  50. };
  51. // A wrapper around WritableFileWriter* file
  52. // is written to or sync'ed.
  53. class TestWritableFile : public WritableFile {
  54. public:
  55. explicit TestWritableFile(const std::string& fname,
  56. std::unique_ptr<WritableFile>&& f,
  57. FaultInjectionTestEnv* env);
  58. virtual ~TestWritableFile();
  59. Status Append(const Slice& data) override;
  60. Status Append(const Slice& data,
  61. const DataVerificationInfo& /*verification_info*/) override {
  62. return Append(data);
  63. }
  64. Status Truncate(uint64_t size) override { return target_->Truncate(size); }
  65. Status Close() override;
  66. Status Flush() override;
  67. Status Sync() override;
  68. bool IsSyncThreadSafe() const override { return true; }
  69. Status PositionedAppend(const Slice& data, uint64_t offset) override {
  70. return target_->PositionedAppend(data, offset);
  71. }
  72. Status PositionedAppend(
  73. const Slice& data, uint64_t offset,
  74. const DataVerificationInfo& /*verification_info*/) override {
  75. return PositionedAppend(data, offset);
  76. }
  77. bool use_direct_io() const override { return target_->use_direct_io(); }
  78. uint64_t GetFileSize() final { return target_->GetFileSize(); }
  79. private:
  80. FileState state_;
  81. std::unique_ptr<WritableFile> target_;
  82. bool writable_file_opened_;
  83. FaultInjectionTestEnv* env_;
  84. };
  85. // A wrapper around WritableFileWriter* file
  86. // is written to or sync'ed.
  87. class TestRandomRWFile : public RandomRWFile {
  88. public:
  89. explicit TestRandomRWFile(const std::string& fname,
  90. std::unique_ptr<RandomRWFile>&& f,
  91. FaultInjectionTestEnv* env);
  92. virtual ~TestRandomRWFile();
  93. Status Write(uint64_t offset, const Slice& data) override;
  94. Status Read(uint64_t offset, size_t n, Slice* result,
  95. char* scratch) const override;
  96. Status Close() override;
  97. Status Flush() override;
  98. Status Sync() override;
  99. size_t GetRequiredBufferAlignment() const override {
  100. return target_->GetRequiredBufferAlignment();
  101. }
  102. bool use_direct_io() const override { return target_->use_direct_io(); }
  103. private:
  104. std::unique_ptr<RandomRWFile> target_;
  105. bool file_opened_;
  106. FaultInjectionTestEnv* env_;
  107. };
  108. class TestDirectory : public Directory {
  109. public:
  110. explicit TestDirectory(FaultInjectionTestEnv* env, std::string dirname,
  111. Directory* dir)
  112. : env_(env), dirname_(dirname), dir_(dir) {}
  113. ~TestDirectory() {}
  114. Status Fsync() override;
  115. Status Close() override;
  116. private:
  117. FaultInjectionTestEnv* env_;
  118. std::string dirname_;
  119. std::unique_ptr<Directory> dir_;
  120. };
  121. class FaultInjectionTestEnv : public EnvWrapper {
  122. public:
  123. explicit FaultInjectionTestEnv(Env* base)
  124. : EnvWrapper(base), filesystem_active_(true) {}
  125. virtual ~FaultInjectionTestEnv() { error_.PermitUncheckedError(); }
  126. static const char* kClassName() { return "FaultInjectionTestEnv"; }
  127. const char* Name() const override { return kClassName(); }
  128. Status NewDirectory(const std::string& name,
  129. std::unique_ptr<Directory>* result) override;
  130. Status NewWritableFile(const std::string& fname,
  131. std::unique_ptr<WritableFile>* result,
  132. const EnvOptions& soptions) override;
  133. Status ReopenWritableFile(const std::string& fname,
  134. std::unique_ptr<WritableFile>* result,
  135. const EnvOptions& soptions) override;
  136. Status NewRandomRWFile(const std::string& fname,
  137. std::unique_ptr<RandomRWFile>* result,
  138. const EnvOptions& soptions) override;
  139. Status NewRandomAccessFile(const std::string& fname,
  140. std::unique_ptr<RandomAccessFile>* result,
  141. const EnvOptions& soptions) override;
  142. Status DeleteFile(const std::string& f) override;
  143. Status RenameFile(const std::string& s, const std::string& t) override;
  144. Status LinkFile(const std::string& s, const std::string& t) override;
  145. // Undef to eliminate clash on Windows
  146. #undef GetFreeSpace
  147. Status GetFreeSpace(const std::string& path, uint64_t* disk_free) override {
  148. if (!IsFilesystemActive() &&
  149. error_.subcode() == IOStatus::SubCode::kNoSpace) {
  150. *disk_free = 0;
  151. return Status::OK();
  152. } else {
  153. return target()->GetFreeSpace(path, disk_free);
  154. }
  155. }
  156. void WritableFileClosed(const FileState& state);
  157. void WritableFileSynced(const FileState& state);
  158. void WritableFileAppended(const FileState& state);
  159. // For every file that is not fully synced, make a call to `func` with
  160. // FileState of the file as the parameter.
  161. Status DropFileData(std::function<Status(Env*, FileState)> func);
  162. Status DropUnsyncedFileData();
  163. Status DropRandomUnsyncedFileData(Random* rnd);
  164. Status DeleteFilesCreatedAfterLastDirSync();
  165. void ResetState();
  166. void UntrackFile(const std::string& f);
  167. void SyncDir(const std::string& dirname) {
  168. MutexLock l(&mutex_);
  169. dir_to_new_files_since_last_sync_.erase(dirname);
  170. }
  171. // Setting the filesystem to inactive is the test equivalent to simulating a
  172. // system reset. Setting to inactive will freeze our saved filesystem state so
  173. // that it will stop being recorded. It can then be reset back to the state at
  174. // the time of the reset.
  175. bool IsFilesystemActive() {
  176. MutexLock l(&mutex_);
  177. return filesystem_active_;
  178. }
  179. void SetFilesystemActiveNoLock(
  180. bool active, Status error = Status::Corruption("Not active")) {
  181. error.PermitUncheckedError();
  182. filesystem_active_ = active;
  183. if (!active) {
  184. error_ = error;
  185. }
  186. error.PermitUncheckedError();
  187. }
  188. void SetFilesystemActive(bool active,
  189. Status error = Status::Corruption("Not active")) {
  190. error.PermitUncheckedError();
  191. MutexLock l(&mutex_);
  192. SetFilesystemActiveNoLock(active, error);
  193. error.PermitUncheckedError();
  194. }
  195. void AssertNoOpenFile() { assert(open_managed_files_.empty()); }
  196. Status GetError() { return error_; }
  197. private:
  198. port::Mutex mutex_;
  199. std::map<std::string, FileState> db_file_state_;
  200. std::set<std::string> open_managed_files_;
  201. std::unordered_map<std::string, std::set<std::string>>
  202. dir_to_new_files_since_last_sync_;
  203. bool filesystem_active_; // Record flushes, syncs, writes
  204. Status error_;
  205. };
  206. } // namespace ROCKSDB_NAMESPACE