Commit 25b44e5d authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

Use FilesystemProxy in LevelDB ChromiumEnv

This rewrites ChromiumEnv to use the storage::FilesystemProxy
API for all filesystem access. By default it will use unrestricted
instances with direct filesystem access, effectively equivalent to
the status quo. No interesting behavioral or performance changes
are expected here.

This will allow a follow-up CL to implement sandboxing support for
LevelDB by constructing a ChromiumEnv instance over a restricted
FilesystemProxy instance.

Bug: 1052045
Change-Id: Ic23726b3f5abd3f1a322b49827e80dbf424c3de7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2080673
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747584}
parent b0238be0
......@@ -127,6 +127,7 @@ component("leveldatabase") {
deps = [
"//base",
"//components/services/storage/public/cpp/filesystem",
"//third_party/crc32c",
"//third_party/re2",
"//third_party/snappy",
......@@ -162,6 +163,7 @@ static_library("leveldb_static") {
deps = [
"//base",
"//components/services/storage/public/cpp/filesystem",
"//third_party/crc32c",
"//third_party/re2",
"//third_party/snappy",
......
......@@ -7,4 +7,10 @@ include_rules = [
'+leveldb',
'+port',
'+util',
]
\ No newline at end of file
]
specific_include_rules = {
'env_chromium\.cc': [
'+components/services/storage/public/cpp/filesystem',
],
}
......@@ -8,21 +8,15 @@
#include <limits>
#include <utility>
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
#include <dirent.h>
#include <sys/types.h>
#endif
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/process/process_metrics.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
......@@ -36,6 +30,8 @@
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/services/storage/public/cpp/filesystem/file_error_or.h"
#include "components/services/storage/public/cpp/filesystem/filesystem_proxy.h"
#include "third_party/leveldatabase/chromium_logger.h"
#include "third_party/leveldatabase/leveldb_chrome.h"
#include "third_party/leveldatabase/leveldb_features.h"
......@@ -56,6 +52,9 @@ const base::Feature kLevelDBFileHandleEviction{
namespace leveldb_env {
namespace {
template <typename ValueType>
using FileErrorOr = storage::FileErrorOr<ValueType>;
// After this limit we don't bother doing file eviction for leveldb for speed,
// memory usage, and simplicity.
const constexpr size_t kFileLimitToDisableEviction = 10'000;
......@@ -69,65 +68,6 @@ static const FilePath::CharType kLevelDBTestDirectoryPrefix[] =
// able to recover data.
static const char kDatabaseNameSuffixForRebuildDB[] = "__tmp_for_rebuild";
// 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 FilePath& dir_param,
std::vector<FilePath>* result) {
TRACE_EVENT0("leveldb", "ChromiumEnv::GetDirectoryEntries");
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
result->clear();
#if defined(OS_WIN)
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 {
FilePath filepath(find_data.cFileName);
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 = dir_param.AsUTF8Unsafe();
DIR* dir = opendir(dir_string.c_str());
int saved_errno;
if (!dir) {
saved_errno = errno;
VLOG(1) << "Error " << saved_errno << " opening directory \"" << dir_string
<< '"';
return base::File::OSErrorToFileError(saved_errno);
}
struct dirent* dent;
while ((errno = 0, dent = readdir(dir)) != nullptr) {
if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
continue;
result->push_back(FilePath::FromUTF8Unsafe(dent->d_name));
}
saved_errno = errno;
closedir(dir);
if (saved_errno != 0) {
VLOG(1) << "Error " << saved_errno << " listing entries in \"" << dir_string
<< '"';
return base::File::OSErrorToFileError(saved_errno);
}
return base::File::FILE_OK;
#endif
}
// To avoid a dependency on storage_histograms.h and the storageLib,
// we re-implement the BytesCountHistogram functions here.
void RecordStorageBytesWritten(const char* label, int amount) {
......@@ -142,14 +82,14 @@ void RecordStorageBytesRead(const char* label, int amount) {
class ChromiumFileLock : public FileLock {
public:
ChromiumFileLock(base::File file, const std::string& name)
: file_(std::move(file)), name_(name) {}
base::File file_;
std::string name_;
private:
DISALLOW_COPY_AND_ASSIGN(ChromiumFileLock);
ChromiumFileLock(std::unique_ptr<storage::FilesystemProxy::FileLock> lock,
const std::string& name)
: lock(std::move(lock)), name(name) {}
ChromiumFileLock(const ChromiumFileLock&) = delete;
ChromiumFileLock& operator=(const ChromiumFileLock&) = delete;
const std::unique_ptr<storage::FilesystemProxy::FileLock> lock;
const std::string name;
};
class Retrier {
......@@ -279,9 +219,11 @@ class ChromiumEvictableRandomAccessFile : public leveldb::RandomAccessFile {
public:
ChromiumEvictableRandomAccessFile(base::FilePath file_path,
base::File file,
storage::FilesystemProxy* filesystem,
leveldb::Cache* file_cache,
const UMALogger* uma_logger)
: filepath_(std::move(file_path)),
filesystem_(filesystem),
uma_logger_(uma_logger),
file_cache_(file_cache),
cache_key_data_(this),
......@@ -309,12 +251,13 @@ class ChromiumEvictableRandomAccessFile : public leveldb::RandomAccessFile {
leveldb::Cache::Handle* handle = file_cache_->Lookup(cache_key_);
if (!handle) {
int flags = base::File::FLAG_READ | base::File::FLAG_OPEN;
auto new_file = std::make_unique<base::File>(filepath_, flags);
if (!new_file->IsValid()) {
FileErrorOr<base::File> result = filesystem_->OpenFile(filepath_, flags);
if (result.is_error()) {
return MakeIOError(filepath_.AsUTF8Unsafe(), "Could not perform read",
kRandomAccessFileRead);
}
handle = file_cache_->Insert(cache_key_, new_file.release(),
handle = file_cache_->Insert(cache_key_,
new base::File(std::move(result.value())),
sizeof(base::File), &RemoveFile);
}
base::File* file = static_cast<base::File*>(file_cache_->Value(handle));
......@@ -326,6 +269,7 @@ class ChromiumEvictableRandomAccessFile : public leveldb::RandomAccessFile {
private:
const base::FilePath filepath_;
storage::FilesystemProxy* const filesystem_;
const UMALogger* const uma_logger_;
mutable leveldb::Cache* file_cache_;
const ChromiumEvictableRandomAccessFile* cache_key_data_;
......@@ -367,8 +311,9 @@ class ChromiumWritableFile : public leveldb::WritableFile {
public:
ChromiumWritableFile(const std::string& fname,
base::File f,
storage::FilesystemProxy* filesystem,
const UMALogger* uma_logger);
virtual ~ChromiumWritableFile() {}
~ChromiumWritableFile() override = default;
leveldb::Status Append(const leveldb::Slice& data) override;
leveldb::Status Close() override;
leveldb::Status Flush() override;
......@@ -380,6 +325,9 @@ class ChromiumWritableFile : public leveldb::WritableFile {
std::string filename_;
base::File file_;
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
storage::FilesystemProxy* const filesystem_;
#endif
const UMALogger* uma_logger_;
Type file_type_;
std::string parent_dir_;
......@@ -389,9 +337,13 @@ class ChromiumWritableFile : public leveldb::WritableFile {
ChromiumWritableFile::ChromiumWritableFile(const std::string& fname,
base::File f,
storage::FilesystemProxy* filesystem,
const UMALogger* uma_logger)
: filename_(fname),
file_(std::move(f)),
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
filesystem_(filesystem),
#endif
uma_logger_(uma_logger),
file_type_(kOther) {
DCHECK(uma_logger);
......@@ -407,13 +359,14 @@ Status ChromiumWritableFile::SyncParent() {
TRACE_EVENT0("leveldb", "SyncParent");
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
FilePath path = FilePath::FromUTF8Unsafe(parent_dir_);
base::File f(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!f.IsValid()) {
uma_logger_->RecordOSError(kSyncParent, f.error_details());
FileErrorOr<base::File> result = filesystem_->OpenFile(
path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (result.is_error()) {
uma_logger_->RecordOSError(kSyncParent, result.error());
return MakeIOError(parent_dir_, "Unable to open directory", kSyncParent,
f.error_details());
result.error());
}
if (!f.Flush()) {
if (!result->Flush()) {
base::File::Error error = base::File::GetLastFileError();
uma_logger_->RecordOSError(kSyncParent, error);
return MakeIOError(parent_dir_, base::File::ErrorToString(error),
......@@ -477,8 +430,6 @@ Status ChromiumWritableFile::Sync() {
return Status::OK();
}
base::LazyInstance<ChromiumEnv>::Leaky default_env = LAZY_INSTANCE_INITIALIZER;
// Return the maximum number of read-only files to keep open.
size_t GetLevelDBFileLimit(size_t max_file_descriptors) {
// Allow use of 20% of available file descriptors for read-only files.
......@@ -546,7 +497,7 @@ void RecordCacheUsageInTracing(ProcessMemoryDump* pmd,
CreateDumpMalloced(pmd, name, cache_ptr->TotalCharge());
}
} // unnamed namespace
} // namespace
Options::Options() {
// Note: Ensure that these default values correspond to those in
......@@ -793,11 +744,23 @@ size_t WriteBufferSize(int64_t disk_size) {
ChromiumEnv::ChromiumEnv() : ChromiumEnv("LevelDBEnv") {}
ChromiumEnv::ChromiumEnv(std::unique_ptr<storage::FilesystemProxy> filesystem)
: ChromiumEnv("LevelDBEnv", std::move(filesystem)) {}
ChromiumEnv::ChromiumEnv(const std::string& name)
: ChromiumEnv(name,
std::make_unique<storage::FilesystemProxy>(
storage::FilesystemProxy::UNRESTRICTED,
base::FilePath())) {}
ChromiumEnv::ChromiumEnv(const std::string& name,
std::unique_ptr<storage::FilesystemProxy> filesystem)
: kMaxRetryTimeMillis(1000),
filesystem_(std::move(filesystem)),
name_(name),
bgsignal_(&mu_),
started_bgthread_(false) {
DCHECK(filesystem_);
size_t max_open_files = base::GetMaxFds();
if (base::FeatureList::IsEnabled(kLevelDBFileHandleEviction) &&
max_open_files < kFileLimitToDisableEviction) {
......@@ -814,7 +777,7 @@ ChromiumEnv::~ChromiumEnv() {
}
bool ChromiumEnv::FileExists(const std::string& fname) {
return base::PathExists(FilePath::FromUTF8Unsafe(fname));
return filesystem_->PathExists(FilePath::FromUTF8Unsafe(fname));
}
const char* ChromiumEnv::FileErrorString(base::File::Error error) {
......@@ -868,11 +831,15 @@ void ChromiumEnv::RemoveBackupFiles(const FilePath& dir) {
"LevelDBEnv.DeleteTableBackupFile",
base::Histogram::kUmaTargetedHistogramFlag);
base::FileEnumerator dir_reader(dir, false, base::FileEnumerator::FILES,
FILE_PATH_LITERAL("*.bak"));
for (base::FilePath fname = dir_reader.Next(); !fname.empty();
fname = dir_reader.Next()) {
histogram->AddBoolean(base::DeleteFile(fname, false));
FileErrorOr<std::vector<base::FilePath>> result =
filesystem_->GetDirectoryEntries(
dir, storage::FilesystemProxy::DirectoryEntryType::kFilesOnly);
if (result.is_error())
return;
for (const auto& path : result.value()) {
if (path.Extension() == FILE_PATH_LITERAL(".bak"))
histogram->AddBoolean(filesystem_->RemoveFile(path));
}
}
......@@ -887,16 +854,18 @@ Status ChromiumEnv::GetChildren(const std::string& dir,
FilePath dir_path = FilePath::FromUTF8Unsafe(dir);
RemoveBackupFiles(dir_path);
std::vector<FilePath> entries;
base::File::Error error = GetDirectoryEntries(dir_path, &entries);
if (error != base::File::FILE_OK) {
RecordOSError(kGetChildren, error);
FileErrorOr<std::vector<FilePath>> entries_result =
filesystem_->GetDirectoryEntries(
dir_path,
storage::FilesystemProxy::DirectoryEntryType::kFilesAndDirectories);
if (entries_result.is_error()) {
RecordOSError(kGetChildren, entries_result.error());
return MakeIOError(dir, "Could not open/read directory", kGetChildren,
error);
entries_result.error());
}
result->clear();
for (const auto& entry : entries)
for (const auto& entry : entries_result.value())
result->push_back(entry.BaseName().AsUTF8Unsafe());
return Status::OK();
......@@ -905,8 +874,7 @@ Status ChromiumEnv::GetChildren(const std::string& dir,
Status ChromiumEnv::RemoveFile(const std::string& fname) {
Status result;
FilePath fname_filepath = FilePath::FromUTF8Unsafe(fname);
// TODO(jorlow): Should we assert this is a file?
if (!base::DeleteFile(fname_filepath, false)) {
if (!filesystem_->RemoveFile(fname_filepath)) {
result = MakeIOError(fname, "Could not delete file.", kRemoveFile);
RecordErrorAt(kRemoveFile);
}
......@@ -918,8 +886,8 @@ Status ChromiumEnv::CreateDir(const std::string& name) {
base::File::Error error = base::File::FILE_OK;
Retrier retrier(kCreateDir, this);
do {
if (base::CreateDirectoryAndGetError(FilePath::FromUTF8Unsafe(name),
&error))
error = filesystem_->CreateDirectory(base::FilePath::FromUTF8Unsafe(name));
if (error == base::File::FILE_OK)
return result;
} while (retrier.ShouldKeepTrying(error));
result = MakeIOError(name, "Could not create directory.", kCreateDir, error);
......@@ -929,8 +897,7 @@ Status ChromiumEnv::CreateDir(const std::string& name) {
Status ChromiumEnv::RemoveDir(const std::string& name) {
Status result;
// TODO(jorlow): Should we assert this is a directory?
if (!base::DeleteFile(FilePath::FromUTF8Unsafe(name), false)) {
if (!filesystem_->RemoveDirectory(FilePath::FromUTF8Unsafe(name))) {
result = MakeIOError(name, "Could not delete directory.", kRemoveDir);
RecordErrorAt(kRemoveDir);
}
......@@ -939,13 +906,14 @@ Status ChromiumEnv::RemoveDir(const std::string& name) {
Status ChromiumEnv::GetFileSize(const std::string& fname, uint64_t* size) {
Status s;
int64_t signed_size;
if (!base::GetFileSize(FilePath::FromUTF8Unsafe(fname), &signed_size)) {
base::Optional<base::File::Info> info =
filesystem_->GetFileInfo(base::FilePath::FromUTF8Unsafe(fname));
if (!info) {
*size = 0;
s = MakeIOError(fname, "Could not determine file size.", kGetFileSize);
RecordErrorAt(kGetFileSize);
} else {
*size = static_cast<uint64_t>(signed_size);
*size = static_cast<uint64_t>(info->size);
}
return s;
}
......@@ -953,14 +921,15 @@ Status ChromiumEnv::GetFileSize(const std::string& fname, uint64_t* size) {
Status ChromiumEnv::RenameFile(const std::string& src, const std::string& dst) {
Status result;
FilePath src_file_path = FilePath::FromUTF8Unsafe(src);
if (!base::PathExists(src_file_path))
if (!filesystem_->PathExists(src_file_path))
return result;
FilePath destination = FilePath::FromUTF8Unsafe(dst);
Retrier retrier(kRenameFile, this);
base::File::Error error = base::File::FILE_OK;
do {
if (base::ReplaceFile(src_file_path, destination, &error))
error = filesystem_->RenameFile(src_file_path, destination);
if (error == base::File::FILE_OK)
return result;
} while (retrier.ShouldKeepTrying(error));
......@@ -975,49 +944,22 @@ Status ChromiumEnv::RenameFile(const std::string& src, const std::string& dst) {
}
Status ChromiumEnv::LockFile(const std::string& fname, FileLock** lock) {
*lock = NULL;
*lock = nullptr;
Status result;
int flags = base::File::FLAG_OPEN_ALWAYS |
base::File::FLAG_READ |
base::File::FLAG_WRITE;
base::File::Error error_code;
base::File file;
const base::FilePath path = base::FilePath::FromUTF8Unsafe(fname);
Retrier retrier(kLockFile, this);
FileErrorOr<std::unique_ptr<storage::FilesystemProxy::FileLock>> lock_result;
do {
file.Initialize(FilePath::FromUTF8Unsafe(fname), flags);
if (!file.IsValid())
error_code = file.error_details();
} while (!file.IsValid() && retrier.ShouldKeepTrying(error_code));
if (!file.IsValid()) {
result =
MakeIOError(fname, FileErrorString(error_code), kLockFile, error_code);
RecordOSError(kLockFile, error_code);
return result;
}
if (!locks_.Insert(fname)) {
result = MakeIOError(fname, "Lock file already locked.", kLockFile);
return result;
}
#if !defined(OS_FUCHSIA)
Retrier lock_retrier(kLockFile, this);
do {
error_code = file.Lock();
} while (error_code != base::File::FILE_OK &&
retrier.ShouldKeepTrying(error_code));
if (error_code != base::File::FILE_OK) {
locks_.Remove(fname);
result = MakeIOError(fname, FileErrorString(error_code), kLockFile,
error_code);
RecordOSError(kLockFile, error_code);
return result;
lock_result = filesystem_->LockFile(path);
} while (lock_result.is_error() &&
retrier.ShouldKeepTrying(lock_result.error()));
if (lock_result.is_error()) {
RecordOSError(kLockFile, lock_result.error());
return MakeIOError(fname, FileErrorString(lock_result.error()), kLockFile,
lock_result.error());
}
#endif // !defined(OS_FUCHSIA)
*lock = new ChromiumFileLock(std::move(file), fname);
*lock = new ChromiumFileLock(std::move(lock_result.value()), fname);
return result;
}
......@@ -1026,17 +968,12 @@ Status ChromiumEnv::UnlockFile(FileLock* lock) {
reinterpret_cast<ChromiumFileLock*>(lock));
Status result = Status::OK();
#if !defined(OS_FUCHSIA)
base::File::Error error_code = my_lock->file_.Unlock();
base::File::Error error_code = my_lock->lock->Release();
if (error_code != base::File::FILE_OK) {
result =
MakeIOError(my_lock->name_, "Could not unlock lock file.", kUnlockFile);
MakeIOError(my_lock->name, "Could not unlock lock file.", kUnlockFile);
RecordOSError(kUnlockFile, error_code);
}
#endif // !defined(OS_FUCHSIA)
bool removed = locks_.Remove(my_lock->name_);
DCHECK(removed);
return result;
}
......@@ -1059,14 +996,15 @@ Status ChromiumEnv::GetTestDirectory(std::string* path) {
Status ChromiumEnv::NewLogger(const std::string& fname,
leveldb::Logger** result) {
FilePath path = FilePath::FromUTF8Unsafe(fname);
base::File f(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!f.IsValid()) {
*result = NULL;
RecordOSError(kNewLogger, f.error_details());
FileErrorOr<base::File> open_result = filesystem_->OpenFile(
path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (open_result.is_error()) {
*result = nullptr;
RecordOSError(kNewLogger, open_result.error());
return MakeIOError(fname, "Unable to create log file", kNewLogger,
f.error_details());
open_result.error());
} else {
*result = new leveldb::ChromiumLogger(std::move(f));
*result = new leveldb::ChromiumLogger(std::move(open_result.value()));
return Status::OK();
}
}
......@@ -1074,66 +1012,72 @@ Status ChromiumEnv::NewLogger(const std::string& fname,
Status ChromiumEnv::NewSequentialFile(const std::string& fname,
leveldb::SequentialFile** result) {
FilePath path = FilePath::FromUTF8Unsafe(fname);
base::File f(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!f.IsValid()) {
*result = NULL;
RecordOSError(kNewSequentialFile, f.error_details());
FileErrorOr<base::File> open_result = filesystem_->OpenFile(
path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (open_result.is_error()) {
*result = nullptr;
RecordOSError(kNewSequentialFile, open_result.error());
return MakeIOError(fname, "Unable to create sequential file",
kNewSequentialFile, f.error_details());
kNewSequentialFile, open_result.error());
} else {
*result = new ChromiumSequentialFile(fname, std::move(f), this);
*result =
new ChromiumSequentialFile(fname, std::move(open_result.value()), this);
return Status::OK();
}
}
Status ChromiumEnv::NewRandomAccessFile(const std::string& fname,
leveldb::RandomAccessFile** result) {
int flags = base::File::FLAG_READ | base::File::FLAG_OPEN;
base::FilePath file_path = FilePath::FromUTF8Unsafe(fname);
base::File file(file_path, flags);
if (file.IsValid()) {
FileErrorOr<base::File> open_result = filesystem_->OpenFile(
file_path, base::File::FLAG_READ | base::File::FLAG_OPEN);
if (!open_result.is_error()) {
base::File file = std::move(open_result.value());
if (file_cache_) {
*result = new ChromiumEvictableRandomAccessFile(
std::move(file_path), std::move(file), file_cache_.get(), this);
std::move(file_path), std::move(file), filesystem_.get(),
file_cache_.get(), this);
} else {
*result = new ChromiumRandomAccessFile(std::move(file_path),
std::move(file), this);
}
return Status::OK();
}
base::File::Error error_code = file.error_details();
*result = NULL;
RecordOSError(kNewRandomAccessFile, error_code);
return MakeIOError(fname, FileErrorString(error_code), kNewRandomAccessFile,
error_code);
*result = nullptr;
RecordOSError(kNewRandomAccessFile, open_result.error());
return MakeIOError(fname, FileErrorString(open_result.error()),
kNewRandomAccessFile, open_result.error());
}
Status ChromiumEnv::NewWritableFile(const std::string& fname,
leveldb::WritableFile** result) {
*result = NULL;
FilePath path = FilePath::FromUTF8Unsafe(fname);
base::File f(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!f.IsValid()) {
FileErrorOr<base::File> open_result = filesystem_->OpenFile(
path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (open_result.is_error()) {
*result = nullptr;
RecordErrorAt(kNewWritableFile);
return MakeIOError(fname, "Unable to create writable file",
kNewWritableFile, f.error_details());
} else {
*result = new ChromiumWritableFile(fname, std::move(f), this);
return Status::OK();
kNewWritableFile, open_result.error());
}
*result = new ChromiumWritableFile(fname, std::move(open_result.value()),
filesystem_.get(), this);
return Status::OK();
}
Status ChromiumEnv::NewAppendableFile(const std::string& fname,
leveldb::WritableFile** result) {
*result = NULL;
FilePath path = FilePath::FromUTF8Unsafe(fname);
base::File f(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
if (!f.IsValid()) {
FileErrorOr<base::File> open_result = filesystem_->OpenFile(
path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
if (open_result.is_error()) {
*result = nullptr;
RecordErrorAt(kNewAppendableFile);
return MakeIOError(fname, "Unable to create appendable file",
kNewAppendableFile, f.error_details());
kNewAppendableFile, open_result.error());
}
*result = new ChromiumWritableFile(fname, std::move(f), this);
*result = new ChromiumWritableFile(fname, std::move(open_result.value()),
filesystem_.get(), this);
return Status::OK();
}
......@@ -1724,7 +1668,8 @@ leveldb::Slice MakeSlice(base::span<const uint8_t> s) {
namespace leveldb {
Env* Env::Default() {
return leveldb_env::default_env.Pointer();
static base::NoDestructor<leveldb_env::ChromiumEnv> default_env;
return default_env.get();
}
} // namespace leveldb
......@@ -35,6 +35,10 @@ class ProcessMemoryDump;
} // namespace trace_event
} // namespace base
namespace storage {
class FilesystemProxy;
}
namespace leveldb_env {
// These entries map to values in tools/metrics/histograms/histograms.xml. New
......@@ -157,11 +161,16 @@ class LEVELDB_EXPORT ChromiumEnv : public leveldb::Env,
public UMALogger,
public RetrierProvider {
public:
using ScheduleFunc = void(void*);
// Constructs a ChromiumEnv instance with an unrestricted FilesystemProxy
// instance that performs direct filesystem access.
ChromiumEnv();
typedef void(ScheduleFunc)(void*);
// Constructs a ChromiumEnv instance with a custom FilesystemProxy instance.
explicit ChromiumEnv(std::unique_ptr<storage::FilesystemProxy> filesystem);
virtual ~ChromiumEnv();
~ChromiumEnv() override;
bool FileExists(const std::string& fname) override;
leveldb::Status GetChildren(const std::string& dir,
......@@ -195,8 +204,14 @@ class LEVELDB_EXPORT ChromiumEnv : public leveldb::Env,
void SetReadOnlyFileLimitForTesting(int max_open_files);
protected:
// Constructs a ChromiumEnv instance with a local unrestricted FilesystemProxy
// instance that performs direct filesystem access.
explicit ChromiumEnv(const std::string& name);
// Constructs a ChromiumEnv instance with a custom FilesystemProxy instance.
ChromiumEnv(const std::string& name,
std::unique_ptr<storage::FilesystemProxy> filesystem);
static const char* FileErrorString(base::File::Error error);
private:
......@@ -207,23 +222,6 @@ class LEVELDB_EXPORT ChromiumEnv : public leveldb::Env,
base::HistogramBase* GetOSErrorHistogram(MethodID method, int limit) const;
void RemoveBackupFiles(const base::FilePath& dir);
// 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_;
};
const int kMaxRetryTimeMillis;
// BGThread() is the body of the background thread
void BGThread();
......@@ -239,6 +237,8 @@ class LEVELDB_EXPORT ChromiumEnv : public leveldb::Env,
base::HistogramBase* GetRecoveredFromErrorHistogram(
MethodID method) const override;
const std::unique_ptr<storage::FilesystemProxy> filesystem_;
base::FilePath test_directory_;
std::string name_;
......@@ -255,7 +255,6 @@ class LEVELDB_EXPORT ChromiumEnv : public leveldb::Env,
};
using BGQueue = base::circular_deque<BGItem>;
BGQueue queue_;
LockTable locks_;
std::unique_ptr<leveldb::Cache> file_cache_;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment