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