| Index: third_party/leveldatabase/env_chromium.cc
|
| diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
|
| index b34cecd37023e56271966a8bc2b13290d2719582..4603e5d82c21e30d41b8856c073ddc4528a0ae08 100644
|
| --- a/third_party/leveldatabase/env_chromium.cc
|
| +++ b/third_party/leveldatabase/env_chromium.cc
|
| @@ -4,25 +4,22 @@
|
|
|
| #include "third_party/leveldatabase/env_chromium.h"
|
|
|
| -#if defined(OS_WIN)
|
| -#include <io.h>
|
| +#if defined(OS_POSIX)
|
| +#include <dirent.h>
|
| +#include <sys/types.h>
|
| #endif
|
|
|
| #include "base/debug/trace_event.h"
|
| #include "base/files/file_util.h"
|
| #include "base/lazy_instance.h"
|
| +#include "base/memory/shared_memory.h"
|
| #include "base/metrics/histogram.h"
|
| +#include "base/process/process_metrics.h"
|
| #include "base/stl_util.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| -#include "third_party/leveldatabase/env_chromium_stdio.h"
|
| +#include "third_party/leveldatabase/chromium_logger.h"
|
| #include "third_party/re2/re2/re2.h"
|
|
|
| -#if defined(OS_WIN)
|
| -#include "base/command_line.h"
|
| -#include "base/win/win_util.h"
|
| -#include "third_party/leveldatabase/env_chromium_win.h"
|
| -#endif
|
| -
|
| using leveldb::FileLock;
|
| using leveldb::Slice;
|
| using leveldb::Status;
|
| @@ -38,6 +35,65 @@ const base::FilePath::CharType table_extension[] = FILE_PATH_LITERAL(".ldb");
|
| static const base::FilePath::CharType kLevelDBTestDirectoryPrefix[]
|
| = FILE_PATH_LITERAL("leveldb-test-");
|
|
|
| +static base::File::Error LastFileError() {
|
| +#if defined(OS_WIN)
|
| + return base::File::OSErrorToFileError(GetLastError());
|
| +#else
|
| + return base::File::OSErrorToFileError(errno);
|
| +#endif
|
| +}
|
| +
|
| +// Making direct platform in lieu of using base::FileEnumerator because the
|
| +// latter can fail quietly without return an error result.
|
| +static base::File::Error GetDirectoryEntries(
|
| + const base::FilePath& dir_param,
|
| + std::vector<base::FilePath>* result) {
|
| + result->clear();
|
| +#if defined(OS_WIN)
|
| + base::FilePath dir_filepath = dir_param.Append(FILE_PATH_LITERAL("*"));
|
| + WIN32_FIND_DATA find_data;
|
| + HANDLE find_handle = FindFirstFile(dir_filepath.value().c_str(), &find_data);
|
| + if (find_handle == INVALID_HANDLE_VALUE) {
|
| + DWORD last_error = GetLastError();
|
| + if (last_error == ERROR_FILE_NOT_FOUND)
|
| + return base::File::FILE_OK;
|
| + return base::File::OSErrorToFileError(last_error);
|
| + }
|
| + do {
|
| + base::FilePath filepath(find_data.cFileName);
|
| + base::FilePath::StringType basename = filepath.BaseName().value();
|
| + if (basename == FILE_PATH_LITERAL(".") ||
|
| + basename == FILE_PATH_LITERAL(".."))
|
| + continue;
|
| + result->push_back(filepath.BaseName());
|
| + } while (FindNextFile(find_handle, &find_data));
|
| + DWORD last_error = GetLastError();
|
| + base::File::Error return_value = base::File::FILE_OK;
|
| + if (last_error != ERROR_NO_MORE_FILES)
|
| + return_value = base::File::OSErrorToFileError(last_error);
|
| + FindClose(find_handle);
|
| + return return_value;
|
| +#else
|
| + const std::string dir_string = FilePathToString(dir_param);
|
| + DIR* dir = opendir(dir_string.c_str());
|
| + if (!dir)
|
| + return base::File::OSErrorToFileError(errno);
|
| + struct dirent dent_buf;
|
| + struct dirent* dent;
|
| + int readdir_result;
|
| + while ((readdir_result = readdir_r(dir, &dent_buf, &dent)) == 0 && dent) {
|
| + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
|
| + continue;
|
| + result->push_back(ChromiumEnv::CreateFilePath(dent->d_name));
|
| + }
|
| + int saved_errno = errno;
|
| + closedir(dir);
|
| + if (readdir_result != 0)
|
| + return base::File::OSErrorToFileError(saved_errno);
|
| + return base::File::FILE_OK;
|
| +#endif
|
| +}
|
| +
|
| class ChromiumFileLock : public FileLock {
|
| public:
|
| ::base::File file_;
|
| @@ -88,33 +144,196 @@ class Retrier {
|
| RetrierProvider* provider_;
|
| };
|
|
|
| -class IDBEnvStdio : public ChromiumEnvStdio {
|
| +class ChromiumSequentialFile : public leveldb::SequentialFile {
|
| public:
|
| - IDBEnvStdio() : ChromiumEnvStdio() {
|
| - name_ = "LevelDBEnv.IDB";
|
| - make_backup_ = true;
|
| + ChromiumSequentialFile(const std::string& fname,
|
| + base::File* f,
|
| + const UMALogger* uma_logger)
|
| + : filename_(fname), file_(f), uma_logger_(uma_logger) {}
|
| + virtual ~ChromiumSequentialFile() {}
|
| +
|
| + Status Read(size_t n, Slice* result, char* scratch) override {
|
| + int bytes_read = file_->ReadAtCurrentPosNoBestEffort(scratch, n);
|
| + if (bytes_read == -1) {
|
| + base::File::Error error = LastFileError();
|
| + uma_logger_->RecordErrorAt(kSequentialFileRead);
|
| + return MakeIOError(filename_, base::File::ErrorToString(error),
|
| + kSequentialFileRead, error);
|
| + } else {
|
| + *result = Slice(scratch, bytes_read);
|
| + return Status::OK();
|
| + }
|
| }
|
| +
|
| + Status Skip(uint64_t n) override {
|
| + if (file_->Seek(base::File::FROM_CURRENT, n) == -1) {
|
| + base::File::Error error = LastFileError();
|
| + uma_logger_->RecordErrorAt(kSequentialFileSkip);
|
| + return MakeIOError(filename_, base::File::ErrorToString(error),
|
| + kSequentialFileSkip, error);
|
| + } else {
|
| + return Status::OK();
|
| + }
|
| + }
|
| +
|
| + private:
|
| + std::string filename_;
|
| + scoped_ptr<base::File> file_;
|
| + const UMALogger* uma_logger_;
|
| };
|
|
|
| -#if defined(OS_WIN)
|
| -class IDBEnvWin : public ChromiumEnvWin {
|
| +class ChromiumRandomAccessFile : public leveldb::RandomAccessFile {
|
| + public:
|
| + ChromiumRandomAccessFile(const std::string& fname,
|
| + ::base::File file,
|
| + const UMALogger* uma_logger)
|
| + : filename_(fname), file_(file.Pass()), uma_logger_(uma_logger) {}
|
| + virtual ~ChromiumRandomAccessFile() {}
|
| +
|
| + Status Read(uint64_t offset,
|
| + size_t n,
|
| + Slice* result,
|
| + char* scratch) const override {
|
| + Status s;
|
| + int r = file_.Read(offset, scratch, n);
|
| + *result = Slice(scratch, (r < 0) ? 0 : r);
|
| + if (r < 0) {
|
| + // An error: return a non-ok status
|
| + s = MakeIOError(filename_, "Could not perform read",
|
| + kRandomAccessFileRead);
|
| + uma_logger_->RecordErrorAt(kRandomAccessFileRead);
|
| + }
|
| + return s;
|
| + }
|
| +
|
| + private:
|
| + std::string filename_;
|
| + mutable ::base::File file_;
|
| + const UMALogger* uma_logger_;
|
| +};
|
| +
|
| +class ChromiumWritableFile : public leveldb::WritableFile {
|
| + public:
|
| + ChromiumWritableFile(const std::string& fname,
|
| + base::File* f,
|
| + const UMALogger* uma_logger,
|
| + WriteTracker* tracker,
|
| + bool make_backup);
|
| + virtual ~ChromiumWritableFile() {}
|
| + leveldb::Status Append(const leveldb::Slice& data) override;
|
| + leveldb::Status Close() override;
|
| + leveldb::Status Flush() override;
|
| + leveldb::Status Sync() override;
|
| +
|
| + private:
|
| + enum Type { kManifest, kTable, kOther };
|
| + leveldb::Status SyncParent();
|
| +
|
| + std::string filename_;
|
| + scoped_ptr<base::File> file_;
|
| + const UMALogger* uma_logger_;
|
| + WriteTracker* tracker_;
|
| + Type file_type_;
|
| + std::string parent_dir_;
|
| + bool make_backup_;
|
| +};
|
| +
|
| +ChromiumWritableFile::ChromiumWritableFile(const std::string& fname,
|
| + base::File* f,
|
| + const UMALogger* uma_logger,
|
| + WriteTracker* tracker,
|
| + bool make_backup)
|
| + : filename_(fname),
|
| + file_(f),
|
| + uma_logger_(uma_logger),
|
| + tracker_(tracker),
|
| + file_type_(kOther),
|
| + make_backup_(make_backup) {
|
| + base::FilePath path = base::FilePath::FromUTF8Unsafe(fname);
|
| + if (FilePathToString(path.BaseName()).find("MANIFEST") == 0)
|
| + file_type_ = kManifest;
|
| + else if (ChromiumEnv::HasTableExtension(path))
|
| + file_type_ = kTable;
|
| + if (file_type_ != kManifest)
|
| + tracker_->DidCreateNewFile(filename_);
|
| + parent_dir_ = FilePathToString(ChromiumEnv::CreateFilePath(fname).DirName());
|
| +}
|
| +
|
| +Status ChromiumWritableFile::SyncParent() {
|
| + TRACE_EVENT0("leveldb", "SyncParent");
|
| +#if defined(OS_POSIX)
|
| + base::FilePath path = base::FilePath::FromUTF8Unsafe(parent_dir_);
|
| + base::File f(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
| + if (!f.IsValid()) {
|
| + return MakeIOError(parent_dir_, "Unable to open directory", kSyncParent,
|
| + f.error_details());
|
| + }
|
| + if (!f.Flush()) {
|
| + base::File::Error error = LastFileError();
|
| + return MakeIOError(parent_dir_, base::File::ErrorToString(error),
|
| + kSyncParent, error);
|
| + }
|
| +#endif
|
| + return Status::OK();
|
| +}
|
| +
|
| +Status ChromiumWritableFile::Append(const Slice& data) {
|
| + if (file_type_ == kManifest && tracker_->DoesDirNeedSync(filename_)) {
|
| + Status s = SyncParent();
|
| + if (!s.ok())
|
| + return s;
|
| + tracker_->DidSyncDir(filename_);
|
| + }
|
| +
|
| + int bytes_written = file_->WriteAtCurrentPos(data.data(), data.size());
|
| + if (bytes_written != data.size()) {
|
| + base::File::Error error = LastFileError();
|
| + uma_logger_->RecordOSError(kWritableFileAppend, error);
|
| + return MakeIOError(filename_, base::File::ErrorToString(error),
|
| + kWritableFileAppend, error);
|
| + }
|
| +
|
| + return Status::OK();
|
| +}
|
| +
|
| +Status ChromiumWritableFile::Close() {
|
| + file_->Close();
|
| + return Status::OK();
|
| +}
|
| +
|
| +Status ChromiumWritableFile::Flush() {
|
| + // base::File doesn't do buffered I/O (i.e. POSIX FILE streams) so nothing to
|
| + // flush.
|
| + return Status::OK();
|
| +}
|
| +
|
| +Status ChromiumWritableFile::Sync() {
|
| + TRACE_EVENT0("leveldb", "WritableFile::Sync");
|
| +
|
| + if (!file_->Flush()) {
|
| + base::File::Error error = LastFileError();
|
| + uma_logger_->RecordErrorAt(kWritableFileSync);
|
| + return MakeIOError(filename_, base::File::ErrorToString(error),
|
| + kWritableFileSync, error);
|
| + }
|
| +
|
| + if (make_backup_ && file_type_ == kTable)
|
| + uma_logger_->RecordBackupResult(ChromiumEnv::MakeBackup(filename_));
|
| +
|
| + return Status::OK();
|
| +}
|
| +
|
| +class IDBEnv : public ChromiumEnv {
|
| public:
|
| - IDBEnvWin() : ChromiumEnvWin() {
|
| + IDBEnv() : ChromiumEnv() {
|
| name_ = "LevelDBEnv.IDB";
|
| make_backup_ = true;
|
| }
|
| };
|
| -#endif
|
|
|
| -#if defined(OS_WIN)
|
| -::base::LazyInstance<IDBEnvWin>::Leaky idb_env =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| -#else
|
| -::base::LazyInstance<IDBEnvStdio>::Leaky idb_env =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| -#endif
|
| +::base::LazyInstance<IDBEnv>::Leaky idb_env = LAZY_INSTANCE_INITIALIZER;
|
|
|
| -::base::LazyInstance<ChromiumEnvStdio>::Leaky default_env =
|
| +::base::LazyInstance<ChromiumEnv>::Leaky default_env =
|
| LAZY_INSTANCE_INITIALIZER;
|
|
|
| } // unnamed namespace
|
| @@ -172,44 +391,22 @@ const char* MethodIDToString(MethodID method) {
|
| }
|
|
|
| Status MakeIOError(Slice filename,
|
| - const char* message,
|
| - MethodID method,
|
| - int saved_errno) {
|
| - char buf[512];
|
| - snprintf(buf,
|
| - sizeof(buf),
|
| - "%s (ChromeMethodErrno: %d::%s::%d)",
|
| - message,
|
| - method,
|
| - MethodIDToString(method),
|
| - saved_errno);
|
| - return Status::IOError(filename, buf);
|
| -}
|
| -
|
| -Status MakeIOError(Slice filename,
|
| - const char* message,
|
| + const std::string& message,
|
| MethodID method,
|
| base::File::Error error) {
|
| DCHECK_LT(error, 0);
|
| char buf[512];
|
| - snprintf(buf,
|
| - sizeof(buf),
|
| - "%s (ChromeMethodPFE: %d::%s::%d)",
|
| - message,
|
| - method,
|
| - MethodIDToString(method),
|
| - -error);
|
| + snprintf(buf, sizeof(buf), "%s (ChromeMethodPFE: %d::%s::%d)",
|
| + message.c_str(), method, MethodIDToString(method), -error);
|
| return Status::IOError(filename, buf);
|
| }
|
|
|
| -Status MakeIOError(Slice filename, const char* message, MethodID method) {
|
| +Status MakeIOError(Slice filename,
|
| + const std::string& message,
|
| + MethodID method) {
|
| char buf[512];
|
| - snprintf(buf,
|
| - sizeof(buf),
|
| - "%s (ChromeMethodOnly: %d::%s)",
|
| - message,
|
| - method,
|
| - MethodIDToString(method));
|
| + snprintf(buf, sizeof(buf), "%s (ChromeMethodOnly: %d::%s)", message.c_str(),
|
| + method, MethodIDToString(method));
|
| return Status::IOError(filename, buf);
|
| }
|
|
|
| @@ -474,15 +671,14 @@ Status ChromiumEnv::GetChildren(const std::string& dir_string,
|
| return MakeIOError(
|
| dir_string, "Could not open/read directory", kGetChildren, error);
|
| }
|
| +
|
| result->clear();
|
| - for (std::vector<base::FilePath>::iterator it = entries.begin();
|
| - it != entries.end();
|
| - ++it) {
|
| - result->push_back(FilePathToString(*it));
|
| - }
|
| + for (const auto& entry : entries)
|
| + result->push_back(FilePathToString(entry));
|
|
|
| if (make_backup_)
|
| RestoreIfNecessary(dir_string, result);
|
| +
|
| return Status::OK();
|
| }
|
|
|
| @@ -655,6 +851,85 @@ Status ChromiumEnv::GetTestDirectory(std::string* path) {
|
| return Status::OK();
|
| }
|
|
|
| +Status ChromiumEnv::NewLogger(const std::string& fname,
|
| + leveldb::Logger** result) {
|
| + base::FilePath path = CreateFilePath(fname);
|
| + scoped_ptr<base::File> f(new base::File(
|
| + path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
|
| + if (!f->IsValid()) {
|
| + *result = NULL;
|
| + RecordOSError(kNewLogger, f->error_details());
|
| + return MakeIOError(fname, "Unable to create log file", kNewLogger,
|
| + f->error_details());
|
| + } else {
|
| + *result = new leveldb::ChromiumLogger(f.release());
|
| + return Status::OK();
|
| + }
|
| +}
|
| +
|
| +Status ChromiumEnv::NewSequentialFile(const std::string& fname,
|
| + leveldb::SequentialFile** result) {
|
| + base::FilePath path = CreateFilePath(fname);
|
| + scoped_ptr<base::File> f(
|
| + new base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ));
|
| + if (!f->IsValid()) {
|
| + *result = NULL;
|
| + RecordOSError(kNewSequentialFile, f->error_details());
|
| + return MakeIOError(fname, "Unable to create sequential file",
|
| + kNewSequentialFile, f->error_details());
|
| + } else {
|
| + *result = new ChromiumSequentialFile(fname, f.release(), this);
|
| + return Status::OK();
|
| + }
|
| +}
|
| +
|
| +void ChromiumEnv::RecordOpenFilesLimit(const std::string& type) {
|
| +#if defined(OS_POSIX)
|
| + GetMaxFDHistogram(type)->Add(base::GetMaxFds());
|
| +#elif defined(OS_WIN)
|
| +// Windows is only limited by available memory
|
| +#else
|
| +#error "Need to determine limit to open files for this OS"
|
| +#endif
|
| +}
|
| +
|
| +Status ChromiumEnv::NewRandomAccessFile(const std::string& fname,
|
| + leveldb::RandomAccessFile** result) {
|
| + int flags = ::base::File::FLAG_READ | ::base::File::FLAG_OPEN;
|
| + ::base::File file(ChromiumEnv::CreateFilePath(fname), flags);
|
| + if (file.IsValid()) {
|
| + *result = new ChromiumRandomAccessFile(fname, file.Pass(), this);
|
| + RecordOpenFilesLimit("Success");
|
| + return Status::OK();
|
| + }
|
| + ::base::File::Error error_code = file.error_details();
|
| + if (error_code == ::base::File::FILE_ERROR_TOO_MANY_OPENED)
|
| + RecordOpenFilesLimit("TooManyOpened");
|
| + else
|
| + RecordOpenFilesLimit("OtherError");
|
| + *result = NULL;
|
| + RecordOSError(kNewRandomAccessFile, error_code);
|
| + return MakeIOError(fname, FileErrorString(error_code), kNewRandomAccessFile,
|
| + error_code);
|
| +}
|
| +
|
| +Status ChromiumEnv::NewWritableFile(const std::string& fname,
|
| + leveldb::WritableFile** result) {
|
| + *result = NULL;
|
| + base::FilePath path = CreateFilePath(fname);
|
| + scoped_ptr<base::File> f(new base::File(
|
| + path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
|
| + if (!f->IsValid()) {
|
| + RecordErrorAt(kNewWritableFile);
|
| + return MakeIOError(fname, "Unable to create writable file",
|
| + kNewWritableFile, f->error_details());
|
| + } else {
|
| + *result =
|
| + new ChromiumWritableFile(fname, f.release(), this, this, make_backup_);
|
| + return Status::OK();
|
| + }
|
| +}
|
| +
|
| uint64_t ChromiumEnv::NowMicros() {
|
| return ::base::TimeTicks::Now().ToInternalValue();
|
| }
|
| @@ -679,12 +954,6 @@ void ChromiumEnv::RecordOSError(MethodID method,
|
| GetOSErrorHistogram(method, -base::File::FILE_ERROR_MAX)->Add(-error);
|
| }
|
|
|
| -void ChromiumEnv::RecordOSError(MethodID method, int error) const {
|
| - DCHECK_GT(error, 0);
|
| - RecordErrorAt(method);
|
| - GetOSErrorHistogram(method, ERANGE + 1)->Add(error);
|
| -}
|
| -
|
| void ChromiumEnv::RecordBackupResult(bool result) const {
|
| std::string uma_name(name_);
|
| uma_name.append(".TableBackup");
|
| @@ -765,7 +1034,7 @@ class Thread : public ::base::PlatformThread::Delegate {
|
| DCHECK(success);
|
| }
|
| virtual ~Thread() {}
|
| - virtual void ThreadMain() {
|
| + void ThreadMain() override {
|
| (*function_)(arg_);
|
| delete this;
|
| }
|
|
|