1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
// 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 <deque>
#include <set>
#include <string>
#include <vector>
#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
};
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_PFE,
METHOD_AND_ERRNO,
NONE,
};
ErrorParsingResult ParseMethodAndError(const leveldb::Status& status,
MethodID* method,
int* 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 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 ChromiumEnv : public leveldb::Env,
public UMALogger,
public RetrierProvider,
public WriteTracker {
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<std::string>* 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:
virtual void DidSyncDir(const std::string& fname);
std::string name_;
bool make_backup_;
private:
static const char* FileErrorString(base::File::Error error);
virtual void DidCreateNewFile(const std::string& fname);
virtual bool DoesDirNeedSync(const std::string& fname);
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<std::string> locked_files_;
};
std::set<std::string> directories_needing_sync_;
base::Lock directory_sync_lock_;
const int kMaxRetryTimeMillis;
// BGThread() is the body of the background thread
void BGThread();
static void BGThreadWrapper(void* arg) {
reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
}
virtual void RecordBackupResult(bool result) const;
void RestoreIfNecessary(const std::string& dir,
std::vector<std::string>* 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_;
base::Lock mu_;
base::ConditionVariable bgsignal_;
bool started_bgthread_;
// Entry per Schedule() call
struct BGItem {
void* arg;
void (*function)(void*);
};
typedef std::deque<BGItem> BGQueue;
BGQueue queue_;
LockTable locks_;
};
} // namespace leveldb_env
#endif // THIRD_PARTY_LEVELDATABASE_ENV_CHROMIUM_H_
|