]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/utilities/fault_injection_env.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / utilities / fault_injection_env.h
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
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).
7c673cae
FG
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
11fdf7f2 14#pragma once
7c673cae
FG
15
16#include <map>
17#include <set>
18#include <string>
19
f67539c2 20#include "file/filename.h"
7c673cae 21#include "rocksdb/env.h"
7c673cae 22#include "util/mutexlock.h"
7c673cae 23
f67539c2 24namespace ROCKSDB_NAMESPACE {
20effc67 25class Random;
7c673cae
FG
26class TestWritableFile;
27class FaultInjectionTestEnv;
28
29struct FileState {
30 std::string filename_;
31 ssize_t pos_;
32 ssize_t pos_at_last_sync_;
33 ssize_t pos_at_last_flush_;
34
35 explicit FileState(const std::string& filename)
36 : filename_(filename),
37 pos_(-1),
38 pos_at_last_sync_(-1),
39 pos_at_last_flush_(-1) {}
40
41 FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {}
42
43 bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; }
44
45 Status DropUnsyncedData(Env* env) const;
46
47 Status DropRandomUnsyncedData(Env* env, Random* rand) const;
48};
49
20effc67
TL
50class TestRandomAccessFile : public RandomAccessFile {
51 public:
52 TestRandomAccessFile(std::unique_ptr<RandomAccessFile>&& target,
53 FaultInjectionTestEnv* env);
54
55 Status Read(uint64_t offset, size_t n, Slice* result,
56 char* scratch) const override;
57
58 Status Prefetch(uint64_t offset, size_t n) override;
59
60 Status MultiRead(ReadRequest* reqs, size_t num_reqs) override;
61
62 private:
63 std::unique_ptr<RandomAccessFile> target_;
64 FaultInjectionTestEnv* env_;
65};
66
7c673cae
FG
67// A wrapper around WritableFileWriter* file
68// is written to or sync'ed.
69class TestWritableFile : public WritableFile {
70 public:
71 explicit TestWritableFile(const std::string& fname,
494da23a 72 std::unique_ptr<WritableFile>&& f,
7c673cae
FG
73 FaultInjectionTestEnv* env);
74 virtual ~TestWritableFile();
75 virtual Status Append(const Slice& data) override;
1e59de90
TL
76 virtual Status Append(
77 const Slice& data,
78 const DataVerificationInfo& /*verification_info*/) override {
79 return Append(data);
80 }
7c673cae
FG
81 virtual Status Truncate(uint64_t size) override {
82 return target_->Truncate(size);
83 }
84 virtual Status Close() override;
85 virtual Status Flush() override;
86 virtual Status Sync() override;
87 virtual bool IsSyncThreadSafe() const override { return true; }
1e59de90 88 virtual Status PositionedAppend(const Slice& data, uint64_t offset) override {
11fdf7f2
TL
89 return target_->PositionedAppend(data, offset);
90 }
1e59de90
TL
91 virtual Status PositionedAppend(
92 const Slice& data, uint64_t offset,
93 const DataVerificationInfo& /*verification_info*/) override {
94 return PositionedAppend(data, offset);
95 }
11fdf7f2
TL
96 virtual bool use_direct_io() const override {
97 return target_->use_direct_io();
98 };
7c673cae
FG
99
100 private:
101 FileState state_;
494da23a 102 std::unique_ptr<WritableFile> target_;
7c673cae
FG
103 bool writable_file_opened_;
104 FaultInjectionTestEnv* env_;
105};
106
f67539c2
TL
107// A wrapper around WritableFileWriter* file
108// is written to or sync'ed.
109class TestRandomRWFile : public RandomRWFile {
110 public:
111 explicit TestRandomRWFile(const std::string& fname,
112 std::unique_ptr<RandomRWFile>&& f,
113 FaultInjectionTestEnv* env);
114 virtual ~TestRandomRWFile();
115 Status Write(uint64_t offset, const Slice& data) override;
116 Status Read(uint64_t offset, size_t n, Slice* result,
117 char* scratch) const override;
118 Status Close() override;
119 Status Flush() override;
120 Status Sync() override;
121 size_t GetRequiredBufferAlignment() const override {
122 return target_->GetRequiredBufferAlignment();
123 }
124 bool use_direct_io() const override { return target_->use_direct_io(); };
125
126 private:
127 std::unique_ptr<RandomRWFile> target_;
128 bool file_opened_;
129 FaultInjectionTestEnv* env_;
130};
131
7c673cae
FG
132class TestDirectory : public Directory {
133 public:
134 explicit TestDirectory(FaultInjectionTestEnv* env, std::string dirname,
135 Directory* dir)
136 : env_(env), dirname_(dirname), dir_(dir) {}
137 ~TestDirectory() {}
138
139 virtual Status Fsync() override;
1e59de90 140 virtual Status Close() override;
7c673cae
FG
141
142 private:
143 FaultInjectionTestEnv* env_;
144 std::string dirname_;
494da23a 145 std::unique_ptr<Directory> dir_;
7c673cae
FG
146};
147
148class FaultInjectionTestEnv : public EnvWrapper {
149 public:
150 explicit FaultInjectionTestEnv(Env* base)
151 : EnvWrapper(base), filesystem_active_(true) {}
20effc67 152 virtual ~FaultInjectionTestEnv() { error_.PermitUncheckedError(); }
7c673cae 153
1e59de90
TL
154 static const char* kClassName() { return "FaultInjectionTestEnv"; }
155 const char* Name() const override { return kClassName(); }
156
7c673cae 157 Status NewDirectory(const std::string& name,
494da23a 158 std::unique_ptr<Directory>* result) override;
7c673cae
FG
159
160 Status NewWritableFile(const std::string& fname,
494da23a 161 std::unique_ptr<WritableFile>* result,
7c673cae
FG
162 const EnvOptions& soptions) override;
163
494da23a
TL
164 Status ReopenWritableFile(const std::string& fname,
165 std::unique_ptr<WritableFile>* result,
166 const EnvOptions& soptions) override;
167
f67539c2
TL
168 Status NewRandomRWFile(const std::string& fname,
169 std::unique_ptr<RandomRWFile>* result,
170 const EnvOptions& soptions) override;
171
11fdf7f2
TL
172 Status NewRandomAccessFile(const std::string& fname,
173 std::unique_ptr<RandomAccessFile>* result,
174 const EnvOptions& soptions) override;
175
7c673cae
FG
176 virtual Status DeleteFile(const std::string& f) override;
177
178 virtual Status RenameFile(const std::string& s,
179 const std::string& t) override;
180
1e59de90
TL
181 virtual Status LinkFile(const std::string& s, const std::string& t) override;
182
f67539c2
TL
183// Undef to eliminate clash on Windows
184#undef GetFreeSpace
11fdf7f2
TL
185 virtual Status GetFreeSpace(const std::string& path,
186 uint64_t* disk_free) override {
1e59de90
TL
187 if (!IsFilesystemActive() &&
188 error_.subcode() == IOStatus::SubCode::kNoSpace) {
11fdf7f2
TL
189 *disk_free = 0;
190 return Status::OK();
191 } else {
192 return target()->GetFreeSpace(path, disk_free);
193 }
194 }
195
7c673cae
FG
196 void WritableFileClosed(const FileState& state);
197
494da23a
TL
198 void WritableFileSynced(const FileState& state);
199
200 void WritableFileAppended(const FileState& state);
201
7c673cae
FG
202 // For every file that is not fully synced, make a call to `func` with
203 // FileState of the file as the parameter.
204 Status DropFileData(std::function<Status(Env*, FileState)> func);
205
206 Status DropUnsyncedFileData();
207
208 Status DropRandomUnsyncedFileData(Random* rnd);
209
210 Status DeleteFilesCreatedAfterLastDirSync();
211
212 void ResetState();
213
214 void UntrackFile(const std::string& f);
215
216 void SyncDir(const std::string& dirname) {
217 MutexLock l(&mutex_);
218 dir_to_new_files_since_last_sync_.erase(dirname);
219 }
220
221 // Setting the filesystem to inactive is the test equivalent to simulating a
222 // system reset. Setting to inactive will freeze our saved filesystem state so
223 // that it will stop being recorded. It can then be reset back to the state at
224 // the time of the reset.
225 bool IsFilesystemActive() {
226 MutexLock l(&mutex_);
227 return filesystem_active_;
228 }
1e59de90
TL
229 void SetFilesystemActiveNoLock(
230 bool active, Status error = Status::Corruption("Not active")) {
20effc67 231 error.PermitUncheckedError();
11fdf7f2
TL
232 filesystem_active_ = active;
233 if (!active) {
234 error_ = error;
235 }
20effc67 236 error.PermitUncheckedError();
11fdf7f2
TL
237 }
238 void SetFilesystemActive(bool active,
1e59de90 239 Status error = Status::Corruption("Not active")) {
20effc67 240 error.PermitUncheckedError();
7c673cae 241 MutexLock l(&mutex_);
11fdf7f2 242 SetFilesystemActiveNoLock(active, error);
20effc67 243 error.PermitUncheckedError();
7c673cae 244 }
1e59de90 245 void AssertNoOpenFile() { assert(open_managed_files_.empty()); }
11fdf7f2 246 Status GetError() { return error_; }
7c673cae
FG
247
248 private:
249 port::Mutex mutex_;
250 std::map<std::string, FileState> db_file_state_;
1e59de90 251 std::set<std::string> open_managed_files_;
7c673cae
FG
252 std::unordered_map<std::string, std::set<std::string>>
253 dir_to_new_files_since_last_sync_;
254 bool filesystem_active_; // Record flushes, syncs, writes
11fdf7f2 255 Status error_;
7c673cae
FG
256};
257
f67539c2 258} // namespace ROCKSDB_NAMESPACE