1*9507f98cSAndroid Build Coastguard Worker // Copyright 2014 The LevelDB Authors. All rights reserved.
2*9507f98cSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*9507f98cSAndroid Build Coastguard Worker // found in the LICENSE file. See the AUTHORS file for names of contributors.
4*9507f98cSAndroid Build Coastguard Worker
5*9507f98cSAndroid Build Coastguard Worker // This test uses a custom Env to keep track of the state of a filesystem as of
6*9507f98cSAndroid Build Coastguard Worker // the last "sync". It then checks for data loss errors by purposely dropping
7*9507f98cSAndroid Build Coastguard Worker // file data (or entire files) not protected by a "sync".
8*9507f98cSAndroid Build Coastguard Worker
9*9507f98cSAndroid Build Coastguard Worker #include <map>
10*9507f98cSAndroid Build Coastguard Worker #include <set>
11*9507f98cSAndroid Build Coastguard Worker
12*9507f98cSAndroid Build Coastguard Worker #include "gtest/gtest.h"
13*9507f98cSAndroid Build Coastguard Worker #include "db/db_impl.h"
14*9507f98cSAndroid Build Coastguard Worker #include "db/filename.h"
15*9507f98cSAndroid Build Coastguard Worker #include "db/log_format.h"
16*9507f98cSAndroid Build Coastguard Worker #include "db/version_set.h"
17*9507f98cSAndroid Build Coastguard Worker #include "leveldb/cache.h"
18*9507f98cSAndroid Build Coastguard Worker #include "leveldb/db.h"
19*9507f98cSAndroid Build Coastguard Worker #include "leveldb/env.h"
20*9507f98cSAndroid Build Coastguard Worker #include "leveldb/table.h"
21*9507f98cSAndroid Build Coastguard Worker #include "leveldb/write_batch.h"
22*9507f98cSAndroid Build Coastguard Worker #include "port/port.h"
23*9507f98cSAndroid Build Coastguard Worker #include "port/thread_annotations.h"
24*9507f98cSAndroid Build Coastguard Worker #include "util/logging.h"
25*9507f98cSAndroid Build Coastguard Worker #include "util/mutexlock.h"
26*9507f98cSAndroid Build Coastguard Worker #include "util/testutil.h"
27*9507f98cSAndroid Build Coastguard Worker
28*9507f98cSAndroid Build Coastguard Worker namespace leveldb {
29*9507f98cSAndroid Build Coastguard Worker
30*9507f98cSAndroid Build Coastguard Worker static const int kValueSize = 1000;
31*9507f98cSAndroid Build Coastguard Worker static const int kMaxNumValues = 2000;
32*9507f98cSAndroid Build Coastguard Worker static const size_t kNumIterations = 3;
33*9507f98cSAndroid Build Coastguard Worker
34*9507f98cSAndroid Build Coastguard Worker class FaultInjectionTestEnv;
35*9507f98cSAndroid Build Coastguard Worker
36*9507f98cSAndroid Build Coastguard Worker namespace {
37*9507f98cSAndroid Build Coastguard Worker
38*9507f98cSAndroid Build Coastguard Worker // Assume a filename, and not a directory name like "/foo/bar/"
GetDirName(const std::string & filename)39*9507f98cSAndroid Build Coastguard Worker static std::string GetDirName(const std::string& filename) {
40*9507f98cSAndroid Build Coastguard Worker size_t found = filename.find_last_of("/\\");
41*9507f98cSAndroid Build Coastguard Worker if (found == std::string::npos) {
42*9507f98cSAndroid Build Coastguard Worker return "";
43*9507f98cSAndroid Build Coastguard Worker } else {
44*9507f98cSAndroid Build Coastguard Worker return filename.substr(0, found);
45*9507f98cSAndroid Build Coastguard Worker }
46*9507f98cSAndroid Build Coastguard Worker }
47*9507f98cSAndroid Build Coastguard Worker
SyncDir(const std::string & dir)48*9507f98cSAndroid Build Coastguard Worker Status SyncDir(const std::string& dir) {
49*9507f98cSAndroid Build Coastguard Worker // As this is a test it isn't required to *actually* sync this directory.
50*9507f98cSAndroid Build Coastguard Worker return Status::OK();
51*9507f98cSAndroid Build Coastguard Worker }
52*9507f98cSAndroid Build Coastguard Worker
53*9507f98cSAndroid Build Coastguard Worker // A basic file truncation function suitable for this test.
Truncate(const std::string & filename,uint64_t length)54*9507f98cSAndroid Build Coastguard Worker Status Truncate(const std::string& filename, uint64_t length) {
55*9507f98cSAndroid Build Coastguard Worker leveldb::Env* env = leveldb::Env::Default();
56*9507f98cSAndroid Build Coastguard Worker
57*9507f98cSAndroid Build Coastguard Worker SequentialFile* orig_file;
58*9507f98cSAndroid Build Coastguard Worker Status s = env->NewSequentialFile(filename, &orig_file);
59*9507f98cSAndroid Build Coastguard Worker if (!s.ok()) return s;
60*9507f98cSAndroid Build Coastguard Worker
61*9507f98cSAndroid Build Coastguard Worker char* scratch = new char[length];
62*9507f98cSAndroid Build Coastguard Worker leveldb::Slice result;
63*9507f98cSAndroid Build Coastguard Worker s = orig_file->Read(length, &result, scratch);
64*9507f98cSAndroid Build Coastguard Worker delete orig_file;
65*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
66*9507f98cSAndroid Build Coastguard Worker std::string tmp_name = GetDirName(filename) + "/truncate.tmp";
67*9507f98cSAndroid Build Coastguard Worker WritableFile* tmp_file;
68*9507f98cSAndroid Build Coastguard Worker s = env->NewWritableFile(tmp_name, &tmp_file);
69*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
70*9507f98cSAndroid Build Coastguard Worker s = tmp_file->Append(result);
71*9507f98cSAndroid Build Coastguard Worker delete tmp_file;
72*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
73*9507f98cSAndroid Build Coastguard Worker s = env->RenameFile(tmp_name, filename);
74*9507f98cSAndroid Build Coastguard Worker } else {
75*9507f98cSAndroid Build Coastguard Worker env->RemoveFile(tmp_name);
76*9507f98cSAndroid Build Coastguard Worker }
77*9507f98cSAndroid Build Coastguard Worker }
78*9507f98cSAndroid Build Coastguard Worker }
79*9507f98cSAndroid Build Coastguard Worker
80*9507f98cSAndroid Build Coastguard Worker delete[] scratch;
81*9507f98cSAndroid Build Coastguard Worker
82*9507f98cSAndroid Build Coastguard Worker return s;
83*9507f98cSAndroid Build Coastguard Worker }
84*9507f98cSAndroid Build Coastguard Worker
85*9507f98cSAndroid Build Coastguard Worker struct FileState {
86*9507f98cSAndroid Build Coastguard Worker std::string filename_;
87*9507f98cSAndroid Build Coastguard Worker int64_t pos_;
88*9507f98cSAndroid Build Coastguard Worker int64_t pos_at_last_sync_;
89*9507f98cSAndroid Build Coastguard Worker int64_t pos_at_last_flush_;
90*9507f98cSAndroid Build Coastguard Worker
FileStateleveldb::__anond85a411a0111::FileState91*9507f98cSAndroid Build Coastguard Worker FileState(const std::string& filename)
92*9507f98cSAndroid Build Coastguard Worker : filename_(filename),
93*9507f98cSAndroid Build Coastguard Worker pos_(-1),
94*9507f98cSAndroid Build Coastguard Worker pos_at_last_sync_(-1),
95*9507f98cSAndroid Build Coastguard Worker pos_at_last_flush_(-1) {}
96*9507f98cSAndroid Build Coastguard Worker
FileStateleveldb::__anond85a411a0111::FileState97*9507f98cSAndroid Build Coastguard Worker FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {}
98*9507f98cSAndroid Build Coastguard Worker
IsFullySyncedleveldb::__anond85a411a0111::FileState99*9507f98cSAndroid Build Coastguard Worker bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; }
100*9507f98cSAndroid Build Coastguard Worker
101*9507f98cSAndroid Build Coastguard Worker Status DropUnsyncedData() const;
102*9507f98cSAndroid Build Coastguard Worker };
103*9507f98cSAndroid Build Coastguard Worker
104*9507f98cSAndroid Build Coastguard Worker } // anonymous namespace
105*9507f98cSAndroid Build Coastguard Worker
106*9507f98cSAndroid Build Coastguard Worker // A wrapper around WritableFile which informs another Env whenever this file
107*9507f98cSAndroid Build Coastguard Worker // is written to or sync'ed.
108*9507f98cSAndroid Build Coastguard Worker class TestWritableFile : public WritableFile {
109*9507f98cSAndroid Build Coastguard Worker public:
110*9507f98cSAndroid Build Coastguard Worker TestWritableFile(const FileState& state, WritableFile* f,
111*9507f98cSAndroid Build Coastguard Worker FaultInjectionTestEnv* env);
112*9507f98cSAndroid Build Coastguard Worker ~TestWritableFile() override;
113*9507f98cSAndroid Build Coastguard Worker Status Append(const Slice& data) override;
114*9507f98cSAndroid Build Coastguard Worker Status Close() override;
115*9507f98cSAndroid Build Coastguard Worker Status Flush() override;
116*9507f98cSAndroid Build Coastguard Worker Status Sync() override;
117*9507f98cSAndroid Build Coastguard Worker
118*9507f98cSAndroid Build Coastguard Worker private:
119*9507f98cSAndroid Build Coastguard Worker FileState state_;
120*9507f98cSAndroid Build Coastguard Worker WritableFile* target_;
121*9507f98cSAndroid Build Coastguard Worker bool writable_file_opened_;
122*9507f98cSAndroid Build Coastguard Worker FaultInjectionTestEnv* env_;
123*9507f98cSAndroid Build Coastguard Worker
124*9507f98cSAndroid Build Coastguard Worker Status SyncParent();
125*9507f98cSAndroid Build Coastguard Worker };
126*9507f98cSAndroid Build Coastguard Worker
127*9507f98cSAndroid Build Coastguard Worker class FaultInjectionTestEnv : public EnvWrapper {
128*9507f98cSAndroid Build Coastguard Worker public:
FaultInjectionTestEnv()129*9507f98cSAndroid Build Coastguard Worker FaultInjectionTestEnv()
130*9507f98cSAndroid Build Coastguard Worker : EnvWrapper(Env::Default()), filesystem_active_(true) {}
131*9507f98cSAndroid Build Coastguard Worker ~FaultInjectionTestEnv() override = default;
132*9507f98cSAndroid Build Coastguard Worker Status NewWritableFile(const std::string& fname,
133*9507f98cSAndroid Build Coastguard Worker WritableFile** result) override;
134*9507f98cSAndroid Build Coastguard Worker Status NewAppendableFile(const std::string& fname,
135*9507f98cSAndroid Build Coastguard Worker WritableFile** result) override;
136*9507f98cSAndroid Build Coastguard Worker Status RemoveFile(const std::string& f) override;
137*9507f98cSAndroid Build Coastguard Worker Status RenameFile(const std::string& s, const std::string& t) override;
138*9507f98cSAndroid Build Coastguard Worker
139*9507f98cSAndroid Build Coastguard Worker void WritableFileClosed(const FileState& state);
140*9507f98cSAndroid Build Coastguard Worker Status DropUnsyncedFileData();
141*9507f98cSAndroid Build Coastguard Worker Status RemoveFilesCreatedAfterLastDirSync();
142*9507f98cSAndroid Build Coastguard Worker void DirWasSynced();
143*9507f98cSAndroid Build Coastguard Worker bool IsFileCreatedSinceLastDirSync(const std::string& filename);
144*9507f98cSAndroid Build Coastguard Worker void ResetState();
145*9507f98cSAndroid Build Coastguard Worker void UntrackFile(const std::string& f);
146*9507f98cSAndroid Build Coastguard Worker // Setting the filesystem to inactive is the test equivalent to simulating a
147*9507f98cSAndroid Build Coastguard Worker // system reset. Setting to inactive will freeze our saved filesystem state so
148*9507f98cSAndroid Build Coastguard Worker // that it will stop being recorded. It can then be reset back to the state at
149*9507f98cSAndroid Build Coastguard Worker // the time of the reset.
IsFilesystemActive()150*9507f98cSAndroid Build Coastguard Worker bool IsFilesystemActive() LOCKS_EXCLUDED(mutex_) {
151*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
152*9507f98cSAndroid Build Coastguard Worker return filesystem_active_;
153*9507f98cSAndroid Build Coastguard Worker }
SetFilesystemActive(bool active)154*9507f98cSAndroid Build Coastguard Worker void SetFilesystemActive(bool active) LOCKS_EXCLUDED(mutex_) {
155*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
156*9507f98cSAndroid Build Coastguard Worker filesystem_active_ = active;
157*9507f98cSAndroid Build Coastguard Worker }
158*9507f98cSAndroid Build Coastguard Worker
159*9507f98cSAndroid Build Coastguard Worker private:
160*9507f98cSAndroid Build Coastguard Worker port::Mutex mutex_;
161*9507f98cSAndroid Build Coastguard Worker std::map<std::string, FileState> db_file_state_ GUARDED_BY(mutex_);
162*9507f98cSAndroid Build Coastguard Worker std::set<std::string> new_files_since_last_dir_sync_ GUARDED_BY(mutex_);
163*9507f98cSAndroid Build Coastguard Worker bool filesystem_active_ GUARDED_BY(mutex_); // Record flushes, syncs, writes
164*9507f98cSAndroid Build Coastguard Worker };
165*9507f98cSAndroid Build Coastguard Worker
TestWritableFile(const FileState & state,WritableFile * f,FaultInjectionTestEnv * env)166*9507f98cSAndroid Build Coastguard Worker TestWritableFile::TestWritableFile(const FileState& state, WritableFile* f,
167*9507f98cSAndroid Build Coastguard Worker FaultInjectionTestEnv* env)
168*9507f98cSAndroid Build Coastguard Worker : state_(state), target_(f), writable_file_opened_(true), env_(env) {
169*9507f98cSAndroid Build Coastguard Worker assert(f != nullptr);
170*9507f98cSAndroid Build Coastguard Worker }
171*9507f98cSAndroid Build Coastguard Worker
~TestWritableFile()172*9507f98cSAndroid Build Coastguard Worker TestWritableFile::~TestWritableFile() {
173*9507f98cSAndroid Build Coastguard Worker if (writable_file_opened_) {
174*9507f98cSAndroid Build Coastguard Worker Close();
175*9507f98cSAndroid Build Coastguard Worker }
176*9507f98cSAndroid Build Coastguard Worker delete target_;
177*9507f98cSAndroid Build Coastguard Worker }
178*9507f98cSAndroid Build Coastguard Worker
Append(const Slice & data)179*9507f98cSAndroid Build Coastguard Worker Status TestWritableFile::Append(const Slice& data) {
180*9507f98cSAndroid Build Coastguard Worker Status s = target_->Append(data);
181*9507f98cSAndroid Build Coastguard Worker if (s.ok() && env_->IsFilesystemActive()) {
182*9507f98cSAndroid Build Coastguard Worker state_.pos_ += data.size();
183*9507f98cSAndroid Build Coastguard Worker }
184*9507f98cSAndroid Build Coastguard Worker return s;
185*9507f98cSAndroid Build Coastguard Worker }
186*9507f98cSAndroid Build Coastguard Worker
Close()187*9507f98cSAndroid Build Coastguard Worker Status TestWritableFile::Close() {
188*9507f98cSAndroid Build Coastguard Worker writable_file_opened_ = false;
189*9507f98cSAndroid Build Coastguard Worker Status s = target_->Close();
190*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
191*9507f98cSAndroid Build Coastguard Worker env_->WritableFileClosed(state_);
192*9507f98cSAndroid Build Coastguard Worker }
193*9507f98cSAndroid Build Coastguard Worker return s;
194*9507f98cSAndroid Build Coastguard Worker }
195*9507f98cSAndroid Build Coastguard Worker
Flush()196*9507f98cSAndroid Build Coastguard Worker Status TestWritableFile::Flush() {
197*9507f98cSAndroid Build Coastguard Worker Status s = target_->Flush();
198*9507f98cSAndroid Build Coastguard Worker if (s.ok() && env_->IsFilesystemActive()) {
199*9507f98cSAndroid Build Coastguard Worker state_.pos_at_last_flush_ = state_.pos_;
200*9507f98cSAndroid Build Coastguard Worker }
201*9507f98cSAndroid Build Coastguard Worker return s;
202*9507f98cSAndroid Build Coastguard Worker }
203*9507f98cSAndroid Build Coastguard Worker
SyncParent()204*9507f98cSAndroid Build Coastguard Worker Status TestWritableFile::SyncParent() {
205*9507f98cSAndroid Build Coastguard Worker Status s = SyncDir(GetDirName(state_.filename_));
206*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
207*9507f98cSAndroid Build Coastguard Worker env_->DirWasSynced();
208*9507f98cSAndroid Build Coastguard Worker }
209*9507f98cSAndroid Build Coastguard Worker return s;
210*9507f98cSAndroid Build Coastguard Worker }
211*9507f98cSAndroid Build Coastguard Worker
Sync()212*9507f98cSAndroid Build Coastguard Worker Status TestWritableFile::Sync() {
213*9507f98cSAndroid Build Coastguard Worker if (!env_->IsFilesystemActive()) {
214*9507f98cSAndroid Build Coastguard Worker return Status::OK();
215*9507f98cSAndroid Build Coastguard Worker }
216*9507f98cSAndroid Build Coastguard Worker // Ensure new files referred to by the manifest are in the filesystem.
217*9507f98cSAndroid Build Coastguard Worker Status s = target_->Sync();
218*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
219*9507f98cSAndroid Build Coastguard Worker state_.pos_at_last_sync_ = state_.pos_;
220*9507f98cSAndroid Build Coastguard Worker }
221*9507f98cSAndroid Build Coastguard Worker if (env_->IsFileCreatedSinceLastDirSync(state_.filename_)) {
222*9507f98cSAndroid Build Coastguard Worker Status ps = SyncParent();
223*9507f98cSAndroid Build Coastguard Worker if (s.ok() && !ps.ok()) {
224*9507f98cSAndroid Build Coastguard Worker s = ps;
225*9507f98cSAndroid Build Coastguard Worker }
226*9507f98cSAndroid Build Coastguard Worker }
227*9507f98cSAndroid Build Coastguard Worker return s;
228*9507f98cSAndroid Build Coastguard Worker }
229*9507f98cSAndroid Build Coastguard Worker
NewWritableFile(const std::string & fname,WritableFile ** result)230*9507f98cSAndroid Build Coastguard Worker Status FaultInjectionTestEnv::NewWritableFile(const std::string& fname,
231*9507f98cSAndroid Build Coastguard Worker WritableFile** result) {
232*9507f98cSAndroid Build Coastguard Worker WritableFile* actual_writable_file;
233*9507f98cSAndroid Build Coastguard Worker Status s = target()->NewWritableFile(fname, &actual_writable_file);
234*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
235*9507f98cSAndroid Build Coastguard Worker FileState state(fname);
236*9507f98cSAndroid Build Coastguard Worker state.pos_ = 0;
237*9507f98cSAndroid Build Coastguard Worker *result = new TestWritableFile(state, actual_writable_file, this);
238*9507f98cSAndroid Build Coastguard Worker // NewWritableFile doesn't append to files, so if the same file is
239*9507f98cSAndroid Build Coastguard Worker // opened again then it will be truncated - so forget our saved
240*9507f98cSAndroid Build Coastguard Worker // state.
241*9507f98cSAndroid Build Coastguard Worker UntrackFile(fname);
242*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
243*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.insert(fname);
244*9507f98cSAndroid Build Coastguard Worker }
245*9507f98cSAndroid Build Coastguard Worker return s;
246*9507f98cSAndroid Build Coastguard Worker }
247*9507f98cSAndroid Build Coastguard Worker
NewAppendableFile(const std::string & fname,WritableFile ** result)248*9507f98cSAndroid Build Coastguard Worker Status FaultInjectionTestEnv::NewAppendableFile(const std::string& fname,
249*9507f98cSAndroid Build Coastguard Worker WritableFile** result) {
250*9507f98cSAndroid Build Coastguard Worker WritableFile* actual_writable_file;
251*9507f98cSAndroid Build Coastguard Worker Status s = target()->NewAppendableFile(fname, &actual_writable_file);
252*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
253*9507f98cSAndroid Build Coastguard Worker FileState state(fname);
254*9507f98cSAndroid Build Coastguard Worker state.pos_ = 0;
255*9507f98cSAndroid Build Coastguard Worker {
256*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
257*9507f98cSAndroid Build Coastguard Worker if (db_file_state_.count(fname) == 0) {
258*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.insert(fname);
259*9507f98cSAndroid Build Coastguard Worker } else {
260*9507f98cSAndroid Build Coastguard Worker state = db_file_state_[fname];
261*9507f98cSAndroid Build Coastguard Worker }
262*9507f98cSAndroid Build Coastguard Worker }
263*9507f98cSAndroid Build Coastguard Worker *result = new TestWritableFile(state, actual_writable_file, this);
264*9507f98cSAndroid Build Coastguard Worker }
265*9507f98cSAndroid Build Coastguard Worker return s;
266*9507f98cSAndroid Build Coastguard Worker }
267*9507f98cSAndroid Build Coastguard Worker
DropUnsyncedFileData()268*9507f98cSAndroid Build Coastguard Worker Status FaultInjectionTestEnv::DropUnsyncedFileData() {
269*9507f98cSAndroid Build Coastguard Worker Status s;
270*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
271*9507f98cSAndroid Build Coastguard Worker for (const auto& kvp : db_file_state_) {
272*9507f98cSAndroid Build Coastguard Worker if (!s.ok()) {
273*9507f98cSAndroid Build Coastguard Worker break;
274*9507f98cSAndroid Build Coastguard Worker }
275*9507f98cSAndroid Build Coastguard Worker const FileState& state = kvp.second;
276*9507f98cSAndroid Build Coastguard Worker if (!state.IsFullySynced()) {
277*9507f98cSAndroid Build Coastguard Worker s = state.DropUnsyncedData();
278*9507f98cSAndroid Build Coastguard Worker }
279*9507f98cSAndroid Build Coastguard Worker }
280*9507f98cSAndroid Build Coastguard Worker return s;
281*9507f98cSAndroid Build Coastguard Worker }
282*9507f98cSAndroid Build Coastguard Worker
DirWasSynced()283*9507f98cSAndroid Build Coastguard Worker void FaultInjectionTestEnv::DirWasSynced() {
284*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
285*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.clear();
286*9507f98cSAndroid Build Coastguard Worker }
287*9507f98cSAndroid Build Coastguard Worker
IsFileCreatedSinceLastDirSync(const std::string & filename)288*9507f98cSAndroid Build Coastguard Worker bool FaultInjectionTestEnv::IsFileCreatedSinceLastDirSync(
289*9507f98cSAndroid Build Coastguard Worker const std::string& filename) {
290*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
291*9507f98cSAndroid Build Coastguard Worker return new_files_since_last_dir_sync_.find(filename) !=
292*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.end();
293*9507f98cSAndroid Build Coastguard Worker }
294*9507f98cSAndroid Build Coastguard Worker
UntrackFile(const std::string & f)295*9507f98cSAndroid Build Coastguard Worker void FaultInjectionTestEnv::UntrackFile(const std::string& f) {
296*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
297*9507f98cSAndroid Build Coastguard Worker db_file_state_.erase(f);
298*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.erase(f);
299*9507f98cSAndroid Build Coastguard Worker }
300*9507f98cSAndroid Build Coastguard Worker
RemoveFile(const std::string & f)301*9507f98cSAndroid Build Coastguard Worker Status FaultInjectionTestEnv::RemoveFile(const std::string& f) {
302*9507f98cSAndroid Build Coastguard Worker Status s = EnvWrapper::RemoveFile(f);
303*9507f98cSAndroid Build Coastguard Worker EXPECT_LEVELDB_OK(s);
304*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
305*9507f98cSAndroid Build Coastguard Worker UntrackFile(f);
306*9507f98cSAndroid Build Coastguard Worker }
307*9507f98cSAndroid Build Coastguard Worker return s;
308*9507f98cSAndroid Build Coastguard Worker }
309*9507f98cSAndroid Build Coastguard Worker
RenameFile(const std::string & s,const std::string & t)310*9507f98cSAndroid Build Coastguard Worker Status FaultInjectionTestEnv::RenameFile(const std::string& s,
311*9507f98cSAndroid Build Coastguard Worker const std::string& t) {
312*9507f98cSAndroid Build Coastguard Worker Status ret = EnvWrapper::RenameFile(s, t);
313*9507f98cSAndroid Build Coastguard Worker
314*9507f98cSAndroid Build Coastguard Worker if (ret.ok()) {
315*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
316*9507f98cSAndroid Build Coastguard Worker if (db_file_state_.find(s) != db_file_state_.end()) {
317*9507f98cSAndroid Build Coastguard Worker db_file_state_[t] = db_file_state_[s];
318*9507f98cSAndroid Build Coastguard Worker db_file_state_.erase(s);
319*9507f98cSAndroid Build Coastguard Worker }
320*9507f98cSAndroid Build Coastguard Worker
321*9507f98cSAndroid Build Coastguard Worker if (new_files_since_last_dir_sync_.erase(s) != 0) {
322*9507f98cSAndroid Build Coastguard Worker assert(new_files_since_last_dir_sync_.find(t) ==
323*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.end());
324*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.insert(t);
325*9507f98cSAndroid Build Coastguard Worker }
326*9507f98cSAndroid Build Coastguard Worker }
327*9507f98cSAndroid Build Coastguard Worker
328*9507f98cSAndroid Build Coastguard Worker return ret;
329*9507f98cSAndroid Build Coastguard Worker }
330*9507f98cSAndroid Build Coastguard Worker
ResetState()331*9507f98cSAndroid Build Coastguard Worker void FaultInjectionTestEnv::ResetState() {
332*9507f98cSAndroid Build Coastguard Worker // Since we are not destroying the database, the existing files
333*9507f98cSAndroid Build Coastguard Worker // should keep their recorded synced/flushed state. Therefore
334*9507f98cSAndroid Build Coastguard Worker // we do not reset db_file_state_ and new_files_since_last_dir_sync_.
335*9507f98cSAndroid Build Coastguard Worker SetFilesystemActive(true);
336*9507f98cSAndroid Build Coastguard Worker }
337*9507f98cSAndroid Build Coastguard Worker
RemoveFilesCreatedAfterLastDirSync()338*9507f98cSAndroid Build Coastguard Worker Status FaultInjectionTestEnv::RemoveFilesCreatedAfterLastDirSync() {
339*9507f98cSAndroid Build Coastguard Worker // Because RemoveFile access this container make a copy to avoid deadlock
340*9507f98cSAndroid Build Coastguard Worker mutex_.Lock();
341*9507f98cSAndroid Build Coastguard Worker std::set<std::string> new_files(new_files_since_last_dir_sync_.begin(),
342*9507f98cSAndroid Build Coastguard Worker new_files_since_last_dir_sync_.end());
343*9507f98cSAndroid Build Coastguard Worker mutex_.Unlock();
344*9507f98cSAndroid Build Coastguard Worker Status status;
345*9507f98cSAndroid Build Coastguard Worker for (const auto& new_file : new_files) {
346*9507f98cSAndroid Build Coastguard Worker Status remove_status = RemoveFile(new_file);
347*9507f98cSAndroid Build Coastguard Worker if (!remove_status.ok() && status.ok()) {
348*9507f98cSAndroid Build Coastguard Worker status = std::move(remove_status);
349*9507f98cSAndroid Build Coastguard Worker }
350*9507f98cSAndroid Build Coastguard Worker }
351*9507f98cSAndroid Build Coastguard Worker return status;
352*9507f98cSAndroid Build Coastguard Worker }
353*9507f98cSAndroid Build Coastguard Worker
WritableFileClosed(const FileState & state)354*9507f98cSAndroid Build Coastguard Worker void FaultInjectionTestEnv::WritableFileClosed(const FileState& state) {
355*9507f98cSAndroid Build Coastguard Worker MutexLock l(&mutex_);
356*9507f98cSAndroid Build Coastguard Worker db_file_state_[state.filename_] = state;
357*9507f98cSAndroid Build Coastguard Worker }
358*9507f98cSAndroid Build Coastguard Worker
DropUnsyncedData() const359*9507f98cSAndroid Build Coastguard Worker Status FileState::DropUnsyncedData() const {
360*9507f98cSAndroid Build Coastguard Worker int64_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_;
361*9507f98cSAndroid Build Coastguard Worker return Truncate(filename_, sync_pos);
362*9507f98cSAndroid Build Coastguard Worker }
363*9507f98cSAndroid Build Coastguard Worker
364*9507f98cSAndroid Build Coastguard Worker class FaultInjectionTest : public testing::Test {
365*9507f98cSAndroid Build Coastguard Worker public:
366*9507f98cSAndroid Build Coastguard Worker enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR };
367*9507f98cSAndroid Build Coastguard Worker enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_FILES };
368*9507f98cSAndroid Build Coastguard Worker
369*9507f98cSAndroid Build Coastguard Worker FaultInjectionTestEnv* env_;
370*9507f98cSAndroid Build Coastguard Worker std::string dbname_;
371*9507f98cSAndroid Build Coastguard Worker Cache* tiny_cache_;
372*9507f98cSAndroid Build Coastguard Worker Options options_;
373*9507f98cSAndroid Build Coastguard Worker DB* db_;
374*9507f98cSAndroid Build Coastguard Worker
FaultInjectionTest()375*9507f98cSAndroid Build Coastguard Worker FaultInjectionTest()
376*9507f98cSAndroid Build Coastguard Worker : env_(new FaultInjectionTestEnv),
377*9507f98cSAndroid Build Coastguard Worker tiny_cache_(NewLRUCache(100)),
378*9507f98cSAndroid Build Coastguard Worker db_(nullptr) {
379*9507f98cSAndroid Build Coastguard Worker dbname_ = testing::TempDir() + "fault_test";
380*9507f98cSAndroid Build Coastguard Worker DestroyDB(dbname_, Options()); // Destroy any db from earlier run
381*9507f98cSAndroid Build Coastguard Worker options_.reuse_logs = true;
382*9507f98cSAndroid Build Coastguard Worker options_.env = env_;
383*9507f98cSAndroid Build Coastguard Worker options_.paranoid_checks = true;
384*9507f98cSAndroid Build Coastguard Worker options_.block_cache = tiny_cache_;
385*9507f98cSAndroid Build Coastguard Worker options_.create_if_missing = true;
386*9507f98cSAndroid Build Coastguard Worker }
387*9507f98cSAndroid Build Coastguard Worker
~FaultInjectionTest()388*9507f98cSAndroid Build Coastguard Worker ~FaultInjectionTest() {
389*9507f98cSAndroid Build Coastguard Worker CloseDB();
390*9507f98cSAndroid Build Coastguard Worker DestroyDB(dbname_, Options());
391*9507f98cSAndroid Build Coastguard Worker delete tiny_cache_;
392*9507f98cSAndroid Build Coastguard Worker delete env_;
393*9507f98cSAndroid Build Coastguard Worker }
394*9507f98cSAndroid Build Coastguard Worker
ReuseLogs(bool reuse)395*9507f98cSAndroid Build Coastguard Worker void ReuseLogs(bool reuse) { options_.reuse_logs = reuse; }
396*9507f98cSAndroid Build Coastguard Worker
Build(int start_idx,int num_vals)397*9507f98cSAndroid Build Coastguard Worker void Build(int start_idx, int num_vals) {
398*9507f98cSAndroid Build Coastguard Worker std::string key_space, value_space;
399*9507f98cSAndroid Build Coastguard Worker WriteBatch batch;
400*9507f98cSAndroid Build Coastguard Worker for (int i = start_idx; i < start_idx + num_vals; i++) {
401*9507f98cSAndroid Build Coastguard Worker Slice key = Key(i, &key_space);
402*9507f98cSAndroid Build Coastguard Worker batch.Clear();
403*9507f98cSAndroid Build Coastguard Worker batch.Put(key, Value(i, &value_space));
404*9507f98cSAndroid Build Coastguard Worker WriteOptions options;
405*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(db_->Write(options, &batch));
406*9507f98cSAndroid Build Coastguard Worker }
407*9507f98cSAndroid Build Coastguard Worker }
408*9507f98cSAndroid Build Coastguard Worker
ReadValue(int i,std::string * val) const409*9507f98cSAndroid Build Coastguard Worker Status ReadValue(int i, std::string* val) const {
410*9507f98cSAndroid Build Coastguard Worker std::string key_space, value_space;
411*9507f98cSAndroid Build Coastguard Worker Slice key = Key(i, &key_space);
412*9507f98cSAndroid Build Coastguard Worker Value(i, &value_space);
413*9507f98cSAndroid Build Coastguard Worker ReadOptions options;
414*9507f98cSAndroid Build Coastguard Worker return db_->Get(options, key, val);
415*9507f98cSAndroid Build Coastguard Worker }
416*9507f98cSAndroid Build Coastguard Worker
Verify(int start_idx,int num_vals,ExpectedVerifResult expected) const417*9507f98cSAndroid Build Coastguard Worker Status Verify(int start_idx, int num_vals,
418*9507f98cSAndroid Build Coastguard Worker ExpectedVerifResult expected) const {
419*9507f98cSAndroid Build Coastguard Worker std::string val;
420*9507f98cSAndroid Build Coastguard Worker std::string value_space;
421*9507f98cSAndroid Build Coastguard Worker Status s;
422*9507f98cSAndroid Build Coastguard Worker for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) {
423*9507f98cSAndroid Build Coastguard Worker Value(i, &value_space);
424*9507f98cSAndroid Build Coastguard Worker s = ReadValue(i, &val);
425*9507f98cSAndroid Build Coastguard Worker if (expected == VAL_EXPECT_NO_ERROR) {
426*9507f98cSAndroid Build Coastguard Worker if (s.ok()) {
427*9507f98cSAndroid Build Coastguard Worker EXPECT_EQ(value_space, val);
428*9507f98cSAndroid Build Coastguard Worker }
429*9507f98cSAndroid Build Coastguard Worker } else if (s.ok()) {
430*9507f98cSAndroid Build Coastguard Worker std::fprintf(stderr, "Expected an error at %d, but was OK\n", i);
431*9507f98cSAndroid Build Coastguard Worker s = Status::IOError(dbname_, "Expected value error:");
432*9507f98cSAndroid Build Coastguard Worker } else {
433*9507f98cSAndroid Build Coastguard Worker s = Status::OK(); // An expected error
434*9507f98cSAndroid Build Coastguard Worker }
435*9507f98cSAndroid Build Coastguard Worker }
436*9507f98cSAndroid Build Coastguard Worker return s;
437*9507f98cSAndroid Build Coastguard Worker }
438*9507f98cSAndroid Build Coastguard Worker
439*9507f98cSAndroid Build Coastguard Worker // Return the ith key
Key(int i,std::string * storage) const440*9507f98cSAndroid Build Coastguard Worker Slice Key(int i, std::string* storage) const {
441*9507f98cSAndroid Build Coastguard Worker char buf[100];
442*9507f98cSAndroid Build Coastguard Worker std::snprintf(buf, sizeof(buf), "%016d", i);
443*9507f98cSAndroid Build Coastguard Worker storage->assign(buf, strlen(buf));
444*9507f98cSAndroid Build Coastguard Worker return Slice(*storage);
445*9507f98cSAndroid Build Coastguard Worker }
446*9507f98cSAndroid Build Coastguard Worker
447*9507f98cSAndroid Build Coastguard Worker // Return the value to associate with the specified key
Value(int k,std::string * storage) const448*9507f98cSAndroid Build Coastguard Worker Slice Value(int k, std::string* storage) const {
449*9507f98cSAndroid Build Coastguard Worker Random r(k);
450*9507f98cSAndroid Build Coastguard Worker return test::RandomString(&r, kValueSize, storage);
451*9507f98cSAndroid Build Coastguard Worker }
452*9507f98cSAndroid Build Coastguard Worker
OpenDB()453*9507f98cSAndroid Build Coastguard Worker Status OpenDB() {
454*9507f98cSAndroid Build Coastguard Worker delete db_;
455*9507f98cSAndroid Build Coastguard Worker db_ = nullptr;
456*9507f98cSAndroid Build Coastguard Worker env_->ResetState();
457*9507f98cSAndroid Build Coastguard Worker return DB::Open(options_, dbname_, &db_);
458*9507f98cSAndroid Build Coastguard Worker }
459*9507f98cSAndroid Build Coastguard Worker
CloseDB()460*9507f98cSAndroid Build Coastguard Worker void CloseDB() {
461*9507f98cSAndroid Build Coastguard Worker delete db_;
462*9507f98cSAndroid Build Coastguard Worker db_ = nullptr;
463*9507f98cSAndroid Build Coastguard Worker }
464*9507f98cSAndroid Build Coastguard Worker
DeleteAllData()465*9507f98cSAndroid Build Coastguard Worker void DeleteAllData() {
466*9507f98cSAndroid Build Coastguard Worker Iterator* iter = db_->NewIterator(ReadOptions());
467*9507f98cSAndroid Build Coastguard Worker for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
468*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(db_->Delete(WriteOptions(), iter->key()));
469*9507f98cSAndroid Build Coastguard Worker }
470*9507f98cSAndroid Build Coastguard Worker
471*9507f98cSAndroid Build Coastguard Worker delete iter;
472*9507f98cSAndroid Build Coastguard Worker }
473*9507f98cSAndroid Build Coastguard Worker
ResetDBState(ResetMethod reset_method)474*9507f98cSAndroid Build Coastguard Worker void ResetDBState(ResetMethod reset_method) {
475*9507f98cSAndroid Build Coastguard Worker switch (reset_method) {
476*9507f98cSAndroid Build Coastguard Worker case RESET_DROP_UNSYNCED_DATA:
477*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(env_->DropUnsyncedFileData());
478*9507f98cSAndroid Build Coastguard Worker break;
479*9507f98cSAndroid Build Coastguard Worker case RESET_DELETE_UNSYNCED_FILES:
480*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(env_->RemoveFilesCreatedAfterLastDirSync());
481*9507f98cSAndroid Build Coastguard Worker break;
482*9507f98cSAndroid Build Coastguard Worker default:
483*9507f98cSAndroid Build Coastguard Worker assert(false);
484*9507f98cSAndroid Build Coastguard Worker }
485*9507f98cSAndroid Build Coastguard Worker }
486*9507f98cSAndroid Build Coastguard Worker
PartialCompactTestPreFault(int num_pre_sync,int num_post_sync)487*9507f98cSAndroid Build Coastguard Worker void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) {
488*9507f98cSAndroid Build Coastguard Worker DeleteAllData();
489*9507f98cSAndroid Build Coastguard Worker Build(0, num_pre_sync);
490*9507f98cSAndroid Build Coastguard Worker db_->CompactRange(nullptr, nullptr);
491*9507f98cSAndroid Build Coastguard Worker Build(num_pre_sync, num_post_sync);
492*9507f98cSAndroid Build Coastguard Worker }
493*9507f98cSAndroid Build Coastguard Worker
PartialCompactTestReopenWithFault(ResetMethod reset_method,int num_pre_sync,int num_post_sync)494*9507f98cSAndroid Build Coastguard Worker void PartialCompactTestReopenWithFault(ResetMethod reset_method,
495*9507f98cSAndroid Build Coastguard Worker int num_pre_sync, int num_post_sync) {
496*9507f98cSAndroid Build Coastguard Worker env_->SetFilesystemActive(false);
497*9507f98cSAndroid Build Coastguard Worker CloseDB();
498*9507f98cSAndroid Build Coastguard Worker ResetDBState(reset_method);
499*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(OpenDB());
500*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(
501*9507f98cSAndroid Build Coastguard Worker Verify(0, num_pre_sync, FaultInjectionTest::VAL_EXPECT_NO_ERROR));
502*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Verify(num_pre_sync, num_post_sync,
503*9507f98cSAndroid Build Coastguard Worker FaultInjectionTest::VAL_EXPECT_ERROR));
504*9507f98cSAndroid Build Coastguard Worker }
505*9507f98cSAndroid Build Coastguard Worker
NoWriteTestPreFault()506*9507f98cSAndroid Build Coastguard Worker void NoWriteTestPreFault() {}
507*9507f98cSAndroid Build Coastguard Worker
NoWriteTestReopenWithFault(ResetMethod reset_method)508*9507f98cSAndroid Build Coastguard Worker void NoWriteTestReopenWithFault(ResetMethod reset_method) {
509*9507f98cSAndroid Build Coastguard Worker CloseDB();
510*9507f98cSAndroid Build Coastguard Worker ResetDBState(reset_method);
511*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(OpenDB());
512*9507f98cSAndroid Build Coastguard Worker }
513*9507f98cSAndroid Build Coastguard Worker
DoTest()514*9507f98cSAndroid Build Coastguard Worker void DoTest() {
515*9507f98cSAndroid Build Coastguard Worker Random rnd(0);
516*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(OpenDB());
517*9507f98cSAndroid Build Coastguard Worker for (size_t idx = 0; idx < kNumIterations; idx++) {
518*9507f98cSAndroid Build Coastguard Worker int num_pre_sync = rnd.Uniform(kMaxNumValues);
519*9507f98cSAndroid Build Coastguard Worker int num_post_sync = rnd.Uniform(kMaxNumValues);
520*9507f98cSAndroid Build Coastguard Worker
521*9507f98cSAndroid Build Coastguard Worker PartialCompactTestPreFault(num_pre_sync, num_post_sync);
522*9507f98cSAndroid Build Coastguard Worker PartialCompactTestReopenWithFault(RESET_DROP_UNSYNCED_DATA, num_pre_sync,
523*9507f98cSAndroid Build Coastguard Worker num_post_sync);
524*9507f98cSAndroid Build Coastguard Worker
525*9507f98cSAndroid Build Coastguard Worker NoWriteTestPreFault();
526*9507f98cSAndroid Build Coastguard Worker NoWriteTestReopenWithFault(RESET_DROP_UNSYNCED_DATA);
527*9507f98cSAndroid Build Coastguard Worker
528*9507f98cSAndroid Build Coastguard Worker PartialCompactTestPreFault(num_pre_sync, num_post_sync);
529*9507f98cSAndroid Build Coastguard Worker // No new files created so we expect all values since no files will be
530*9507f98cSAndroid Build Coastguard Worker // dropped.
531*9507f98cSAndroid Build Coastguard Worker PartialCompactTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES,
532*9507f98cSAndroid Build Coastguard Worker num_pre_sync + num_post_sync, 0);
533*9507f98cSAndroid Build Coastguard Worker
534*9507f98cSAndroid Build Coastguard Worker NoWriteTestPreFault();
535*9507f98cSAndroid Build Coastguard Worker NoWriteTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES);
536*9507f98cSAndroid Build Coastguard Worker }
537*9507f98cSAndroid Build Coastguard Worker }
538*9507f98cSAndroid Build Coastguard Worker };
539*9507f98cSAndroid Build Coastguard Worker
TEST_F(FaultInjectionTest,FaultTestNoLogReuse)540*9507f98cSAndroid Build Coastguard Worker TEST_F(FaultInjectionTest, FaultTestNoLogReuse) {
541*9507f98cSAndroid Build Coastguard Worker ReuseLogs(false);
542*9507f98cSAndroid Build Coastguard Worker DoTest();
543*9507f98cSAndroid Build Coastguard Worker }
544*9507f98cSAndroid Build Coastguard Worker
TEST_F(FaultInjectionTest,FaultTestWithLogReuse)545*9507f98cSAndroid Build Coastguard Worker TEST_F(FaultInjectionTest, FaultTestWithLogReuse) {
546*9507f98cSAndroid Build Coastguard Worker ReuseLogs(true);
547*9507f98cSAndroid Build Coastguard Worker DoTest();
548*9507f98cSAndroid Build Coastguard Worker }
549*9507f98cSAndroid Build Coastguard Worker
550*9507f98cSAndroid Build Coastguard Worker } // namespace leveldb
551*9507f98cSAndroid Build Coastguard Worker
552