123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- // 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/offline_pages/core/offline_page_metadata_store.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/location.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/task/sequenced_task_runner.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/trace_event/trace_event.h"
- #include "components/offline_pages/core/client_namespace_constants.h"
- #include "components/offline_pages/core/offline_page_item.h"
- #include "components/offline_pages/core/offline_store_types.h"
- #include "components/offline_pages/core/offline_store_utils.h"
- #include "sql/database.h"
- #include "sql/meta_table.h"
- #include "sql/statement.h"
- #include "sql/transaction.h"
- namespace offline_pages {
- const int OfflinePageMetadataStore::kFirstPostLegacyVersion;
- const int OfflinePageMetadataStore::kCurrentVersion;
- const int OfflinePageMetadataStore::kCompatibleVersion;
- namespace {
- // This is a macro instead of a const so that
- // it can be used inline in other SQL statements below.
- #define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1"
- void ReportStoreEvent(OfflinePagesStoreEvent event) {
- UMA_HISTOGRAM_ENUMERATION("OfflinePages.SQLStorage.StoreEvent", event);
- }
- bool CreateOfflinePagesTable(sql::Database* db) {
- static const char kCreateLatestOfflinePagesTableSql[] =
- "CREATE TABLE IF NOT EXISTS " OFFLINE_PAGES_TABLE_NAME
- "(offline_id INTEGER PRIMARY KEY NOT NULL,"
- " creation_time INTEGER NOT NULL,"
- " file_size INTEGER NOT NULL,"
- " last_access_time INTEGER NOT NULL,"
- " access_count INTEGER NOT NULL,"
- " system_download_id INTEGER NOT NULL DEFAULT 0,"
- " file_missing_time INTEGER NOT NULL DEFAULT 0,"
- // upgrade_attempt is deprecated, and should be removed next time the
- // schema needs to be updated.
- " upgrade_attempt INTEGER NOT NULL DEFAULT 0,"
- " client_namespace VARCHAR NOT NULL,"
- " client_id VARCHAR NOT NULL,"
- " online_url VARCHAR NOT NULL,"
- " file_path VARCHAR NOT NULL,"
- " title VARCHAR NOT NULL DEFAULT '',"
- " original_url VARCHAR NOT NULL DEFAULT '',"
- " request_origin VARCHAR NOT NULL DEFAULT '',"
- " digest VARCHAR NOT NULL DEFAULT '',"
- " snippet VARCHAR NOT NULL DEFAULT '',"
- " attribution VARCHAR NOT NULL DEFAULT ''"
- ")";
- return db->Execute(kCreateLatestOfflinePagesTableSql);
- }
- bool UpgradeWithQuery(sql::Database* db, const char* upgrade_sql) {
- if (!db->Execute("ALTER TABLE " OFFLINE_PAGES_TABLE_NAME
- " RENAME TO temp_" OFFLINE_PAGES_TABLE_NAME)) {
- return false;
- }
- static const char kCreateOfflinePagesTableVersion1Sql[] =
- "CREATE TABLE IF NOT EXISTS " OFFLINE_PAGES_TABLE_NAME
- "(offline_id INTEGER PRIMARY KEY NOT NULL,"
- " creation_time INTEGER NOT NULL,"
- " file_size INTEGER NOT NULL,"
- " last_access_time INTEGER NOT NULL,"
- " access_count INTEGER NOT NULL,"
- " system_download_id INTEGER NOT NULL DEFAULT 0,"
- " file_missing_time INTEGER NOT NULL DEFAULT 0,"
- " upgrade_attempt INTEGER NOT NULL DEFAULT 0,"
- " client_namespace VARCHAR NOT NULL,"
- " client_id VARCHAR NOT NULL,"
- " online_url VARCHAR NOT NULL,"
- " file_path VARCHAR NOT NULL,"
- " title VARCHAR NOT NULL DEFAULT '',"
- " original_url VARCHAR NOT NULL DEFAULT '',"
- " request_origin VARCHAR NOT NULL DEFAULT '',"
- " digest VARCHAR NOT NULL DEFAULT ''"
- ")";
- if (!db->Execute(kCreateOfflinePagesTableVersion1Sql))
- return false;
- if (!db->Execute(upgrade_sql))
- return false;
- if (!db->Execute("DROP TABLE IF EXISTS temp_" OFFLINE_PAGES_TABLE_NAME))
- return false;
- return true;
- }
- bool UpgradeFrom52(sql::Database* db) {
- static const char kSql[] =
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, "
- "online_url, file_path) "
- "SELECT "
- "offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, "
- "online_url, file_path "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
- return UpgradeWithQuery(db, kSql);
- }
- bool UpgradeFrom53(sql::Database* db) {
- static const char kSql[] =
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path) "
- "SELECT "
- "offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
- return UpgradeWithQuery(db, kSql);
- }
- bool UpgradeFrom54(sql::Database* db) {
- static const char kSql[] =
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title) "
- "SELECT "
- "offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
- return UpgradeWithQuery(db, kSql);
- }
- bool UpgradeFrom55(sql::Database* db) {
- static const char kSql[] =
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title) "
- "SELECT "
- "offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
- return UpgradeWithQuery(db, kSql);
- }
- bool UpgradeFrom56(sql::Database* db) {
- static const char kSql[] =
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title, original_url) "
- "SELECT "
- "offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title, original_url "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
- return UpgradeWithQuery(db, kSql);
- }
- bool UpgradeFrom57(sql::Database* db) {
- static const char kSql[] =
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title, original_url) "
- "SELECT "
- "offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title, original_url "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
- return UpgradeWithQuery(db, kSql);
- }
- bool UpgradeFrom61(sql::Database* db) {
- static const char kSql[] =
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title, original_url, request_origin) "
- "SELECT "
- "offline_id, creation_time, file_size, last_access_time, "
- "access_count, client_namespace, client_id, online_url, "
- "file_path, title, original_url, request_origin "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
- return UpgradeWithQuery(db, kSql);
- }
- bool CreatePageThumbnailsTable(sql::Database* db) {
- // TODO: The next schema change that modifies existing columns on this table
- // should also add "DEFAULT x''" to the definition of the "thumbnail" column.
- static const char kSql[] =
- "CREATE TABLE IF NOT EXISTS page_thumbnails"
- " (offline_id INTEGER PRIMARY KEY NOT NULL,"
- " expiration INTEGER NOT NULL,"
- " thumbnail BLOB NOT NULL,"
- " favicon BLOB NOT NULL DEFAULT x''"
- ")";
- return db->Execute(kSql);
- }
- bool CreateLatestSchema(sql::Database* db) {
- sql::Transaction transaction(db);
- if (!transaction.Begin())
- return false;
- // First time database initialization.
- if (!CreateOfflinePagesTable(db))
- return false;
- if (!CreatePageThumbnailsTable(db))
- return false;
- sql::MetaTable meta_table;
- if (!meta_table.Init(db, OfflinePageMetadataStore::kCurrentVersion,
- OfflinePageMetadataStore::kCompatibleVersion))
- return false;
- return transaction.Commit();
- }
- // Upgrades the database from before the database version was stored in the
- // MetaTable. This function should never need to be modified.
- bool UpgradeFromLegacyVersion(sql::Database* db) {
- sql::Transaction transaction(db);
- if (!transaction.Begin())
- return false;
- // Legacy upgrade section. Details are described in the header file.
- if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "expiration_time") &&
- !db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "title")) {
- if (!UpgradeFrom52(db))
- return false;
- } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "title")) {
- if (!UpgradeFrom53(db))
- return false;
- } else if (db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "offline_url")) {
- if (!UpgradeFrom54(db))
- return false;
- } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "original_url")) {
- if (!UpgradeFrom55(db))
- return false;
- } else if (db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "expiration_time")) {
- if (!UpgradeFrom56(db))
- return false;
- } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "request_origin")) {
- if (!UpgradeFrom57(db))
- return false;
- } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "digest")) {
- if (!UpgradeFrom61(db))
- return false;
- }
- sql::MetaTable meta_table;
- if (!meta_table.Init(db, OfflinePageMetadataStore::kFirstPostLegacyVersion,
- OfflinePageMetadataStore::kCompatibleVersion))
- return false;
- return transaction.Commit();
- }
- bool UpgradeFromVersion1ToVersion2(sql::Database* db,
- sql::MetaTable* meta_table) {
- meta_table->SetVersionNumber(2);
- // No actual changes necessary, because upgrade_attempt was deprecated.
- return true;
- }
- bool UpgradeFromVersion2ToVersion3(sql::Database* db,
- sql::MetaTable* meta_table) {
- sql::Transaction transaction(db);
- if (!transaction.Begin())
- return false;
- static const char kCreatePageThumbnailsSql[] =
- "CREATE TABLE IF NOT EXISTS page_thumbnails"
- " (offline_id INTEGER PRIMARY KEY NOT NULL,"
- "expiration INTEGER NOT NULL,"
- "thumbnail BLOB NOT NULL"
- ")";
- if (!db->Execute(kCreatePageThumbnailsSql))
- return false;
- meta_table->SetVersionNumber(3);
- return transaction.Commit();
- }
- bool UpgradeFromVersion3ToVersion4(sql::Database* db,
- sql::MetaTable* meta_table) {
- sql::Transaction transaction(db);
- if (!transaction.Begin())
- return false;
- const char kSql[] = "ALTER TABLE " OFFLINE_PAGES_TABLE_NAME
- " ADD COLUMN snippet VARCHAR NOT NULL DEFAULT ''; "
- "ALTER TABLE " OFFLINE_PAGES_TABLE_NAME
- " ADD COLUMN attribution VARCHAR NOT NULL DEFAULT '';";
- if (!db->Execute(kSql))
- return false;
- const char kUpgradeThumbnailsTableSql[] =
- "ALTER TABLE page_thumbnails"
- " ADD COLUMN favicon BLOB NOT NULL DEFAULT x''";
- if (!db->Execute(kUpgradeThumbnailsTableSql))
- return false;
- meta_table->SetVersionNumber(4);
- return transaction.Commit();
- }
- bool CreateSchema(sql::Database* db) {
- if (!sql::MetaTable::DoesTableExist(db)) {
- // If this looks like a completely empty DB, simply start from scratch.
- if (!db->DoesTableExist(OFFLINE_PAGES_TABLE_NAME))
- return CreateLatestSchema(db);
- // Otherwise we need to run a legacy upgrade.
- if (!UpgradeFromLegacyVersion(db))
- return false;
- }
- sql::MetaTable meta_table;
- if (!meta_table.Init(db, OfflinePageMetadataStore::kCurrentVersion,
- OfflinePageMetadataStore::kCompatibleVersion))
- return false;
- for (;;) {
- switch (meta_table.GetVersionNumber()) {
- case 1:
- if (!UpgradeFromVersion1ToVersion2(db, &meta_table))
- return false;
- break;
- case 2:
- if (!UpgradeFromVersion2ToVersion3(db, &meta_table))
- return false;
- break;
- case 3:
- if (!UpgradeFromVersion3ToVersion4(db, &meta_table))
- return false;
- break;
- case OfflinePageMetadataStore::kCurrentVersion:
- return true;
- default:
- return false;
- }
- }
- }
- StoreState InitializationStatusToStoreState(
- SqlStoreBase::InitializationStatus status) {
- switch (status) {
- case SqlStoreBase::InitializationStatus::kNotInitialized:
- return StoreState::NOT_LOADED;
- case SqlStoreBase::InitializationStatus::kInProgress:
- return StoreState::INITIALIZING;
- case SqlStoreBase::InitializationStatus::kSuccess:
- return StoreState::LOADED;
- case SqlStoreBase::InitializationStatus::kFailure:
- return StoreState::FAILED_LOADING;
- }
- }
- } // anonymous namespace
- OfflinePageMetadataStore::OfflinePageMetadataStore(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner)
- : SqlStoreBase("OfflinePageMetadata",
- std::move(background_task_runner),
- base::FilePath()) {}
- OfflinePageMetadataStore::OfflinePageMetadataStore(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner,
- const base::FilePath& path)
- : SqlStoreBase("OfflinePageMetadata",
- std::move(background_task_runner),
- path.AppendASCII("OfflinePages.db")) {}
- OfflinePageMetadataStore::~OfflinePageMetadataStore() = default;
- base::OnceCallback<bool(sql::Database* db)>
- OfflinePageMetadataStore::GetSchemaInitializationFunction() {
- return base::BindOnce(&CreateSchema);
- }
- StoreState OfflinePageMetadataStore::GetStateForTesting() const {
- return InitializationStatusToStoreState(initialization_status_for_testing());
- }
- void OfflinePageMetadataStore::OnOpenStart(base::TimeTicks last_closing_time) {
- TRACE_EVENT_ASYNC_BEGIN1("offline_pages", "Metadata Store", this, "is reopen",
- !last_closing_time.is_null());
- ReportStoreEvent(last_closing_time.is_null()
- ? OfflinePagesStoreEvent::kOpenedFirstTime
- : OfflinePagesStoreEvent::kReopened);
- }
- void OfflinePageMetadataStore::OnOpenDone(bool success) {
- TRACE_EVENT_ASYNC_STEP_PAST1("offline_pages", "Metadata Store", this,
- "Initializing", "succeeded", success);
- if (!success) {
- TRACE_EVENT_ASYNC_END0("offline_pages", "Metadata Store", this);
- }
- }
- void OfflinePageMetadataStore::OnTaskBegin(bool is_initialized) {
- TRACE_EVENT_ASYNC_BEGIN1("offline_pages", "Metadata Store: task execution",
- this, "is store loaded", is_initialized);
- }
- void OfflinePageMetadataStore::OnTaskRunComplete() {
- // Note: the time recorded for this trace step will include thread hop wait
- // times to the background thread and back.
- TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages",
- "Metadata Store: task execution", this, "Task");
- }
- void OfflinePageMetadataStore::OnTaskReturnComplete() {
- TRACE_EVENT_ASYNC_STEP_PAST0(
- "offline_pages", "Metadata Store: task execution", this, "Callback");
- TRACE_EVENT_ASYNC_END0("offline_pages", "Metadata Store: task execution",
- this);
- }
- void OfflinePageMetadataStore::OnCloseStart(
- InitializationStatus status_before_close) {
- if (status_before_close != InitializationStatus::kSuccess) {
- ReportStoreEvent(OfflinePagesStoreEvent::kCloseSkipped);
- return;
- }
- TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", "Metadata Store", this, "Open");
- ReportStoreEvent(OfflinePagesStoreEvent::kClosed);
- }
- void OfflinePageMetadataStore::OnCloseComplete() {
- TRACE_EVENT_ASYNC_STEP_PAST0("offline_pages", "Metadata Store", this,
- "Closing");
- TRACE_EVENT_ASYNC_END0("offline_pages", "Metadata Store", this);
- }
- } // namespace offline_pages
|