diff options
Diffstat (limited to 'chromium/components/services')
43 files changed, 637 insertions, 3516 deletions
diff --git a/chromium/components/services/app_service/public/cpp/BUILD.gn b/chromium/components/services/app_service/public/cpp/BUILD.gn index 502f85ca84b..1e6408f3617 100644 --- a/chromium/components/services/app_service/public/cpp/BUILD.gn +++ b/chromium/components/services/app_service/public/cpp/BUILD.gn @@ -8,3 +8,14 @@ source_set("app_file_handling") { "file_handler_info.h", ] } + +source_set("intent_util") { + sources = [ + "intent_util.cc", + "intent_util.h", + ] + + deps = [ + "//base", + ] +} diff --git a/chromium/components/services/app_service/public/cpp/intent_util.cc b/chromium/components/services/app_service/public/cpp/intent_util.cc new file mode 100644 index 00000000000..fe37332d916 --- /dev/null +++ b/chromium/components/services/app_service/public/cpp/intent_util.cc @@ -0,0 +1,95 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/services/app_service/public/cpp/intent_util.h" + +#include "base/compiler_specific.h" + +namespace apps_util { + +// TODO(crbug.com/853604): For glob match, it is currently only for Android +// intent filters, so we will use the ARC intent filter implementation that is +// transcribed from Android codebase, to prevent divergence from Android code. +bool MatchGlob(const std::string& value, const std::string& pattern) { +#define GET_CHAR(s, i) ((UNLIKELY(i >= s.length())) ? '\0' : s[i]) + + const size_t NP = pattern.length(); + const size_t NS = value.length(); + if (NP == 0) { + return NS == 0; + } + size_t ip = 0, is = 0; + char nextChar = GET_CHAR(pattern, 0); + while (ip < NP && is < NS) { + char c = nextChar; + ++ip; + nextChar = GET_CHAR(pattern, ip); + const bool escaped = (c == '\\'); + if (escaped) { + c = nextChar; + ++ip; + nextChar = GET_CHAR(pattern, ip); + } + if (nextChar == '*') { + if (!escaped && c == '.') { + if (ip >= (NP - 1)) { + // At the end with a pattern match + return true; + } + ++ip; + nextChar = GET_CHAR(pattern, ip); + // Consume everything until the next char in the pattern is found. + if (nextChar == '\\') { + ++ip; + nextChar = GET_CHAR(pattern, ip); + } + do { + if (GET_CHAR(value, is) == nextChar) { + break; + } + ++is; + } while (is < NS); + if (is == NS) { + // Next char in the pattern didn't exist in the match. + return false; + } + ++ip; + nextChar = GET_CHAR(pattern, ip); + ++is; + } else { + // Consume only characters matching the one before '*'. + do { + if (GET_CHAR(value, is) != c) { + break; + } + ++is; + } while (is < NS); + ++ip; + nextChar = GET_CHAR(pattern, ip); + } + } else { + if (c != '.' && GET_CHAR(value, is) != c) + return false; + ++is; + } + } + + if (ip >= NP && is >= NS) { + // Reached the end of both strings + return true; + } + + // One last check: we may have finished the match string, but still have a + // '.*' at the end of the pattern, which is still a match. + if (ip == NP - 2 && GET_CHAR(pattern, ip) == '.' && + GET_CHAR(pattern, ip + 1) == '*') { + return true; + } + + return false; + +#undef GET_CHAR +} + +} // namespace apps_util diff --git a/chromium/components/services/app_service/public/cpp/intent_util.h b/chromium/components/services/app_service/public/cpp/intent_util.h new file mode 100644 index 00000000000..acd63593307 --- /dev/null +++ b/chromium/components/services/app_service/public/cpp/intent_util.h @@ -0,0 +1,31 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_ +#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_ + +// Utility functions for App Service intent handling. +// This function is needed for both components/arc and +// chrome/services/app_service at the moment. We are planning to remove the need +// for this in the components/arc directory and this function can be combined +// with other intent utility functions for the App service. + +#include <string> + +namespace apps_util { + +// Return true if |value| matches |pattern| with simple glob syntax. +// In this syntax, you can use the '*' character to match against zero or +// more occurrences of the character immediately before. If the character +// before it is '.' it will match any character. The character '\' can be +// used as an escape. This essentially provides only the '*' wildcard part +// of a normal regexp. +// This function is transcribed from android's PatternMatcher#matchPattern. +// See +// https://android.googlesource.com/platform/frameworks/base.git/+/e93165456c3c28278f275566bd90bfbcf1a0e5f7/core/java/android/os/PatternMatcher.java#186 +bool MatchGlob(const std::string& value, const std::string& pattern); + +} // namespace apps_util + +#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
\ No newline at end of file diff --git a/chromium/components/services/app_service/public/mojom/types.mojom b/chromium/components/services/app_service/public/mojom/types.mojom index 5e4aaa69a4a..21eca6c2044 100644 --- a/chromium/components/services/app_service/public/mojom/types.mojom +++ b/chromium/components/services/app_service/public/mojom/types.mojom @@ -34,6 +34,7 @@ enum AppLaunchSource { kSourceInstalledNotification = 20, kSourceContextMenu = 21, kSourceArc = 22, + kSourceIntentUrl = 23, // App launch triggered by a URL. }; // Don't remove items or change the order of this enum. It's used in diff --git a/chromium/components/services/font/font_service_app.cc b/chromium/components/services/font/font_service_app.cc index 16c1958793e..210c2b8b387 100644 --- a/chromium/components/services/font/font_service_app.cc +++ b/chromium/components/services/font/font_service_app.cc @@ -10,10 +10,12 @@ #include "base/command_line.h" #include "base/files/file.h" #include "base/files/file_path.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "components/services/font/fontconfig_matching.h" #include "mojo/public/cpp/system/platform_handle.h" #include "ppapi/buildflags/buildflags.h" +#include "skia/ext/skia_utils_base.h" #include "ui/gfx/font_fallback_linux.h" #include "ui/gfx/font_render_params.h" @@ -115,7 +117,8 @@ void FontServiceApp::MatchFamilyName(const std::string& family_name, // Stash away the returned path, so we can give it an ID (index) // which will later be given to us in a request to open the file. - int index = FindOrAddPath(result_identity.fString); + base::FilePath path(result_identity.fString.c_str()); + size_t index = FindOrAddPath(path); mojom::FontIdentityPtr identity(mojom::FontIdentity::New()); identity->id = static_cast<uint32_t>(index); @@ -137,9 +140,8 @@ void FontServiceApp::OpenStream(uint32_t id_number, DCHECK_LT(id_number, static_cast<uint32_t>(paths_.size())); base::File file; - if (id_number < static_cast<uint32_t>(paths_.size())) { - file = GetFileForPath(base::FilePath(paths_[id_number].c_str())); - } + if (id_number < static_cast<uint32_t>(paths_.size())) + file = GetFileForPath(paths_[id_number]); std::move(callback).Run(std::move(file)); } @@ -151,7 +153,7 @@ void FontServiceApp::FallbackFontForCharacter( TRACE_EVENT0("fonts", "FontServiceApp::FallbackFontForCharacter"); auto fallback_font = gfx::GetFallbackFontForChar(character, locale); - int index = FindOrAddPath(SkString(fallback_font.filename.data())); + size_t index = FindOrAddPath(base::FilePath(fallback_font.filename)); mojom::FontIdentityPtr identity(mojom::FontIdentity::New()); identity->id = static_cast<uint32_t>(index); @@ -206,8 +208,7 @@ void FontServiceApp::MatchFontByPostscriptNameOrFullFontName( base::Optional<FontConfigLocalMatching::FontConfigMatchResult> match_result = FontConfigLocalMatching::FindFontByPostscriptNameOrFullFontName(family); if (match_result) { - uint32_t fontconfig_interface_id = - FindOrAddPath(SkString(match_result->file_path.value().c_str())); + uint32_t fontconfig_interface_id = FindOrAddPath(match_result->file_path); mojom::FontIdentityPtr font_identity = mojom::FontIdentityPtr(mojom::FontIdentity::New( fontconfig_interface_id, match_result->ttc_index, @@ -240,11 +241,11 @@ void FontServiceApp::MatchFontWithFallback( #endif } -int FontServiceApp::FindOrAddPath(const SkString& path) { +size_t FontServiceApp::FindOrAddPath(const base::FilePath& path) { TRACE_EVENT1("fonts", "FontServiceApp::FindOrAddPath", "path", - TRACE_STR_COPY(path.c_str())); - int count = paths_.size(); - for (int i = 0; i < count; ++i) { + path.AsUTF8Unsafe()); + size_t count = paths_.size(); + for (size_t i = 0; i < count; ++i) { if (path == paths_[i]) return i; } diff --git a/chromium/components/services/font/font_service_app.h b/chromium/components/services/font/font_service_app.h index eb920d55798..e46d79f5c6f 100644 --- a/chromium/components/services/font/font_service_app.h +++ b/chromium/components/services/font/font_service_app.h @@ -8,10 +8,10 @@ #include <stdint.h> #include <vector> +#include "base/files/file_path.h" #include "base/macros.h" #include "components/services/font/public/mojom/font_service.mojom.h" #include "mojo/public/cpp/bindings/receiver_set.h" -#include "skia/ext/skia_utils_base.h" namespace font_service { @@ -48,13 +48,13 @@ class FontServiceApp : public mojom::FontService { uint32_t charset, uint32_t fallbackFamilyType, MatchFontWithFallbackCallback callback) override; - int FindOrAddPath(const SkString& path); + size_t FindOrAddPath(const base::FilePath& path); mojo::ReceiverSet<mojom::FontService> receivers_; // We don't want to leak paths to our callers; we thus enumerate the paths of // fonts. - std::vector<SkString> paths_; + std::vector<base::FilePath> paths_; DISALLOW_COPY_AND_ASSIGN(FontServiceApp); }; diff --git a/chromium/components/services/heap_profiling/heap_profiling_service.cc b/chromium/components/services/heap_profiling/heap_profiling_service.cc index 5900052850d..1b66c1bfefe 100644 --- a/chromium/components/services/heap_profiling/heap_profiling_service.cc +++ b/chromium/components/services/heap_profiling/heap_profiling_service.cc @@ -20,7 +20,6 @@ #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/system/platform_handle.h" #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h" -#include "services/resource_coordinator/public/mojom/service_constants.mojom.h" namespace heap_profiling { diff --git a/chromium/components/services/heap_profiling/json_exporter.cc b/chromium/components/services/heap_profiling/json_exporter.cc index e2ec70c5b42..ea9f2be67b7 100644 --- a/chromium/components/services/heap_profiling/json_exporter.cc +++ b/chromium/components/services/heap_profiling/json_exporter.cc @@ -234,10 +234,12 @@ base::Value BuildAllocations(const AllocationMap& allocations, for (const auto& alloc : allocations) { int allocator = static_cast<int>(alloc.first.allocator); + // We use double to store size and count, as it can precisely represent + // values up to 2^52 ~ 4.5 petabytes. counts[allocator].push_back( - base::Value(static_cast<int>(alloc.second.count))); + base::Value(static_cast<double>(alloc.second.count))); sizes[allocator].push_back( - base::Value(static_cast<int>(alloc.second.size))); + base::Value(static_cast<double>(alloc.second.size))); types[allocator].push_back(base::Value(alloc.first.context_id)); nodes[allocator].push_back(base::Value(alloc_to_node_id.at(&alloc.first))); } @@ -300,7 +302,9 @@ std::string ExportMemoryMapsAndV2StackTraceToJSON(ExportParams* params) { result.SetKey("heaps_v2", std::move(heaps_v2)); std::string result_json; - bool ok = base::JSONWriter::Write(result, &result_json); + bool ok = base::JSONWriter::WriteWithOptions( + result, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, + &result_json); DCHECK(ok); return result_json; } diff --git a/chromium/components/services/heap_profiling/json_exporter_unittest.cc b/chromium/components/services/heap_profiling/json_exporter_unittest.cc index e9974d9af95..f9bf760435b 100644 --- a/chromium/components/services/heap_profiling/json_exporter_unittest.cc +++ b/chromium/components/services/heap_profiling/json_exporter_unittest.cc @@ -421,4 +421,43 @@ TEST(ProfilingJsonExporterTest, Context) { ASSERT_TRUE(found_no_context); } +#if defined(ARCH_CPU_64_BITS) +TEST(ProfilingJsonExporterTest, LargeAllocation) { + std::vector<Address> stack1{Address(0x5678), Address(0x1234)}; + AllocationMap allocs; + InsertAllocation(&allocs, AllocatorType::kMalloc, + static_cast<size_t>(0x9876543210ul), stack1, 0); + + ExportParams params; + params.allocs = std::move(allocs); + std::string json = ExportMemoryMapsAndV2StackTraceToJSON(¶ms); + + // JSON should parse. + base::JSONReader json_reader(base::JSON_PARSE_RFC); + base::Optional<base::Value> result = json_reader.ReadToValue(json); + ASSERT_TRUE(result.has_value()) << json_reader.GetErrorMessage(); + + // Validate the allocators summary. + const base::Value* malloc_summary = + result.value().FindPath({"allocators", "malloc"}); + ASSERT_TRUE(malloc_summary); + const base::Value* malloc_size = + malloc_summary->FindPath({"attrs", "size", "value"}); + ASSERT_TRUE(malloc_size); + EXPECT_EQ("9876543210", malloc_size->GetString()); + const base::Value* malloc_virtual_size = + malloc_summary->FindPath({"attrs", "virtual_size", "value"}); + ASSERT_TRUE(malloc_virtual_size); + EXPECT_EQ("9876543210", malloc_virtual_size->GetString()); + + // Validate allocators details. + // heaps_v2.allocators.malloc.sizes.reduce((a,s)=>a+s,0). + const base::Value* malloc = + result.value().FindPath({"heaps_v2", "allocators", "malloc"}); + const base::Value* malloc_sizes = malloc->FindKey("sizes"); + EXPECT_EQ(1u, malloc_sizes->GetList().size()); + EXPECT_EQ(0x9876543210ul, malloc_sizes->GetList()[0].GetDouble()); +} +#endif + } // namespace heap_profiling diff --git a/chromium/components/services/leveldb/BUILD.gn b/chromium/components/services/leveldb/BUILD.gn index b4a651097cf..624c887c6f7 100644 --- a/chromium/components/services/leveldb/BUILD.gn +++ b/chromium/components/services/leveldb/BUILD.gn @@ -6,20 +6,14 @@ import("//testing/test.gni") static_library("lib") { sources = [ - "env_mojo.cc", - "env_mojo.h", "leveldb_database_impl.cc", "leveldb_database_impl.h", - "leveldb_mojo_proxy.cc", - "leveldb_mojo_proxy.h", - "leveldb_service_impl.cc", - "leveldb_service_impl.h", ] public_deps = [ - "//components/services/filesystem/public/mojom", "//components/services/leveldb/public/cpp", "//components/services/leveldb/public/mojom", + "//components/services/storage", ] deps = [ @@ -27,27 +21,3 @@ static_library("lib") { "//third_party/leveldatabase", ] } - -test("leveldb_service_unittests") { - sources = [ - "leveldb_mojo_unittest.cc", - "leveldb_service_unittest.cc", - "remote_iterator_unittest.cc", - ] - - deps = [ - ":lib", - "//base", - "//base/test:test_support", - "//components/services/filesystem:lib", - "//components/services/filesystem:test_support", - "//components/services/filesystem/public/mojom", - "//components/services/leveldb/public/cpp", - "//components/services/leveldb/public/mojom", - "//mojo/core/test:run_all_unittests", - "//mojo/public/cpp/bindings", - "//mojo/public/cpp/system", - "//testing/gtest", - "//third_party/leveldatabase", - ] -} diff --git a/chromium/components/services/leveldb/DEPS b/chromium/components/services/leveldb/DEPS index 1debd9d34f1..995db6c575d 100644 --- a/chromium/components/services/leveldb/DEPS +++ b/chromium/components/services/leveldb/DEPS @@ -1,5 +1,4 @@ include_rules = [ - "+components/services/filesystem/public/mojom", - "+mojo/public", + "+components/services/storage/dom_storage", "+third_party/leveldatabase", ] diff --git a/chromium/components/services/leveldb/env_mojo.cc b/chromium/components/services/leveldb/env_mojo.cc deleted file mode 100644 index 01561482cee..00000000000 --- a/chromium/components/services/leveldb/env_mojo.cc +++ /dev/null @@ -1,577 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/services/leveldb/env_mojo.h" - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/string_util.h" -#include "base/task/post_task.h" -#include "base/trace_event/trace_event.h" -#include "third_party/leveldatabase/chromium_logger.h" -#include "third_party/leveldatabase/src/include/leveldb/status.h" - -#if defined(OS_WIN) && defined(DeleteFile) -#undef DeleteFile -#endif - -using leveldb_env::UMALogger; - -namespace leveldb { - -namespace { - -const base::FilePath::CharType table_extension[] = FILE_PATH_LITERAL(".ldb"); - -Status FilesystemErrorToStatus(base::File::Error error, - const std::string& filename, - leveldb_env::MethodID method) { - if (error == base::File::Error::FILE_OK) - return Status::OK(); - - std::string err_str = base::File::ErrorToString(error); - - char buf[512]; - snprintf(buf, sizeof(buf), "%s (MojoFSError: %d::%s)", err_str.c_str(), - method, MethodIDToString(method)); - - // TOOD(https://crbug.com/760362): Map base::File::Error::NOT_FOUND to - // Status::NotFound, after fixing LevelDB to handle the NotFound correctly. - return Status::IOError(filename, buf); -} - -class MojoFileLock : public FileLock { - public: - MojoFileLock(LevelDBMojoProxy::OpaqueLock* lock, const std::string& name) - : fname_(name), lock_(lock) {} - ~MojoFileLock() override { DCHECK(!lock_); } - - const std::string& name() const { return fname_; } - - LevelDBMojoProxy::OpaqueLock* TakeLock() { - LevelDBMojoProxy::OpaqueLock* to_return = lock_; - lock_ = nullptr; - return to_return; - } - - private: - std::string fname_; - LevelDBMojoProxy::OpaqueLock* lock_; -}; - -class MojoSequentialFile : public leveldb::SequentialFile { - public: - MojoSequentialFile(const std::string& fname, - base::File f, - const UMALogger* uma_logger) - : filename_(fname), file_(std::move(f)), uma_logger_(uma_logger) {} - ~MojoSequentialFile() override {} - - Status Read(size_t n, Slice* result, char* scratch) override { - int bytes_read = - file_.ReadAtCurrentPosNoBestEffort(scratch, static_cast<int>(n)); - if (bytes_read == -1) { - base::File::Error error = base::File::GetLastFileError(); - uma_logger_->RecordOSError(leveldb_env::kSequentialFileRead, error); - return MakeIOError(filename_, base::File::ErrorToString(error), - leveldb_env::kSequentialFileRead, error); - } - if (bytes_read > 0) - uma_logger_->RecordBytesRead(bytes_read); - *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 = base::File::GetLastFileError(); - uma_logger_->RecordOSError(leveldb_env::kSequentialFileSkip, error); - return MakeIOError(filename_, base::File::ErrorToString(error), - leveldb_env::kSequentialFileSkip, error); - } - return Status::OK(); - } - - private: - std::string filename_; - base::File file_; - const UMALogger* uma_logger_; - - DISALLOW_COPY_AND_ASSIGN(MojoSequentialFile); -}; - -class MojoRandomAccessFile : public leveldb::RandomAccessFile { - public: - MojoRandomAccessFile(const std::string& fname, - base::File file, - const UMALogger* uma_logger) - : filename_(fname), file_(std::move(file)), uma_logger_(uma_logger) {} - ~MojoRandomAccessFile() override {} - - Status Read(uint64_t offset, - size_t n, - Slice* result, - char* scratch) const override { - int bytes_read = file_.Read(offset, scratch, static_cast<int>(n)); - *result = Slice(scratch, (bytes_read < 0) ? 0 : bytes_read); - if (bytes_read < 0) { - uma_logger_->RecordOSError(leveldb_env::kRandomAccessFileRead, - base::File::GetLastFileError()); - return MakeIOError(filename_, "Could not perform read", - leveldb_env::kRandomAccessFileRead); - } - if (bytes_read > 0) - uma_logger_->RecordBytesRead(bytes_read); - return Status::OK(); - } - - private: - std::string filename_; - mutable base::File file_; - const UMALogger* uma_logger_; - - DISALLOW_COPY_AND_ASSIGN(MojoRandomAccessFile); -}; - -class MojoWritableFile : public leveldb::WritableFile { - public: - MojoWritableFile(LevelDBMojoProxy::OpaqueDir* dir, - const std::string& fname, - base::File f, - scoped_refptr<LevelDBMojoProxy> thread, - const UMALogger* uma_logger) - : filename_(fname), - file_(std::move(f)), - file_type_(kOther), - dir_(dir), - thread_(thread), - uma_logger_(uma_logger) { - base::FilePath path = base::FilePath::FromUTF8Unsafe(fname); - if (base::StartsWith(path.BaseName().AsUTF8Unsafe(), "MANIFEST", - base::CompareCase::SENSITIVE)) { - file_type_ = kManifest; - } else if (path.MatchesExtension(table_extension)) { - file_type_ = kTable; - } - parent_dir_ = - base::FilePath::FromUTF8Unsafe(fname).DirName().AsUTF8Unsafe(); - } - - ~MojoWritableFile() override {} - - leveldb::Status Append(const leveldb::Slice& data) override { - int bytes_written = - file_.WriteAtCurrentPos(data.data(), static_cast<int>(data.size())); - if (bytes_written != static_cast<int>(data.size())) { - base::File::Error error = base::File::GetLastFileError(); - uma_logger_->RecordOSError(leveldb_env::kWritableFileAppend, error); - return MakeIOError(filename_, base::File::ErrorToString(error), - leveldb_env::kWritableFileAppend, error); - } - if (bytes_written > 0) - uma_logger_->RecordBytesWritten(bytes_written); - return Status::OK(); - } - - leveldb::Status Close() override { - file_.Close(); - return Status::OK(); - } - - leveldb::Status Flush() override { - // base::File doesn't do buffered I/O (i.e. POSIX FILE streams) so nothing - // to flush. - return Status::OK(); - } - - leveldb::Status Sync() override { - TRACE_EVENT0("leveldb", "MojoWritableFile::Sync"); - - if (!file_.Flush()) { - base::File::Error error = base::File::GetLastFileError(); - uma_logger_->RecordOSError(leveldb_env::kWritableFileSync, error); - return MakeIOError(filename_, base::File::ErrorToString(error), - leveldb_env::kWritableFileSync, error); - } - - // leveldb's implicit contract for Sync() is that if this instance is for a - // manifest file then the directory is also sync'ed. See leveldb's - // env_posix.cc. - if (file_type_ == kManifest) - return SyncParent(); - - return Status::OK(); - } - - private: - enum Type { kManifest, kTable, kOther }; - - leveldb::Status SyncParent() { - base::File::Error error = thread_->SyncDirectory(dir_, parent_dir_); - if (error != base::File::Error::FILE_OK) { - uma_logger_->RecordOSError(leveldb_env::kSyncParent, - static_cast<base::File::Error>(error)); - } - return error == base::File::Error::FILE_OK - ? Status::OK() - : Status::IOError(filename_, - base::File::ErrorToString(base::File::Error( - static_cast<int>(error)))); - } - - std::string filename_; - base::File file_; - Type file_type_; - LevelDBMojoProxy::OpaqueDir* dir_; - std::string parent_dir_; - scoped_refptr<LevelDBMojoProxy> thread_; - const UMALogger* uma_logger_; - - DISALLOW_COPY_AND_ASSIGN(MojoWritableFile); -}; - -class Thread : public base::PlatformThread::Delegate { - public: - Thread(void (*function)(void* arg), void* arg) - : function_(function), arg_(arg) { - base::PlatformThreadHandle handle; - bool success = base::PlatformThread::Create(0, this, &handle); - DCHECK(success); - } - ~Thread() override {} - void ThreadMain() override { - (*function_)(arg_); - delete this; - } - - private: - void (*function_)(void* arg); - void* arg_; - - DISALLOW_COPY_AND_ASSIGN(Thread); -}; - -class Retrier { - public: - Retrier(leveldb_env::MethodID method, MojoRetrierProvider* provider) - : start_(base::TimeTicks::Now()), - limit_(start_ + base::TimeDelta::FromMilliseconds( - provider->MaxRetryTimeMillis())), - last_(start_), - time_to_sleep_(base::TimeDelta::FromMilliseconds(10)), - success_(true), - method_(method), - last_error_(base::File::FILE_OK), - provider_(provider) {} - - ~Retrier() { - if (success_) { - provider_->RecordRetryTime(method_, last_ - start_); - if (last_error_ != base::File::FILE_OK) { - DCHECK_LT(last_error_, 0); - provider_->RecordRecoveredFromError(method_, last_error_); - } - } - } - - bool ShouldKeepTrying(base::File::Error last_error) { - DCHECK_NE(last_error, base::File::FILE_OK); - last_error_ = last_error; - if (last_ < limit_) { - base::PlatformThread::Sleep(time_to_sleep_); - last_ = base::TimeTicks::Now(); - return true; - } - success_ = false; - return false; - } - - private: - base::TimeTicks start_; - base::TimeTicks limit_; - base::TimeTicks last_; - base::TimeDelta time_to_sleep_; - bool success_; - leveldb_env::MethodID method_; - base::File::Error last_error_; - MojoRetrierProvider* provider_; - - DISALLOW_COPY_AND_ASSIGN(Retrier); -}; - -} // namespace - -MojoEnv::MojoEnv(scoped_refptr<LevelDBMojoProxy> file_thread, - LevelDBMojoProxy::OpaqueDir* dir) - : thread_(file_thread), dir_(dir) {} - -MojoEnv::~MojoEnv() { - thread_->UnregisterDirectory(dir_); -} - -Status MojoEnv::NewSequentialFile(const std::string& fname, - SequentialFile** result) { - TRACE_EVENT1("leveldb", "MojoEnv::NewSequentialFile", "fname", fname); - base::File f = thread_->OpenFileHandle( - dir_, fname, filesystem::mojom::kFlagOpen | filesystem::mojom::kFlagRead); - if (!f.IsValid()) { - *result = nullptr; - RecordOSError(leveldb_env::kNewSequentialFile, f.error_details()); - return MakeIOError(fname, "Unable to create sequential file", - leveldb_env::kNewSequentialFile, f.error_details()); - } - - *result = new MojoSequentialFile(fname, std::move(f), this); - return Status::OK(); -} - -Status MojoEnv::NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) { - TRACE_EVENT1("leveldb", "MojoEnv::NewRandomAccessFile", "fname", fname); - base::File f = thread_->OpenFileHandle( - dir_, fname, filesystem::mojom::kFlagRead | filesystem::mojom::kFlagOpen); - if (!f.IsValid()) { - *result = nullptr; - base::File::Error error_code = f.error_details(); - RecordOSError(leveldb_env::kNewRandomAccessFile, error_code); - return MakeIOError(fname, base::File::ErrorToString(error_code), - leveldb_env::kNewRandomAccessFile, error_code); - } - - *result = new MojoRandomAccessFile(fname, std::move(f), this); - return Status::OK(); -} - -Status MojoEnv::NewWritableFile(const std::string& fname, - WritableFile** result) { - TRACE_EVENT1("leveldb", "MojoEnv::NewWritableFile", "fname", fname); - base::File f = thread_->OpenFileHandle( - dir_, fname, - filesystem::mojom::kCreateAlways | filesystem::mojom::kFlagWrite); - if (!f.IsValid()) { - *result = nullptr; - RecordOSError(leveldb_env::kNewWritableFile, f.error_details()); - return MakeIOError(fname, "Unable to create writable file", - leveldb_env::kNewWritableFile, f.error_details()); - } - - *result = new MojoWritableFile(dir_, fname, std::move(f), thread_, this); - return Status::OK(); -} - -Status MojoEnv::NewAppendableFile(const std::string& fname, - WritableFile** result) { - TRACE_EVENT1("leveldb", "MojoEnv::NewAppendableFile", "fname", fname); - base::File f = thread_->OpenFileHandle( - dir_, fname, - filesystem::mojom::kFlagOpenAlways | filesystem::mojom::kFlagAppend); - if (!f.IsValid()) { - *result = nullptr; - RecordOSError(leveldb_env::kNewAppendableFile, f.error_details()); - return MakeIOError(fname, "Unable to create appendable file", - leveldb_env::kNewAppendableFile, f.error_details()); - } - - *result = new MojoWritableFile(dir_, fname, std::move(f), thread_, this); - return Status::OK(); -} - -bool MojoEnv::FileExists(const std::string& fname) { - TRACE_EVENT1("leveldb", "MojoEnv::FileExists", "fname", fname); - return thread_->FileExists(dir_, fname); -} - -Status MojoEnv::GetChildren(const std::string& path, - std::vector<std::string>* result) { - TRACE_EVENT1("leveldb", "MojoEnv::GetChildren", "path", path); - base::File::Error error = thread_->GetChildren(dir_, path, result); - if (error != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kGetChildren, error); - return FilesystemErrorToStatus(error, path, leveldb_env::kGetChildren); -} - -Status MojoEnv::DeleteFile(const std::string& fname) { - TRACE_EVENT1("leveldb", "MojoEnv::DeleteFile", "fname", fname); - base::File::Error error = thread_->Delete(dir_, fname, 0); - if (error != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kDeleteFile, error); - return FilesystemErrorToStatus(error, fname, leveldb_env::kDeleteFile); -} - -Status MojoEnv::CreateDir(const std::string& dirname) { - TRACE_EVENT1("leveldb", "MojoEnv::CreateDir", "dirname", dirname); - Retrier retrier(leveldb_env::kCreateDir, this); - base::File::Error error; - do { - error = thread_->CreateDir(dir_, dirname); - } while (error != base::File::Error::FILE_OK && - retrier.ShouldKeepTrying(error)); - if (error != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kCreateDir, error); - return FilesystemErrorToStatus(error, dirname, leveldb_env::kCreateDir); -} - -Status MojoEnv::DeleteDir(const std::string& dirname) { - TRACE_EVENT1("leveldb", "MojoEnv::DeleteDir", "dirname", dirname); - base::File::Error error = - thread_->Delete(dir_, dirname, filesystem::mojom::kDeleteFlagRecursive); - if (error != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kDeleteDir, error); - return FilesystemErrorToStatus(error, dirname, leveldb_env::kDeleteDir); -} - -Status MojoEnv::GetFileSize(const std::string& fname, uint64_t* file_size) { - TRACE_EVENT1("leveldb", "MojoEnv::GetFileSize", "fname", fname); - base::File::Error error = thread_->GetFileSize(dir_, fname, file_size); - if (error != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kGetFileSize, error); - return FilesystemErrorToStatus(error, fname, leveldb_env::kGetFileSize); -} - -Status MojoEnv::RenameFile(const std::string& src, const std::string& target) { - TRACE_EVENT2("leveldb", "MojoEnv::RenameFile", "src", src, "target", target); - if (!thread_->FileExists(dir_, src)) - return Status::OK(); - Retrier retrier(leveldb_env::kRenameFile, this); - base::File::Error error; - do { - error = thread_->RenameFile(dir_, src, target); - } while (error != base::File::Error::FILE_OK && - retrier.ShouldKeepTrying(error)); - if (error != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kRenameFile, error); - return FilesystemErrorToStatus(error, src, leveldb_env::kRenameFile); -} - -Status MojoEnv::LockFile(const std::string& fname, FileLock** lock) { - TRACE_EVENT1("leveldb", "MojoEnv::LockFile", "fname", fname); - - Retrier retrier(leveldb_env::kLockFile, this); - std::pair<base::File::Error, LevelDBMojoProxy::OpaqueLock*> p; - do { - p = thread_->LockFile(dir_, fname); - } while (p.first != base::File::Error::FILE_OK && - retrier.ShouldKeepTrying(p.first)); - - if (p.first != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kLockFile, p.first); - - if (p.second) - *lock = new MojoFileLock(p.second, fname); - - return FilesystemErrorToStatus(p.first, fname, leveldb_env::kLockFile); -} - -Status MojoEnv::UnlockFile(FileLock* lock) { - MojoFileLock* my_lock = reinterpret_cast<MojoFileLock*>(lock); - - std::string fname = my_lock ? my_lock->name() : "(invalid)"; - TRACE_EVENT1("leveldb", "MojoEnv::UnlockFile", "fname", fname); - - base::File::Error error = thread_->UnlockFile(my_lock->TakeLock()); - if (error != base::File::Error::FILE_OK) - RecordFileError(leveldb_env::kUnlockFile, error); - delete my_lock; - return FilesystemErrorToStatus(error, fname, leveldb_env::kUnlockFile); -} - -Status MojoEnv::GetTestDirectory(std::string* path) { - // TODO(erg): This method is actually only used from the test harness in - // leveldb. And when we go and port that test stuff to a - // service_manager::ServiceTest, - // we probably won't use it since the mojo filesystem actually handles - // temporary filesystems just fine. - NOTREACHED(); - return Status::OK(); -} - -Status MojoEnv::NewLogger(const std::string& fname, Logger** result) { - TRACE_EVENT1("leveldb", "MojoEnv::NewLogger", "fname", fname); - base::File f(thread_->OpenFileHandle( - dir_, fname, - filesystem::mojom::kCreateAlways | filesystem::mojom::kFlagWrite)); - if (!f.IsValid()) { - *result = nullptr; - RecordOSError(leveldb_env::kNewLogger, f.error_details()); - return MakeIOError(fname, "Unable to create log file", - leveldb_env::kNewLogger, f.error_details()); - } - *result = new leveldb::ChromiumLogger(std::move(f)); - return Status::OK(); -} - -uint64_t MojoEnv::NowMicros() { - return base::TimeTicks::Now().ToInternalValue(); -} - -void MojoEnv::SleepForMicroseconds(int micros) { - // Round up to the next millisecond. - base::PlatformThread::Sleep(base::TimeDelta::FromMicroseconds(micros)); -} - -void MojoEnv::Schedule(void (*function)(void* arg), void* arg) { - base::PostTask( - FROM_HERE, - {base::ThreadPool(), base::MayBlock(), base::WithBaseSyncPrimitives(), - base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, - base::BindOnce(function, arg)); -} - -void MojoEnv::StartThread(void (*function)(void* arg), void* arg) { - new Thread(function, arg); // Will self-delete. -} - -void MojoEnv::RecordErrorAt(leveldb_env::MethodID method) const { - UMA_HISTOGRAM_ENUMERATION("MojoLevelDBEnv.IOError", method, - leveldb_env::kNumEntries); -} - -void MojoEnv::RecordOSError(leveldb_env::MethodID method, - base::File::Error error) const { - RecordErrorAt(method); - std::string uma_name = - std::string("MojoLevelDBEnv.IOError.BFE.") + MethodIDToString(method); - base::UmaHistogramExactLinear(uma_name, -error, -base::File::FILE_ERROR_MAX); -} - -void MojoEnv::RecordBytesRead(int amount) const { - UMA_HISTOGRAM_COUNTS_10M("Storage.BytesRead.MojoLevelDBEnv", amount); -} - -void MojoEnv::RecordBytesWritten(int amount) const { - UMA_HISTOGRAM_COUNTS_10M("Storage.BytesWritten.MojoLevelDBEnv", amount); -} - -int MojoEnv::MaxRetryTimeMillis() const { - return 1000; -} - -void MojoEnv::RecordRetryTime(leveldb_env::MethodID method, - base::TimeDelta time) const { - std::string uma_name = std::string("MojoLevelDBEnv.TimeUntilSuccessFor") + - MethodIDToString(method); - UmaHistogramCustomTimes(uma_name, time, base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMilliseconds(1001), 42); -} - -void MojoEnv::RecordRecoveredFromError(leveldb_env::MethodID method, - base::File::Error error) const { - std::string uma_name = - std::string("MojoLevelDBEnv.RetryRecoveredFromErrorIn") + - MethodIDToString(method); - base::UmaHistogramExactLinear(uma_name, -error, -base::File::FILE_ERROR_MAX); -} - -void MojoEnv::RecordFileError(leveldb_env::MethodID method, - base::File::Error error) const { - RecordOSError(method, static_cast<base::File::Error>(error)); -} - -} // namespace leveldb diff --git a/chromium/components/services/leveldb/env_mojo.h b/chromium/components/services/leveldb/env_mojo.h deleted file mode 100644 index 0529d9c5836..00000000000 --- a/chromium/components/services/leveldb/env_mojo.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SERVICES_LEVELDB_ENV_MOJO_H_ -#define COMPONENTS_SERVICES_LEVELDB_ENV_MOJO_H_ - -#include <string> -#include <vector> - -#include "build/build_config.h" -#include "components/services/filesystem/public/mojom/directory.mojom.h" -#include "components/services/leveldb/leveldb_mojo_proxy.h" -#include "third_party/leveldatabase/env_chromium.h" -#include "third_party/leveldatabase/src/include/leveldb/env.h" - -#if defined(OS_WIN) && defined(DeleteFile) -// See comment in env.h. -#undef DeleteFile -#define ENV_MOJO_DELETEFILE_UNDEFINED -#endif // defined(OS_WIN) && defined(DeleteFile) - -namespace leveldb { - -class MojoRetrierProvider { - public: - virtual int MaxRetryTimeMillis() const = 0; - virtual void RecordRetryTime(leveldb_env::MethodID method, - base::TimeDelta time) const = 0; - virtual void RecordRecoveredFromError(leveldb_env::MethodID method, - base::File::Error error) const = 0; -}; - -// An implementation of the leveldb operating system interaction code which -// proxies to a specified mojo:filesystem directory. Most of these methods are -// synchronous and block on responses from the filesystem service. That's fine -// since, for the most part, they merely open files or check for a file's -// existence. -class MojoEnv : public Env, - public leveldb_env::UMALogger, - public MojoRetrierProvider { - public: - MojoEnv(scoped_refptr<LevelDBMojoProxy> file_thread, - LevelDBMojoProxy::OpaqueDir* dir); - ~MojoEnv() override; - - // Overridden from leveldb::Env: - Status NewSequentialFile(const std::string& fname, - SequentialFile** result) override; - Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) override; - Status NewWritableFile(const std::string& fname, - WritableFile** result) override; - Status NewAppendableFile(const std::string& fname, - WritableFile** result) override; - bool FileExists(const std::string& fname) override; - Status GetChildren(const std::string& dir, - std::vector<std::string>* result) override; - Status DeleteFile(const std::string& fname) override; - Status CreateDir(const std::string& dirname) override; - Status DeleteDir(const std::string& dirname) override; - Status GetFileSize(const std::string& fname, uint64_t* file_size) override; - Status RenameFile(const std::string& src, const std::string& target) override; - Status LockFile(const std::string& fname, FileLock** lock) override; - Status UnlockFile(FileLock* lock) override; - Status GetTestDirectory(std::string* path) override; - Status NewLogger(const std::string& fname, Logger** result) override; - - uint64_t NowMicros() override; - void SleepForMicroseconds(int micros) override; - void Schedule(void (*function)(void* arg), void* arg) override; - void StartThread(void (*function)(void* arg), void* arg) override; - - private: - void RecordErrorAt(leveldb_env::MethodID method) const override; - void RecordOSError(leveldb_env::MethodID method, - base::File::Error error) const override; - void RecordBytesRead(int amount) const override; - void RecordBytesWritten(int amount) const override; - int MaxRetryTimeMillis() const override; - void RecordRetryTime(leveldb_env::MethodID method, - base::TimeDelta time) const override; - void RecordRecoveredFromError(leveldb_env::MethodID method, - base::File::Error error) const override; - - void RecordFileError(leveldb_env::MethodID method, - base::File::Error error) const; - - scoped_refptr<LevelDBMojoProxy> thread_; - LevelDBMojoProxy::OpaqueDir* dir_; - - DISALLOW_COPY_AND_ASSIGN(MojoEnv); -}; - -} // namespace leveldb - -// Redefine DeleteFile if necessary. -#if defined(OS_WIN) && defined(ENV_MOJO_DELETEFILE_UNDEFINED) -#define DeleteFile DeleteFileW -#endif - -#endif // COMPONENTS_SERVICES_LEVELDB_ENV_MOJO_H_ diff --git a/chromium/components/services/leveldb/leveldb.typemap b/chromium/components/services/leveldb/leveldb.typemap deleted file mode 100644 index 1af5cdfe363..00000000000 --- a/chromium/components/services/leveldb/leveldb.typemap +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2017 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -mojom = "//components/services/leveldb/public/mojom/leveldb.mojom" -public_headers = [ "//third_party/leveldatabase/env_chromium.h" ] -traits_headers = [ "//components/services/leveldb/leveldb_mojom_traits.h" ] -sources = [ - "//components/services/leveldb/leveldb_mojom_traits.cc", -] -deps = [] -public_deps = [ - "//mojo/public/cpp/bindings", - "//third_party/leveldatabase", -] -type_mappings = [ "leveldb.mojom.OpenOptions=::leveldb_env::Options" ] diff --git a/chromium/components/services/leveldb/leveldb_database_impl.cc b/chromium/components/services/leveldb/leveldb_database_impl.cc index b0970698c17..14e056aaf69 100644 --- a/chromium/components/services/leveldb/leveldb_database_impl.cc +++ b/chromium/components/services/leveldb/leveldb_database_impl.cc @@ -5,6 +5,7 @@ #include "components/services/leveldb/leveldb_database_impl.h" #include <inttypes.h> + #include <algorithm> #include <map> #include <string> @@ -14,417 +15,221 @@ #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" -#include "base/trace_event/memory_dump_manager.h" -#include "components/services/leveldb/env_mojo.h" #include "components/services/leveldb/public/cpp/util.h" #include "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" namespace leveldb { -namespace { - -template <typename FunctionType> -leveldb::Status ForEachWithPrefix(leveldb::DB* db, - const leveldb::Slice& key_prefix, - FunctionType function) { - leveldb::ReadOptions read_options; - // Disable filling the cache for bulk scans. Either this is for deletion - // (where caching those blocks doesn't make sense) or a mass-read, which the - // user "should" be caching / only needing once. - read_options.fill_cache = false; - std::unique_ptr<leveldb::Iterator> it(db->NewIterator(read_options)); - it->Seek(key_prefix); - for (; it->Valid(); it->Next()) { - if (!it->key().starts_with(key_prefix)) - break; - function(it->key(), it->value()); - } - return it->status(); -} - -} // namespace -LevelDBDatabaseImpl::LevelDBDatabaseImpl( - std::unique_ptr<Env> environment, - std::unique_ptr<DB> db, - std::unique_ptr<Cache> cache, +// static +std::unique_ptr<LevelDBDatabaseImpl> LevelDBDatabaseImpl::OpenDirectory( const leveldb_env::Options& options, - const std::string& name, - base::Optional<base::trace_event::MemoryAllocatorDumpGuid> memory_dump_id) - : environment_(std::move(environment)), - cache_(std::move(cache)), - db_(std::move(db)), - options_(options), - name_(name), - memory_dump_id_(memory_dump_id) { - base::trace_event::MemoryDumpManager::GetInstance() - ->RegisterDumpProviderWithSequencedTaskRunner( - this, "MojoLevelDB", base::SequencedTaskRunnerHandle::Get(), - MemoryDumpProvider::Options()); -} - -LevelDBDatabaseImpl::~LevelDBDatabaseImpl() { - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - this); - for (auto& p : iterator_map_) - delete p.second; - for (auto& p : snapshot_map_) - db_->ReleaseSnapshot(p.second); -} + const base::FilePath& directory, + const std::string& dbname, + const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& + memory_dump_id, + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, + StatusCallback callback) { + std::unique_ptr<LevelDBDatabaseImpl> db(new LevelDBDatabaseImpl); + storage::DomStorageDatabase::OpenDirectory( + directory, dbname, options, memory_dump_id, + std::move(blocking_task_runner), + base::BindOnce(&LevelDBDatabaseImpl::OnDatabaseOpened, + db->weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + return db; +} + +// static +std::unique_ptr<LevelDBDatabaseImpl> LevelDBDatabaseImpl::OpenInMemory( + const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& + memory_dump_id, + const std::string& tracking_name, + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, + StatusCallback callback) { + std::unique_ptr<LevelDBDatabaseImpl> db(new LevelDBDatabaseImpl); + storage::DomStorageDatabase::OpenInMemory( + tracking_name, memory_dump_id, std::move(blocking_task_runner), + base::BindOnce(&LevelDBDatabaseImpl::OnDatabaseOpened, + db->weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + return db; +} + +LevelDBDatabaseImpl::LevelDBDatabaseImpl() = default; + +LevelDBDatabaseImpl::~LevelDBDatabaseImpl() = default; void LevelDBDatabaseImpl::Put(const std::vector<uint8_t>& key, const std::vector<uint8_t>& value, - PutCallback callback) { - Status status = - db_->Put(leveldb::WriteOptions(), GetSliceFor(key), GetSliceFor(value)); - std::move(callback).Run(LeveldbStatusToError(status)); + StatusCallback callback) { + RunDatabaseTask( + base::BindOnce( + [](const std::vector<uint8_t>& key, const std::vector<uint8_t>& value, + const storage::DomStorageDatabase& db) { + return db.Put(key, value); + }, + key, value), + std::move(callback)); } void LevelDBDatabaseImpl::Delete(const std::vector<uint8_t>& key, - DeleteCallback callback) { - Status status = db_->Delete(leveldb::WriteOptions(), GetSliceFor(key)); - std::move(callback).Run(LeveldbStatusToError(status)); + StatusCallback callback) { + RunDatabaseTask( + base::BindOnce( + [](const std::vector<uint8_t>& key, + const storage::DomStorageDatabase& db) { return db.Delete(key); }, + key), + std::move(callback)); } void LevelDBDatabaseImpl::DeletePrefixed(const std::vector<uint8_t>& key_prefix, - DeletePrefixedCallback callback) { - WriteBatch batch; - Status status = DeletePrefixedHelper(GetSliceFor(key_prefix), &batch); - if (status.ok()) - status = db_->Write(leveldb::WriteOptions(), &batch); - std::move(callback).Run(LeveldbStatusToError(status)); -} - -void LevelDBDatabaseImpl::RewriteDB(RewriteDBCallback callback) { - Status status = leveldb_env::RewriteDB(options_, name_, &db_); - std::move(callback).Run(LeveldbStatusToError(status)); - if (!db_ && close_binding_) { - // There is no point in existence without a db_. - std::move(close_binding_).Run(); - } -} - -void LevelDBDatabaseImpl::SetCloseBindingClosure( - base::OnceClosure close_binding) { - close_binding_ = std::move(close_binding); + StatusCallback callback) { + RunDatabaseTask(base::BindOnce( + [](const std::vector<uint8_t>& prefix, + const storage::DomStorageDatabase& db) { + WriteBatch batch; + Status status = db.DeletePrefixed(prefix, &batch); + if (!status.ok()) + return status; + return db.Commit(&batch); + }, + key_prefix), + std::move(callback)); +} + +void LevelDBDatabaseImpl::RewriteDB(StatusCallback callback) { + DCHECK(database_); + database_.PostTaskWithThisObject( + FROM_HERE, + base::BindOnce( + [](StatusCallback callback, + scoped_refptr<base::SequencedTaskRunner> callback_task_runner, + storage::DomStorageDatabase* db) { + callback_task_runner->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), db->RewriteDB())); + }, + std::move(callback), base::SequencedTaskRunnerHandle::Get())); } void LevelDBDatabaseImpl::Write( std::vector<mojom::BatchedOperationPtr> operations, - WriteCallback callback) { - WriteBatch batch; - - for (size_t i = 0; i < operations.size(); ++i) { - switch (operations[i]->type) { - case mojom::BatchOperationType::PUT_KEY: { - if (operations[i]->value) { - batch.Put(GetSliceFor(operations[i]->key), - GetSliceFor(*(operations[i]->value))); - } else { - batch.Put(GetSliceFor(operations[i]->key), Slice()); - } - break; - } - case mojom::BatchOperationType::DELETE_KEY: { - batch.Delete(GetSliceFor(operations[i]->key)); - break; - } - case mojom::BatchOperationType::DELETE_PREFIXED_KEY: { - DeletePrefixedHelper(GetSliceFor(operations[i]->key), &batch); - break; - } - case mojom::BatchOperationType::COPY_PREFIXED_KEY: { - if (!operations[i]->value) { - mojo::ReportBadMessage( - "COPY_PREFIXED_KEY operation must provide a value."); - std::move(callback).Run(mojom::DatabaseError::INVALID_ARGUMENT); - return; - } - CopyPrefixedHelper(operations[i]->key, *(operations[i]->value), &batch); - break; - } - } - } - - Status status = db_->Write(leveldb::WriteOptions(), &batch); - std::move(callback).Run(LeveldbStatusToError(status)); + StatusCallback callback) { + RunDatabaseTask( + base::BindOnce( + [](std::vector<mojom::BatchedOperationPtr> operations, + const storage::DomStorageDatabase& db) { + WriteBatch batch; + for (auto& op : operations) { + switch (op->type) { + case mojom::BatchOperationType::PUT_KEY: { + if (op->value) { + batch.Put(GetSliceFor(op->key), GetSliceFor(*(op->value))); + } else { + batch.Put(GetSliceFor(op->key), Slice()); + } + break; + } + case mojom::BatchOperationType::DELETE_KEY: { + batch.Delete(GetSliceFor(op->key)); + break; + } + case mojom::BatchOperationType::DELETE_PREFIXED_KEY: { + db.DeletePrefixed(op->key, &batch); + break; + } + case mojom::BatchOperationType::COPY_PREFIXED_KEY: { + // DCHECK is fine here since browser code is the only caller. + DCHECK(op->value); + db.CopyPrefixed(op->key, *(op->value), &batch); + break; + } + } + } + return db.Commit(&batch); + }, + std::move(operations)), + std::move(callback)); } void LevelDBDatabaseImpl::Get(const std::vector<uint8_t>& key, GetCallback callback) { - std::string value; - Status status = db_->Get(leveldb::ReadOptions(), GetSliceFor(key), &value); - std::move(callback).Run(LeveldbStatusToError(status), - StdStringToUint8Vector(value)); -} - -void LevelDBDatabaseImpl::GetMany( - std::vector<mojom::GetManyRequestPtr> keys_or_prefixes, - GetManyCallback callback) { - std::vector<mojom::GetManyResultPtr> data; - - for (const auto& request : keys_or_prefixes) { - mojom::GetManyResultPtr result = mojom::GetManyResult::New(); + struct GetResult { Status status; - - if (request->is_key()) { - const std::vector<uint8_t>& key = request->get_key(); - std::string value; - status = db_->Get(leveldb::ReadOptions(), GetSliceFor(key), &value); - if (status.ok()) - result->set_key_value(StdStringToUint8Vector(value)); - else - result->set_status(LeveldbStatusToError(status)); - } else { - const std::vector<uint8_t>& key_prefix = request->get_key_prefix(); - std::vector<mojom::KeyValuePtr> values; - std::tie(status, values) = GetPrefixedHelper(key_prefix); - if (status.ok()) - result->set_key_prefix_values(std::move(values)); - else - result->set_status(LeveldbStatusToError(status)); - } - - data.push_back(std::move(result)); - } - - std::move(callback).Run(std::move(data)); + storage::DomStorageDatabase::Value value; + }; + RunDatabaseTask(base::BindOnce( + [](const std::vector<uint8_t>& key, + const storage::DomStorageDatabase& db) { + GetResult result; + result.status = db.Get(key, &result.value); + return result; + }, + key), + base::BindOnce( + [](GetCallback callback, GetResult result) { + std::move(callback).Run(result.status, result.value); + }, + std::move(callback))); } void LevelDBDatabaseImpl::GetPrefixed(const std::vector<uint8_t>& key_prefix, GetPrefixedCallback callback) { - std::vector<mojom::KeyValuePtr> data; - Status status; - std::tie(status, data) = GetPrefixedHelper(key_prefix); - std::move(callback).Run(LeveldbStatusToError(status), std::move(data)); + struct GetPrefixedResult { + Status status; + std::vector<storage::DomStorageDatabase::KeyValuePair> entries; + }; + + RunDatabaseTask( + base::BindOnce( + [](const std::vector<uint8_t>& prefix, + const storage::DomStorageDatabase& db) { + GetPrefixedResult result; + result.status = db.GetPrefixed(prefix, &result.entries); + return result; + }, + key_prefix), + base::BindOnce( + [](GetPrefixedCallback callback, GetPrefixedResult result) { + std::vector<mojom::KeyValuePtr> entries; + for (auto& entry : result.entries) + entries.push_back(mojom::KeyValue::New(entry.key, entry.value)); + std::move(callback).Run(result.status, std::move(entries)); + }, + std::move(callback))); } void LevelDBDatabaseImpl::CopyPrefixed( const std::vector<uint8_t>& source_key_prefix, const std::vector<uint8_t>& destination_key_prefix, - CopyPrefixedCallback callback) { - WriteBatch batch; - Status status = - CopyPrefixedHelper(source_key_prefix, destination_key_prefix, &batch); - if (status.ok()) - status = db_->Write(leveldb::WriteOptions(), &batch); - std::move(callback).Run(LeveldbStatusToError(status)); -} - -void LevelDBDatabaseImpl::GetSnapshot(GetSnapshotCallback callback) { - const Snapshot* s = db_->GetSnapshot(); - base::UnguessableToken token = base::UnguessableToken::Create(); - snapshot_map_.insert(std::make_pair(token, s)); - std::move(callback).Run(token); -} - -void LevelDBDatabaseImpl::ReleaseSnapshot( - const base::UnguessableToken& snapshot) { - auto it = snapshot_map_.find(snapshot); - if (it != snapshot_map_.end()) { - db_->ReleaseSnapshot(it->second); - snapshot_map_.erase(it); - } -} - -void LevelDBDatabaseImpl::GetFromSnapshot( - const base::UnguessableToken& snapshot, - const std::vector<uint8_t>& key, - GetCallback callback) { - // If the snapshot id is invalid, send back invalid argument - auto it = snapshot_map_.find(snapshot); - if (it == snapshot_map_.end()) { - std::move(callback).Run(mojom::DatabaseError::INVALID_ARGUMENT, - std::vector<uint8_t>()); - return; + StatusCallback callback) { + RunDatabaseTask(base::BindOnce( + [](const std::vector<uint8_t>& prefix, + const std::vector<uint8_t>& new_prefix, + const storage::DomStorageDatabase& db) { + WriteBatch batch; + Status status = + db.CopyPrefixed(prefix, new_prefix, &batch); + if (!status.ok()) + return status; + return db.Commit(&batch); + }, + source_key_prefix, destination_key_prefix), + std::move(callback)); +} + +void LevelDBDatabaseImpl::OnDatabaseOpened( + StatusCallback callback, + base::SequenceBound<storage::DomStorageDatabase> database, + leveldb::Status status) { + database_ = std::move(database); + std::vector<DatabaseTask> tasks; + std::swap(tasks, tasks_to_run_on_open_); + if (status.ok()) { + for (auto& task : tasks) + database_.PostTaskWithThisObject(FROM_HERE, std::move(task)); } - - std::string value; - leveldb::ReadOptions options; - options.snapshot = it->second; - Status status = db_->Get(options, GetSliceFor(key), &value); - std::move(callback).Run(LeveldbStatusToError(status), - StdStringToUint8Vector(value)); -} - -void LevelDBDatabaseImpl::NewIterator(NewIteratorCallback callback) { - Iterator* iterator = db_->NewIterator(leveldb::ReadOptions()); - base::UnguessableToken token = base::UnguessableToken::Create(); - iterator_map_.insert(std::make_pair(token, iterator)); - std::move(callback).Run(token); -} - -void LevelDBDatabaseImpl::NewIteratorFromSnapshot( - const base::UnguessableToken& snapshot, - NewIteratorFromSnapshotCallback callback) { - // If the snapshot id is invalid, send back invalid argument - auto it = snapshot_map_.find(snapshot); - if (it == snapshot_map_.end()) { - std::move(callback).Run(base::Optional<base::UnguessableToken>()); - return; - } - - leveldb::ReadOptions options; - options.snapshot = it->second; - - Iterator* iterator = db_->NewIterator(options); - base::UnguessableToken new_token = base::UnguessableToken::Create(); - iterator_map_.insert(std::make_pair(new_token, iterator)); - std::move(callback).Run(new_token); -} - -void LevelDBDatabaseImpl::ReleaseIterator( - const base::UnguessableToken& iterator) { - auto it = iterator_map_.find(iterator); - if (it != iterator_map_.end()) { - delete it->second; - iterator_map_.erase(it); - } -} - -void LevelDBDatabaseImpl::IteratorSeekToFirst( - const base::UnguessableToken& iterator, - IteratorSeekToFirstCallback callback) { - auto it = iterator_map_.find(iterator); - if (it == iterator_map_.end()) { - std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT, - base::nullopt, base::nullopt); - return; - } - - it->second->SeekToFirst(); - - ReplyToIteratorMessage(it->second, std::move(callback)); -} - -void LevelDBDatabaseImpl::IteratorSeekToLast( - const base::UnguessableToken& iterator, - IteratorSeekToLastCallback callback) { - auto it = iterator_map_.find(iterator); - if (it == iterator_map_.end()) { - std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT, - base::nullopt, base::nullopt); - return; - } - - it->second->SeekToLast(); - - ReplyToIteratorMessage(it->second, std::move(callback)); -} - -void LevelDBDatabaseImpl::IteratorSeek(const base::UnguessableToken& iterator, - const std::vector<uint8_t>& target, - IteratorSeekToLastCallback callback) { - auto it = iterator_map_.find(iterator); - if (it == iterator_map_.end()) { - std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT, - base::nullopt, base::nullopt); - return; - } - - it->second->Seek(GetSliceFor(target)); - - ReplyToIteratorMessage(it->second, std::move(callback)); -} - -void LevelDBDatabaseImpl::IteratorNext(const base::UnguessableToken& iterator, - IteratorNextCallback callback) { - auto it = iterator_map_.find(iterator); - if (it == iterator_map_.end()) { - std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT, - base::nullopt, base::nullopt); - return; - } - - it->second->Next(); - - ReplyToIteratorMessage(it->second, std::move(callback)); -} - -void LevelDBDatabaseImpl::IteratorPrev(const base::UnguessableToken& iterator, - IteratorPrevCallback callback) { - auto it = iterator_map_.find(iterator); - if (it == iterator_map_.end()) { - std::move(callback).Run(false, mojom::DatabaseError::INVALID_ARGUMENT, - base::nullopt, base::nullopt); - return; - } - - it->second->Prev(); - - ReplyToIteratorMessage(it->second, std::move(callback)); -} - -bool LevelDBDatabaseImpl::OnMemoryDump( - const base::trace_event::MemoryDumpArgs& args, - base::trace_event::ProcessMemoryDump* pmd) { - auto* dump = leveldb_env::DBTracker::GetOrCreateAllocatorDump(pmd, db_.get()); - if (!dump) - return true; - auto* global_dump = pmd->CreateSharedGlobalAllocatorDump(*memory_dump_id_); - pmd->AddOwnershipEdge(global_dump->guid(), dump->guid()); - // Add size to global dump to propagate the size of the database to the - // client's dump. - global_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, - base::trace_event::MemoryAllocatorDump::kUnitsBytes, - dump->GetSizeInternal()); - return true; -} - -void LevelDBDatabaseImpl::ReplyToIteratorMessage( - leveldb::Iterator* it, - IteratorSeekToFirstCallback callback) { - if (!it->Valid()) { - std::move(callback).Run(false, LeveldbStatusToError(it->status()), - base::nullopt, base::nullopt); - return; - } - - std::move(callback).Run(true, LeveldbStatusToError(it->status()), - GetVectorFor(it->key()), GetVectorFor(it->value())); -} - -LevelDBDatabaseImpl::StatusAndKeyValues LevelDBDatabaseImpl::GetPrefixedHelper( - const std::vector<uint8_t>& key_prefix) { - std::vector<mojom::KeyValuePtr> data; - Status status = - ForEachWithPrefix(db_.get(), GetSliceFor(key_prefix), - [&data](const Slice& key, const Slice& value) { - mojom::KeyValuePtr kv = mojom::KeyValue::New(); - kv->key = GetVectorFor(key); - kv->value = GetVectorFor(value); - data.push_back(std::move(kv)); - }); - return std::make_tuple(status, std::move(data)); -} - -Status LevelDBDatabaseImpl::DeletePrefixedHelper(const Slice& key_prefix, - WriteBatch* batch) { - Status status = ForEachWithPrefix( - db_.get(), key_prefix, - [batch](const Slice& key, const Slice& value) { batch->Delete(key); }); - return status; -} - -Status LevelDBDatabaseImpl::CopyPrefixedHelper( - const std::vector<uint8_t>& source_key_prefix, - const std::vector<uint8_t>& destination_key_prefix, - leveldb::WriteBatch* batch) { - std::vector<uint8_t> new_prefix = destination_key_prefix; - size_t source_key_prefix_size = source_key_prefix.size(); - size_t destination_key_prefix_size = destination_key_prefix.size(); - Status status = ForEachWithPrefix( - db_.get(), GetSliceFor(source_key_prefix), - [&batch, &new_prefix, source_key_prefix_size, - destination_key_prefix_size](const Slice& key, const Slice& value) { - size_t excess_key = key.size() - source_key_prefix_size; - new_prefix.resize(destination_key_prefix_size + excess_key); - std::copy(key.data() + source_key_prefix_size, key.data() + key.size(), - new_prefix.begin() + destination_key_prefix_size); - batch->Put(GetSliceFor(new_prefix), value); - }); - return status; + std::move(callback).Run(status); } } // namespace leveldb diff --git a/chromium/components/services/leveldb/leveldb_database_impl.h b/chromium/components/services/leveldb/leveldb_database_impl.h index aff55f034d3..6ddee8265dd 100644 --- a/chromium/components/services/leveldb/leveldb_database_impl.h +++ b/chromium/components/services/leveldb/leveldb_database_impl.h @@ -9,115 +9,120 @@ #include <tuple> #include <vector> -#include "base/trace_event/memory_dump_provider.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequenced_task_runner.h" +#include "base/threading/sequence_bound.h" #include "base/unguessable_token.h" #include "components/services/leveldb/public/mojom/leveldb.mojom.h" -#include "mojo/public/cpp/bindings/interface_request.h" +#include "components/services/storage/dom_storage/dom_storage_database.h" #include "third_party/leveldatabase/src/include/leveldb/cache.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" namespace leveldb { -// The backing to a database object that we pass to our called. -class LevelDBDatabaseImpl : public mojom::LevelDBDatabase, - public base::trace_event::MemoryDumpProvider { +// A temporary wrapper around the Storage Service's DomStorageDatabase class, +// consumed by LocalStorageContextMojo, SessionStorageContextMojo, and related +// classes. +// +// TODO(https://crbug.com/1000959): Delete this class. +class LevelDBDatabaseImpl { public: - LevelDBDatabaseImpl(std::unique_ptr<leveldb::Env> environment, - std::unique_ptr<leveldb::DB> db, - std::unique_ptr<leveldb::Cache> cache, - const leveldb_env::Options& options, - const std::string& name, - base::Optional<base::trace_event::MemoryAllocatorDumpGuid> - memory_dump_id); - ~LevelDBDatabaseImpl() override; + using StatusCallback = base::OnceCallback<void(Status)>; + + ~LevelDBDatabaseImpl(); + + static std::unique_ptr<LevelDBDatabaseImpl> OpenDirectory( + const leveldb_env::Options& options, + const base::FilePath& directory, + const std::string& dbname, + const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& + memory_dump_id, + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, + StatusCallback callback); + + static std::unique_ptr<LevelDBDatabaseImpl> OpenInMemory( + const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& + memory_dump_id, + const std::string& tracking_name, + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, + StatusCallback callback); + + base::SequenceBound<storage::DomStorageDatabase>& database() { + return database_; + } + const base::SequenceBound<storage::DomStorageDatabase>& database() const { + return database_; + } // Overridden from LevelDBDatabase: void Put(const std::vector<uint8_t>& key, const std::vector<uint8_t>& value, - PutCallback callback) override; - void Delete(const std::vector<uint8_t>& key, - DeleteCallback callback) override; + StatusCallback callback); + + void Delete(const std::vector<uint8_t>& key, StatusCallback callback); + void DeletePrefixed(const std::vector<uint8_t>& key_prefix, - DeletePrefixedCallback callback) override; - void RewriteDB(RewriteDBCallback callback) override; + StatusCallback callback); + + void RewriteDB(StatusCallback callback); + void Write(std::vector<mojom::BatchedOperationPtr> operations, - WriteCallback callback) override; - void Get(const std::vector<uint8_t>& key, GetCallback callback) override; + StatusCallback callback); + + using GetCallback = + base::OnceCallback<void(Status status, const std::vector<uint8_t>&)>; + void Get(const std::vector<uint8_t>& key, GetCallback callback); + + using GetPrefixedCallback = + base::OnceCallback<void(Status status, std::vector<mojom::KeyValuePtr>)>; void GetPrefixed(const std::vector<uint8_t>& key_prefix, - GetPrefixedCallback callback) override; - void GetMany(std::vector<mojom::GetManyRequestPtr> keys_or_prefixes, - GetManyCallback callback) override; + GetPrefixedCallback callback); + void CopyPrefixed(const std::vector<uint8_t>& source_key_prefix, const std::vector<uint8_t>& destination_key_prefix, - CopyPrefixedCallback callback) override; - void GetSnapshot(GetSnapshotCallback callback) override; - void ReleaseSnapshot(const base::UnguessableToken& snapshot) override; - void GetFromSnapshot(const base::UnguessableToken& snapshot, - const std::vector<uint8_t>& key, - GetCallback callback) override; - void NewIterator(NewIteratorCallback callback) override; - void NewIteratorFromSnapshot( - const base::UnguessableToken& snapshot, - NewIteratorFromSnapshotCallback callback) override; - void ReleaseIterator(const base::UnguessableToken& iterator) override; - void IteratorSeekToFirst(const base::UnguessableToken& iterator, - IteratorSeekToFirstCallback callback) override; - void IteratorSeekToLast(const base::UnguessableToken& iterator, - IteratorSeekToLastCallback callback) override; - void IteratorSeek(const base::UnguessableToken& iterator, - const std::vector<uint8_t>& target, - IteratorSeekToLastCallback callback) override; - void IteratorNext(const base::UnguessableToken& iterator, - IteratorNextCallback callback) override; - void IteratorPrev(const base::UnguessableToken& iterator, - IteratorPrevCallback callback) override; - - // base::trace_event::MemoryDumpProvider implementation. - bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, - base::trace_event::ProcessMemoryDump* pmd) override; - - // Set a closure that will close the mojo connection to this object. - // The closure will be called if this database becomes unusable e.g. - // due to a failed rewrite attempt. - void SetCloseBindingClosure(base::OnceClosure close_binding); + StatusCallback callback); + + template <typename ResultType> + void RunDatabaseTask( + base::OnceCallback<ResultType(const storage::DomStorageDatabase&)> task, + base::OnceCallback<void(ResultType)> callback) { + auto wrapped_task = base::BindOnce( + [](base::OnceCallback<ResultType(const storage::DomStorageDatabase&)> + task, + base::OnceCallback<void(ResultType)> callback, + scoped_refptr<base::SequencedTaskRunner> callback_task_runner, + const storage::DomStorageDatabase& db) { + callback_task_runner->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), std::move(task).Run(db))); + }, + std::move(task), std::move(callback), + base::SequencedTaskRunnerHandle::Get()); + if (database_) { + database_.PostTaskWithThisObject(FROM_HERE, std::move(wrapped_task)); + } else { + tasks_to_run_on_open_.push_back(std::move(wrapped_task)); + } + } private: using StatusAndKeyValues = std::tuple<Status, std::vector<mojom::KeyValuePtr>>; - // Returns the state of |it| to a caller. Note: This assumes that all the - // iterator movement methods have the same callback signature. We don't - // directly reference the underlying type in case of bindings change. - void ReplyToIteratorMessage(leveldb::Iterator* it, - IteratorSeekToFirstCallback callback); - - StatusAndKeyValues GetPrefixedHelper(const std::vector<uint8_t>& key_prefix); - - leveldb::Status DeletePrefixedHelper(const leveldb::Slice& key_prefix, - leveldb::WriteBatch* batch); - - leveldb::Status CopyPrefixedHelper( - const std::vector<uint8_t>& source_key_prefix, - const std::vector<uint8_t>& destination_key_prefix, - leveldb::WriteBatch* batch); - - std::unique_ptr<leveldb::Env> environment_; - std::unique_ptr<leveldb::Cache> cache_; - std::unique_ptr<leveldb::DB> db_; - leveldb_env::Options options_; - std::string name_; - base::Optional<base::trace_event::MemoryAllocatorDumpGuid> memory_dump_id_; + void OnDatabaseOpened( + StatusCallback callback, + base::SequenceBound<storage::DomStorageDatabase> database, + leveldb::Status status); - std::map<base::UnguessableToken, const Snapshot*> snapshot_map_; + explicit LevelDBDatabaseImpl(); - // TODO(erg): If we have an existing iterator which depends on a snapshot, - // and delete the snapshot from the client side, that shouldn't delete the - // snapshot maybe? At worse it's a DDoS if there's multiple users of the - // system, but this maybe should be fixed... + base::SequenceBound<storage::DomStorageDatabase> database_; - std::map<base::UnguessableToken, Iterator*> iterator_map_; + using DatabaseTask = + base::OnceCallback<void(const storage::DomStorageDatabase&)>; + std::vector<DatabaseTask> tasks_to_run_on_open_; - base::OnceClosure close_binding_; + base::WeakPtrFactory<LevelDBDatabaseImpl> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(LevelDBDatabaseImpl); }; diff --git a/chromium/components/services/leveldb/leveldb_mojo_proxy.cc b/chromium/components/services/leveldb/leveldb_mojo_proxy.cc deleted file mode 100644 index 85f037586c4..00000000000 --- a/chromium/components/services/leveldb/leveldb_mojo_proxy.cc +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/services/leveldb/leveldb_mojo_proxy.h" - -#include <set> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/files/file_path.h" -#include "base/threading/thread_restrictions.h" -#include "mojo/public/cpp/bindings/interface_request.h" -#include "mojo/public/cpp/bindings/sync_call_restrictions.h" - -namespace leveldb { - -struct LevelDBMojoProxy::OpaqueLock { - filesystem::mojom::FilePtr lock_file; -}; - -struct LevelDBMojoProxy::OpaqueDir { - explicit OpaqueDir( - mojo::InterfacePtrInfo<filesystem::mojom::Directory> directory_info) { - directory.Bind(std::move(directory_info)); - } - - filesystem::mojom::DirectoryPtr directory; -}; - -LevelDBMojoProxy::LevelDBMojoProxy( - scoped_refptr<base::SequencedTaskRunner> task_runner) - : task_runner_(std::move(task_runner)), outstanding_opaque_dirs_(0) { - DCHECK(!task_runner_->RunsTasksInCurrentSequence()); -} - -LevelDBMojoProxy::OpaqueDir* LevelDBMojoProxy::RegisterDirectory( - filesystem::mojom::DirectoryPtr directory) { - OpaqueDir* out_dir = nullptr; - RunInternal(base::Bind(&LevelDBMojoProxy::RegisterDirectoryImpl, this, - base::Passed(directory.PassInterface()), &out_dir)); - - return out_dir; -} - -void LevelDBMojoProxy::UnregisterDirectory(OpaqueDir* dir) { - RunInternal( - base::Bind(&LevelDBMojoProxy::UnregisterDirectoryImpl, this, dir)); -} - -base::File LevelDBMojoProxy::OpenFileHandle(OpaqueDir* dir, - const std::string& name, - uint32_t open_flags) { - base::File file; - RunInternal(base::Bind(&LevelDBMojoProxy::OpenFileHandleImpl, this, dir, name, - open_flags, &file)); - return file; -} - -base::File::Error LevelDBMojoProxy::SyncDirectory(OpaqueDir* dir, - const std::string& name) { - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - RunInternal(base::Bind(&LevelDBMojoProxy::SyncDirectoryImpl, this, dir, name, - &error)); - return error; -} - -bool LevelDBMojoProxy::FileExists(OpaqueDir* dir, const std::string& name) { - bool exists = false; - RunInternal( - base::Bind(&LevelDBMojoProxy::FileExistsImpl, this, dir, name, &exists)); - return exists; -} - -base::File::Error LevelDBMojoProxy::GetChildren( - OpaqueDir* dir, - const std::string& path, - std::vector<std::string>* result) { - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - RunInternal(base::Bind(&LevelDBMojoProxy::GetChildrenImpl, this, dir, path, - result, &error)); - return error; -} - -base::File::Error LevelDBMojoProxy::Delete(OpaqueDir* dir, - const std::string& path, - uint32_t delete_flags) { - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - RunInternal(base::Bind(&LevelDBMojoProxy::DeleteImpl, this, dir, path, - delete_flags, &error)); - return error; -} - -base::File::Error LevelDBMojoProxy::CreateDir(OpaqueDir* dir, - const std::string& path) { - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - RunInternal( - base::Bind(&LevelDBMojoProxy::CreateDirImpl, this, dir, path, &error)); - return error; -} - -base::File::Error LevelDBMojoProxy::GetFileSize(OpaqueDir* dir, - const std::string& path, - uint64_t* file_size) { - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - RunInternal(base::Bind(&LevelDBMojoProxy::GetFileSizeImpl, this, dir, path, - file_size, &error)); - return error; -} - -base::File::Error LevelDBMojoProxy::RenameFile(OpaqueDir* dir, - const std::string& old_path, - const std::string& new_path) { - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - RunInternal(base::Bind(&LevelDBMojoProxy::RenameFileImpl, this, dir, old_path, - new_path, &error)); - return error; -} - -std::pair<base::File::Error, LevelDBMojoProxy::OpaqueLock*> -LevelDBMojoProxy::LockFile(OpaqueDir* dir, const std::string& path) { - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - OpaqueLock* out_lock = nullptr; - RunInternal(base::Bind(&LevelDBMojoProxy::LockFileImpl, this, dir, path, - &error, &out_lock)); - return std::make_pair(error, out_lock); -} - -base::File::Error LevelDBMojoProxy::UnlockFile(OpaqueLock* lock) { - // Take ownership of the incoming lock so it gets destroyed whatever happens. - std::unique_ptr<OpaqueLock> scoped_lock(lock); - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - RunInternal(base::Bind(&LevelDBMojoProxy::UnlockFileImpl, this, - base::Passed(&scoped_lock), &error)); - return error; -} - -LevelDBMojoProxy::~LevelDBMojoProxy() { - DCHECK_EQ(0, outstanding_opaque_dirs_); -} - -void LevelDBMojoProxy::RunInternal(const base::Closure& task) { - if (task_runner_->RunsTasksInCurrentSequence()) { - task.Run(); - } else { - base::WaitableEvent done_event( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&LevelDBMojoProxy::DoOnOtherThread, this, - task, base::Unretained(&done_event))); - base::ScopedAllowBaseSyncPrimitives allow_base_sync_primitives; - done_event.Wait(); - } -} - -void LevelDBMojoProxy::DoOnOtherThread(const base::Closure& c, - base::WaitableEvent* event) { - c.Run(); - event->Signal(); -} - -void LevelDBMojoProxy::RegisterDirectoryImpl( - mojo::InterfacePtrInfo<filesystem::mojom::Directory> directory_info, - OpaqueDir** out_dir) { - // Take the Directory pipe and bind it on this thread. - *out_dir = new OpaqueDir(std::move(directory_info)); - outstanding_opaque_dirs_++; -} - -void LevelDBMojoProxy::UnregisterDirectoryImpl(OpaqueDir* dir) { - // Only delete the directories on the thread that owns them. - delete dir; - outstanding_opaque_dirs_--; -} - -void LevelDBMojoProxy::OpenFileHandleImpl(OpaqueDir* dir, - std::string name, - uint32_t open_flags, - base::File* output_file) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - base::File file; - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - bool completed = - dir->directory->OpenFileHandle(name, open_flags, &error, &file); - DCHECK(completed); - - if (error != base::File::Error::FILE_OK) { - *output_file = base::File(error); - } else { - *output_file = std::move(file); - } -} - -void LevelDBMojoProxy::SyncDirectoryImpl(OpaqueDir* dir, - std::string name, - base::File::Error* out_error) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - filesystem::mojom::DirectoryPtr target; - bool completed = dir->directory->OpenDirectory( - name, MakeRequest(&target), - filesystem::mojom::kFlagRead | filesystem::mojom::kFlagWrite, out_error); - DCHECK(completed); - - if (*out_error != base::File::Error::FILE_OK) - return; - - completed = target->Flush(out_error); - DCHECK(completed); -} - -void LevelDBMojoProxy::FileExistsImpl(OpaqueDir* dir, - std::string name, - bool* exists) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - base::File::Error error = base::File::Error::FILE_ERROR_FAILED; - bool completed = dir->directory->Exists(name, &error, exists); - DCHECK(completed); -} - -void LevelDBMojoProxy::GetChildrenImpl(OpaqueDir* dir, - std::string name, - std::vector<std::string>* out_contents, - base::File::Error* out_error) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - filesystem::mojom::DirectoryPtr target; - bool completed = dir->directory->OpenDirectory( - name, mojo::MakeRequest(&target), - filesystem::mojom::kFlagRead | filesystem::mojom::kFlagWrite, out_error); - DCHECK(completed); - - if (*out_error != base::File::Error::FILE_OK) - return; - - base::Optional<std::vector<filesystem::mojom::DirectoryEntryPtr>> - directory_contents; - completed = target->Read(out_error, &directory_contents); - DCHECK(completed); - - if (directory_contents.has_value()) { - for (size_t i = 0; i < directory_contents->size(); ++i) - out_contents->push_back( - directory_contents.value()[i]->name.AsUTF8Unsafe()); - } -} - -void LevelDBMojoProxy::DeleteImpl(OpaqueDir* dir, - std::string name, - uint32_t delete_flags, - base::File::Error* out_error) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - bool completed = dir->directory->Delete(name, delete_flags, out_error); - DCHECK(completed); -} - -void LevelDBMojoProxy::CreateDirImpl(OpaqueDir* dir, - std::string name, - base::File::Error* out_error) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - bool completed = dir->directory->OpenDirectory( - name, mojo::NullReceiver(), - filesystem::mojom::kFlagRead | filesystem::mojom::kFlagWrite | - filesystem::mojom::kFlagCreate, - out_error); - DCHECK(completed); -} - -void LevelDBMojoProxy::GetFileSizeImpl(OpaqueDir* dir, - const std::string& path, - uint64_t* file_size, - base::File::Error* out_error) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - filesystem::mojom::FileInformationPtr info; - bool completed = dir->directory->StatFile(path, out_error, &info); - DCHECK(completed); - if (info) - *file_size = info->size; -} - -void LevelDBMojoProxy::RenameFileImpl(OpaqueDir* dir, - const std::string& old_path, - const std::string& new_path, - base::File::Error* out_error) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - bool completed = dir->directory->Replace(old_path, new_path, out_error); - DCHECK(completed); -} - -void LevelDBMojoProxy::LockFileImpl(OpaqueDir* dir, - const std::string& path, - base::File::Error* out_error, - OpaqueLock** out_lock) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - // Since a lock is associated with a file descriptor, we need to open and - // have a persistent file on the other side of the connection. - filesystem::mojom::FilePtr target; - bool completed = dir->directory->OpenFile(path, mojo::MakeRequest(&target), - filesystem::mojom::kFlagOpenAlways | - filesystem::mojom::kFlagRead | - filesystem::mojom::kFlagWrite, - out_error); - DCHECK(completed); - - if (*out_error != base::File::Error::FILE_OK) - return; - - completed = target->Lock(out_error); - DCHECK(completed); - - if (*out_error == base::File::Error::FILE_OK) { - OpaqueLock* l = new OpaqueLock; - l->lock_file = std::move(target); - *out_lock = l; - } -} - -void LevelDBMojoProxy::UnlockFileImpl(std::unique_ptr<OpaqueLock> lock, - base::File::Error* out_error) { - mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync; - lock->lock_file->Unlock(out_error); -} - -} // namespace leveldb diff --git a/chromium/components/services/leveldb/leveldb_mojo_proxy.h b/chromium/components/services/leveldb/leveldb_mojo_proxy.h deleted file mode 100644 index 3c9309e979d..00000000000 --- a/chromium/components/services/leveldb/leveldb_mojo_proxy.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJO_PROXY_H_ -#define COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJO_PROXY_H_ - -#include <map> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/callback_forward.h" -#include "base/files/file.h" -#include "base/memory/ref_counted.h" -#include "base/sequenced_task_runner.h" - -#include "base/synchronization/waitable_event.h" -#include "components/services/filesystem/public/mojom/directory.mojom.h" - -namespace leveldb { - -// A proxy for thread safe access to Mojo objects from multiple threads. -// -// MojoEnv is an object passed to the LevelDB implementation which can be -// called from multiple threads. Mojo pipes are bound to a single -// thread. Because of this mismatch, we create a proxy object which will -// redirect calls to the thread which owns the Mojo pipe, sends and receives -// messages. -// -// All public methods can be accessed from any thread. -class LevelDBMojoProxy : public base::RefCountedThreadSafe<LevelDBMojoProxy> { - public: - explicit LevelDBMojoProxy( - scoped_refptr<base::SequencedTaskRunner> task_runner); - - // A private struct to hide the underlying file that holds the lock from our - // callers, forcing them to go through our LockFile()/UnlockFile() interface - // so that they don't try to use the underlying pointer from an unsafe thread. - struct OpaqueLock; - - // A private struct to hide the underlying root directory that we're - // operating in. LevelDBMojoProxy will want to own all the directory - // pointers, so while opening a database, we pass the directory to the thread - // it will be operated on. - struct OpaqueDir; - - // Passes ownership of a |directory| to the other thread, giving a reference - // handle back to the caller. - OpaqueDir* RegisterDirectory(filesystem::mojom::DirectoryPtr directory); - void UnregisterDirectory(OpaqueDir* dir); - - // Synchronously calls Directory.OpenFileHandle(). - base::File OpenFileHandle(OpaqueDir* dir, - const std::string& name, - uint32_t open_flags); - - // Synchronously syncs |directory_|. - base::File::Error SyncDirectory(OpaqueDir* dir, const std::string& name); - - // Synchronously checks whether |name| exists. - bool FileExists(OpaqueDir* dir, const std::string& name); - - // Synchronously returns the filenames of all files in |path|. - base::File::Error GetChildren(OpaqueDir* dir, - const std::string& path, - std::vector<std::string>* result); - - // Synchronously deletes |path|. - base::File::Error Delete(OpaqueDir* dir, - const std::string& path, - uint32_t delete_flags); - - // Synchronously creates |path|. - base::File::Error CreateDir(OpaqueDir* dir, const std::string& path); - - // Synchronously gets the size of a file. - base::File::Error GetFileSize(OpaqueDir* dir, - const std::string& path, - uint64_t* file_size); - - // Synchronously renames a file. - base::File::Error RenameFile(OpaqueDir* dir, - const std::string& old_path, - const std::string& new_path); - - // Synchronously locks a file. Returns both the file return code, and if OK, - // an opaque object to the lock to enforce going through this interface to - // unlock the file so that unlocking happens on the correct thread. - std::pair<base::File::Error, OpaqueLock*> LockFile(OpaqueDir* dir, - const std::string& path); - - // Unlocks a file. LevelDBMojoProxy takes ownership of lock. (We don't make - // this a scoped_ptr because exporting the ctor/dtor for this struct publicly - // defeats the purpose of the struct.) - base::File::Error UnlockFile(OpaqueLock* lock); - - private: - friend class base::RefCountedThreadSafe<LevelDBMojoProxy>; - ~LevelDBMojoProxy(); - - void RunInternal(const base::Closure& task); - - void DoOnOtherThread(const base::Closure& c, base::WaitableEvent* event); - - // Implementation methods of the public interface. Depending on whether they - // were called from the thread that |task_runner_| is, these might be run - // on the current thread or through PostTask(). - void RegisterDirectoryImpl( - mojo::InterfacePtrInfo<filesystem::mojom::Directory> directory_info, - OpaqueDir** out_dir); - void UnregisterDirectoryImpl(OpaqueDir* dir); - void OpenFileHandleImpl(OpaqueDir* dir, - std::string name, - uint32_t open_flags, - base::File* out_file); - void SyncDirectoryImpl(OpaqueDir* dir, - std::string name, - base::File::Error* out_error); - void FileExistsImpl(OpaqueDir* dir, std::string name, bool* exists); - void GetChildrenImpl(OpaqueDir* dir, - std::string name, - std::vector<std::string>* contents, - base::File::Error* out_error); - void DeleteImpl(OpaqueDir* dir, - std::string name, - uint32_t delete_flags, - base::File::Error* out_error); - void CreateDirImpl(OpaqueDir* dir, - std::string name, - base::File::Error* out_error); - void GetFileSizeImpl(OpaqueDir* dir, - const std::string& path, - uint64_t* file_size, - base::File::Error* out_error); - void RenameFileImpl(OpaqueDir* dir, - const std::string& old_path, - const std::string& new_path, - base::File::Error* out_error); - void LockFileImpl(OpaqueDir* dir, - const std::string& path, - base::File::Error* out_error, - OpaqueLock** out_lock); - void UnlockFileImpl(std::unique_ptr<OpaqueLock> lock, - base::File::Error* out_error); - - // The task runner which represents the sequence that all mojo objects are - // bound to. - scoped_refptr<base::SequencedTaskRunner> task_runner_; - - int outstanding_opaque_dirs_; - - DISALLOW_COPY_AND_ASSIGN(LevelDBMojoProxy); -}; - -} // namespace leveldb - -#endif // COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJO_PROXY_H_ diff --git a/chromium/components/services/leveldb/leveldb_mojo_unittest.cc b/chromium/components/services/leveldb/leveldb_mojo_unittest.cc deleted file mode 100644 index 8a1efefcc6f..00000000000 --- a/chromium/components/services/leveldb/leveldb_mojo_unittest.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -#include "components/services/leveldb/leveldb_mojom_traits.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/leveldatabase/leveldb_chrome.h" - -namespace { - -class LevelDBServiceMojoTest : public testing::Test {}; - -} // namespace - -TEST(LevelDBServiceMojoTest, TestSerialization) { - leveldb_env::Options input; - // Tweak all input values to have a non-default value. - input.create_if_missing = !input.create_if_missing; - input.error_if_exists = !input.error_if_exists; - input.paranoid_checks = !input.paranoid_checks; - input.write_buffer_size += 1; - input.max_open_files += 1; - input.block_cache = leveldb_chrome::GetSharedWebBlockCache(); - - leveldb_env::Options output; - ASSERT_TRUE(leveldb::mojom::OpenOptions::Deserialize( - leveldb::mojom::OpenOptions::Serialize(&input), &output)); - - EXPECT_EQ(output.create_if_missing, output.create_if_missing); - EXPECT_EQ(output.error_if_exists, output.error_if_exists); - EXPECT_EQ(output.paranoid_checks, output.paranoid_checks); - EXPECT_EQ(output.write_buffer_size, output.write_buffer_size); - EXPECT_EQ(output.max_open_files, output.max_open_files); - EXPECT_EQ(leveldb_chrome::GetSharedWebBlockCache(), output.block_cache); -} diff --git a/chromium/components/services/leveldb/leveldb_mojom_traits.cc b/chromium/components/services/leveldb/leveldb_mojom_traits.cc deleted file mode 100644 index 0403c350907..00000000000 --- a/chromium/components/services/leveldb/leveldb_mojom_traits.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/services/leveldb/leveldb_mojom_traits.h" - -#include "third_party/leveldatabase/env_chromium.h" -#include "third_party/leveldatabase/leveldb_chrome.h" - -namespace mojo { - -bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>:: - create_if_missing(const leveldb_env::Options& options) { - return options.create_if_missing; -} - -bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>:: - error_if_exists(const leveldb_env::Options& options) { - return options.error_if_exists; -} - -bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>:: - paranoid_checks(const leveldb_env::Options& options) { - return options.paranoid_checks; -} - -uint64_t -StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>:: - write_buffer_size(const leveldb_env::Options& options) { - return options.write_buffer_size; -} - -int32_t StructTraits< - leveldb::mojom::OpenOptionsDataView, - leveldb_env::Options>::max_open_files(const leveldb_env::Options& options) { - return options.max_open_files; -} - -leveldb::mojom::SharedReadCache -StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>:: - shared_block_read_cache(const leveldb_env::Options& options) { - // The Mojo wrapper for leveldb only supports using one of two different - // shared caches. Chrome's Mojo wrapper does not currently support custom - // caches, nor nullptr to have leveldb create the block read cache. - if (!options.block_cache) { - // Specify either Default or Web. - NOTREACHED(); - return leveldb::mojom::SharedReadCache::Default; - } - if (options.block_cache == leveldb_chrome::GetSharedWebBlockCache()) - return leveldb::mojom::SharedReadCache::Web; - - leveldb_env::Options default_options; - // If failing see comment above. - DCHECK_EQ(default_options.block_cache, options.block_cache); - - return leveldb::mojom::SharedReadCache::Default; -} - -bool StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options>:: - Read(leveldb::mojom::OpenOptionsDataView data, leveldb_env::Options* out) { - out->create_if_missing = data.create_if_missing(); - out->error_if_exists = data.error_if_exists(); - out->paranoid_checks = data.paranoid_checks(); - out->write_buffer_size = data.write_buffer_size(); - out->max_open_files = data.max_open_files(); - switch (data.shared_block_read_cache()) { - case leveldb::mojom::SharedReadCache::Default: { - leveldb_env::Options options; - out->block_cache = options.block_cache; - } break; - case leveldb::mojom::SharedReadCache::Web: - out->block_cache = leveldb_chrome::GetSharedWebBlockCache(); - break; - } - - return true; -} - -} // namespace mojo diff --git a/chromium/components/services/leveldb/leveldb_mojom_traits.h b/chromium/components/services/leveldb/leveldb_mojom_traits.h deleted file mode 100644 index 2bbfafd503e..00000000000 --- a/chromium/components/services/leveldb/leveldb_mojom_traits.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJOM_TRAITS_H_ -#define COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJOM_TRAITS_H_ - -#include "components/services/leveldb/public/mojom/leveldb.mojom.h" - -namespace mojo { - -template <> -struct StructTraits<leveldb::mojom::OpenOptionsDataView, leveldb_env::Options> { - static bool create_if_missing(const leveldb_env::Options& options); - static bool error_if_exists(const leveldb_env::Options& options); - static bool paranoid_checks(const leveldb_env::Options& options); - static uint64_t write_buffer_size(const leveldb_env::Options& options); - static int32_t max_open_files(const leveldb_env::Options& options); - static ::leveldb::mojom::SharedReadCache shared_block_read_cache( - const leveldb_env::Options& options); - static bool Read(::leveldb::mojom::OpenOptionsDataView data, - leveldb_env::Options* out); -}; - -} // namespace mojo - -#endif // COMPONENTS_SERVICES_LEVELDB_LEVELDB_MOJOM_TRAITS_H_ diff --git a/chromium/components/services/leveldb/leveldb_service_impl.cc b/chromium/components/services/leveldb/leveldb_service_impl.cc deleted file mode 100644 index ca312231e1e..00000000000 --- a/chromium/components/services/leveldb/leveldb_service_impl.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/services/leveldb/leveldb_service_impl.h" - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/sequenced_task_runner.h" -#include "components/services/leveldb/env_mojo.h" -#include "components/services/leveldb/leveldb_database_impl.h" -#include "components/services/leveldb/public/cpp/util.h" -#include "mojo/public/cpp/bindings/pending_associated_receiver.h" -#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" -#include "third_party/leveldatabase/leveldb_chrome.h" -#include "third_party/leveldatabase/src/include/leveldb/db.h" -#include "third_party/leveldatabase/src/include/leveldb/filter_policy.h" -#include "third_party/leveldatabase/src/include/leveldb/slice.h" - -namespace leveldb { - -namespace { -void CreateReceiver( - std::unique_ptr<LevelDBDatabaseImpl> db, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> receiver) { - // The database should be able to close the binding if it gets into an - // error condition that can't be recovered. - LevelDBDatabaseImpl* impl = db.get(); - impl->SetCloseBindingClosure(base::BindOnce( - &mojo::StrongAssociatedBinding<mojom::LevelDBDatabase>::Close, - mojo::MakeSelfOwnedAssociatedReceiver(std::move(db), - std::move(receiver)))); -} - -} // namespace - -LevelDBServiceImpl::LevelDBServiceImpl( - scoped_refptr<base::SequencedTaskRunner> file_task_runner) - : thread_(new LevelDBMojoProxy(std::move(file_task_runner))) {} - -LevelDBServiceImpl::~LevelDBServiceImpl() {} - -void LevelDBServiceImpl::Open( - filesystem::mojom::DirectoryPtr directory, - const std::string& dbname, - const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& - memory_dump_id, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> database, - OpenCallback callback) { - leveldb_env::Options options; - // the default here to 80 instead of leveldb's default 1000 because we don't - // want to consume all file descriptors. See - // https://code.google.com/p/chromium/issues/detail?id=227313#c11 for - // details.) - options.max_open_files = 80; - - OpenWithOptions(options, std::move(directory), dbname, memory_dump_id, - std::move(database), std::move(callback)); -} - -void LevelDBServiceImpl::OpenWithOptions( - const leveldb_env::Options& options, - filesystem::mojom::DirectoryPtr directory, - const std::string& dbname, - const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& - memory_dump_id, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> database, - OpenCallback callback) { - // Register our directory with the file thread. - LevelDBMojoProxy::OpaqueDir* dir = - thread_->RegisterDirectory(std::move(directory)); - - std::unique_ptr<MojoEnv> env_mojo(new MojoEnv(thread_, dir)); - leveldb_env::Options open_options = options; - open_options.env = env_mojo.get(); - - std::unique_ptr<leveldb::DB> db; - leveldb::Status s = leveldb_env::OpenDB(open_options, dbname, &db); - - if (s.ok()) { - CreateReceiver(std::make_unique<LevelDBDatabaseImpl>( - std::move(env_mojo), std::move(db), nullptr, - open_options, dbname, memory_dump_id), - std::move(database)); - } - - std::move(callback).Run(LeveldbStatusToError(s)); -} - -void LevelDBServiceImpl::OpenInMemory( - const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& - memory_dump_id, - const std::string& tracking_name, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> database, - OpenCallback callback) { - leveldb_env::Options options; - options.create_if_missing = true; - options.max_open_files = 0; // Use minimum. - - auto env = leveldb_chrome::NewMemEnv(tracking_name); - options.env = env.get(); - - std::unique_ptr<leveldb::DB> db; - leveldb::Status s = leveldb_env::OpenDB(options, "", &db); - - if (s.ok()) { - CreateReceiver(std::make_unique<LevelDBDatabaseImpl>( - std::move(env), std::move(db), nullptr, options, - tracking_name, memory_dump_id), - std::move(database)); - } - - std::move(callback).Run(LeveldbStatusToError(s)); -} - -void LevelDBServiceImpl::Destroy(filesystem::mojom::DirectoryPtr directory, - const std::string& dbname, - DestroyCallback callback) { - leveldb_env::Options options; - // Register our directory with the file thread. - LevelDBMojoProxy::OpaqueDir* dir = - thread_->RegisterDirectory(std::move(directory)); - std::unique_ptr<MojoEnv> env_mojo(new MojoEnv(thread_, dir)); - options.env = env_mojo.get(); - std::move(callback).Run( - LeveldbStatusToError(leveldb::DestroyDB(dbname, options))); -} - -} // namespace leveldb diff --git a/chromium/components/services/leveldb/leveldb_service_impl.h b/chromium/components/services/leveldb/leveldb_service_impl.h deleted file mode 100644 index 0665d5abbf5..00000000000 --- a/chromium/components/services/leveldb/leveldb_service_impl.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SERVICES_LEVELDB_LEVELDB_SERVICE_IMPL_H_ -#define COMPONENTS_SERVICES_LEVELDB_LEVELDB_SERVICE_IMPL_H_ - -#include "base/memory/ref_counted.h" -#include "components/services/leveldb/leveldb_mojo_proxy.h" -#include "components/services/leveldb/public/mojom/leveldb.mojom.h" -#include "mojo/public/cpp/bindings/pending_associated_receiver.h" - -namespace base { -class SequencedTaskRunner; -} - -namespace leveldb { - -// Creates LevelDBDatabases based scoped to a |directory|/|dbname|. -class LevelDBServiceImpl : public mojom::LevelDBService { - public: - // The |file_task_runner| is used to run tasks to interact with the - // file_service. Specifically this task runner must NOT be the same as the - // task runner this implementation runs on, or deadlock might occur. - explicit LevelDBServiceImpl( - scoped_refptr<base::SequencedTaskRunner> file_task_runner); - ~LevelDBServiceImpl() override; - - // Overridden from LevelDBService: - void Open( - filesystem::mojom::DirectoryPtr directory, - const std::string& dbname, - const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& - memory_dump_id, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> database, - OpenCallback callback) override; - void OpenWithOptions( - const leveldb_env::Options& open_options, - filesystem::mojom::DirectoryPtr directory, - const std::string& dbname, - const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& - memory_dump_id, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> database, - OpenCallback callback) override; - void OpenInMemory( - const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>& - memory_dump_id, - const std::string& tracking_name, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> database, - OpenInMemoryCallback callback) override; - void Destroy(filesystem::mojom::DirectoryPtr directory, - const std::string& dbname, - DestroyCallback callback) override; - - private: - // Thread to own the mojo message pipe. Because leveldb spawns multiple - // threads that want to call file stuff, we create a dedicated thread to send - // and receive mojo message calls. - scoped_refptr<LevelDBMojoProxy> thread_; - - DISALLOW_COPY_AND_ASSIGN(LevelDBServiceImpl); -}; - -} // namespace leveldb - -#endif // COMPONENTS_SERVICES_LEVELDB_LEVELDB_SERVICE_IMPL_H_ diff --git a/chromium/components/services/leveldb/leveldb_service_unittest.cc b/chromium/components/services/leveldb/leveldb_service_unittest.cc deleted file mode 100644 index 0dc185c481e..00000000000 --- a/chromium/components/services/leveldb/leveldb_service_unittest.cc +++ /dev/null @@ -1,833 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "base/task/post_task.h" -#include "base/test/scoped_feature_list.h" -#include "base/test/task_environment.h" -#include "components/services/filesystem/directory_test_helper.h" -#include "components/services/filesystem/public/mojom/directory.mojom.h" -#include "components/services/filesystem/public/mojom/types.mojom.h" -#include "components/services/leveldb/leveldb_service_impl.h" -#include "components/services/leveldb/public/cpp/util.h" -#include "components/services/leveldb/public/mojom/leveldb.mojom.h" -#include "mojo/public/cpp/bindings/associated_remote.h" -#include "mojo/public/cpp/bindings/pending_associated_receiver.h" -#include "mojo/public/cpp/bindings/remote.h" -#include "mojo/public/cpp/bindings/self_owned_receiver.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/leveldatabase/leveldb_features.h" - -namespace leveldb { -namespace { - -template <typename... Args> -void IgnoreAllArgs(Args&&...) {} - -template <typename... Args> -void DoCaptures(typename std::decay<Args>::type*... out_args, - const base::Closure& quit_closure, - Args... in_args) { - IgnoreAllArgs((*out_args = std::move(in_args))...); - quit_closure.Run(); -} - -template <typename T1> -base::Callback<void(T1)> Capture(T1* t1, const base::Closure& quit_closure) { - return base::Bind(&DoCaptures<T1>, t1, quit_closure); -} - -template <typename T1, typename T2> -base::Callback<void(T1, T2)> Capture(T1* t1, - T2* t2, - const base::Closure& quit_closure) { - return base::Bind(&DoCaptures<T1, T2>, t1, t2, quit_closure); -} - -template <typename T1> -base::Callback<void(const T1&)> CaptureConstRef( - T1* t1, - const base::Closure& quit_closure) { - return base::Bind(&DoCaptures<const T1&>, t1, quit_closure); -} - -template <typename T1, typename T2> -base::Callback<void(T1, const T2&)> -CaptureConstRef(T1* t1, T2* t2, const base::Closure& quit_closure) { - return base::Bind(&DoCaptures<T1, const T2&>, t1, t2, quit_closure); -} - -void DatabaseSyncPut(mojom::LevelDBDatabase* database, - const std::string& key, - const std::string& value, - mojom::DatabaseError* out_error) { - base::RunLoop run_loop; - database->Put(StdStringToUint8Vector(key), StdStringToUint8Vector(value), - Capture(out_error, run_loop.QuitClosure())); - run_loop.Run(); -} - -void DatabaseSyncGet(mojom::LevelDBDatabase* database, - const std::string& key, - mojom::DatabaseError* out_error, - std::vector<uint8_t>* out_value) { - base::RunLoop run_loop; - database->Get(StdStringToUint8Vector(key), - CaptureConstRef(out_error, out_value, run_loop.QuitClosure())); - run_loop.Run(); -} - -void DatabaseSyncGetPrefixed(mojom::LevelDBDatabase* database, - const std::string& key_prefix, - mojom::DatabaseError* out_error, - std::vector<mojom::KeyValuePtr>* out_key_values) { - base::RunLoop run_loop; - database->GetPrefixed( - StdStringToUint8Vector(key_prefix), - Capture(out_error, out_key_values, run_loop.QuitClosure())); - run_loop.Run(); -} - -void DatabaseSyncGetMany( - mojom::LevelDBDatabase* database, - std::vector<mojom::GetManyRequestPtr>& keys_or_prefixes, - std::vector<mojom::GetManyResultPtr>* out_values) { - base::RunLoop run_loop; - database->GetMany(std::move(keys_or_prefixes), - Capture(out_values, run_loop.QuitClosure())); - run_loop.Run(); -} - -void DatabaseSyncCopyPrefixed(mojom::LevelDBDatabase* database, - const std::string& source_key_prefix, - const std::string& destination_key_prefix, - mojom::DatabaseError* out_error) { - base::RunLoop run_loop; - database->CopyPrefixed(StdStringToUint8Vector(source_key_prefix), - StdStringToUint8Vector(destination_key_prefix), - Capture(out_error, run_loop.QuitClosure())); - run_loop.Run(); -} - -void DatabaseSyncDelete(mojom::LevelDBDatabase* database, - const std::string& key, - mojom::DatabaseError* out_error) { - base::RunLoop run_loop; - database->Delete(StdStringToUint8Vector(key), - Capture(out_error, run_loop.QuitClosure())); - run_loop.Run(); -} - -void DatabaseSyncDeletePrefixed(mojom::LevelDBDatabase* database, - const std::string& key_prefix, - mojom::DatabaseError* out_error) { - base::RunLoop run_loop; - database->DeletePrefixed(StdStringToUint8Vector(key_prefix), - Capture(out_error, run_loop.QuitClosure())); - run_loop.Run(); -} - -void DatabaseSyncRewrite(mojom::LevelDBDatabase* database, - mojom::DatabaseError* out_error) { - base::RunLoop run_loop; - database->RewriteDB(Capture(out_error, run_loop.QuitClosure())); - run_loop.Run(); -} - -void LevelDBSyncOpenInMemory( - mojom::LevelDBService* leveldb, - mojo::PendingAssociatedReceiver<leveldb::mojom::LevelDBDatabase> database, - mojom::DatabaseError* out_error) { - base::RunLoop run_loop; - leveldb->OpenInMemory(base::nullopt, "LevelDBSync", std::move(database), - Capture(out_error, run_loop.QuitClosure())); - run_loop.Run(); -} - -void AddKeyToGetManyRequest(const std::string& key, - std::vector<mojom::GetManyRequestPtr>* list) { - std::vector<uint8_t> in_arg = StdStringToUint8Vector(key); - list->emplace_back(mojom::GetManyRequest::NewKey(in_arg)); -} - -void AddKeyPrefixToGetManyRequest(const std::string& key_prefix, - std::vector<mojom::GetManyRequestPtr>* list) { - std::vector<uint8_t> in_arg = StdStringToUint8Vector(key_prefix); - list->emplace_back(mojom::GetManyRequest::NewKeyPrefix(in_arg)); -} - -class LevelDBServiceTest : public testing::Test { - public: - LevelDBServiceTest() - : leveldb_service_(base::CreateSequencedTaskRunner( - {base::ThreadPool(), base::MayBlock(), - base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), - leveldb_receiver_(&leveldb_service_, - leveldb_remote_.BindNewPipeAndPassReceiver()) {} - ~LevelDBServiceTest() override = default; - - protected: - void SetUp() override { - // TODO(dullweber): This doesn't seem to work. The reason is probably that - // the LevelDB service is a separate executable here. How should we set - // features that affect a service? - feature_list_.InitAndEnableFeature(leveldb::kLevelDBRewriteFeature); - } - - mojo::Remote<filesystem::mojom::Directory> CreateTempDir() { - return directory_helper_.CreateTempDir(); - } - - mojo::Remote<mojom::LevelDBService>& leveldb() { return leveldb_remote_; } - - private: - base::test::TaskEnvironment task_environment_; - base::test::ScopedFeatureList feature_list_; - filesystem::DirectoryTestHelper directory_helper_; - LevelDBServiceImpl leveldb_service_; - mojo::Remote<mojom::LevelDBService> leveldb_remote_; - mojo::Receiver<mojom::LevelDBService> leveldb_receiver_; - - DISALLOW_COPY_AND_ASSIGN(LevelDBServiceTest); -}; - -TEST_F(LevelDBServiceTest, Basic) { - mojom::DatabaseError error; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write a key to the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Read the key back from the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - std::vector<uint8_t> value; - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); - - // Delete the key from the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncDelete(database.get(), "key", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Read the key back from the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - value.clear(); - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error); - EXPECT_EQ("", Uint8VectorToStdString(value)); -} - -TEST_F(LevelDBServiceTest, WriteBatch) { - mojom::DatabaseError error; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write a key to the database. - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Create a batched operation which both deletes "key" and adds another write. - std::vector<mojom::BatchedOperationPtr> operations; - mojom::BatchedOperationPtr item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::DELETE_KEY; - item->key = StdStringToUint8Vector("key"); - operations.push_back(std::move(item)); - - item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::PUT_KEY; - item->key = StdStringToUint8Vector("other"); - item->value = StdStringToUint8Vector("more"); - operations.push_back(std::move(item)); - - base::RunLoop run_loop; - database->Write(std::move(operations), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Reading "key" should be invalid now. - error = mojom::DatabaseError::INVALID_ARGUMENT; - std::vector<uint8_t> value; - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error); - EXPECT_EQ("", Uint8VectorToStdString(value)); - - // Reading "other" should return "more" - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncGet(database.get(), "other", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("more", Uint8VectorToStdString(value)); - - // Write a some prefixed keys to the database. - DatabaseSyncPut(database.get(), "prefix-key1", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - DatabaseSyncPut(database.get(), "prefix-key2", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Create batched operations to copy and then delete the 'prefix' data. - operations.clear(); - item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::COPY_PREFIXED_KEY; - item->key = StdStringToUint8Vector("prefix"); - item->value = StdStringToUint8Vector("copy-prefix"); - operations.push_back(std::move(item)); - item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::DELETE_PREFIXED_KEY; - item->key = StdStringToUint8Vector("prefix"); - operations.push_back(std::move(item)); - base::RunLoop run_loop2; - database->Write(std::move(operations), - Capture(&error, run_loop2.QuitClosure())); - run_loop2.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Reading all "prefix" keys should be invalid now. - error = mojom::DatabaseError::INVALID_ARGUMENT; - value.clear(); - DatabaseSyncGet(database.get(), "prefix-key1", &error, &value); - EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error); - EXPECT_EQ("", Uint8VectorToStdString(value)); - // Reading "key" should be invalid now. - error = mojom::DatabaseError::INVALID_ARGUMENT; - value.clear(); - DatabaseSyncGet(database.get(), "prefix-key2", &error, &value); - EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error); - EXPECT_EQ("", Uint8VectorToStdString(value)); - - // Prefix keys should have been copied to 'copy-prefix' before deletion. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncGet(database.get(), "copy-prefix-key1", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncGet(database.get(), "copy-prefix-key2", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); -} - -TEST_F(LevelDBServiceTest, WriteBatchPrefixesAndDeletes) { - // This test makes sure that prefixes & deletes happen before all other batch - // operations. - mojom::DatabaseError error; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write a key to the database. - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // The copy applies as if it happens before this write batch. - // The delete applies to all keys that existed before these changes. - std::vector<mojom::BatchedOperationPtr> operations; - mojom::BatchedOperationPtr item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::PUT_KEY; - item->key = StdStringToUint8Vector("key"); - item->value = StdStringToUint8Vector("new_value"); - operations.push_back(std::move(item)); - - item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::PUT_KEY; - item->key = StdStringToUint8Vector("key2"); - item->value = StdStringToUint8Vector("value2"); - operations.push_back(std::move(item)); - - item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::DELETE_PREFIXED_KEY; - item->key = StdStringToUint8Vector("k"); - operations.push_back(std::move(item)); - - item = mojom::BatchedOperation::New(); - item->type = mojom::BatchOperationType::COPY_PREFIXED_KEY; - item->key = StdStringToUint8Vector("k"); - item->value = StdStringToUint8Vector("f"); - operations.push_back(std::move(item)); - base::RunLoop run_loop; - database->Write(std::move(operations), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - std::vector<uint8_t> value; - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error); - DatabaseSyncGet(database.get(), "key2", &error, &value); - EXPECT_EQ("value2", Uint8VectorToStdString(value)); - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncGet(database.get(), "fey", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); -} - -TEST_F(LevelDBServiceTest, Reconnect) { - mojom::DatabaseError error; - - mojo::Remote<filesystem::mojom::Directory> temp_directory = CreateTempDir(); - - { - filesystem::mojom::DirectoryPtr directory; - temp_directory->Clone(MakeRequest(&directory)); - - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - leveldb_env::Options options; - options.error_if_exists = true; - options.create_if_missing = true; - base::RunLoop run_loop; - leveldb()->OpenWithOptions(std::move(options), std::move(directory), "test", - base::nullopt, - database.BindNewEndpointAndPassReceiver(), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write a key to the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // The database should go out of scope here. - } - - { - filesystem::mojom::DirectoryPtr directory; - temp_directory->Clone(MakeRequest(&directory)); - - // Reconnect to the database. - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - base::RunLoop run_loop; - leveldb()->Open(std::move(directory), "test", base::nullopt, - database.BindNewEndpointAndPassReceiver(), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // We should still be able to read the key back from the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - std::vector<uint8_t> value; - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); - } -} - -TEST_F(LevelDBServiceTest, Destroy) { - mojom::DatabaseError error; - - mojo::Remote<filesystem::mojom::Directory> temp_directory = CreateTempDir(); - - { - filesystem::mojom::DirectoryPtr directory; - temp_directory->Clone(MakeRequest(&directory)); - - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - leveldb_env::Options options; - options.error_if_exists = true; - options.create_if_missing = true; - base::RunLoop run_loop; - leveldb()->OpenWithOptions(std::move(options), std::move(directory), "test", - base::nullopt, - database.BindNewEndpointAndPassReceiver(), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write a key to the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // The database should go out of scope here. - } - - { - filesystem::mojom::DirectoryPtr directory; - temp_directory->Clone(MakeRequest(&directory)); - - // Destroy the database. - base::RunLoop run_loop; - leveldb()->Destroy(std::move(directory), "test", - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - } - - { - filesystem::mojom::DirectoryPtr directory; - temp_directory->Clone(MakeRequest(&directory)); - - // Reconnect to the database should fail. - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - base::RunLoop run_loop; - leveldb()->Open(std::move(directory), "test", base::nullopt, - database.BindNewEndpointAndPassReceiver(), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::INVALID_ARGUMENT, error); - } - - { - filesystem::mojom::DirectoryPtr directory; - temp_directory->Clone(MakeRequest(&directory)); - - // Destroying a non-existant database should still succeed. - base::RunLoop run_loop; - leveldb()->Destroy(std::move(directory), "test", - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - } -} - -TEST_F(LevelDBServiceTest, GetSnapshotSimple) { - mojom::DatabaseError error; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - base::UnguessableToken snapshot; - base::RunLoop run_loop; - database->GetSnapshot(CaptureConstRef(&snapshot, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_FALSE(snapshot.is_empty()); -} - -TEST_F(LevelDBServiceTest, GetFromSnapshots) { - mojom::DatabaseError error; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write a key to the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Take a snapshot where key=value. - base::UnguessableToken key_value_snapshot; - base::RunLoop run_loop; - database->GetSnapshot( - CaptureConstRef(&key_value_snapshot, run_loop.QuitClosure())); - run_loop.Run(); - - // Change key to "yek". - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "key", "yek", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // (Ensure this change is live on the database.) - error = mojom::DatabaseError::INVALID_ARGUMENT; - std::vector<uint8_t> value; - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("yek", Uint8VectorToStdString(value)); - - // But if we were to read from the snapshot, we'd still get value. - error = mojom::DatabaseError::INVALID_ARGUMENT; - value.clear(); - base::RunLoop run_loop2; - database->GetFromSnapshot( - key_value_snapshot, StdStringToUint8Vector("key"), - CaptureConstRef(&error, &value, run_loop2.QuitClosure())); - run_loop2.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); -} - -TEST_F(LevelDBServiceTest, InvalidArgumentOnInvalidSnapshot) { - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - mojom::DatabaseError error = mojom::DatabaseError::INVALID_ARGUMENT; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - base::UnguessableToken invalid_snapshot = base::UnguessableToken::Create(); - - error = mojom::DatabaseError::OK; - std::vector<uint8_t> value; - base::RunLoop run_loop; - database->GetFromSnapshot( - invalid_snapshot, StdStringToUint8Vector("key"), - CaptureConstRef(&error, &value, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::INVALID_ARGUMENT, error); -} - -TEST_F(LevelDBServiceTest, MemoryDBReadWrite) { - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - mojom::DatabaseError error = mojom::DatabaseError::INVALID_ARGUMENT; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write a key to the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Read the key back from the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - std::vector<uint8_t> value; - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); - - // Delete the key from the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncDelete(database.get(), "key", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Read the key back from the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - value.clear(); - DatabaseSyncGet(database.get(), "key", &error, &value); - EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error); - EXPECT_EQ("", Uint8VectorToStdString(value)); -} - -TEST_F(LevelDBServiceTest, Prefixed) { - // Open an in memory database for speed. - mojom::DatabaseError error = mojom::DatabaseError::INVALID_ARGUMENT; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - const std::string prefix("prefix"); - const std::string copy_prefix("foo"); - std::vector<mojom::KeyValuePtr> key_values; - - // Completely empty database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_TRUE(key_values.empty()); - - // No values with our prefix, but values before and after. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "a-before-prefix", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "z-after-prefix", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - key_values.clear(); - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_TRUE(key_values.empty()); - - // One value with the exact prefix. - DatabaseSyncPut(database.get(), prefix, "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - error = mojom::DatabaseError::INVALID_ARGUMENT; - key_values.clear(); - DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ(1u, key_values.size()); - EXPECT_EQ("prefix", Uint8VectorToStdString(key_values[0]->key)); - EXPECT_EQ("value", Uint8VectorToStdString(key_values[0]->value)); - - // Multiple values with starting with the prefix. - DatabaseSyncPut(database.get(), (prefix + "2"), "value2", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - error = mojom::DatabaseError::INVALID_ARGUMENT; - key_values.clear(); - DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ(2u, key_values.size()); - EXPECT_EQ("prefix", Uint8VectorToStdString(key_values[0]->key)); - EXPECT_EQ("value", Uint8VectorToStdString(key_values[0]->value)); - EXPECT_EQ("prefix2", Uint8VectorToStdString(key_values[1]->key)); - EXPECT_EQ("value2", Uint8VectorToStdString(key_values[1]->value)); - - // Copy to a different prefix - DatabaseSyncCopyPrefixed(database.get(), prefix, copy_prefix, &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - DatabaseSyncGetPrefixed(database.get(), copy_prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - ASSERT_EQ(2u, key_values.size()); - EXPECT_EQ("foo", Uint8VectorToStdString(key_values[0]->key)); - EXPECT_EQ("value", Uint8VectorToStdString(key_values[0]->value)); - EXPECT_EQ("foo2", Uint8VectorToStdString(key_values[1]->key)); - EXPECT_EQ("value2", Uint8VectorToStdString(key_values[1]->value)); - - // Delete the prefixed values. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncDeletePrefixed(database.get(), prefix, &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - error = mojom::DatabaseError::INVALID_ARGUMENT; - key_values.clear(); - DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_TRUE(key_values.empty()); - - // Make sure the others are not deleted. - std::vector<uint8_t> value; - DatabaseSyncGet(database.get(), "a-before-prefix", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); - value.clear(); - DatabaseSyncGet(database.get(), "z-after-prefix", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value", Uint8VectorToStdString(value)); - DatabaseSyncGetPrefixed(database.get(), copy_prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ(2u, key_values.size()); - - // A key having our prefix, but no key matching it exactly. - // Even thought there is no exact matching key, GetPrefixed - // and DeletePrefixed still operate on the values. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), (prefix + "2"), "value2", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - error = mojom::DatabaseError::INVALID_ARGUMENT; - key_values.clear(); - DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ(1u, key_values.size()); - EXPECT_EQ("prefix2", Uint8VectorToStdString(key_values[0]->key)); - EXPECT_EQ("value2", Uint8VectorToStdString(key_values[0]->value)); - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncDeletePrefixed(database.get(), prefix, &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - error = mojom::DatabaseError::INVALID_ARGUMENT; - key_values.clear(); - DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_TRUE(key_values.empty()); -} - -TEST_F(LevelDBServiceTest, RewriteDB) { - mojom::DatabaseError error; - filesystem::mojom::DirectoryPtr directory(CreateTempDir().Unbind()); - - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - leveldb_env::Options options; - options.create_if_missing = true; - base::RunLoop run_loop; - leveldb()->OpenWithOptions(std::move(options), std::move(directory), "test", - base::nullopt, - database.BindNewEndpointAndPassReceiver(), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write entries to the database. - DatabaseSyncPut(database.get(), "key1", "value1", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - DatabaseSyncPut(database.get(), "key2", "value2", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Delete key 1. - DatabaseSyncDelete(database.get(), "key1", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Perform a rewrite. - DatabaseSyncRewrite(database.get(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Read the keys back from the database. - std::vector<uint8_t> value; - DatabaseSyncGet(database.get(), "key1", &error, &value); - EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error); - DatabaseSyncGet(database.get(), "key2", &error, &value); - EXPECT_EQ(mojom::DatabaseError::OK, error); - EXPECT_EQ("value2", Uint8VectorToStdString(value)); -} - -TEST_F(LevelDBServiceTest, GetMany) { - mojom::DatabaseError error; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database; - LevelDBSyncOpenInMemory(leveldb().get(), - database.BindNewEndpointAndPassReceiver(), &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - // Write two keys to the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - DatabaseSyncPut(database.get(), "key", "value", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - DatabaseSyncPut(database.get(), "key1", "value1", &error); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - std::vector<mojom::GetManyRequestPtr> requests; - std::vector<mojom::GetManyResultPtr> results; - - // Test: Read keys back from the database - AddKeyToGetManyRequest("key", &requests); - AddKeyToGetManyRequest("key1", &requests); - AddKeyPrefixToGetManyRequest("key", &requests); - DatabaseSyncGetMany(database.get(), requests, &results); - - ASSERT_EQ(results.size(), 3UL); - EXPECT_TRUE(results[0]->is_key_value()); - EXPECT_TRUE(results[1]->is_key_value()); - EXPECT_EQ(Uint8VectorToStdString(results[0]->get_key_value()), "value"); - EXPECT_EQ(Uint8VectorToStdString(results[1]->get_key_value()), "value1"); - - // Test: the last key-prefix read should correctly return a list of KeyValue - EXPECT_TRUE(results[2]->is_key_prefix_values()); - const std::vector<mojom::KeyValuePtr>& kv = - results[2]->get_key_prefix_values(); - ASSERT_EQ(2UL, kv.size()); - EXPECT_EQ("key", Uint8VectorToStdString(kv[0]->key)); - EXPECT_EQ("value", Uint8VectorToStdString(kv[0]->value)); - EXPECT_EQ("key1", Uint8VectorToStdString(kv[1]->key)); - EXPECT_EQ("value1", Uint8VectorToStdString(kv[1]->value)); - - // Test: Read a sequence of (existing key, non-existing key, - // existing key), GetMany should return NOT_FOUND for the non-existing key - requests.clear(); - results.clear(); - - AddKeyToGetManyRequest("key", &requests); - AddKeyToGetManyRequest("key-not-found", &requests); - AddKeyToGetManyRequest("key", &requests); - DatabaseSyncGetMany(database.get(), requests, &results); - - ASSERT_EQ(results.size(), 3UL); - EXPECT_EQ(Uint8VectorToStdString(results[0]->get_key_value()), "value"); - EXPECT_TRUE(results[1]->is_status()); - EXPECT_TRUE(results[1]->get_status() == mojom::DatabaseError::NOT_FOUND); - EXPECT_EQ(Uint8VectorToStdString(results[2]->get_key_value()), "value"); - - // Test: Read a sequence of (existing key, non-existing key prefix, - // existing key), GetMany should return empty data for the non-existing - // key prefix - requests.clear(); - results.clear(); - - AddKeyToGetManyRequest("key", &requests); - AddKeyPrefixToGetManyRequest("key-prefix-not-found", &requests); - AddKeyToGetManyRequest("key", &requests); - DatabaseSyncGetMany(database.get(), requests, &results); - - ASSERT_EQ(results.size(), 3UL); - EXPECT_EQ(Uint8VectorToStdString(results[0]->get_key_value()), "value"); - EXPECT_TRUE(results[1]->get_key_prefix_values().empty()); - EXPECT_EQ(Uint8VectorToStdString(results[2]->get_key_value()), "value"); - - // Test: Read empty data - requests.clear(); - results.clear(); - DatabaseSyncGetMany(database.get(), requests, &results); - EXPECT_TRUE(results.empty()); -} - -} // namespace -} // namespace leveldb diff --git a/chromium/components/services/leveldb/public/cpp/BUILD.gn b/chromium/components/services/leveldb/public/cpp/BUILD.gn index 033466eb05a..24e3edb522f 100644 --- a/chromium/components/services/leveldb/public/cpp/BUILD.gn +++ b/chromium/components/services/leveldb/public/cpp/BUILD.gn @@ -4,8 +4,6 @@ static_library("cpp") { sources = [ - "remote_iterator.cc", - "remote_iterator.h", "util.cc", "util.h", ] diff --git a/chromium/components/services/leveldb/public/cpp/remote_iterator.cc b/chromium/components/services/leveldb/public/cpp/remote_iterator.cc deleted file mode 100644 index 0f9b5996100..00000000000 --- a/chromium/components/services/leveldb/public/cpp/remote_iterator.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/services/leveldb/public/cpp/remote_iterator.h" - -#include "components/services/leveldb/public/cpp/util.h" - -namespace leveldb { - -RemoteIterator::RemoteIterator(mojom::LevelDBDatabase* database, - const base::UnguessableToken& iterator) - : database_(database), - iterator_(iterator), - valid_(false), - status_(mojom::DatabaseError::OK) {} - -RemoteIterator::~RemoteIterator() { - database_->ReleaseIterator(iterator_); -} - -bool RemoteIterator::Valid() const { - return valid_; -} - -void RemoteIterator::SeekToFirst() { - database_->IteratorSeekToFirst(iterator_, &valid_, &status_, &key_, &value_); -} - -void RemoteIterator::SeekToLast() { - database_->IteratorSeekToLast(iterator_, &valid_, &status_, &key_, &value_); -} - -void RemoteIterator::Seek(const Slice& target) { - database_->IteratorSeek(iterator_, GetVectorFor(target), &valid_, &status_, - &key_, &value_); -} - -void RemoteIterator::Next() { - database_->IteratorNext(iterator_, &valid_, &status_, &key_, &value_); -} - -void RemoteIterator::Prev() { - database_->IteratorPrev(iterator_, &valid_, &status_, &key_, &value_); -} - -Slice RemoteIterator::key() const { - if (!key_) - return leveldb::Slice(); - return GetSliceFor(*key_); -} - -Slice RemoteIterator::value() const { - if (!value_) - return leveldb::Slice(); - return GetSliceFor(*value_); -} - -Status RemoteIterator::status() const { - return DatabaseErrorToStatus(status_, key(), value()); -} - -} // namespace leveldb diff --git a/chromium/components/services/leveldb/public/cpp/remote_iterator.h b/chromium/components/services/leveldb/public/cpp/remote_iterator.h deleted file mode 100644 index cad8da8b839..00000000000 --- a/chromium/components/services/leveldb/public/cpp/remote_iterator.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SERVICES_LEVELDB_PUBLIC_CPP_REMOTE_ITERATOR_H_ -#define COMPONENTS_SERVICES_LEVELDB_PUBLIC_CPP_REMOTE_ITERATOR_H_ - -#include "base/unguessable_token.h" -#include "components/services/leveldb/public/mojom/leveldb.mojom.h" -#include "third_party/leveldatabase/src/include/leveldb/iterator.h" - -namespace leveldb { - -// A wrapper around the raw iterator movement methods on the mojo leveldb -// interface to allow drop in replacement to current leveldb usage. -// -// Note: Next(), Prev() and all the Seek*() calls cause mojo sync calls. -class RemoteIterator : public Iterator { - public: - RemoteIterator(mojom::LevelDBDatabase* database, - const base::UnguessableToken& iterator); - ~RemoteIterator() override; - - // Overridden from leveldb::Iterator: - bool Valid() const override; - void SeekToFirst() override; - void SeekToLast() override; - void Seek(const Slice& target) override; - void Next() override; - void Prev() override; - Slice key() const override; - Slice value() const override; - Status status() const override; - - private: - mojom::LevelDBDatabase* database_; - base::UnguessableToken iterator_; - - bool valid_; - mojom::DatabaseError status_; - base::Optional<std::vector<uint8_t>> key_; - base::Optional<std::vector<uint8_t>> value_; - - DISALLOW_COPY_AND_ASSIGN(RemoteIterator); -}; - -} // namespace leveldb - -#endif // COMPONENTS_SERVICES_LEVELDB_PUBLIC_CPP_REMOTE_ITERATOR_H_ diff --git a/chromium/components/services/leveldb/public/cpp/util.cc b/chromium/components/services/leveldb/public/cpp/util.cc index 0bcdcfe4309..0b61b11bd54 100644 --- a/chromium/components/services/leveldb/public/cpp/util.cc +++ b/chromium/components/services/leveldb/public/cpp/util.cc @@ -10,63 +10,6 @@ namespace leveldb { -mojom::DatabaseError LeveldbStatusToError(const leveldb::Status& s) { - if (s.ok()) - return mojom::DatabaseError::OK; - if (s.IsNotFound()) - return mojom::DatabaseError::NOT_FOUND; - if (s.IsCorruption()) - return mojom::DatabaseError::CORRUPTION; - if (s.IsNotSupportedError()) - return mojom::DatabaseError::NOT_SUPPORTED; - if (s.IsIOError()) - return mojom::DatabaseError::IO_ERROR; - return mojom::DatabaseError::INVALID_ARGUMENT; -} - -leveldb::Status DatabaseErrorToStatus(mojom::DatabaseError e, - const Slice& msg, - const Slice& msg2) { - switch (e) { - case mojom::DatabaseError::OK: - return leveldb::Status::OK(); - case mojom::DatabaseError::NOT_FOUND: - return leveldb::Status::NotFound(msg, msg2); - case mojom::DatabaseError::CORRUPTION: - return leveldb::Status::Corruption(msg, msg2); - case mojom::DatabaseError::NOT_SUPPORTED: - return leveldb::Status::NotSupported(msg, msg2); - case mojom::DatabaseError::INVALID_ARGUMENT: - return leveldb::Status::InvalidArgument(msg, msg2); - case mojom::DatabaseError::IO_ERROR: - return leveldb::Status::IOError(msg, msg2); - } - - // This will never be reached, but we still have configurations which don't - // do switch enum checking. - return leveldb::Status::InvalidArgument(msg, msg2); -} - -leveldb_env::LevelDBStatusValue GetLevelDBStatusUMAValue( - mojom::DatabaseError status) { - switch (status) { - case mojom::DatabaseError::OK: - return leveldb_env::LEVELDB_STATUS_OK; - case mojom::DatabaseError::NOT_FOUND: - return leveldb_env::LEVELDB_STATUS_NOT_FOUND; - case mojom::DatabaseError::CORRUPTION: - return leveldb_env::LEVELDB_STATUS_CORRUPTION; - case mojom::DatabaseError::NOT_SUPPORTED: - return leveldb_env::LEVELDB_STATUS_NOT_SUPPORTED; - case mojom::DatabaseError::INVALID_ARGUMENT: - return leveldb_env::LEVELDB_STATUS_INVALID_ARGUMENT; - case mojom::DatabaseError::IO_ERROR: - return leveldb_env::LEVELDB_STATUS_IO_ERROR; - } - NOTREACHED(); - return leveldb_env::LEVELDB_STATUS_OK; -} - leveldb::Slice GetSliceFor(const std::vector<uint8_t>& key) { if (key.size() == 0) return leveldb::Slice(); diff --git a/chromium/components/services/leveldb/public/cpp/util.h b/chromium/components/services/leveldb/public/cpp/util.h index b45b2fa9596..a3044e74f4e 100644 --- a/chromium/components/services/leveldb/public/cpp/util.h +++ b/chromium/components/services/leveldb/public/cpp/util.h @@ -9,27 +9,11 @@ #include <vector> #include "base/strings/string16.h" -#include "components/services/leveldb/public/mojom/leveldb.mojom.h" #include "third_party/leveldatabase/env_chromium.h" namespace leveldb { class Slice; -class Status; - -// Builds a mojo mojom::DatabaseError from a leveldb::Status object. -mojom::DatabaseError LeveldbStatusToError(const leveldb::Status& s); - -// Creates a leveldb Status object form a database error and two optional -// messages. A mojoification of the various static leveldb::Status -// constructors. -leveldb::Status DatabaseErrorToStatus(mojom::DatabaseError e, - const Slice& msg, - const Slice& msg2); - -// Returns an UMA value for a mojom::DatabaseError. -leveldb_env::LevelDBStatusValue GetLevelDBStatusUMAValue( - mojom::DatabaseError status); // Builds a Slice pointing to the data inside |a|. This is not a type-converter // as it is not a copy operation; the returned Slice points into |a| and must diff --git a/chromium/components/services/leveldb/public/mojom/BUILD.gn b/chromium/components/services/leveldb/public/mojom/BUILD.gn index 79572d0f510..6434221598f 100644 --- a/chromium/components/services/leveldb/public/mojom/BUILD.gn +++ b/chromium/components/services/leveldb/public/mojom/BUILD.gn @@ -5,17 +5,7 @@ import("//mojo/public/tools/bindings/mojom.gni") mojom("mojom") { - support_lazy_serialization = true - sources = [ "leveldb.mojom", ] - - deps = [ - "//components/services/filesystem/public/mojom", - ] - - public_deps = [ - "//mojo/public/mojom/base", - ] } diff --git a/chromium/components/services/leveldb/public/mojom/leveldb.mojom b/chromium/components/services/leveldb/public/mojom/leveldb.mojom index 3de269f8cf5..4bc70cf1f83 100644 --- a/chromium/components/services/leveldb/public/mojom/leveldb.mojom +++ b/chromium/components/services/leveldb/public/mojom/leveldb.mojom @@ -4,19 +4,6 @@ module leveldb.mojom; -import "components/services/filesystem/public/mojom/directory.mojom"; -import "mojo/public/mojom/base/memory_allocator_dump_cross_process_uid.mojom"; -import "mojo/public/mojom/base/unguessable_token.mojom"; - -enum DatabaseError { - OK, - NOT_FOUND, - CORRUPTION, - NOT_SUPPORTED, - INVALID_ARGUMENT, - IO_ERROR -}; - enum BatchOperationType { PUT_KEY, DELETE_KEY, @@ -37,178 +24,3 @@ struct KeyValue { array<uint8> key; array<uint8> value; }; - -union GetManyRequest { - array<uint8> key_prefix; - array<uint8> key; -}; - -union GetManyResult { - DatabaseError status; - array<KeyValue> key_prefix_values; - array<uint8> key_value; -}; - -enum SharedReadCache { - Default, - Web, -}; - -// Options which control the behavior of a database. (This struct corresponds -// with the struct in leveldb's options.h.) -// -// Note: This struct does not have default values. The values are set by a -// struct trait which copies values to/from a leveldb_env::Options instance. -struct OpenOptions { - // TODO(erg): Find all comparators and copy them into the service. - - // If true, the database will be created if it is missing. - bool create_if_missing; - - // If true, an error is raised if the database already exists. - bool error_if_exists; - - // If true, the implementation will do aggressive checking of the - // data it is processing and will stop early if it detects any - // errors. - bool paranoid_checks; - - // Amount of data to build up in memory (backed by an unsorted log - // on disk) before converting to a sorted on-disk file. - uint64 write_buffer_size; - - // Number of open files that can be used by the DB. - int32 max_open_files; - - // The shared read cache to use. - SharedReadCache shared_block_read_cache = SharedReadCache.Default; -}; - -// Service which hands out databases. -interface LevelDBService { - // Open the database with the specified "name" in the specified "directory". - // Fails if the database doesn't already exist. - Open(filesystem.mojom.Directory directory, - string dbname, - mojo_base.mojom.MemoryAllocatorDumpCrossProcessUid? memory_dump_id, - pending_associated_receiver<LevelDBDatabase> database) - => (DatabaseError status); - - // Open the database with the specified "name" in the specified "directory". - OpenWithOptions(OpenOptions options, - filesystem.mojom.Directory directory, - string dbname, - mojo_base.mojom.MemoryAllocatorDumpCrossProcessUid? - memory_dump_id, - pending_associated_receiver<LevelDBDatabase> database) - => (DatabaseError status); - - // Opens a database stored purely in memory. - // "tracking_name" will be used for memory-infra reporting to associate memory - // use with its origin. - OpenInMemory(mojo_base.mojom.MemoryAllocatorDumpCrossProcessUid? - memory_dump_id, string tracking_name, - pending_associated_receiver<LevelDBDatabase> database) - => (DatabaseError status); - - // Destroys the contents of the specified database. Returns OK if the database - // already didn't exist. - Destroy(filesystem.mojom.Directory directory, - string dbname) => (DatabaseError status); -}; - -// A leveldb database. -interface LevelDBDatabase { - // Basic Interface ------------------------------------------------------- - - // Sets the database entry for "key" to "value". Returns OK on success. - Put(array<uint8> key, array<uint8> value) => (DatabaseError status); - - // Remove the database entry (if any) for "key". Returns OK on - // success, and a non-OK status on error. It is not an error if "key" - // did not exist in the database. - Delete(array<uint8> key) => (DatabaseError status); - - DeletePrefixed(array<uint8> key_prefix) => (DatabaseError status); - - // Rewrites the database to remove traces of deleted entries from disk. - // Returns OK on success. A non-OK error means that the rewrite failed. - // If the status is not OK, the database can become unusable which will close - // the mojo connection. - RewriteDB() => (DatabaseError status); - - // Atomically performs all |operations|. - // The DELETE_PREFIXED_KEY applies to all keys that exist before these - // operations execute. If a 'put' operation precedes a delete prefix, then it - // will only be deleted if it was a previously-populated key in the database. - // The COPY_PREFIXED_KEY operations will always ignore all other changes in - // the operations batch. It will not copy records that were inserted earlier - // in the operations list. - Write(array<BatchedOperation> operations) => (DatabaseError status); - - Get(array<uint8> key) => (DatabaseError status, array<uint8> value); - - GetPrefixed(array<uint8> key_prefix) - => (DatabaseError status, array<KeyValue> data); - - // Get multiple keys and key prefixes and return corresponding values or - // non-OK error in the same order. Each request has a corresponding result - // in the same array position. A result can only be either a non-OK - // db status or a value for the key or key prefix. - GetMany(array<GetManyRequest> keys_or_prefixes) - => (array<GetManyResult> data); - - // Copies all data from the source prefix to the destination prefix. Useful - // for deep copies. - CopyPrefixed(array<uint8> source_key_prefix, - array<uint8> destination_key_prefix) - => (DatabaseError status); - - // Snapshots ------------------------------------------------------------- - - // Returns a handle to the current database state. - GetSnapshot() => (mojo_base.mojom.UnguessableToken snapshot); - - // Releases a previously acquired snapshot. - ReleaseSnapshot(mojo_base.mojom.UnguessableToken snapshot); - - // If |key| exists at the time |snapshot_id| was taken, return OK and the - // value. Otherwise return NOT_FOUND. - GetFromSnapshot(mojo_base.mojom.UnguessableToken snapshot, - array<uint8> key) - => (DatabaseError status, array<uint8> value); - - // Iteartors ------------------------------------------------------------- - - // Creates an iterator, either from the current view or from a snapshot. - NewIterator() => (mojo_base.mojom.UnguessableToken iterator); - NewIteratorFromSnapshot(mojo_base.mojom.UnguessableToken snapshot) - => (mojo_base.mojom.UnguessableToken? iterator); - - ReleaseIterator(mojo_base.mojom.UnguessableToken iterator); - - // Positions the iterator at the first key, last key, or the first key after - // |target|. - [Sync] - IteratorSeekToFirst(mojo_base.mojom.UnguessableToken iterator) - => (bool valid, DatabaseError status, array<uint8>? key, - array<uint8>? value); - [Sync] - IteratorSeekToLast(mojo_base.mojom.UnguessableToken iterator) - => (bool valid, DatabaseError status, array<uint8>? key, - array<uint8>? value); - [Sync] - IteratorSeek(mojo_base.mojom.UnguessableToken iterator, array<uint8> target) - => (bool valid, DatabaseError status, array<uint8>? key, - array<uint8>? value); - - // Moves forward or backwards in iterator space. - [Sync] - IteratorNext(mojo_base.mojom.UnguessableToken iterator) - => (bool valid, DatabaseError status, array<uint8>? key, - array<uint8>? value); - [Sync] - IteratorPrev(mojo_base.mojom.UnguessableToken iterator) - => (bool valid, DatabaseError status, array<uint8>? key, - array<uint8>? value); -}; diff --git a/chromium/components/services/leveldb/remote_iterator_unittest.cc b/chromium/components/services/leveldb/remote_iterator_unittest.cc deleted file mode 100644 index a53273331de..00000000000 --- a/chromium/components/services/leveldb/remote_iterator_unittest.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <map> - -#include "base/bind.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "base/task/post_task.h" -#include "base/test/task_environment.h" -#include "components/services/leveldb/leveldb_service_impl.h" -#include "components/services/leveldb/public/cpp/remote_iterator.h" -#include "components/services/leveldb/public/cpp/util.h" -#include "components/services/leveldb/public/mojom/leveldb.mojom.h" -#include "mojo/public/cpp/bindings/associated_remote.h" -#include "mojo/public/cpp/bindings/receiver.h" -#include "mojo/public/cpp/bindings/remote.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace leveldb { -namespace { - -template <typename... Args> -void IgnoreAllArgs(Args&&...) {} - -template <typename... Args> -void DoCaptures(typename std::decay<Args>::type*... out_args, - const base::Closure& quit_closure, - Args... in_args) { - IgnoreAllArgs((*out_args = std::move(in_args))...); - quit_closure.Run(); -} - -template <typename T1> -base::Callback<void(T1)> Capture(T1* t1, const base::Closure& quit_closure) { - return base::Bind(&DoCaptures<T1>, t1, quit_closure); -} - -base::Callback<void(const base::UnguessableToken&)> CaptureToken( - base::UnguessableToken* t1, - const base::Closure& quit_closure) { - return base::Bind(&DoCaptures<const base::UnguessableToken&>, t1, - quit_closure); -} - -class RemoteIteratorTest : public testing::Test { - public: - RemoteIteratorTest() - : leveldb_service_(base::CreateSequencedTaskRunner( - {base::ThreadPool(), base::MayBlock(), - base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), - leveldb_receiver_(&leveldb_service_, - leveldb_remote_.BindNewPipeAndPassReceiver()) {} - ~RemoteIteratorTest() override = default; - - protected: - void SetUp() override { - mojom::DatabaseError error; - base::RunLoop run_loop; - leveldb()->OpenInMemory(base::nullopt, "RemoteIteratorTest", - database_.BindNewEndpointAndPassReceiver(), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - - std::map<std::string, std::string> data{ - {"a", "first"}, {"b:suffix", "second"}, {"c", "third"}}; - - for (auto p : data) { - // Write a key to the database. - error = mojom::DatabaseError::INVALID_ARGUMENT; - base::RunLoop run_loop; - database_->Put(StdStringToUint8Vector(p.first), - StdStringToUint8Vector(p.second), - Capture(&error, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_EQ(mojom::DatabaseError::OK, error); - } - } - - mojo::Remote<mojom::LevelDBService>& leveldb() { return leveldb_remote_; } - mojo::AssociatedRemote<mojom::LevelDBDatabase>& database() { - return database_; - } - - private: - base::test::TaskEnvironment task_environment_; - LevelDBServiceImpl leveldb_service_; - mojo::Remote<mojom::LevelDBService> leveldb_remote_; - mojo::Receiver<mojom::LevelDBService> leveldb_receiver_; - mojo::AssociatedRemote<mojom::LevelDBDatabase> database_; - - DISALLOW_COPY_AND_ASSIGN(RemoteIteratorTest); -}; - -TEST_F(RemoteIteratorTest, Seeking) { - base::UnguessableToken iterator; - base::RunLoop run_loop; - database()->NewIterator(CaptureToken(&iterator, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_FALSE(iterator.is_empty()); - - RemoteIterator it(database().get(), iterator); - EXPECT_FALSE(it.Valid()); - - it.SeekToFirst(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("a", it.key()); - EXPECT_EQ("first", it.value()); - - it.SeekToLast(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("c", it.key()); - EXPECT_EQ("third", it.value()); - - it.Seek("b"); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("b:suffix", it.key()); - EXPECT_EQ("second", it.value()); -} - -TEST_F(RemoteIteratorTest, Next) { - base::UnguessableToken iterator; - base::RunLoop run_loop; - database()->NewIterator(CaptureToken(&iterator, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_FALSE(iterator.is_empty()); - - RemoteIterator it(database().get(), iterator); - EXPECT_FALSE(it.Valid()); - - it.SeekToFirst(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("a", it.key()); - EXPECT_EQ("first", it.value()); - - it.Next(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("b:suffix", it.key()); - EXPECT_EQ("second", it.value()); - - it.Next(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("c", it.key()); - EXPECT_EQ("third", it.value()); - - it.Next(); - EXPECT_FALSE(it.Valid()); -} - -TEST_F(RemoteIteratorTest, Prev) { - base::UnguessableToken iterator; - base::RunLoop run_loop; - database()->NewIterator(CaptureToken(&iterator, run_loop.QuitClosure())); - run_loop.Run(); - EXPECT_FALSE(iterator.is_empty()); - - RemoteIterator it(database().get(), iterator); - EXPECT_FALSE(it.Valid()); - - it.SeekToLast(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("c", it.key()); - EXPECT_EQ("third", it.value()); - - it.Prev(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("b:suffix", it.key()); - EXPECT_EQ("second", it.value()); - - it.Prev(); - EXPECT_TRUE(it.Valid()); - EXPECT_EQ("a", it.key()); - EXPECT_EQ("first", it.value()); - - it.Prev(); - EXPECT_FALSE(it.Valid()); -} - -} // namespace -} // namespace leveldb diff --git a/chromium/components/services/patch/public/cpp/patch.cc b/chromium/components/services/patch/public/cpp/patch.cc index 60c3a2f2774..83fcbc62adf 100644 --- a/chromium/components/services/patch/public/cpp/patch.cc +++ b/chromium/components/services/patch/public/cpp/patch.cc @@ -38,8 +38,8 @@ class PatchParams : public base::RefCounted<PatchParams> { ~PatchParams() = default; - // The FilePatcherPtr is stored so it does not get deleted before the callback - // runs. + // The mojo::Remote<FilePatcher> is stored so it does not get deleted before + // the callback runs. mojo::Remote<mojom::FilePatcher> file_patcher_; PatchCallback callback_; diff --git a/chromium/components/services/pdf_compositor/pdf_compositor_impl.cc b/chromium/components/services/pdf_compositor/pdf_compositor_impl.cc index b4fd83e3e2c..a1d3264e413 100644 --- a/chromium/components/services/pdf_compositor/pdf_compositor_impl.cc +++ b/chromium/components/services/pdf_compositor/pdf_compositor_impl.cc @@ -18,6 +18,7 @@ #include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h" #include "content/public/utility/utility_thread.h" #include "mojo/public/cpp/base/shared_memory_utils.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/system/platform_handle.h" #include "printing/common/metafile_utils.h" #include "third_party/blink/public/platform/web_image_generator.h" @@ -46,6 +47,9 @@ PdfCompositorImpl::PdfCompositorImpl( if (receiver) receiver_.Bind(std::move(receiver)); + if (!initialize_environment) + return; + #if defined(OS_WIN) // Initialize direct write font proxy so skia can use it. content::InitializeDWriteFontProxy(); @@ -55,9 +59,6 @@ PdfCompositorImpl::PdfCompositorImpl( SkGraphics::SetImageGeneratorFromEncodedDataFactory( blink::WebImageGenerator::CreateAsSkImageGenerator); - if (!initialize_environment) - return; - #if defined(OS_POSIX) && !defined(OS_ANDROID) content::UtilityThread::Get()->EnsureBlinkInitializedWithSandboxSupport(); // Check that we have sandbox support on this platform. @@ -85,11 +86,11 @@ void PdfCompositorImpl::SetDiscardableSharedMemoryManager( mojo::PendingRemote< discardable_memory::mojom::DiscardableSharedMemoryManager> manager) { // Set up discardable memory manager. - discardable_memory::mojom::DiscardableSharedMemoryManagerPtr manager_ptr( - std::move(manager)); + mojo::PendingRemote<discardable_memory::mojom::DiscardableSharedMemoryManager> + manager_remote(std::move(manager)); discardable_shared_memory_manager_ = std::make_unique< discardable_memory::ClientDiscardableSharedMemoryManager>( - std::move(manager_ptr), io_task_runner_); + std::move(manager_remote), io_task_runner_); base::DiscardableMemoryAllocator::SetInstance( discardable_shared_memory_manager_.get()); } diff --git a/chromium/components/services/storage/dom_storage/dom_storage_database.cc b/chromium/components/services/storage/dom_storage/dom_storage_database.cc index 184a55008e1..43ee71d3cc1 100644 --- a/chromium/components/services/storage/dom_storage/dom_storage_database.cc +++ b/chromium/components/services/storage/dom_storage/dom_storage_database.cc @@ -21,6 +21,10 @@ namespace storage { namespace { +// IOError message returned whenever a call is made on a DomStorageDatabase +// which has been invalidated (e.g. by a failed |RewriteDB()| operation). +const char kInvalidDatabaseMessage[] = "DomStorageDatabase no longer valid."; + class DomStorageDatabaseEnv : public leveldb_env::ChromiumEnv { public: DomStorageDatabaseEnv() : ChromiumEnv("ChromiumEnv.StorageService") {} @@ -167,11 +171,11 @@ DomStorageDatabase::DomStorageDatabase( env_(std::move(env)), options_(AddEnvToOptions(options, env_ ? env_.get() : GetDomStorageDatabaseEnv())), + memory_dump_id_(memory_dump_id), db_(TryOpenDB(options_, name, std::move(callback_task_runner), - std::move(callback))), - memory_dump_id_(memory_dump_id) { + std::move(callback))) { base::trace_event::MemoryDumpManager::GetInstance() ->RegisterDumpProviderWithSequencedTaskRunner( this, "MojoLevelDB", base::SequencedTaskRunnerHandle::Get(), @@ -181,6 +185,8 @@ DomStorageDatabase::DomStorageDatabase( DomStorageDatabase::~DomStorageDatabase() { base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( this); + if (destruction_callback_) + std::move(destruction_callback_).Run(); } // static @@ -258,6 +264,8 @@ void DomStorageDatabase::Destroy( DomStorageDatabase::Status DomStorageDatabase::Get(KeyView key, Value* out_value) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); std::string value; Status status = db_->Get(leveldb::ReadOptions(), MakeSlice(key), &value); *out_value = Value(value.begin(), value.end()); @@ -267,11 +275,15 @@ DomStorageDatabase::Status DomStorageDatabase::Get(KeyView key, DomStorageDatabase::Status DomStorageDatabase::Put(KeyView key, ValueView value) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); return db_->Put(leveldb::WriteOptions(), MakeSlice(key), MakeSlice(value)); } DomStorageDatabase::Status DomStorageDatabase::Delete(KeyView key) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); return db_->Delete(leveldb::WriteOptions(), MakeSlice(key)); } @@ -279,6 +291,8 @@ DomStorageDatabase::Status DomStorageDatabase::GetPrefixed( KeyView prefix, std::vector<KeyValuePair>* entries) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); return ForEachWithPrefix( db_.get(), prefix, [&](const leveldb::Slice& key, const leveldb::Slice& value) { @@ -287,24 +301,26 @@ DomStorageDatabase::Status DomStorageDatabase::GetPrefixed( } DomStorageDatabase::Status DomStorageDatabase::DeletePrefixed( - KeyView prefix) const { + KeyView prefix, + leveldb::WriteBatch* batch) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - leveldb::WriteBatch batch; + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); Status status = ForEachWithPrefix( db_.get(), prefix, [&](const leveldb::Slice& key, const leveldb::Slice& value) { - batch.Delete(key); + batch->Delete(key); }); - if (!status.ok()) - return status; - return db_->Write(leveldb::WriteOptions(), &batch); + return status; } DomStorageDatabase::Status DomStorageDatabase::CopyPrefixed( KeyView prefix, - KeyView new_prefix) const { + KeyView new_prefix, + leveldb::WriteBatch* batch) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - leveldb::WriteBatch batch; + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); Key new_key(new_prefix.begin(), new_prefix.end()); Status status = ForEachWithPrefix( db_.get(), prefix, @@ -314,11 +330,27 @@ DomStorageDatabase::Status DomStorageDatabase::CopyPrefixed( new_key.resize(new_prefix.size() + suffix_length); std::copy(key.data() + prefix.size(), key.data() + key.size(), new_key.begin() + new_prefix.size()); - batch.Put(MakeSlice(new_key), value); + batch->Put(MakeSlice(new_key), value); }); + return status; +} + +DomStorageDatabase::Status DomStorageDatabase::Commit( + leveldb::WriteBatch* batch) const { + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); + if (fail_commits_for_testing_) + return Status::IOError("Simulated I/O Error"); + return db_->Write(leveldb::WriteOptions(), batch); +} + +DomStorageDatabase::Status DomStorageDatabase::RewriteDB() { + if (!db_) + return Status::IOError(kInvalidDatabaseMessage); + Status status = leveldb_env::RewriteDB(options_, name_, &db_); if (!status.ok()) - return status; - return db_->Write(leveldb::WriteOptions(), &batch); + db_.reset(); + return status; } bool DomStorageDatabase::OnMemoryDump( diff --git a/chromium/components/services/storage/dom_storage/dom_storage_database.h b/chromium/components/services/storage/dom_storage/dom_storage_database.h index aac805a0c6b..ffe142c3c6e 100644 --- a/chromium/components/services/storage/dom_storage/dom_storage_database.h +++ b/chromium/components/services/storage/dom_storage/dom_storage_database.h @@ -25,6 +25,7 @@ #include "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" #include "third_party/leveldatabase/src/include/leveldb/env.h" +#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" namespace storage { @@ -125,12 +126,31 @@ class DomStorageDatabase : private base::trace_event::MemoryDumpProvider { // Gets all database entries whose key starts with |prefix|. Status GetPrefixed(KeyView prefix, std::vector<KeyValuePair>* entries) const; - // Deletes all database entries whose key starts with |prefix|. - Status DeletePrefixed(KeyView prefix) const; + // Adds operations to |batch| which will delete all database entries whose key + // starts with |prefix| when committed. + Status DeletePrefixed(KeyView prefix, leveldb::WriteBatch* batch) const; - // Copies all database entries whose key starts with |prefix| over to new - // entries with |prefix| replaced by |new_prefix| in each new key. - Status CopyPrefixed(KeyView prefix, KeyView new_prefix) const; + // Adds operations to |batch| which when committed will copy all database + // entries whose key starts with |prefix| over to new entries with |prefix| + // replaced by |new_prefix| in each new key. + Status CopyPrefixed(KeyView prefix, + KeyView new_prefix, + leveldb::WriteBatch* batch) const; + + // Commits operations in |batch| to the database. + Status Commit(leveldb::WriteBatch* batch) const; + + // Rewrites the database on disk to clean up traces of deleted entries. + // + // NOTE: If |RewriteDB()| fails, this DomStorageDatabase may no longer be + // usable; in such cases, all future operations will return an IOError status. + Status RewriteDB(); + + void SetDestructionCallbackForTesting(base::OnceClosure callback) { + destruction_callback_ = std::move(callback); + } + + void MakeAllCommitsFailForTesting() { fail_commits_for_testing_ = true; } private: friend class base::SequenceBound<DomStorageDatabase>; @@ -176,9 +196,16 @@ class DomStorageDatabase : private base::trace_event::MemoryDumpProvider { const std::string name_; const std::unique_ptr<leveldb::Env> env_; const leveldb_env::Options options_; - const std::unique_ptr<leveldb::DB> db_; const base::Optional<base::trace_event::MemoryAllocatorDumpGuid> memory_dump_id_; + std::unique_ptr<leveldb::DB> db_; + + // Causes all calls to |Commit()| to fail with an IOError for simulated + // disk failures in testing. + bool fail_commits_for_testing_ = false; + + // Callback to run on destruction in tests. + base::OnceClosure destruction_callback_; SEQUENCE_CHECKER(sequence_checker_); diff --git a/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc b/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc index e3982fc23dd..70fd9a9a222 100644 --- a/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc +++ b/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc @@ -19,6 +19,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/leveldatabase/env_chromium.h" +#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" using ::testing::UnorderedElementsAreArray; @@ -362,7 +363,9 @@ TEST_F(StorageServiceDomStorageDatabaseTest, DeletePrefixed) { // Wipe out the first prefix. We should still see the second prefix. std::vector<DomStorageDatabase::KeyValuePair> entries; - EXPECT_STATUS_OK(db.DeletePrefixed(MakeBytes(kTestPrefix1))); + leveldb::WriteBatch batch; + EXPECT_STATUS_OK(db.DeletePrefixed(MakeBytes(kTestPrefix1), &batch)); + EXPECT_STATUS_OK(db.Commit(&batch)); EXPECT_STATUS_OK(db.GetPrefixed(MakeBytes(kTestPrefix1), &entries)); EXPECT_TRUE(entries.empty()); EXPECT_STATUS_OK(db.GetPrefixed(MakeBytes(kTestPrefix2), &entries)); @@ -372,7 +375,9 @@ TEST_F(StorageServiceDomStorageDatabaseTest, DeletePrefixed) { MakeKeyValuePair(kTestPrefix2Key2, kTestValue3)})); // Wipe out the second prefix. - EXPECT_STATUS_OK(db.DeletePrefixed(MakeBytes(kTestPrefix2))); + batch.Clear(); + EXPECT_STATUS_OK(db.DeletePrefixed(MakeBytes(kTestPrefix2), &batch)); + EXPECT_STATUS_OK(db.Commit(&batch)); EXPECT_STATUS_OK(db.GetPrefixed(MakeBytes(kTestPrefix2), &entries)); // The lone unprefixed value should still exist. @@ -414,8 +419,10 @@ TEST_F(StorageServiceDomStorageDatabaseTest, CopyPrefixed) { // Copy the prefixed entries to |kTestPrefix2| and verify that we have the // expected entries. - EXPECT_STATUS_OK( - db.CopyPrefixed(MakeBytes(kTestPrefix1), MakeBytes(kTestPrefix2))); + leveldb::WriteBatch batch; + EXPECT_STATUS_OK(db.CopyPrefixed(MakeBytes(kTestPrefix1), + MakeBytes(kTestPrefix2), &batch)); + EXPECT_STATUS_OK(db.Commit(&batch)); std::vector<DomStorageDatabase::KeyValuePair> entries; EXPECT_STATUS_OK(db.GetPrefixed(MakeBytes(kTestPrefix2), &entries)); diff --git a/chromium/components/services/storage/partition_impl_unittest.cc b/chromium/components/services/storage/partition_impl_unittest.cc index baa6f45f106..1cd6ad7ac78 100644 --- a/chromium/components/services/storage/partition_impl_unittest.cc +++ b/chromium/components/services/storage/partition_impl_unittest.cc @@ -38,7 +38,7 @@ class StorageServicePartitionImplTest : public testing::Test { PartitionImpl* test_partition_impl() { return test_partition_impl_; } private: - base::test::ScopedTaskEnvironment task_environment_; + base::test::TaskEnvironment task_environment_; mojo::Remote<mojom::StorageService> remote_service_; StorageServiceImpl service_{remote_service_.BindNewPipeAndPassReceiver()}; mojo::Remote<mojom::Partition> remote_test_partition_; diff --git a/chromium/components/services/storage/storage_service_impl_unittest.cc b/chromium/components/services/storage/storage_service_impl_unittest.cc index b852bbccf6c..0533bf31aa7 100644 --- a/chromium/components/services/storage/storage_service_impl_unittest.cc +++ b/chromium/components/services/storage/storage_service_impl_unittest.cc @@ -26,7 +26,7 @@ class StorageServiceImplTest : public testing::Test { StorageServiceImpl& service_impl() { return service_; } private: - base::test::ScopedTaskEnvironment task_environment_; + base::test::TaskEnvironment task_environment_; mojo::Remote<mojom::StorageService> remote_service_; StorageServiceImpl service_{remote_service_.BindNewPipeAndPassReceiver()}; diff --git a/chromium/components/services/unzip/public/cpp/unzip.cc b/chromium/components/services/unzip/public/cpp/unzip.cc index 5e8ffb3b497..d254d6e7f3b 100644 --- a/chromium/components/services/unzip/public/cpp/unzip.cc +++ b/chromium/components/services/unzip/public/cpp/unzip.cc @@ -19,8 +19,9 @@ #include "components/services/filesystem/directory_impl.h" #include "components/services/filesystem/lock_table.h" #include "components/services/unzip/public/mojom/unzipper.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" namespace unzip { @@ -28,9 +29,10 @@ namespace { class UnzipFilter : public unzip::mojom::UnzipFilter { public: - UnzipFilter(unzip::mojom::UnzipFilterRequest request, + UnzipFilter(mojo::PendingReceiver<unzip::mojom::UnzipFilter> receiver, UnzipFilterCallback filter_callback) - : binding_(this, std::move(request)), filter_callback_(filter_callback) {} + : receiver_(this, std::move(receiver)), + filter_callback_(filter_callback) {} private: // unzip::mojom::UnzipFilter implementation: @@ -39,7 +41,7 @@ class UnzipFilter : public unzip::mojom::UnzipFilter { std::move(callback).Run(filter_callback_.Run(path)); } - mojo::Binding<unzip::mojom::UnzipFilter> binding_; + mojo::Receiver<unzip::mojom::UnzipFilter> receiver_; UnzipFilterCallback filter_callback_; DISALLOW_COPY_AND_ASSIGN(UnzipFilter); @@ -111,10 +113,10 @@ void DoUnzipWithFilter( return; } - filesystem::mojom::DirectoryPtr directory_ptr; - mojo::MakeStrongBinding( + mojo::PendingRemote<filesystem::mojom::Directory> directory_remote; + mojo::MakeSelfOwnedReceiver( std::make_unique<filesystem::DirectoryImpl>(output_dir, nullptr, nullptr), - mojo::MakeRequest(&directory_ptr)); + directory_remote.InitWithNewPipeAndPassReceiver()); // |result_callback| is shared between the connection error handler and the // Unzip call using a refcounted UnzipParams object that owns @@ -128,18 +130,18 @@ void DoUnzipWithFilter( if (filter_callback.is_null()) { unzip_params->unzipper()->Unzip(std::move(zip_file), - std::move(directory_ptr), + std::move(directory_remote), base::BindOnce(&UnzipDone, unzip_params)); return; } - unzip::mojom::UnzipFilterPtr unzip_filter_ptr; + mojo::PendingRemote<unzip::mojom::UnzipFilter> unzip_filter_remote; unzip_params->set_unzip_filter(std::make_unique<UnzipFilter>( - mojo::MakeRequest(&unzip_filter_ptr), filter_callback)); + unzip_filter_remote.InitWithNewPipeAndPassReceiver(), filter_callback)); unzip_params->unzipper()->UnzipWithFilter( - std::move(zip_file), std::move(directory_ptr), - std::move(unzip_filter_ptr), base::BindOnce(&UnzipDone, unzip_params)); + std::move(zip_file), std::move(directory_remote), + std::move(unzip_filter_remote), base::BindOnce(&UnzipDone, unzip_params)); } } // namespace diff --git a/chromium/components/services/unzip/public/mojom/unzipper.mojom b/chromium/components/services/unzip/public/mojom/unzipper.mojom index ece5f106949..8fd46f5a943 100644 --- a/chromium/components/services/unzip/public/mojom/unzipper.mojom +++ b/chromium/components/services/unzip/public/mojom/unzipper.mojom @@ -16,13 +16,14 @@ interface UnzipFilter { interface Unzipper { // Unzip |zip_file| into |output_dir|. // Returns true on success, false otherwise. - Unzip(mojo_base.mojom.File zip_file, filesystem.mojom.Directory output_dir) - => (bool result); + Unzip(mojo_base.mojom.File zip_file, + pending_remote<filesystem.mojom.Directory> output_dir) + => (bool result); // Same as |unzip| but only includes the files for which |filter| returns // true. Note that this incurs one IPC for each file of the archive. UnzipWithFilter( mojo_base.mojom.File zip_file, - filesystem.mojom.Directory output_dir, - UnzipFilter filter) => (bool result); + pending_remote<filesystem.mojom.Directory> output_dir, + pending_remote<UnzipFilter> filter) => (bool result); }; diff --git a/chromium/components/services/unzip/unzipper_impl.cc b/chromium/components/services/unzip/unzipper_impl.cc index 76b8a50810d..04602bbf402 100644 --- a/chromium/components/services/unzip/unzipper_impl.cc +++ b/chromium/components/services/unzip/unzipper_impl.cc @@ -12,6 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/services/filesystem/public/mojom/directory.mojom.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/zlib/google/zip.h" #include "third_party/zlib/google/zip_reader.h" @@ -43,26 +44,24 @@ std::string PathToMojoString(const base::FilePath& path) { } // Modifies output_dir to point to the final directory. -bool CreateDirectory(filesystem::mojom::DirectoryPtr* output_dir, +bool CreateDirectory(filesystem::mojom::Directory* output_dir, const base::FilePath& path) { base::File::Error err = base::File::Error::FILE_OK; - return (*output_dir) - ->OpenDirectory(PathToMojoString(path), mojo::NullReceiver(), - filesystem::mojom::kFlagOpenAlways, &err) && + return output_dir->OpenDirectory(PathToMojoString(path), mojo::NullReceiver(), + filesystem::mojom::kFlagOpenAlways, &err) && err == base::File::Error::FILE_OK; } std::unique_ptr<zip::WriterDelegate> MakeFileWriterDelegateNoParent( - filesystem::mojom::DirectoryPtr* output_dir, + filesystem::mojom::Directory* output_dir, const base::FilePath& path) { auto file = std::make_unique<base::File>(); base::File::Error err; - if (!(*output_dir) - ->OpenFileHandle(PathToMojoString(path), - filesystem::mojom::kFlagCreate | - filesystem::mojom::kFlagWrite | - filesystem::mojom::kFlagWriteAttributes, - &err, file.get()) || + if (!output_dir->OpenFileHandle(PathToMojoString(path), + filesystem::mojom::kFlagCreate | + filesystem::mojom::kFlagWrite | + filesystem::mojom::kFlagWriteAttributes, + &err, file.get()) || err != base::File::Error::FILE_OK) { return std::make_unique<DudWriterDelegate>(); } @@ -70,30 +69,29 @@ std::unique_ptr<zip::WriterDelegate> MakeFileWriterDelegateNoParent( } std::unique_ptr<zip::WriterDelegate> MakeFileWriterDelegate( - filesystem::mojom::DirectoryPtr* output_dir, + filesystem::mojom::Directory* output_dir, const base::FilePath& path) { if (path == path.BaseName()) return MakeFileWriterDelegateNoParent(output_dir, path); - filesystem::mojom::DirectoryPtr parent; + mojo::Remote<filesystem::mojom::Directory> parent; base::File::Error err; - if (!(*output_dir) - ->OpenDirectory(PathToMojoString(path.DirName()), - mojo::MakeRequest(&parent), - filesystem::mojom::kFlagOpenAlways, &err) || + if (!output_dir->OpenDirectory(PathToMojoString(path.DirName()), + parent.BindNewPipeAndPassReceiver(), + filesystem::mojom::kFlagOpenAlways, &err) || err != base::File::Error::FILE_OK) { return std::make_unique<DudWriterDelegate>(); } - return MakeFileWriterDelegateNoParent(&parent, path.BaseName()); + return MakeFileWriterDelegateNoParent(parent.get(), path.BaseName()); } bool FilterNoFiles(const base::FilePath& unused) { return true; } -bool FilterWithFilterPtr(mojom::UnzipFilterPtr* filter, - const base::FilePath& path) { +bool FilterWithFilterRemote(mojom::UnzipFilter* filter, + const base::FilePath& path) { bool result = false; - (*filter)->ShouldUnzipFile(path, &result); + filter->ShouldUnzipFile(path, &result); return result; } @@ -106,22 +104,29 @@ UnzipperImpl::UnzipperImpl(mojo::PendingReceiver<mojom::Unzipper> receiver) UnzipperImpl::~UnzipperImpl() = default; -void UnzipperImpl::Unzip(base::File zip_file, - filesystem::mojom::DirectoryPtr output_dir, - UnzipCallback callback) { +void UnzipperImpl::Unzip( + base::File zip_file, + mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote, + UnzipCallback callback) { DCHECK(zip_file.IsValid()); + mojo::Remote<filesystem::mojom::Directory> output_dir( + std::move(output_dir_remote)); std::move(callback).Run(zip::UnzipWithFilterAndWriters( zip_file.GetPlatformFile(), - base::BindRepeating(&MakeFileWriterDelegate, &output_dir), - base::BindRepeating(&CreateDirectory, &output_dir), + base::BindRepeating(&MakeFileWriterDelegate, output_dir.get()), + base::BindRepeating(&CreateDirectory, output_dir.get()), base::BindRepeating(&FilterNoFiles), /*log_skipped_files=*/false)); } -void UnzipperImpl::UnzipWithFilter(base::File zip_file, - filesystem::mojom::DirectoryPtr output_dir, - mojom::UnzipFilterPtr filter, - UnzipCallback callback) { +void UnzipperImpl::UnzipWithFilter( + base::File zip_file, + mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote, + mojo::PendingRemote<mojom::UnzipFilter> filter_remote, + UnzipCallback callback) { DCHECK(zip_file.IsValid()); + mojo::Remote<filesystem::mojom::Directory> output_dir( + std::move(output_dir_remote)); + mojo::Remote<mojom::UnzipFilter> filter(std::move(filter_remote)); // Note that we pass a pointer to |filter| below, as it is a repeating // callback and transferring its value would cause the callback to fail when @@ -130,9 +135,9 @@ void UnzipperImpl::UnzipWithFilter(base::File zip_file, // the method returns. std::move(callback).Run(zip::UnzipWithFilterAndWriters( zip_file.GetPlatformFile(), - base::BindRepeating(&MakeFileWriterDelegate, &output_dir), - base::BindRepeating(&CreateDirectory, &output_dir), - base::BindRepeating(&FilterWithFilterPtr, &filter), + base::BindRepeating(&MakeFileWriterDelegate, output_dir.get()), + base::BindRepeating(&CreateDirectory, output_dir.get()), + base::BindRepeating(&FilterWithFilterRemote, filter.get()), /*log_skipped_files=*/false)); } diff --git a/chromium/components/services/unzip/unzipper_impl.h b/chromium/components/services/unzip/unzipper_impl.h index d5cc821e78c..9de2a096f96 100644 --- a/chromium/components/services/unzip/unzipper_impl.h +++ b/chromium/components/services/unzip/unzipper_impl.h @@ -11,6 +11,7 @@ #include "base/macros.h" #include "components/services/unzip/public/mojom/unzipper.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" namespace unzip { @@ -28,14 +29,16 @@ class UnzipperImpl : public mojom::Unzipper { private: // unzip::mojom::Unzipper: - void Unzip(base::File zip_file, - filesystem::mojom::DirectoryPtr output_dir, - UnzipCallback callback) override; - - void UnzipWithFilter(base::File zip_file, - filesystem::mojom::DirectoryPtr output_dir, - mojom::UnzipFilterPtr filter, - UnzipWithFilterCallback callback) override; + void Unzip( + base::File zip_file, + mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote, + UnzipCallback callback) override; + + void UnzipWithFilter( + base::File zip_file, + mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote, + mojo::PendingRemote<mojom::UnzipFilter> filter_remote, + UnzipWithFilterCallback callback) override; mojo::Receiver<mojom::Unzipper> receiver_{this}; |