]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/test_util/fault_injection_test_env.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / test_util / fault_injection_test_env.h
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
10 // This test uses a custom Env to keep track of the state of a filesystem as of
11 // the last "sync". It then checks for data loss errors by purposely dropping
12 // file data (or entire files) not protected by a "sync".
13
14 #pragma once
15
16 #include <map>
17 #include <set>
18 #include <string>
19
20 #include "db/version_set.h"
21 #include "env/mock_env.h"
22 #include "file/filename.h"
23 #include "rocksdb/db.h"
24 #include "rocksdb/env.h"
25 #include "util/mutexlock.h"
26 #include "util/random.h"
27
28 namespace ROCKSDB_NAMESPACE {
29
30 class TestWritableFile;
31 class FaultInjectionTestEnv;
32
33 struct FileState {
34 std::string filename_;
35 ssize_t pos_;
36 ssize_t pos_at_last_sync_;
37 ssize_t pos_at_last_flush_;
38
39 explicit FileState(const std::string& filename)
40 : filename_(filename),
41 pos_(-1),
42 pos_at_last_sync_(-1),
43 pos_at_last_flush_(-1) {}
44
45 FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {}
46
47 bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; }
48
49 Status DropUnsyncedData(Env* env) const;
50
51 Status DropRandomUnsyncedData(Env* env, Random* rand) const;
52 };
53
54 // A wrapper around WritableFileWriter* file
55 // is written to or sync'ed.
56 class TestWritableFile : public WritableFile {
57 public:
58 explicit TestWritableFile(const std::string& fname,
59 std::unique_ptr<WritableFile>&& f,
60 FaultInjectionTestEnv* env);
61 virtual ~TestWritableFile();
62 virtual Status Append(const Slice& data) override;
63 virtual Status Truncate(uint64_t size) override {
64 return target_->Truncate(size);
65 }
66 virtual Status Close() override;
67 virtual Status Flush() override;
68 virtual Status Sync() override;
69 virtual bool IsSyncThreadSafe() const override { return true; }
70 virtual Status PositionedAppend(const Slice& data,
71 uint64_t offset) override {
72 return target_->PositionedAppend(data, offset);
73 }
74 virtual bool use_direct_io() const override {
75 return target_->use_direct_io();
76 };
77
78 private:
79 FileState state_;
80 std::unique_ptr<WritableFile> target_;
81 bool writable_file_opened_;
82 FaultInjectionTestEnv* env_;
83 };
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
104 private:
105 std::unique_ptr<RandomRWFile> target_;
106 bool file_opened_;
107 FaultInjectionTestEnv* env_;
108 };
109
110 class TestDirectory : public Directory {
111 public:
112 explicit TestDirectory(FaultInjectionTestEnv* env, std::string dirname,
113 Directory* dir)
114 : env_(env), dirname_(dirname), dir_(dir) {}
115 ~TestDirectory() {}
116
117 virtual Status Fsync() override;
118
119 private:
120 FaultInjectionTestEnv* env_;
121 std::string dirname_;
122 std::unique_ptr<Directory> dir_;
123 };
124
125 class FaultInjectionTestEnv : public EnvWrapper {
126 public:
127 explicit FaultInjectionTestEnv(Env* base)
128 : EnvWrapper(base), filesystem_active_(true) {}
129 virtual ~FaultInjectionTestEnv() {}
130
131 Status NewDirectory(const std::string& name,
132 std::unique_ptr<Directory>* result) override;
133
134 Status NewWritableFile(const std::string& fname,
135 std::unique_ptr<WritableFile>* result,
136 const EnvOptions& soptions) override;
137
138 Status ReopenWritableFile(const std::string& fname,
139 std::unique_ptr<WritableFile>* result,
140 const EnvOptions& soptions) override;
141
142 Status NewRandomRWFile(const std::string& fname,
143 std::unique_ptr<RandomRWFile>* result,
144 const EnvOptions& soptions) override;
145
146 Status NewRandomAccessFile(const std::string& fname,
147 std::unique_ptr<RandomAccessFile>* result,
148 const EnvOptions& soptions) override;
149
150 virtual Status DeleteFile(const std::string& f) override;
151
152 virtual Status RenameFile(const std::string& s,
153 const std::string& t) override;
154
155 // Undef to eliminate clash on Windows
156 #undef GetFreeSpace
157 virtual Status GetFreeSpace(const std::string& path,
158 uint64_t* disk_free) override {
159 if (!IsFilesystemActive() && error_ == Status::NoSpace()) {
160 *disk_free = 0;
161 return Status::OK();
162 } else {
163 return target()->GetFreeSpace(path, disk_free);
164 }
165 }
166
167 void WritableFileClosed(const FileState& state);
168
169 void WritableFileSynced(const FileState& state);
170
171 void WritableFileAppended(const FileState& state);
172
173 // For every file that is not fully synced, make a call to `func` with
174 // FileState of the file as the parameter.
175 Status DropFileData(std::function<Status(Env*, FileState)> func);
176
177 Status DropUnsyncedFileData();
178
179 Status DropRandomUnsyncedFileData(Random* rnd);
180
181 Status DeleteFilesCreatedAfterLastDirSync();
182
183 void ResetState();
184
185 void UntrackFile(const std::string& f);
186
187 void SyncDir(const std::string& dirname) {
188 MutexLock l(&mutex_);
189 dir_to_new_files_since_last_sync_.erase(dirname);
190 }
191
192 // Setting the filesystem to inactive is the test equivalent to simulating a
193 // system reset. Setting to inactive will freeze our saved filesystem state so
194 // that it will stop being recorded. It can then be reset back to the state at
195 // the time of the reset.
196 bool IsFilesystemActive() {
197 MutexLock l(&mutex_);
198 return filesystem_active_;
199 }
200 void SetFilesystemActiveNoLock(bool active,
201 Status error = Status::Corruption("Not active")) {
202 filesystem_active_ = active;
203 if (!active) {
204 error_ = error;
205 }
206 }
207 void SetFilesystemActive(bool active,
208 Status error = Status::Corruption("Not active")) {
209 MutexLock l(&mutex_);
210 SetFilesystemActiveNoLock(active, error);
211 }
212 void AssertNoOpenFile() { assert(open_files_.empty()); }
213 Status GetError() { return error_; }
214
215 private:
216 port::Mutex mutex_;
217 std::map<std::string, FileState> db_file_state_;
218 std::set<std::string> open_files_;
219 std::unordered_map<std::string, std::set<std::string>>
220 dir_to_new_files_since_last_sync_;
221 bool filesystem_active_; // Record flushes, syncs, writes
222 Status error_;
223 };
224
225 } // namespace ROCKSDB_NAMESPACE