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 #ifndef ROCKSDB_LITE
11 
12 #include "rocksdb/utilities/env_mirror.h"
13 
14 namespace ROCKSDB_NAMESPACE {
15 
16 // An implementation of Env that mirrors all work over two backend
17 // Env's.  This is useful for debugging purposes.
18 class SequentialFileMirror : public SequentialFile {
19  public:
20   std::unique_ptr<SequentialFile> a_, b_;
21   std::string fname;
SequentialFileMirror(std::string f)22   explicit SequentialFileMirror(std::string f) : fname(f) {}
23 
Read(size_t n,Slice * result,char * scratch)24   Status Read(size_t n, Slice* result, char* scratch) override {
25     Slice aslice;
26     Status as = a_->Read(n, &aslice, scratch);
27     if (as == Status::OK()) {
28       char* bscratch = new char[n];
29       Slice bslice;
30       size_t off = 0;
31       size_t left = aslice.size();
32       while (left) {
33         Status bs = b_->Read(left, &bslice, bscratch);
34         assert(as == bs);
35         assert(memcmp(bscratch, scratch + off, bslice.size()) == 0);
36         off += bslice.size();
37         left -= bslice.size();
38       }
39       delete[] bscratch;
40       *result = aslice;
41     } else {
42       Status bs = b_->Read(n, result, scratch);
43       assert(as == bs);
44     }
45     return as;
46   }
47 
Skip(uint64_t n)48   Status Skip(uint64_t n) override {
49     Status as = a_->Skip(n);
50     Status bs = b_->Skip(n);
51     assert(as == bs);
52     return as;
53   }
InvalidateCache(size_t offset,size_t length)54   Status InvalidateCache(size_t offset, size_t length) override {
55     Status as = a_->InvalidateCache(offset, length);
56     Status bs = b_->InvalidateCache(offset, length);
57     assert(as == bs);
58     return as;
59   };
60 };
61 
62 class RandomAccessFileMirror : public RandomAccessFile {
63  public:
64   std::unique_ptr<RandomAccessFile> a_, b_;
65   std::string fname;
RandomAccessFileMirror(std::string f)66   explicit RandomAccessFileMirror(std::string f) : fname(f) {}
67 
Read(uint64_t offset,size_t n,Slice * result,char * scratch) const68   Status Read(uint64_t offset, size_t n, Slice* result,
69               char* scratch) const override {
70     Status as = a_->Read(offset, n, result, scratch);
71     if (as == Status::OK()) {
72       char* bscratch = new char[n];
73       Slice bslice;
74       size_t off = 0;
75       size_t left = result->size();
76       while (left) {
77         Status bs = b_->Read(offset + off, left, &bslice, bscratch);
78         assert(as == bs);
79         assert(memcmp(bscratch, scratch + off, bslice.size()) == 0);
80         off += bslice.size();
81         left -= bslice.size();
82       }
83       delete[] bscratch;
84     } else {
85       Status bs = b_->Read(offset, n, result, scratch);
86       assert(as == bs);
87     }
88     return as;
89   }
90 
GetUniqueId(char * id,size_t max_size) const91   size_t GetUniqueId(char* id, size_t max_size) const override {
92     // NOTE: not verified
93     return a_->GetUniqueId(id, max_size);
94   }
95 };
96 
97 class WritableFileMirror : public WritableFile {
98  public:
99   std::unique_ptr<WritableFile> a_, b_;
100   std::string fname;
WritableFileMirror(std::string f,const EnvOptions & options)101   explicit WritableFileMirror(std::string f, const EnvOptions& options)
102       : WritableFile(options), fname(f) {}
103 
Append(const Slice & data)104   Status Append(const Slice& data) override {
105     Status as = a_->Append(data);
106     Status bs = b_->Append(data);
107     assert(as == bs);
108     return as;
109   }
PositionedAppend(const Slice & data,uint64_t offset)110   Status PositionedAppend(const Slice& data, uint64_t offset) override {
111     Status as = a_->PositionedAppend(data, offset);
112     Status bs = b_->PositionedAppend(data, offset);
113     assert(as == bs);
114     return as;
115   }
Truncate(uint64_t size)116   Status Truncate(uint64_t size) override {
117     Status as = a_->Truncate(size);
118     Status bs = b_->Truncate(size);
119     assert(as == bs);
120     return as;
121   }
Close()122   Status Close() override {
123     Status as = a_->Close();
124     Status bs = b_->Close();
125     assert(as == bs);
126     return as;
127   }
Flush()128   Status Flush() override {
129     Status as = a_->Flush();
130     Status bs = b_->Flush();
131     assert(as == bs);
132     return as;
133   }
Sync()134   Status Sync() override {
135     Status as = a_->Sync();
136     Status bs = b_->Sync();
137     assert(as == bs);
138     return as;
139   }
Fsync()140   Status Fsync() override {
141     Status as = a_->Fsync();
142     Status bs = b_->Fsync();
143     assert(as == bs);
144     return as;
145   }
IsSyncThreadSafe() const146   bool IsSyncThreadSafe() const override {
147     bool as = a_->IsSyncThreadSafe();
148     assert(as == b_->IsSyncThreadSafe());
149     return as;
150   }
SetIOPriority(Env::IOPriority pri)151   void SetIOPriority(Env::IOPriority pri) override {
152     a_->SetIOPriority(pri);
153     b_->SetIOPriority(pri);
154   }
GetIOPriority()155   Env::IOPriority GetIOPriority() override {
156     // NOTE: we don't verify this one
157     return a_->GetIOPriority();
158   }
GetFileSize()159   uint64_t GetFileSize() override {
160     uint64_t as = a_->GetFileSize();
161     assert(as == b_->GetFileSize());
162     return as;
163   }
GetPreallocationStatus(size_t * block_size,size_t * last_allocated_block)164   void GetPreallocationStatus(size_t* block_size,
165                               size_t* last_allocated_block) override {
166     // NOTE: we don't verify this one
167     return a_->GetPreallocationStatus(block_size, last_allocated_block);
168   }
GetUniqueId(char * id,size_t max_size) const169   size_t GetUniqueId(char* id, size_t max_size) const override {
170     // NOTE: we don't verify this one
171     return a_->GetUniqueId(id, max_size);
172   }
InvalidateCache(size_t offset,size_t length)173   Status InvalidateCache(size_t offset, size_t length) override {
174     Status as = a_->InvalidateCache(offset, length);
175     Status bs = b_->InvalidateCache(offset, length);
176     assert(as == bs);
177     return as;
178   }
179 
180  protected:
Allocate(uint64_t offset,uint64_t length)181   Status Allocate(uint64_t offset, uint64_t length) override {
182     Status as = a_->Allocate(offset, length);
183     Status bs = b_->Allocate(offset, length);
184     assert(as == bs);
185     return as;
186   }
RangeSync(uint64_t offset,uint64_t nbytes)187   Status RangeSync(uint64_t offset, uint64_t nbytes) override {
188     Status as = a_->RangeSync(offset, nbytes);
189     Status bs = b_->RangeSync(offset, nbytes);
190     assert(as == bs);
191     return as;
192   }
193 };
194 
NewSequentialFile(const std::string & f,std::unique_ptr<SequentialFile> * r,const EnvOptions & options)195 Status EnvMirror::NewSequentialFile(const std::string& f,
196                                     std::unique_ptr<SequentialFile>* r,
197                                     const EnvOptions& options) {
198   if (f.find("/proc/") == 0) {
199     return a_->NewSequentialFile(f, r, options);
200   }
201   SequentialFileMirror* mf = new SequentialFileMirror(f);
202   Status as = a_->NewSequentialFile(f, &mf->a_, options);
203   Status bs = b_->NewSequentialFile(f, &mf->b_, options);
204   assert(as == bs);
205   if (as.ok())
206     r->reset(mf);
207   else
208     delete mf;
209   return as;
210 }
211 
NewRandomAccessFile(const std::string & f,std::unique_ptr<RandomAccessFile> * r,const EnvOptions & options)212 Status EnvMirror::NewRandomAccessFile(const std::string& f,
213                                       std::unique_ptr<RandomAccessFile>* r,
214                                       const EnvOptions& options) {
215   if (f.find("/proc/") == 0) {
216     return a_->NewRandomAccessFile(f, r, options);
217   }
218   RandomAccessFileMirror* mf = new RandomAccessFileMirror(f);
219   Status as = a_->NewRandomAccessFile(f, &mf->a_, options);
220   Status bs = b_->NewRandomAccessFile(f, &mf->b_, options);
221   assert(as == bs);
222   if (as.ok())
223     r->reset(mf);
224   else
225     delete mf;
226   return as;
227 }
228 
NewWritableFile(const std::string & f,std::unique_ptr<WritableFile> * r,const EnvOptions & options)229 Status EnvMirror::NewWritableFile(const std::string& f,
230                                   std::unique_ptr<WritableFile>* r,
231                                   const EnvOptions& options) {
232   if (f.find("/proc/") == 0) return a_->NewWritableFile(f, r, options);
233   WritableFileMirror* mf = new WritableFileMirror(f, options);
234   Status as = a_->NewWritableFile(f, &mf->a_, options);
235   Status bs = b_->NewWritableFile(f, &mf->b_, options);
236   assert(as == bs);
237   if (as.ok())
238     r->reset(mf);
239   else
240     delete mf;
241   return as;
242 }
243 
ReuseWritableFile(const std::string & fname,const std::string & old_fname,std::unique_ptr<WritableFile> * r,const EnvOptions & options)244 Status EnvMirror::ReuseWritableFile(const std::string& fname,
245                                     const std::string& old_fname,
246                                     std::unique_ptr<WritableFile>* r,
247                                     const EnvOptions& options) {
248   if (fname.find("/proc/") == 0)
249     return a_->ReuseWritableFile(fname, old_fname, r, options);
250   WritableFileMirror* mf = new WritableFileMirror(fname, options);
251   Status as = a_->ReuseWritableFile(fname, old_fname, &mf->a_, options);
252   Status bs = b_->ReuseWritableFile(fname, old_fname, &mf->b_, options);
253   assert(as == bs);
254   if (as.ok())
255     r->reset(mf);
256   else
257     delete mf;
258   return as;
259 }
260 
261 }  // namespace ROCKSDB_NAMESPACE
262 #endif
263