Commit 02b84338 authored by Daniel Murphy's avatar Daniel Murphy Committed by Commit Bot

[LevelDBWrapper] Allow Observers to be managed externally.

This change is necessary for mojo'd SessionStorage to manage observers
for shallow copying.

Bug: 716490
Change-Id: I5a899be566327decc3a447fe56b72bfba735ffd6
Reviewed-on: https://chromium-review.googlesource.com/984859Reviewed-by: default avatarKen Rockot <rockot@chromium.org>
Reviewed-by: default avatarOliver Chang <ochang@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Commit-Queue: Daniel Murphy <dmurph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#547619}
parent 195beedf
......@@ -63,7 +63,17 @@ LevelDBWrapperImpl::LevelDBWrapperImpl(
const std::string& prefix,
Delegate* delegate,
const Options& options)
: prefix_(leveldb::StdStringToUint8Vector(prefix)),
: LevelDBWrapperImpl(database,
leveldb::StdStringToUint8Vector(prefix),
delegate,
options) {}
LevelDBWrapperImpl::LevelDBWrapperImpl(
leveldb::mojom::LevelDBDatabase* database,
std::vector<uint8_t> prefix,
Delegate* delegate,
const Options& options)
: prefix_(std::move(prefix)),
delegate_(delegate),
database_(database),
cache_mode_(database ? options.cache_mode : CacheMode::KEYS_AND_VALUES),
......@@ -105,8 +115,16 @@ std::unique_ptr<LevelDBWrapperImpl> LevelDBWrapperImpl::ForkToNewPrefix(
const std::string& new_prefix,
Delegate* delegate,
const Options& options) {
return ForkToNewPrefix(leveldb::StdStringToUint8Vector(new_prefix), delegate,
options);
}
std::unique_ptr<LevelDBWrapperImpl> LevelDBWrapperImpl::ForkToNewPrefix(
std::vector<uint8_t> new_prefix,
Delegate* delegate,
const Options& options) {
auto forked_wrapper = std::make_unique<LevelDBWrapperImpl>(
database_, new_prefix, delegate, options);
database_, std::move(new_prefix), delegate, options);
forked_wrapper->map_state_ = MapState::LOADING_FROM_FORK;
......@@ -196,13 +214,25 @@ void LevelDBWrapperImpl::SetCacheModeForTesting(CacheMode cache_mode) {
SetCacheMode(cache_mode);
}
mojo::InterfacePtrSetElementId LevelDBWrapperImpl::AddObserver(
mojom::LevelDBObserverAssociatedPtr observer) {
if (cache_mode_ == CacheMode::KEYS_AND_VALUES)
observer->ShouldSendOldValueOnMutations(false);
return observers_.AddPtr(std::move(observer));
}
bool LevelDBWrapperImpl::HasObserver(mojo::InterfacePtrSetElementId id) {
return observers_.HasPtr(id);
}
mojom::LevelDBObserverAssociatedPtr LevelDBWrapperImpl::RemoveObserver(
mojo::InterfacePtrSetElementId id) {
return observers_.RemovePtr(id);
}
void LevelDBWrapperImpl::AddObserver(
mojom::LevelDBObserverAssociatedPtrInfo observer) {
mojom::LevelDBObserverAssociatedPtr observer_ptr;
observer_ptr.Bind(std::move(observer));
if (cache_mode_ == CacheMode::KEYS_AND_VALUES)
observer_ptr->ShouldSendOldValueOnMutations(false);
observers_.AddPtr(std::move(observer_ptr));
AddObserver(mojom::LevelDBObserverAssociatedPtr(std::move(observer)));
}
void LevelDBWrapperImpl::Put(
......@@ -724,7 +754,6 @@ void LevelDBWrapperImpl::CommitChanges() {
bool has_changes = !operations.empty() ||
!commit_batch_->changed_values.empty() ||
!commit_batch_->changed_keys.empty();
if (commit_batch_->clear_all_first) {
BatchedOperationPtr item = BatchedOperation::New();
item->type = leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY;
......
......@@ -87,12 +87,17 @@ class CONTENT_EXPORT LevelDBWrapperImpl : public mojom::LevelDBWrapper {
int max_commits_per_hour = 0;
};
// |no_bindings_callback| will be called when this object has no more
// |Delegate::OnNoBindings| will be called when this object has no more
// bindings and all pending modifications have been processed.
LevelDBWrapperImpl(leveldb::mojom::LevelDBDatabase* database,
const std::string& prefix,
Delegate* delegate,
const Options& options);
LevelDBWrapperImpl(leveldb::mojom::LevelDBDatabase* database,
std::vector<uint8_t> prefix,
Delegate* delegate,
const Options& options);
~LevelDBWrapperImpl() override;
void Bind(mojom::LevelDBWrapperRequest request);
......@@ -104,6 +109,10 @@ class CONTENT_EXPORT LevelDBWrapperImpl : public mojom::LevelDBWrapper {
const std::string& new_prefix,
Delegate* delegate,
const Options& options);
std::unique_ptr<LevelDBWrapperImpl> ForkToNewPrefix(
std::vector<uint8_t> new_prefix,
Delegate* delegate,
const Options& options);
// Cancels all pending load tasks. Useful for emergency destructions. If the
// wrapper is unloaded (initialized() returns false), this will DROP all
......@@ -132,6 +141,8 @@ class CONTENT_EXPORT LevelDBWrapperImpl : public mojom::LevelDBWrapper {
const std::vector<uint8_t>& prefix() { return prefix_; }
leveldb::mojom::LevelDBDatabase* database() { return database_; }
// Commence aggressive flushing. This should be called early during startup,
// before any localStorage writing. Currently scheduled writes will not be
// rescheduled and will be flushed at the scheduled time after which
......@@ -156,6 +167,13 @@ class CONTENT_EXPORT LevelDBWrapperImpl : public mojom::LevelDBWrapper {
// SetCacheMode().
void SetCacheModeForTesting(CacheMode cache_mode);
// Returns a pointer ID for use with HasObserver and RemoveObserver.
mojo::InterfacePtrSetElementId AddObserver(
mojom::LevelDBObserverAssociatedPtr observer);
bool HasObserver(mojo::InterfacePtrSetElementId id);
mojom::LevelDBObserverAssociatedPtr RemoveObserver(
mojo::InterfacePtrSetElementId id);
// LevelDBWrapper:
void AddObserver(mojom::LevelDBObserverAssociatedPtrInfo observer) override;
void Put(const std::vector<uint8_t>& key,
......
......@@ -40,6 +40,9 @@ interface LevelDBWrapperGetAllCallback {
// A wrapper around leveldb that supports giving notifications when values
// change.
// TODO(dmurph): rename & move LevelDBWrapper to DOMStorageDatabase as the
// implementation is now tied specifically to that functionality.
// https://crbug.com/809771
interface LevelDBWrapper {
AddObserver(associated LevelDBObserver observer);
......
......@@ -42,6 +42,8 @@ class AssociatedInterfacePtr {
internal_state_.Swap(&other.internal_state_);
}
explicit AssociatedInterfacePtr(PtrInfoType&& info) { Bind(std::move(info)); }
AssociatedInterfacePtr& operator=(AssociatedInterfacePtr&& other) {
reset();
internal_state_.Swap(&other.internal_state_);
......
......@@ -5,15 +5,19 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_
#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_SET_H_
#include <map>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/stl_util.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
namespace mojo {
using InterfacePtrSetElementId = size_t;
namespace internal {
// TODO(blundell): This class should be rewritten to be structured
......@@ -26,25 +30,28 @@ class PtrSet {
PtrSet() {}
~PtrSet() { CloseAll(); }
void AddPtr(Ptr<Interface> ptr) {
InterfacePtrSetElementId AddPtr(Ptr<Interface> ptr) {
InterfacePtrSetElementId id = next_ptr_id_++;
auto weak_interface_ptr = new Element(std::move(ptr));
ptrs_.push_back(weak_interface_ptr->GetWeakPtr());
ptrs_.emplace(std::piecewise_construct, std::forward_as_tuple(id),
std::forward_as_tuple(weak_interface_ptr->GetWeakPtr()));
ClearNullPtrs();
return id;
}
template <typename FunctionType>
void ForAllPtrs(FunctionType function) {
for (const auto& it : ptrs_) {
if (it)
function(it->get());
if (it.second)
function(it.second->get());
}
ClearNullPtrs();
}
void CloseAll() {
for (const auto& it : ptrs_) {
if (it)
it->Close();
if (it.second)
it.second->Close();
}
ptrs_.clear();
}
......@@ -55,12 +62,27 @@ class PtrSet {
// blocking operation, may be very slow as the number of pointers increases.
void FlushForTesting() {
for (const auto& it : ptrs_) {
if (it)
it->FlushForTesting();
if (it.second)
it.second->FlushForTesting();
}
ClearNullPtrs();
}
bool HasPtr(InterfacePtrSetElementId id) {
return ptrs_.find(id) != ptrs_.end();
}
Ptr<Interface> RemovePtr(InterfacePtrSetElementId id) {
auto it = ptrs_.find(id);
if (it == ptrs_.end())
return Ptr<Interface>();
Ptr<Interface> ptr;
if (it->second)
ptr = it->second->Take();
ptrs_.erase(it);
return ptr;
}
private:
class Element {
public:
......@@ -81,6 +103,8 @@ class PtrSet {
Interface* get() { return ptr_.get(); }
Ptr<Interface> Take() { return std::move(ptr_); }
base::WeakPtr<Element> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
......@@ -97,14 +121,11 @@ class PtrSet {
};
void ClearNullPtrs() {
ptrs_.erase(std::remove_if(ptrs_.begin(), ptrs_.end(),
[](const base::WeakPtr<Element>& p) {
return p.get() == nullptr;
}),
ptrs_.end());
base::EraseIf(ptrs_, [](const auto& pair) { return !(pair.second); });
}
std::vector<base::WeakPtr<Element>> ptrs_;
InterfacePtrSetElementId next_ptr_id_ = 0;
std::map<InterfacePtrSetElementId, base::WeakPtr<Element>> ptrs_;
};
} // namespace internal
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment