1 // Copyright (c) 2013 The LevelDB Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. See the AUTHORS file for names of contributors. 4 5 #ifndef THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_ 6 #define THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_ 7 8 #include <deque> 9 #include <map> 10 #include <set> 11 12 #include "base/files/file.h" 13 #include "base/metrics/histogram.h" 14 #include "leveldb/env.h" 15 #include "port/port_chromium.h" 16 #include "util/mutexlock.h" 17 18 namespace leveldb_env { 19 20 enum MethodID { 21 kSequentialFileRead, 22 kSequentialFileSkip, 23 kRandomAccessFileRead, 24 kWritableFileAppend, 25 kWritableFileClose, 26 kWritableFileFlush, 27 kWritableFileSync, 28 kNewSequentialFile, 29 kNewRandomAccessFile, 30 kNewWritableFile, 31 kDeleteFile, 32 kCreateDir, 33 kDeleteDir, 34 kGetFileSize, 35 kRenameFile, 36 kLockFile, 37 kUnlockFile, 38 kGetTestDirectory, 39 kNewLogger, 40 kSyncParent, 41 kGetChildren, 42 kNumEntries 43 }; 44 45 const char* MethodIDToString(MethodID method); 46 47 leveldb::Status MakeIOError(leveldb::Slice filename, 48 const char* message, 49 MethodID method, 50 int saved_errno); 51 leveldb::Status MakeIOError(leveldb::Slice filename, 52 const char* message, 53 MethodID method, 54 base::File::Error error); 55 leveldb::Status MakeIOError(leveldb::Slice filename, 56 const char* message, 57 MethodID method); 58 59 enum ErrorParsingResult { 60 METHOD_ONLY, 61 METHOD_AND_PFE, 62 METHOD_AND_ERRNO, 63 NONE, 64 }; 65 66 ErrorParsingResult ParseMethodAndError(const char* string, 67 MethodID* method, 68 int* error); 69 int GetCorruptionCode(const leveldb::Status& status); 70 int GetNumCorruptionCodes(); 71 std::string GetCorruptionMessage(const leveldb::Status& status); 72 bool IndicatesDiskFull(const leveldb::Status& status); 73 bool IsIOError(const leveldb::Status& status); 74 bool IsCorruption(const leveldb::Status& status); 75 std::string FilePathToString(const base::FilePath& file_path); 76 77 class UMALogger { 78 public: 79 virtual void RecordErrorAt(MethodID method) const = 0; 80 virtual void RecordOSError(MethodID method, int saved_errno) const = 0; 81 virtual void RecordOSError(MethodID method, 82 base::File::Error error) const = 0; 83 virtual void RecordBackupResult(bool success) const = 0; 84 }; 85 86 class RetrierProvider { 87 public: 88 virtual int MaxRetryTimeMillis() const = 0; 89 virtual base::HistogramBase* GetRetryTimeHistogram(MethodID method) const = 0; 90 virtual base::HistogramBase* GetRecoveredFromErrorHistogram( 91 MethodID method) const = 0; 92 }; 93 94 class WriteTracker { 95 public: 96 virtual void DidCreateNewFile(const std::string& fname) = 0; 97 virtual bool DoesDirNeedSync(const std::string& fname) = 0; 98 virtual void DidSyncDir(const std::string& fname) = 0; 99 }; 100 101 class ChromiumEnv : public leveldb::Env, 102 public UMALogger, 103 public RetrierProvider, 104 public WriteTracker { 105 public: 106 static bool MakeBackup(const std::string& fname); 107 static base::FilePath CreateFilePath(const std::string& file_path); 108 static const char* FileErrorString(::base::File::Error error); 109 static bool HasTableExtension(const base::FilePath& path); 110 virtual ~ChromiumEnv(); 111 112 virtual bool FileExists(const std::string& fname); 113 virtual leveldb::Status GetChildren(const std::string& dir, 114 std::vector<std::string>* result); 115 virtual leveldb::Status DeleteFile(const std::string& fname); 116 virtual leveldb::Status CreateDir(const std::string& name); 117 virtual leveldb::Status DeleteDir(const std::string& name); 118 virtual leveldb::Status GetFileSize(const std::string& fname, uint64_t* size); 119 virtual leveldb::Status RenameFile(const std::string& src, 120 const std::string& dst); 121 virtual leveldb::Status LockFile(const std::string& fname, 122 leveldb::FileLock** lock); 123 virtual leveldb::Status UnlockFile(leveldb::FileLock* lock); 124 virtual void Schedule(void (*function)(void*), void* arg); 125 virtual void StartThread(void (*function)(void* arg), void* arg); 126 virtual leveldb::Status GetTestDirectory(std::string* path); 127 virtual uint64_t NowMicros(); 128 virtual void SleepForMicroseconds(int micros); 129 130 protected: 131 ChromiumEnv(); 132 133 virtual void DidCreateNewFile(const std::string& fname); 134 virtual bool DoesDirNeedSync(const std::string& fname); 135 virtual void DidSyncDir(const std::string& fname); 136 virtual base::File::Error GetDirectoryEntries( 137 const base::FilePath& dir_param, 138 std::vector<base::FilePath>* result) const = 0; 139 virtual void RecordErrorAt(MethodID method) const; 140 virtual void RecordOSError(MethodID method, int saved_errno) const; 141 virtual void RecordOSError(MethodID method, 142 base::File::Error error) const; 143 base::HistogramBase* GetMaxFDHistogram(const std::string& type) const; 144 base::HistogramBase* GetOSErrorHistogram(MethodID method, int limit) const; 145 146 std::string name_; 147 bool make_backup_; 148 149 private: 150 // File locks may not be exclusive within a process (e.g. on POSIX). Track 151 // locks held by the ChromiumEnv to prevent access within the process. 152 class LockTable { 153 public: 154 bool Insert(const std::string& fname) { 155 leveldb::MutexLock l(&mu_); 156 return locked_files_.insert(fname).second; 157 } 158 bool Remove(const std::string& fname) { 159 leveldb::MutexLock l(&mu_); 160 return locked_files_.erase(fname) == 1; 161 } 162 private: 163 leveldb::port::Mutex mu_; 164 std::set<std::string> locked_files_; 165 }; 166 167 std::map<std::string, bool> needs_sync_map_; 168 base::Lock map_lock_; 169 170 const int kMaxRetryTimeMillis; 171 // BGThread() is the body of the background thread 172 void BGThread(); 173 static void BGThreadWrapper(void* arg) { 174 reinterpret_cast<ChromiumEnv*>(arg)->BGThread(); 175 } 176 177 virtual void RecordBackupResult(bool result) const; 178 void RestoreIfNecessary(const std::string& dir, 179 std::vector<std::string>* children); 180 base::FilePath RestoreFromBackup(const base::FilePath& base_name); 181 void RecordLockFileAncestors(int num_missing_ancestors) const; 182 base::HistogramBase* GetMethodIOErrorHistogram() const; 183 base::HistogramBase* GetLockFileAncestorHistogram() const; 184 185 // RetrierProvider implementation. 186 virtual int MaxRetryTimeMillis() const { return kMaxRetryTimeMillis; } 187 virtual base::HistogramBase* GetRetryTimeHistogram(MethodID method) const; 188 virtual base::HistogramBase* GetRecoveredFromErrorHistogram( 189 MethodID method) const; 190 191 base::FilePath test_directory_; 192 193 ::base::Lock mu_; 194 ::base::ConditionVariable bgsignal_; 195 bool started_bgthread_; 196 197 // Entry per Schedule() call 198 struct BGItem { 199 void* arg; 200 void (*function)(void*); 201 }; 202 typedef std::deque<BGItem> BGQueue; 203 BGQueue queue_; 204 LockTable locks_; 205 }; 206 207 } // namespace leveldb_env 208 209 #endif 210