1 // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2 // Copyright (c) 2015, Red Hat, Inc.  All rights reserved.
3 //  This source code is licensed under both the GPLv2 (found in the
4 //  COPYING file in the root directory) and Apache 2.0 License
5 //  (found in the LICENSE.Apache file in the root directory).
6 // Copyright (c) 2011 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 // MirrorEnv is an Env implementation that mirrors all file-related
11 // operations to two backing Env's (provided at construction time).
12 // Writes are mirrored.  For read operations, we do the read from both
13 // backends and assert that the results match.
14 //
15 // This is useful when implementing a new Env and ensuring that the
16 // semantics and behavior are correct (in that they match that of an
17 // existing, stable Env, like the default POSIX one).
18 
19 #pragma once
20 
21 #ifndef ROCKSDB_LITE
22 
23 #include <algorithm>
24 #include <iostream>
25 #include <vector>
26 #include "rocksdb/env.h"
27 
28 namespace ROCKSDB_NAMESPACE {
29 
30 class SequentialFileMirror;
31 class RandomAccessFileMirror;
32 class WritableFileMirror;
33 
34 class EnvMirror : public EnvWrapper {
35   Env *a_, *b_;
36   bool free_a_, free_b_;
37 
38  public:
39   EnvMirror(Env* a, Env* b, bool free_a = false, bool free_b = false)
EnvWrapper(a)40       : EnvWrapper(a), a_(a), b_(b), free_a_(free_a), free_b_(free_b) {}
~EnvMirror()41   ~EnvMirror() {
42     if (free_a_) delete a_;
43     if (free_b_) delete b_;
44   }
45 
46   Status NewSequentialFile(const std::string& f,
47                            std::unique_ptr<SequentialFile>* r,
48                            const EnvOptions& options) override;
49   Status NewRandomAccessFile(const std::string& f,
50                              std::unique_ptr<RandomAccessFile>* r,
51                              const EnvOptions& options) override;
52   Status NewWritableFile(const std::string& f, std::unique_ptr<WritableFile>* r,
53                          const EnvOptions& options) override;
54   Status ReuseWritableFile(const std::string& fname,
55                            const std::string& old_fname,
56                            std::unique_ptr<WritableFile>* r,
57                            const EnvOptions& options) override;
NewDirectory(const std::string & name,std::unique_ptr<Directory> * result)58   virtual Status NewDirectory(const std::string& name,
59                               std::unique_ptr<Directory>* result) override {
60     std::unique_ptr<Directory> br;
61     Status as = a_->NewDirectory(name, result);
62     Status bs = b_->NewDirectory(name, &br);
63     assert(as == bs);
64     return as;
65   }
FileExists(const std::string & f)66   Status FileExists(const std::string& f) override {
67     Status as = a_->FileExists(f);
68     Status bs = b_->FileExists(f);
69     assert(as == bs);
70     return as;
71   }
72 #if defined(_MSC_VER)
73 #pragma warning(push)
74 // logical operation on address of string constant
75 #pragma warning(disable : 4130)
76 #endif
GetChildren(const std::string & dir,std::vector<std::string> * r)77   Status GetChildren(const std::string& dir,
78                      std::vector<std::string>* r) override {
79     std::vector<std::string> ar, br;
80     Status as = a_->GetChildren(dir, &ar);
81     Status bs = b_->GetChildren(dir, &br);
82     assert(as == bs);
83     std::sort(ar.begin(), ar.end());
84     std::sort(br.begin(), br.end());
85     if (!as.ok() || ar != br) {
86       assert(0 == "getchildren results don't match");
87     }
88     *r = ar;
89     return as;
90   }
91 #if defined(_MSC_VER)
92 #pragma warning(pop)
93 #endif
DeleteFile(const std::string & f)94   Status DeleteFile(const std::string& f) override {
95     Status as = a_->DeleteFile(f);
96     Status bs = b_->DeleteFile(f);
97     assert(as == bs);
98     return as;
99   }
CreateDir(const std::string & d)100   Status CreateDir(const std::string& d) override {
101     Status as = a_->CreateDir(d);
102     Status bs = b_->CreateDir(d);
103     assert(as == bs);
104     return as;
105   }
CreateDirIfMissing(const std::string & d)106   Status CreateDirIfMissing(const std::string& d) override {
107     Status as = a_->CreateDirIfMissing(d);
108     Status bs = b_->CreateDirIfMissing(d);
109     assert(as == bs);
110     return as;
111   }
DeleteDir(const std::string & d)112   Status DeleteDir(const std::string& d) override {
113     Status as = a_->DeleteDir(d);
114     Status bs = b_->DeleteDir(d);
115     assert(as == bs);
116     return as;
117   }
GetFileSize(const std::string & f,uint64_t * s)118   Status GetFileSize(const std::string& f, uint64_t* s) override {
119     uint64_t asize, bsize;
120     Status as = a_->GetFileSize(f, &asize);
121     Status bs = b_->GetFileSize(f, &bsize);
122     assert(as == bs);
123     assert(!as.ok() || asize == bsize);
124     *s = asize;
125     return as;
126   }
127 
GetFileModificationTime(const std::string & fname,uint64_t * file_mtime)128   Status GetFileModificationTime(const std::string& fname,
129                                  uint64_t* file_mtime) override {
130     uint64_t amtime, bmtime;
131     Status as = a_->GetFileModificationTime(fname, &amtime);
132     Status bs = b_->GetFileModificationTime(fname, &bmtime);
133     assert(as == bs);
134     assert(!as.ok() || amtime - bmtime < 10000 || bmtime - amtime < 10000);
135     *file_mtime = amtime;
136     return as;
137   }
138 
RenameFile(const std::string & s,const std::string & t)139   Status RenameFile(const std::string& s, const std::string& t) override {
140     Status as = a_->RenameFile(s, t);
141     Status bs = b_->RenameFile(s, t);
142     assert(as == bs);
143     return as;
144   }
145 
LinkFile(const std::string & s,const std::string & t)146   Status LinkFile(const std::string& s, const std::string& t) override {
147     Status as = a_->LinkFile(s, t);
148     Status bs = b_->LinkFile(s, t);
149     assert(as == bs);
150     return as;
151   }
152 
153   class FileLockMirror : public FileLock {
154    public:
155     FileLock *a_, *b_;
FileLockMirror(FileLock * a,FileLock * b)156     FileLockMirror(FileLock* a, FileLock* b) : a_(a), b_(b) {}
157   };
158 
LockFile(const std::string & f,FileLock ** l)159   Status LockFile(const std::string& f, FileLock** l) override {
160     FileLock *al, *bl;
161     Status as = a_->LockFile(f, &al);
162     Status bs = b_->LockFile(f, &bl);
163     assert(as == bs);
164     if (as.ok()) *l = new FileLockMirror(al, bl);
165     return as;
166   }
167 
UnlockFile(FileLock * l)168   Status UnlockFile(FileLock* l) override {
169     FileLockMirror* ml = static_cast<FileLockMirror*>(l);
170     Status as = a_->UnlockFile(ml->a_);
171     Status bs = b_->UnlockFile(ml->b_);
172     assert(as == bs);
173     delete ml;
174     return as;
175   }
176 };
177 
178 }  // namespace ROCKSDB_NAMESPACE
179 
180 #endif  // ROCKSDB_LITE
181