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/metrics/histogram.h" 13 #include "base/platform_file.h" 14 #include "base/synchronization/condition_variable.h" 15 #include "leveldb/env.h" 16 #include "leveldb/slice.h" 17 #include "leveldb/status.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::PlatformFileError 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::PlatformFileError 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 ChromiumWritableFile : public leveldb::WritableFile { 105 public: 106 ChromiumWritableFile(const std::string& fname, 107 FILE* f, 108 const UMALogger* uma_logger, 109 WriteTracker* tracker, 110 bool make_backup); 111 virtual ~ChromiumWritableFile(); 112 virtual leveldb::Status Append(const leveldb::Slice& data); 113 virtual leveldb::Status Close(); 114 virtual leveldb::Status Flush(); 115 virtual leveldb::Status Sync(); 116 117 private: 118 enum Type { 119 kManifest, 120 kTable, 121 kOther 122 }; 123 leveldb::Status SyncParent(); 124 125 std::string filename_; 126 FILE* file_; 127 const UMALogger* uma_logger_; 128 WriteTracker* tracker_; 129 Type file_type_; 130 std::string parent_dir_; 131 bool make_backup_; 132 }; 133 134 class ChromiumEnv : public leveldb::Env, 135 public UMALogger, 136 public RetrierProvider, 137 public WriteTracker { 138 public: 139 ChromiumEnv(); 140 virtual ~ChromiumEnv(); 141 142 virtual leveldb::Status NewSequentialFile(const std::string& fname, 143 leveldb::SequentialFile** result); 144 virtual leveldb::Status NewRandomAccessFile( 145 const std::string& fname, 146 leveldb::RandomAccessFile** result); 147 virtual leveldb::Status NewWritableFile(const std::string& fname, 148 leveldb::WritableFile** result); 149 virtual bool FileExists(const std::string& fname); 150 virtual leveldb::Status GetChildren(const std::string& dir, 151 std::vector<std::string>* result); 152 virtual leveldb::Status DeleteFile(const std::string& fname); 153 virtual leveldb::Status CreateDir(const std::string& name); 154 virtual leveldb::Status DeleteDir(const std::string& name); 155 virtual leveldb::Status GetFileSize(const std::string& fname, uint64_t* size); 156 virtual leveldb::Status RenameFile(const std::string& src, 157 const std::string& dst); 158 virtual leveldb::Status LockFile(const std::string& fname, 159 leveldb::FileLock** lock); 160 virtual leveldb::Status UnlockFile(leveldb::FileLock* lock); 161 virtual void Schedule(void (*function)(void*), void* arg); 162 virtual void StartThread(void (*function)(void* arg), void* arg); 163 virtual leveldb::Status GetTestDirectory(std::string* path); 164 virtual leveldb::Status NewLogger(const std::string& fname, 165 leveldb::Logger** result); 166 virtual uint64_t NowMicros(); 167 virtual void SleepForMicroseconds(int micros); 168 169 protected: 170 virtual void DidCreateNewFile(const std::string& fname); 171 virtual bool DoesDirNeedSync(const std::string& fname); 172 virtual void DidSyncDir(const std::string& fname); 173 174 std::string name_; 175 bool make_backup_; 176 177 private: 178 // File locks may not be exclusive within a process (e.g. on POSIX). Track 179 // locks held by the ChromiumEnv to prevent access within the process. 180 class LockTable { 181 public: Insert(const std::string & fname)182 bool Insert(const std::string& fname) { 183 leveldb::MutexLock l(&mu_); 184 return locked_files_.insert(fname).second; 185 } Remove(const std::string & fname)186 bool Remove(const std::string& fname) { 187 leveldb::MutexLock l(&mu_); 188 return locked_files_.erase(fname) == 1; 189 } 190 private: 191 leveldb::port::Mutex mu_; 192 std::set<std::string> locked_files_; 193 }; 194 195 std::map<std::string, bool> needs_sync_map_; 196 base::Lock map_lock_; 197 198 const int kMaxRetryTimeMillis; 199 // BGThread() is the body of the background thread 200 void BGThread(); BGThreadWrapper(void * arg)201 static void BGThreadWrapper(void* arg) { 202 reinterpret_cast<ChromiumEnv*>(arg)->BGThread(); 203 } 204 205 virtual void RecordErrorAt(MethodID method) const; 206 virtual void RecordOSError(MethodID method, int saved_errno) const; 207 virtual void RecordOSError(MethodID method, 208 base::PlatformFileError error) const; 209 virtual void RecordBackupResult(bool result) const; 210 void RestoreIfNecessary(const std::string& dir, 211 std::vector<std::string>* children); 212 base::FilePath RestoreFromBackup(const base::FilePath& base_name); 213 void RecordOpenFilesLimit(const std::string& type); 214 void RecordLockFileAncestors(int num_missing_ancestors) const; 215 base::HistogramBase* GetOSErrorHistogram(MethodID method, int limit) const; 216 base::HistogramBase* GetMethodIOErrorHistogram() const; 217 base::HistogramBase* GetMaxFDHistogram(const std::string& type) const; 218 base::HistogramBase* GetLockFileAncestorHistogram() const; 219 220 // RetrierProvider implementation. MaxRetryTimeMillis()221 virtual int MaxRetryTimeMillis() const { return kMaxRetryTimeMillis; } 222 virtual base::HistogramBase* GetRetryTimeHistogram(MethodID method) const; 223 virtual base::HistogramBase* GetRecoveredFromErrorHistogram( 224 MethodID method) const; 225 226 base::FilePath test_directory_; 227 228 ::base::Lock mu_; 229 ::base::ConditionVariable bgsignal_; 230 bool started_bgthread_; 231 232 // Entry per Schedule() call 233 struct BGItem { 234 void* arg; 235 void (*function)(void*); 236 }; 237 typedef std::deque<BGItem> BGQueue; 238 BGQueue queue_; 239 LockTable locks_; 240 }; 241 242 } // namespace leveldb_env 243 244 #endif 245