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