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