]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/test_util/fault_injection_test_env.h
buildsys: switch source download to quincy
[ceph.git] / ceph / src / rocksdb / test_util / fault_injection_test_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
20#include "db/version_set.h"
21#include "env/mock_env.h"
f67539c2 22#include "file/filename.h"
7c673cae
FG
23#include "rocksdb/db.h"
24#include "rocksdb/env.h"
7c673cae
FG
25#include "util/mutexlock.h"
26#include "util/random.h"
27
f67539c2 28namespace ROCKSDB_NAMESPACE {
7c673cae
FG
29
30class TestWritableFile;
31class FaultInjectionTestEnv;
32
33struct 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.
56class TestWritableFile : public WritableFile {
57 public:
58 explicit TestWritableFile(const std::string& fname,
494da23a 59 std::unique_ptr<WritableFile>&& f,
7c673cae
FG
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; }
11fdf7f2
TL
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 };
7c673cae
FG
77
78 private:
79 FileState state_;
494da23a 80 std::unique_ptr<WritableFile> target_;
7c673cae
FG
81 bool writable_file_opened_;
82 FaultInjectionTestEnv* env_;
83};
84
f67539c2
TL
85// A wrapper around WritableFileWriter* file
86// is written to or sync'ed.
87class 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
7c673cae
FG
110class 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_;
494da23a 122 std::unique_ptr<Directory> dir_;
7c673cae
FG
123};
124
125class 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,
494da23a 132 std::unique_ptr<Directory>* result) override;
7c673cae
FG
133
134 Status NewWritableFile(const std::string& fname,
494da23a 135 std::unique_ptr<WritableFile>* result,
7c673cae
FG
136 const EnvOptions& soptions) override;
137
494da23a
TL
138 Status ReopenWritableFile(const std::string& fname,
139 std::unique_ptr<WritableFile>* result,
140 const EnvOptions& soptions) override;
141
f67539c2
TL
142 Status NewRandomRWFile(const std::string& fname,
143 std::unique_ptr<RandomRWFile>* result,
144 const EnvOptions& soptions) override;
145
11fdf7f2
TL
146 Status NewRandomAccessFile(const std::string& fname,
147 std::unique_ptr<RandomAccessFile>* result,
148 const EnvOptions& soptions) override;
149
7c673cae
FG
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
f67539c2
TL
155// Undef to eliminate clash on Windows
156#undef GetFreeSpace
11fdf7f2
TL
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
7c673cae
FG
167 void WritableFileClosed(const FileState& state);
168
494da23a
TL
169 void WritableFileSynced(const FileState& state);
170
171 void WritableFileAppended(const FileState& state);
172
7c673cae
FG
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 }
11fdf7f2
TL
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")) {
7c673cae 209 MutexLock l(&mutex_);
11fdf7f2 210 SetFilesystemActiveNoLock(active, error);
7c673cae
FG
211 }
212 void AssertNoOpenFile() { assert(open_files_.empty()); }
11fdf7f2 213 Status GetError() { return error_; }
7c673cae
FG
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
11fdf7f2 222 Status error_;
7c673cae
FG
223};
224
f67539c2 225} // namespace ROCKSDB_NAMESPACE