blob: 1003accd1738acea53c2b9bf6bbf9ccf5c0eb28a [file] [log] [blame]
// Copyright 2018 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 "chrome/browser/resource_coordinator/local_site_characteristics_data_store.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h"
#include "chrome/browser/resource_coordinator/local_site_characteristics_data_reader.h"
#include "chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h"
#include "chrome/browser/resource_coordinator/tab_manager_features.h"
#include "components/history/core/browser/history_service.h"
namespace resource_coordinator {
namespace {
constexpr char kSiteCharacteristicsDirectoryName[] =
"Site Characteristics Database";
} // namespace
LocalSiteCharacteristicsDataStore::LocalSiteCharacteristicsDataStore(
Profile* profile)
: history_observer_(this), profile_(profile) {
DCHECK(base::FeatureList::IsEnabled(features::kSiteCharacteristicsDatabase));
database_ = std::make_unique<LevelDBSiteCharacteristicsDatabase>(
profile->GetPath().AppendASCII(kSiteCharacteristicsDirectoryName));
history::HistoryService* history =
HistoryServiceFactory::GetForProfileWithoutCreating(profile);
if (history)
history_observer_.Add(history);
// Register the debug interface against the profile.
LocalSiteCharacteristicsDataStoreInspector::SetForProfile(this, profile);
}
LocalSiteCharacteristicsDataStore::~LocalSiteCharacteristicsDataStore() {
LocalSiteCharacteristicsDataStoreInspector::SetForProfile(nullptr, profile_);
}
std::unique_ptr<SiteCharacteristicsDataReader>
LocalSiteCharacteristicsDataStore::GetReaderForOrigin(
const url::Origin& origin) {
internal::LocalSiteCharacteristicsDataImpl* impl =
GetOrCreateFeatureImpl(origin);
DCHECK(impl);
SiteCharacteristicsDataReader* data_reader =
new LocalSiteCharacteristicsDataReader(impl);
return base::WrapUnique(data_reader);
}
std::unique_ptr<SiteCharacteristicsDataWriter>
LocalSiteCharacteristicsDataStore::GetWriterForOrigin(
const url::Origin& origin,
TabVisibility tab_visibility) {
internal::LocalSiteCharacteristicsDataImpl* impl =
GetOrCreateFeatureImpl(origin);
DCHECK(impl);
LocalSiteCharacteristicsDataWriter* data_writer =
new LocalSiteCharacteristicsDataWriter(impl, tab_visibility);
return base::WrapUnique(data_writer);
}
bool LocalSiteCharacteristicsDataStore::IsRecordingForTesting() {
return true;
}
const char* LocalSiteCharacteristicsDataStore::GetDataStoreName() {
return "LocalSiteCharacteristicsDataStore";
}
std::vector<url::Origin>
LocalSiteCharacteristicsDataStore::GetAllInMemoryOrigins() {
std::vector<url::Origin> ret;
ret.reserve(origin_data_map_.size());
for (const auto& entry : origin_data_map_)
ret.push_back(entry.first);
return ret;
}
void LocalSiteCharacteristicsDataStore::GetDatabaseSize(
DatabaseSizeCallback on_have_data) {
database_->GetDatabaseSize(std::move(on_have_data));
}
bool LocalSiteCharacteristicsDataStore::GetDataForOrigin(
const url::Origin& origin,
bool* is_dirty,
std::unique_ptr<SiteCharacteristicsProto>* data) {
DCHECK_NE(nullptr, data);
const auto it = origin_data_map_.find(origin);
if (it == origin_data_map_.end())
return false;
std::unique_ptr<SiteCharacteristicsProto> ret =
std::make_unique<SiteCharacteristicsProto>();
ret->CopyFrom(it->second->FlushStateToProto());
*is_dirty = it->second->is_dirty();
*data = std::move(ret);
return true;
}
LocalSiteCharacteristicsDataStore*
LocalSiteCharacteristicsDataStore::GetDataStore() {
return this;
}
internal::LocalSiteCharacteristicsDataImpl*
LocalSiteCharacteristicsDataStore::GetOrCreateFeatureImpl(
const url::Origin& origin) {
// Start by checking if there's already an entry for this origin.
auto iter = origin_data_map_.find(origin);
if (iter != origin_data_map_.end())
return iter->second;
// If not create a new one and add it to the map.
internal::LocalSiteCharacteristicsDataImpl* site_characteristic_data =
new internal::LocalSiteCharacteristicsDataImpl(origin, this,
database_.get());
// internal::LocalSiteCharacteristicsDataImpl is a ref-counted object, it's
// safe to store a raw pointer to it here as this class will get notified when
// it's about to be destroyed and it'll be removed from the map.
origin_data_map_.insert(std::make_pair(origin, site_characteristic_data));
return site_characteristic_data;
}
void LocalSiteCharacteristicsDataStore::
OnLocalSiteCharacteristicsDataImplDestroyed(
internal::LocalSiteCharacteristicsDataImpl* impl) {
DCHECK(impl);
DCHECK(base::ContainsKey(origin_data_map_, impl->origin()));
// Remove the entry for this origin as this is about to get destroyed.
auto num_erased = origin_data_map_.erase(impl->origin());
DCHECK_EQ(1U, num_erased);
}
void LocalSiteCharacteristicsDataStore::OnURLsDeleted(
history::HistoryService* history_service,
const history::DeletionInfo& deletion_info) {
// It's not necessary to invalidate the pending DB write operations as they
// run on a sequenced task and so it's guaranteed that the remove operations
// posted here will run after any other pending operation.
if (deletion_info.IsAllHistory()) {
for (auto& data : origin_data_map_)
data.second->ClearObservationsAndInvalidateReadOperation();
database_->ClearDatabase();
} else {
std::vector<url::Origin> entries_to_remove;
for (auto deleted_row : deletion_info.deleted_rows()) {
url::Origin origin = url::Origin::Create(deleted_row.url());
auto map_iter = origin_data_map_.find(origin);
if (map_iter != origin_data_map_.end())
map_iter->second->ClearObservationsAndInvalidateReadOperation();
// The database will ignore the entries that don't exist in it.
entries_to_remove.emplace_back(origin);
}
database_->RemoveSiteCharacteristicsFromDB(entries_to_remove);
}
}
void LocalSiteCharacteristicsDataStore::HistoryServiceBeingDeleted(
history::HistoryService* history_service) {
history_observer_.Remove(history_service);
}
} // namespace resource_coordinator