Home | History | Annotate | Download | only in leveldatabase
      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:
    182     bool Insert(const std::string& fname) {
    183       leveldb::MutexLock l(&mu_);
    184       return locked_files_.insert(fname).second;
    185     }
    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();
    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.
    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