Commit a1b001cf authored by Daniel Murphy's avatar Daniel Murphy Committed by Commit Bot

[SessionStorage] Holding reference to forked map during fork operation.

Maps that are being forked from are not being held open until the fork
operation is complete, which is probably causing the GetAll hanges in
the attached bug.

This idea came from mek@ out of the discussion here:
https://docs.google.com/document/d/1Pw8W74-7NCHpxrtglVHqFZpLV_p2JFwdMNqo03kx2l8/edit#heading=h.lwd5sacdhs8q

R=mek@chromium.org

Bug: 897581
Change-Id: I700bbc580b0f4360354b87b4b9a8cfb3cb4bd6ee
Reviewed-on: https://chromium-review.googlesource.com/c/1489897
Commit-Queue: Daniel Murphy <dmurph@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635779}
parent ccc182fc
...@@ -139,7 +139,7 @@ void SessionStorageAreaImpl::CreateNewMap( ...@@ -139,7 +139,7 @@ void SessionStorageAreaImpl::CreateNewMap(
shared_data_map_ = SessionStorageDataMap::CreateClone( shared_data_map_ = SessionStorageDataMap::CreateClone(
shared_data_map_->listener(), shared_data_map_->listener(),
register_new_map_callback_.Run(namespace_entry_, origin_), register_new_map_callback_.Run(namespace_entry_, origin_),
shared_data_map_->storage_area()); shared_data_map_);
break; break;
case NewMapType::EMPTY_FROM_DELETE_ALL: { case NewMapType::EMPTY_FROM_DELETE_ALL: {
// The code optimizes the 'delete all' for shared maps by just creating // The code optimizes the 'delete all' for shared maps by just creating
......
...@@ -24,9 +24,9 @@ scoped_refptr<SessionStorageDataMap> SessionStorageDataMap::Create( ...@@ -24,9 +24,9 @@ scoped_refptr<SessionStorageDataMap> SessionStorageDataMap::Create(
scoped_refptr<SessionStorageDataMap> SessionStorageDataMap::CreateClone( scoped_refptr<SessionStorageDataMap> SessionStorageDataMap::CreateClone(
Listener* listener, Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_data, scoped_refptr<SessionStorageMetadata::MapData> map_data,
StorageAreaImpl* clone_from) { scoped_refptr<SessionStorageDataMap> clone_from) {
return base::WrapRefCounted( return base::WrapRefCounted(new SessionStorageDataMap(
new SessionStorageDataMap(listener, std::move(map_data), clone_from)); listener, std::move(map_data), std::move(clone_from)));
} }
std::vector<leveldb::mojom::BatchedOperationPtr> std::vector<leveldb::mojom::BatchedOperationPtr>
...@@ -58,12 +58,14 @@ SessionStorageDataMap::SessionStorageDataMap( ...@@ -58,12 +58,14 @@ SessionStorageDataMap::SessionStorageDataMap(
SessionStorageDataMap::SessionStorageDataMap( SessionStorageDataMap::SessionStorageDataMap(
Listener* listener, Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_data, scoped_refptr<SessionStorageMetadata::MapData> map_data,
StorageAreaImpl* forking_from) scoped_refptr<SessionStorageDataMap> forking_from)
: listener_(listener), : listener_(listener),
clone_from_data_map_(std::move(forking_from)),
map_data_(std::move(map_data)), map_data_(std::move(map_data)),
storage_area_impl_(forking_from->ForkToNewPrefix(map_data_->KeyPrefix(), storage_area_impl_(clone_from_data_map_->storage_area()->ForkToNewPrefix(
this, map_data_->KeyPrefix(),
GetOptions())), this,
GetOptions())),
storage_area_ptr_(storage_area_impl_.get()) { storage_area_ptr_(storage_area_impl_.get()) {
DCHECK(listener_); DCHECK(listener_);
DCHECK(map_data_); DCHECK(map_data_);
...@@ -85,6 +87,10 @@ void SessionStorageDataMap::RemoveBindingReference() { ...@@ -85,6 +87,10 @@ void SessionStorageDataMap::RemoveBindingReference() {
storage_area()->ScheduleImmediateCommit(); storage_area()->ScheduleImmediateCommit();
} }
void SessionStorageDataMap::OnMapLoaded(leveldb::mojom::DatabaseError) {
clone_from_data_map_.reset();
}
// static // static
StorageAreaImpl::Options SessionStorageDataMap::GetOptions() { StorageAreaImpl::Options SessionStorageDataMap::GetOptions() {
// Delay for a moment after a value is set in anticipation // Delay for a moment after a value is set in anticipation
......
...@@ -49,7 +49,7 @@ class CONTENT_EXPORT SessionStorageDataMap final ...@@ -49,7 +49,7 @@ class CONTENT_EXPORT SessionStorageDataMap final
static scoped_refptr<SessionStorageDataMap> CreateClone( static scoped_refptr<SessionStorageDataMap> CreateClone(
Listener* listener, Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_data, scoped_refptr<SessionStorageMetadata::MapData> map_data,
StorageAreaImpl* clone_from); scoped_refptr<SessionStorageDataMap> clone_from);
Listener* listener() const { return listener_; } Listener* listener() const { return listener_; }
...@@ -82,13 +82,21 @@ class CONTENT_EXPORT SessionStorageDataMap final ...@@ -82,13 +82,21 @@ class CONTENT_EXPORT SessionStorageDataMap final
SessionStorageDataMap( SessionStorageDataMap(
Listener* listener, Listener* listener,
scoped_refptr<SessionStorageMetadata::MapData> map_entry, scoped_refptr<SessionStorageMetadata::MapData> map_entry,
StorageAreaImpl* forking_from); scoped_refptr<SessionStorageDataMap> forking_from);
~SessionStorageDataMap() override; ~SessionStorageDataMap() override;
void OnMapLoaded(leveldb::mojom::DatabaseError error) override;
static StorageAreaImpl::Options GetOptions(); static StorageAreaImpl::Options GetOptions();
Listener* listener_; Listener* listener_;
int binding_count_ = 0; int binding_count_ = 0;
// If we're cloning from another map, we need to keep it alive while it forks.
// Note, this has to be above the storage_area_impl_ in case the Fork call
// completes synchronously.
scoped_refptr<SessionStorageDataMap> clone_from_data_map_;
scoped_refptr<SessionStorageMetadata::MapData> map_data_; scoped_refptr<SessionStorageMetadata::MapData> map_data_;
std::unique_ptr<StorageAreaImpl> storage_area_impl_; std::unique_ptr<StorageAreaImpl> storage_area_impl_;
// Holds the same value as |storage_area_impl_|. The reason for this is that // Holds the same value as |storage_area_impl_|. The reason for this is that
......
...@@ -153,7 +153,7 @@ TEST_F(SessionStorageDataMapTest, Clone) { ...@@ -153,7 +153,7 @@ TEST_F(SessionStorageDataMapTest, Clone) {
&listener_, &listener_,
base::MakeRefCounted<SessionStorageMetadata::MapData>(2, base::MakeRefCounted<SessionStorageMetadata::MapData>(2,
test_origin_), test_origin_),
map1->storage_area()); map1);
bool success; bool success;
std::vector<blink::mojom::KeyValuePtr> data; std::vector<blink::mojom::KeyValuePtr> data;
......
...@@ -641,6 +641,7 @@ void StorageAreaImpl::OnGotMigrationData(std::unique_ptr<ValueMap> data) { ...@@ -641,6 +641,7 @@ void StorageAreaImpl::OnGotMigrationData(std::unique_ptr<ValueMap> data) {
keys_values_map_ = data ? std::move(*data) : ValueMap(); keys_values_map_ = data ? std::move(*data) : ValueMap();
map_state_ = MapState::LOADED_KEYS_AND_VALUES; map_state_ = MapState::LOADED_KEYS_AND_VALUES;
CalculateStorageAndMemoryUsed(); CalculateStorageAndMemoryUsed();
delegate_->OnMapLoaded(leveldb::mojom::DatabaseError::OK);
if (database_ && !empty()) { if (database_ && !empty()) {
CreateCommitBatchIfNeeded(); CreateCommitBatchIfNeeded();
...@@ -649,7 +650,6 @@ void StorageAreaImpl::OnGotMigrationData(std::unique_ptr<ValueMap> data) { ...@@ -649,7 +650,6 @@ void StorageAreaImpl::OnGotMigrationData(std::unique_ptr<ValueMap> data) {
commit_batch_->changed_keys.insert(it.first); commit_batch_->changed_keys.insert(it.first);
CommitChanges(); CommitChanges();
} }
OnLoadComplete(); OnLoadComplete();
} }
......
...@@ -240,6 +240,9 @@ class StorageAreaImplTest : public testing::Test, ...@@ -240,6 +240,9 @@ class StorageAreaImplTest : public testing::Test,
const std::vector<Observation>& observations() { return observations_; } const std::vector<Observation>& observations() { return observations_; }
MockDelegate* delegate() { return &delegate_; } MockDelegate* delegate() { return &delegate_; }
leveldb::mojom::LevelDBDatabase* database() const {
return level_db_database_ptr_.get();
}
void should_record_send_old_value_observations(bool value) { void should_record_send_old_value_observations(bool value) {
should_record_send_old_value_observations_ = value; should_record_send_old_value_observations_ = value;
...@@ -327,6 +330,19 @@ TEST_F(StorageAreaImplTest, GetLoadedFromMap) { ...@@ -327,6 +330,19 @@ TEST_F(StorageAreaImplTest, GetLoadedFromMap) {
EXPECT_FALSE(GetSync(ToBytes("x"), &result)); EXPECT_FALSE(GetSync(ToBytes("x"), &result));
} }
TEST_F(StorageAreaImplTest, NoDataCallsOnMapLoaded) {
StorageAreaImpl::Options options =
GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE);
// Load an area that has no data inside, so the result will be empty and the
// migration code is triggered.
auto area = std::make_unique<StorageAreaImpl>(database(), test_copy_prefix2_,
delegate(), options);
std::vector<blink::mojom::KeyValuePtr> data;
EXPECT_TRUE(test::GetAllSyncOnDedicatedPipe(area.get(), &data));
EXPECT_TRUE(data.empty());
EXPECT_EQ(1, delegate()->map_load_count());
}
TEST_F(StorageAreaImplTest, GetFromPutOverwrite) { TEST_F(StorageAreaImplTest, GetFromPutOverwrite) {
storage_area_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES); storage_area_impl()->SetCacheModeForTesting(CacheMode::KEYS_AND_VALUES);
std::vector<uint8_t> key = test_key2_bytes_; std::vector<uint8_t> key = test_key2_bytes_;
......
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