// Copyright (c) 2013 The LevelDB Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. #ifndef THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_ #define THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_ #include #include #include #include #include "base/files/file.h" #include "base/files/file_path.h" #include "base/metrics/histogram.h" #include "leveldb/env.h" #include "port/port_chromium.h" #include "util/mutexlock.h" namespace leveldb_env { // These entries map to values in tools/metrics/histograms/histograms.xml. New // values should be appended at the end. enum MethodID { kSequentialFileRead, kSequentialFileSkip, kRandomAccessFileRead, kWritableFileAppend, kWritableFileClose, kWritableFileFlush, kWritableFileSync, kNewSequentialFile, kNewRandomAccessFile, kNewWritableFile, kDeleteFile, kCreateDir, kDeleteDir, kGetFileSize, kRenameFile, kLockFile, kUnlockFile, kGetTestDirectory, kNewLogger, kSyncParent, kGetChildren, kNewAppendableFile, kNumEntries }; // leveldb::Status::Code values are mapped to these values for UMA logging. // Do not change/delete these values as you will break reporting for older // copies of Chrome. Only add new values to the end. enum LevelDBStatusValue { LEVELDB_STATUS_OK = 0, LEVELDB_STATUS_NOT_FOUND, LEVELDB_STATUS_CORRUPTION, LEVELDB_STATUS_NOT_SUPPORTED, LEVELDB_STATUS_INVALID_ARGUMENT, LEVELDB_STATUS_IO_ERROR, LEVELDB_STATUS_MAX }; LevelDBStatusValue GetLevelDBStatusUMAValue(const leveldb::Status& s); // The default value for leveldb::Options::reuse_logs. Currently log reuse is an // experimental feature in leveldb. More info at: // https://github.com/google/leveldb/commit/251ebf5dc70129ad3 #if defined(OS_CHROMEOS) // Reusing logs on Chrome OS resulted in an unacceptably high leveldb corruption // rate (at least for Indexed DB). More info at https://crbug.com/460568 const bool kDefaultLogReuseOptionValue = false; #else const bool kDefaultLogReuseOptionValue = true; #endif const char* MethodIDToString(MethodID method); leveldb::Status MakeIOError(leveldb::Slice filename, const std::string& message, MethodID method, base::File::Error error); leveldb::Status MakeIOError(leveldb::Slice filename, const std::string& message, MethodID method); enum ErrorParsingResult { METHOD_ONLY, METHOD_AND_BFE, NONE, }; ErrorParsingResult ParseMethodAndError(const leveldb::Status& status, MethodID* method, base::File::Error* error); int GetCorruptionCode(const leveldb::Status& status); int GetNumCorruptionCodes(); std::string GetCorruptionMessage(const leveldb::Status& status); bool IndicatesDiskFull(const leveldb::Status& status); class UMALogger { public: virtual void RecordErrorAt(MethodID method) const = 0; virtual void RecordOSError(MethodID method, base::File::Error error) const = 0; virtual void RecordBackupResult(bool success) const = 0; }; class RetrierProvider { public: virtual int MaxRetryTimeMillis() const = 0; virtual base::HistogramBase* GetRetryTimeHistogram(MethodID method) const = 0; virtual base::HistogramBase* GetRecoveredFromErrorHistogram( MethodID method) const = 0; }; class ChromiumEnv : public leveldb::Env, public UMALogger, public RetrierProvider { public: ChromiumEnv(); typedef void(ScheduleFunc)(void*); static bool MakeBackup(const std::string& fname); virtual ~ChromiumEnv(); virtual bool FileExists(const std::string& fname); virtual leveldb::Status GetChildren(const std::string& dir, std::vector* result); virtual leveldb::Status DeleteFile(const std::string& fname); virtual leveldb::Status CreateDir(const std::string& name); virtual leveldb::Status DeleteDir(const std::string& name); virtual leveldb::Status GetFileSize(const std::string& fname, uint64_t* size); virtual leveldb::Status RenameFile(const std::string& src, const std::string& dst); virtual leveldb::Status LockFile(const std::string& fname, leveldb::FileLock** lock); virtual leveldb::Status UnlockFile(leveldb::FileLock* lock); virtual void Schedule(ScheduleFunc*, void* arg); virtual void StartThread(void (*function)(void* arg), void* arg); virtual leveldb::Status GetTestDirectory(std::string* path); virtual uint64_t NowMicros(); virtual void SleepForMicroseconds(int micros); virtual leveldb::Status NewSequentialFile(const std::string& fname, leveldb::SequentialFile** result); virtual leveldb::Status NewRandomAccessFile( const std::string& fname, leveldb::RandomAccessFile** result); virtual leveldb::Status NewWritableFile(const std::string& fname, leveldb::WritableFile** result); virtual leveldb::Status NewAppendableFile(const std::string& fname, leveldb::WritableFile** result); virtual leveldb::Status NewLogger(const std::string& fname, leveldb::Logger** result); protected: ChromiumEnv(const std::string& name, bool make_backup); static const char* FileErrorString(base::File::Error error); private: virtual void RecordErrorAt(MethodID method) const; virtual void RecordOSError(MethodID method, base::File::Error error) const; void RecordOpenFilesLimit(const std::string& type); base::HistogramBase* GetMaxFDHistogram(const std::string& type) const; base::HistogramBase* GetOSErrorHistogram(MethodID method, int limit) const; // File locks may not be exclusive within a process (e.g. on POSIX). Track // locks held by the ChromiumEnv to prevent access within the process. class LockTable { public: bool Insert(const std::string& fname) { leveldb::MutexLock l(&mu_); return locked_files_.insert(fname).second; } bool Remove(const std::string& fname) { leveldb::MutexLock l(&mu_); return locked_files_.erase(fname) == 1; } private: leveldb::port::Mutex mu_; std::set locked_files_; }; const int kMaxRetryTimeMillis; // BGThread() is the body of the background thread void BGThread(); static void BGThreadWrapper(void* arg) { reinterpret_cast(arg)->BGThread(); } virtual void RecordBackupResult(bool result) const; void RestoreIfNecessary(const std::string& dir, std::vector* children); base::FilePath RestoreFromBackup(const base::FilePath& base_name); void RecordLockFileAncestors(int num_missing_ancestors) const; base::HistogramBase* GetMethodIOErrorHistogram() const; base::HistogramBase* GetLockFileAncestorHistogram() const; // RetrierProvider implementation. virtual int MaxRetryTimeMillis() const { return kMaxRetryTimeMillis; } virtual base::HistogramBase* GetRetryTimeHistogram(MethodID method) const; virtual base::HistogramBase* GetRecoveredFromErrorHistogram( MethodID method) const; base::FilePath test_directory_; std::string name_; std::string uma_ioerror_base_name_; bool make_backup_; base::Lock mu_; base::ConditionVariable bgsignal_; bool started_bgthread_; // Entry per Schedule() call struct BGItem { void* arg; void (*function)(void*); }; typedef std::deque BGQueue; BGQueue queue_; LockTable locks_; }; } // namespace leveldb_env #endif // THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_