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