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