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