// 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 "base/metrics/histogram.h" #include "base/platform_file.h" #include "base/synchronization/condition_variable.h" #include "leveldb/env.h" #include "leveldb/slice.h" #include "leveldb/status.h" namespace leveldb_env { enum MethodID { kSequentialFileRead, kSequentialFileSkip, kRandomAccessFileRead, kWritableFileAppend, kWritableFileClose, kWritableFileFlush, kWritableFileSync, kNewSequentialFile, kNewRandomAccessFile, kNewWritableFile, kDeleteFile, kCreateDir, kDeleteDir, kGetFileSize, kRenameFile, kLockFile, kUnlockFile, kGetTestDirectory, kNewLogger, kSyncParent, kNumEntries }; const char* MethodIDToString(MethodID method); leveldb::Status MakeIOError(leveldb::Slice filename, const char* message, MethodID method, int saved_errno); leveldb::Status MakeIOError(leveldb::Slice filename, const char* message, MethodID method, base::PlatformFileError error); leveldb::Status MakeIOError(leveldb::Slice filename, const char* message, MethodID method); enum ErrorParsingResult { METHOD_ONLY, METHOD_AND_PFE, METHOD_AND_ERRNO, NONE, }; ErrorParsingResult ParseMethodAndError(const char* string, MethodID* method, int* error); std::string FilePathToString(const base::FilePath& file_path); class UMALogger { public: virtual void RecordErrorAt(MethodID method) const = 0; virtual void RecordOSError(MethodID method, int saved_errno) const = 0; virtual void RecordOSError(MethodID method, base::PlatformFileError error) 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 WriteTracker { public: virtual void DidCreateNewFile(const std::string& fname) = 0; virtual bool DoesDirNeedSync(const std::string& fname) = 0; virtual void DidSyncDir(const std::string& fname) = 0; }; class ChromiumWritableFile : public leveldb::WritableFile { public: ChromiumWritableFile(const std::string& fname, FILE* f, const UMALogger* uma_logger, WriteTracker* tracker); virtual ~ChromiumWritableFile(); virtual leveldb::Status Append(const leveldb::Slice& data); virtual leveldb::Status Close(); virtual leveldb::Status Flush(); virtual leveldb::Status Sync(); private: leveldb::Status SyncParent(); std::string filename_; FILE* file_; const UMALogger* uma_logger_; WriteTracker* tracker_; bool is_manifest_; std::string parent_dir_; }; class ChromiumEnv : public leveldb::Env, public UMALogger, public RetrierProvider, public WriteTracker { public: ChromiumEnv(); virtual ~ChromiumEnv(); 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 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(void (*function)(void*), void* arg); virtual void StartThread(void (*function)(void* arg), void* arg); virtual leveldb::Status GetTestDirectory(std::string* path); virtual leveldb::Status NewLogger(const std::string& fname, leveldb::Logger** result); virtual uint64_t NowMicros(); virtual void SleepForMicroseconds(int micros); protected: virtual void DidCreateNewFile(const std::string& fname); virtual bool DoesDirNeedSync(const std::string& fname); virtual void DidSyncDir(const std::string& fname); std::string name_; private: std::map needs_sync_map_; base::Lock map_lock_; const int kMaxRetryTimeMillis; // BGThread() is the body of the background thread void BGThread(); static void BGThreadWrapper(void* arg) { reinterpret_cast(arg)->BGThread(); } virtual void RecordErrorAt(MethodID method) const; virtual void RecordOSError(MethodID method, int saved_errno) const; virtual void RecordOSError(MethodID method, base::PlatformFileError error) const; void RecordOpenFilesLimit(const std::string& type); void RecordLockFileAncestors(int num_missing_ancestors) const; base::HistogramBase* GetOSErrorHistogram(MethodID method, int limit) const; base::HistogramBase* GetMethodIOErrorHistogram() const; base::HistogramBase* GetMaxFDHistogram(const std::string& type) 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_; ::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_; }; } // namespace leveldb_env #endif