Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/offline_pages/offline_page_metadata_store_sql.h" | 5 #include "components/offline_pages/offline_page_metadata_store_sql.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 | 26 |
| 27 // This is a macro instead of a const so that | 27 // This is a macro instead of a const so that |
| 28 // it can be used inline in other SQL statements below. | 28 // it can be used inline in other SQL statements below. |
| 29 #define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1" | 29 #define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1" |
| 30 | 30 |
| 31 bool CreateOfflinePagesTable(sql::Connection* db) { | 31 bool CreateOfflinePagesTable(sql::Connection* db) { |
| 32 const char kSql[] = "CREATE TABLE IF NOT EXISTS " OFFLINE_PAGES_TABLE_NAME | 32 const char kSql[] = "CREATE TABLE IF NOT EXISTS " OFFLINE_PAGES_TABLE_NAME |
| 33 "(offline_id INTEGER PRIMARY KEY NOT NULL," | 33 "(offline_id INTEGER PRIMARY KEY NOT NULL," |
| 34 " creation_time INTEGER NOT NULL," | 34 " creation_time INTEGER NOT NULL," |
| 35 " file_size INTEGER NOT NULL," | 35 " file_size INTEGER NOT NULL," |
| 36 " version INTEGER NOT NULL," | |
| 37 " last_access_time INTEGER NOT NULL," | 36 " last_access_time INTEGER NOT NULL," |
| 38 " access_count INTEGER NOT NULL," | 37 " access_count INTEGER NOT NULL," |
| 39 // TODO(fgorski): Remove. Never used. | |
| 40 " status INTEGER NOT NULL DEFAULT 0," | |
| 41 // A note on this field: It will be NULL for now and is | |
| 42 // reserved for later use. We will treat NULL as | |
| 43 // "Unknown" in any subsequent queries for user_initiated | |
| 44 // values. | |
| 45 " user_initiated INTEGER," // this is actually a boolean | |
| 46 " expiration_time INTEGER NOT NULL DEFAULT 0," | 38 " expiration_time INTEGER NOT NULL DEFAULT 0," |
| 47 " client_namespace VARCHAR NOT NULL," | 39 " client_namespace VARCHAR NOT NULL," |
| 48 " client_id VARCHAR NOT NULL," | 40 " client_id VARCHAR NOT NULL," |
| 49 " online_url VARCHAR NOT NULL," | 41 " online_url VARCHAR NOT NULL," |
| 50 // TODO(fgorski): Remove. Never used. | |
| 51 " offline_url VARCHAR NOT NULL DEFAULT ''," | |
| 52 " file_path VARCHAR NOT NULL," | 42 " file_path VARCHAR NOT NULL," |
| 53 " title VARCHAR NOT NULL DEFAULT ''" | 43 " title VARCHAR NOT NULL DEFAULT ''" |
| 54 ")"; | 44 ")"; |
| 55 return db->Execute(kSql); | 45 return db->Execute(kSql); |
| 56 } | 46 } |
| 57 | 47 |
| 58 bool RefreshColumnsFrom52To54(sql::Connection* db) { | 48 bool UpgradeWithQuery(sql::Connection* db, const char* upgrade_sql) { |
| 59 if (!db->Execute("ALTER TABLE " OFFLINE_PAGES_TABLE_NAME | 49 if (!db->Execute("ALTER TABLE " OFFLINE_PAGES_TABLE_NAME |
| 60 " RENAME TO temp_" OFFLINE_PAGES_TABLE_NAME)) { | 50 " RENAME TO temp_" OFFLINE_PAGES_TABLE_NAME)) { |
| 61 return false; | 51 return false; |
| 62 } | 52 } |
| 63 if (!CreateOfflinePagesTable(db)) | 53 if (!CreateOfflinePagesTable(db)) |
| 64 return false; | 54 return false; |
| 65 if (!db->Execute( | 55 if (!db->Execute(upgrade_sql)) |
| 66 "INSERT INTO " OFFLINE_PAGES_TABLE_NAME | |
| 67 " (offline_id, creation_time, file_size, version, last_access_time, " | |
| 68 "access_count, status, user_initiated, client_namespace, client_id, " | |
| 69 "online_url, offline_url, file_path) " | |
| 70 "SELECT offline_id, creation_time, file_size, version, " | |
| 71 "last_access_time, " | |
| 72 "access_count, status, user_initiated, client_namespace, client_id, " | |
| 73 "online_url, offline_url, file_path " | |
| 74 "FROM temp_" OFFLINE_PAGES_TABLE_NAME)) { | |
| 75 return false; | 56 return false; |
| 76 } | |
| 77 if (!db->Execute("DROP TABLE IF EXISTS temp_" OFFLINE_PAGES_TABLE_NAME)) | 57 if (!db->Execute("DROP TABLE IF EXISTS temp_" OFFLINE_PAGES_TABLE_NAME)) |
| 78 return false; | 58 return false; |
| 79 | |
| 80 return true; | 59 return true; |
| 81 } | 60 } |
| 82 | 61 |
| 83 bool RefreshColumnsFrom53To54(sql::Connection* db) { | 62 bool UpgradeFrom52(sql::Connection* db) { |
| 84 if (!db->Execute("ALTER TABLE " OFFLINE_PAGES_TABLE_NAME | 63 const char kSql[] = |
| 85 " RENAME TO temp_" OFFLINE_PAGES_TABLE_NAME)) { | 64 "INSERT INTO " OFFLINE_PAGES_TABLE_NAME |
| 86 return false; | 65 " (offline_id, creation_time, file_size, last_access_time, " |
| 87 } | 66 "access_count, client_namespace, client_id, " |
| 88 if (!CreateOfflinePagesTable(db)) | 67 "online_url, file_path) " |
| 89 return false; | 68 "SELECT " |
| 90 if (!db->Execute( | 69 "offline_id, creation_time, file_size, last_access_time, " |
| 91 "INSERT INTO " OFFLINE_PAGES_TABLE_NAME | 70 "access_count, client_namespace, client_id, " |
| 92 " (offline_id, creation_time, file_size, version, last_access_time, " | 71 "online_url, file_path " |
| 93 "access_count, status, user_initiated, client_namespace, client_id, " | 72 "FROM temp_" OFFLINE_PAGES_TABLE_NAME; |
| 94 "online_url, offline_url, file_path, expiration_time) " | 73 return UpgradeWithQuery(db, kSql); |
| 95 "SELECT offline_id, creation_time, file_size, version, " | 74 } |
| 96 "last_access_time, " | |
| 97 "access_count, status, user_initiated, client_namespace, client_id, " | |
| 98 "online_url, offline_url, file_path, expiration_time " | |
| 99 "FROM temp_" OFFLINE_PAGES_TABLE_NAME)) { | |
| 100 return false; | |
| 101 } | |
| 102 if (!db->Execute("DROP TABLE IF EXISTS temp_" OFFLINE_PAGES_TABLE_NAME)) | |
| 103 return false; | |
| 104 | 75 |
| 105 return true; | 76 bool UpgradeFrom53(sql::Connection* db) { |
| 77 const char kSql[] = | |
| 78 "INSERT INTO " OFFLINE_PAGES_TABLE_NAME | |
| 79 " (offline_id, creation_time, file_size, last_access_time, " | |
| 80 "access_count, expiration_time, client_namespace, client_id, " | |
| 81 "online_url, file_path) " | |
| 82 "SELECT " | |
| 83 "offline_id, creation_time, file_size, last_access_time, " | |
| 84 "access_count, expiration_time, client_namespace, client_id, " | |
| 85 "online_url, file_path " | |
| 86 "FROM temp_" OFFLINE_PAGES_TABLE_NAME; | |
| 87 return UpgradeWithQuery(db, kSql); | |
| 88 } | |
| 89 | |
| 90 bool UpgradeFrom54(sql::Connection* db) { | |
| 91 const char kSql[] = | |
| 92 "INSERT INTO " OFFLINE_PAGES_TABLE_NAME | |
| 93 " (offline_id, creation_time, file_size, last_access_time, " | |
| 94 "access_count, expiration_time, client_namespace, client_id, " | |
| 95 "online_url, file_path, title) " | |
| 96 "SELECT " | |
| 97 "offline_id, creation_time, file_size, last_access_time, " | |
| 98 "access_count, expiration_time, client_namespace, client_id, " | |
| 99 "online_url, file_path, title " | |
| 100 "FROM temp_" OFFLINE_PAGES_TABLE_NAME; | |
| 101 return UpgradeWithQuery(db, kSql); | |
| 106 } | 102 } |
| 107 | 103 |
| 108 bool CreateSchema(sql::Connection* db) { | 104 bool CreateSchema(sql::Connection* db) { |
| 109 // If you create a transaction but don't Commit() it is automatically | 105 // If you create a transaction but don't Commit() it is automatically |
| 110 // rolled back by its destructor when it falls out of scope. | 106 // rolled back by its destructor when it falls out of scope. |
| 111 sql::Transaction transaction(db); | 107 sql::Transaction transaction(db); |
| 112 if (!transaction.Begin()) | 108 if (!transaction.Begin()) |
| 113 return false; | 109 return false; |
| 114 | 110 |
| 115 if (!db->DoesTableExist(OFFLINE_PAGES_TABLE_NAME)) { | 111 if (!db->DoesTableExist(OFFLINE_PAGES_TABLE_NAME)) { |
| 116 if (!CreateOfflinePagesTable(db)) | 112 if (!CreateOfflinePagesTable(db)) |
| 117 return false; | 113 return false; |
| 118 } | 114 } |
| 119 | 115 |
| 116 // Upgrade section. Details are described in the header file. | |
| 120 if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "expiration_time")) { | 117 if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "expiration_time")) { |
| 121 if (!RefreshColumnsFrom52To54(db)) | 118 if (!UpgradeFrom52(db)) |
| 122 return false; | 119 return false; |
| 123 } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "title")) { | 120 } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "title")) { |
| 124 if (!RefreshColumnsFrom53To54(db)) | 121 if (!UpgradeFrom53(db)) |
| 122 return false; | |
| 123 } else if (db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "offline_url")) { | |
| 124 if (!UpgradeFrom54(db)) | |
| 125 return false; | 125 return false; |
| 126 } | 126 } |
| 127 | 127 |
| 128 // TODO(bburns): Add indices here. | 128 // TODO(bburns): Add indices here. |
| 129 return transaction.Commit(); | 129 return transaction.Commit(); |
| 130 } | 130 } |
| 131 | 131 |
| 132 bool DeleteByOfflineId(sql::Connection* db, int64_t offline_id) { | 132 bool DeleteByOfflineId(sql::Connection* db, int64_t offline_id) { |
| 133 static const char kSql[] = | 133 static const char kSql[] = |
| 134 "DELETE FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id=?"; | 134 "DELETE FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id=?"; |
| 135 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql)); | 135 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql)); |
| 136 statement.BindInt64(0, offline_id); | 136 statement.BindInt64(0, offline_id); |
| 137 return statement.Run(); | 137 return statement.Run(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 base::FilePath GetPathFromUTF8String(const std::string& path_string) { | |
| 141 #if defined(OS_POSIX) | |
| 142 return base::FilePath(path_string); | |
| 143 #elif defined(OS_WIN) | |
| 144 return base::FilePath(base::UTF8ToWide(path_string)); | |
| 145 #else | |
| 146 #error Unknown OS | |
| 147 #endif | |
| 148 } | |
| 149 | |
| 150 std::string GetUTF8StringFromPath(const base::FilePath& path) { | |
| 151 #if defined(OS_POSIX) | |
| 152 return path.value(); | |
| 153 #elif defined(OS_WIN) | |
| 154 return base::WideToUTF8(path.value()); | |
| 155 #else | |
| 156 #error Unknown OS | |
| 157 #endif | |
| 158 } | |
| 159 | |
| 140 // Create an offline page item from a SQL result. Expects complete rows with | 160 // Create an offline page item from a SQL result. Expects complete rows with |
| 141 // all columns present. | 161 // all columns present. |
| 142 OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) { | 162 OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) { |
| 143 int64_t id = statement->ColumnInt64(0); | 163 int64_t id = statement->ColumnInt64(0); |
| 144 base::Time creation_time = | 164 base::Time creation_time = |
| 145 base::Time::FromInternalValue(statement->ColumnInt64(1)); | 165 base::Time::FromInternalValue(statement->ColumnInt64(1)); |
| 146 int64_t file_size = statement->ColumnInt64(2); | 166 int64_t file_size = statement->ColumnInt64(2); |
| 147 ClientId client_id(statement->ColumnString(9), | 167 base::Time last_access_time = |
| 148 statement->ColumnString(10)); | 168 base::Time::FromInternalValue(statement->ColumnInt64(3)); |
| 149 GURL url(statement->ColumnString(11)); | 169 int access_count = statement->ColumnInt(4); |
| 150 #if defined(OS_POSIX) | 170 base::Time expiration_time = |
| 151 base::FilePath path(statement->ColumnString(13)); | 171 base::Time::FromInternalValue(statement->ColumnInt64(5)); |
| 152 #elif defined(OS_WIN) | 172 ClientId client_id(statement->ColumnString(6), statement->ColumnString(7)); |
| 153 base::FilePath path(base::UTF8ToWide(statement->ColumnString(13))); | 173 GURL url(statement->ColumnString(8)); |
| 154 #else | 174 base::FilePath path(GetPathFromUTF8String(statement->ColumnString(9))); |
| 155 #error Unknown OS | 175 base::string16 title = statement->ColumnString16(10); |
| 156 #endif | |
| 157 | 176 |
| 158 OfflinePageItem item(url, id, client_id, path, file_size, creation_time); | 177 OfflinePageItem item(url, id, client_id, path, file_size, creation_time); |
| 159 item.version = statement->ColumnInt(3); | 178 item.last_access_time = last_access_time; |
| 160 item.last_access_time = base::Time::FromInternalValue( | 179 item.access_count = access_count; |
| 161 statement->ColumnInt64(4)); | 180 item.expiration_time = expiration_time; |
| 162 item.access_count = statement->ColumnInt(5); | 181 item.title = title; |
| 163 item.expiration_time = | |
| 164 base::Time::FromInternalValue(statement->ColumnInt64(8)); | |
| 165 item.title = statement->ColumnString16(14); | |
| 166 return item; | 182 return item; |
| 167 } | 183 } |
| 168 | 184 |
| 169 bool InsertOrReplace(sql::Connection* db, const OfflinePageItem& item) { | 185 bool InsertOrReplace(sql::Connection* db, const OfflinePageItem& item) { |
| 170 const char kSql[] = | 186 const char kSql[] = |
| 171 "INSERT OR REPLACE INTO " OFFLINE_PAGES_TABLE_NAME | 187 "INSERT OR REPLACE INTO " OFFLINE_PAGES_TABLE_NAME |
| 172 " (offline_id, online_url, client_namespace, client_id, file_path, " | 188 " (offline_id, online_url, client_namespace, client_id, file_path, " |
| 173 "file_size, creation_time, last_access_time, version, access_count, " | 189 "file_size, creation_time, last_access_time, access_count, " |
| 174 "expiration_time, title)" | 190 "expiration_time, title)" |
| 175 " VALUES " | 191 " VALUES " |
| 176 " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; | 192 " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
| 177 | 193 |
| 178 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql)); | 194 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql)); |
| 179 statement.BindInt64(0, item.offline_id); | 195 statement.BindInt64(0, item.offline_id); |
| 180 statement.BindString(1, item.url.spec()); | 196 statement.BindString(1, item.url.spec()); |
| 181 statement.BindString(2, item.client_id.name_space); | 197 statement.BindString(2, item.client_id.name_space); |
| 182 statement.BindString(3, item.client_id.id); | 198 statement.BindString(3, item.client_id.id); |
| 183 #if defined(OS_POSIX) | 199 statement.BindString(4, GetUTF8StringFromPath(item.file_path)); |
| 184 std::string path_string = item.file_path.value(); | |
| 185 #elif defined(OS_WIN) | |
| 186 std::string path_string = base::WideToUTF8(item.file_path.value()); | |
| 187 #else | |
| 188 #error Unknown OS | |
| 189 #endif | |
| 190 statement.BindString(4, path_string); | |
| 191 statement.BindInt64(5, item.file_size); | 200 statement.BindInt64(5, item.file_size); |
| 192 statement.BindInt64(6, item.creation_time.ToInternalValue()); | 201 statement.BindInt64(6, item.creation_time.ToInternalValue()); |
| 193 statement.BindInt64(7, item.last_access_time.ToInternalValue()); | 202 statement.BindInt64(7, item.last_access_time.ToInternalValue()); |
| 194 statement.BindInt(8, item.version); | 203 statement.BindInt(8, item.access_count); |
| 195 statement.BindInt(9, item.access_count); | 204 statement.BindInt64(9, item.expiration_time.ToInternalValue()); |
| 196 statement.BindInt64(10, item.expiration_time.ToInternalValue()); | 205 statement.BindString16(10, item.title); |
| 197 statement.BindString16(11, item.title); | |
| 198 return statement.Run(); | 206 return statement.Run(); |
| 199 } | 207 } |
| 200 | 208 |
| 201 bool InitDatabase(sql::Connection* db, base::FilePath path) { | 209 bool InitDatabase(sql::Connection* db, base::FilePath path) { |
| 202 db->set_page_size(4096); | 210 db->set_page_size(4096); |
| 203 db->set_cache_size(500); | 211 db->set_cache_size(500); |
| 204 db->set_histogram_tag("OfflinePageMetadata"); | 212 db->set_histogram_tag("OfflinePageMetadata"); |
| 205 db->set_exclusive_locking(); | 213 db->set_exclusive_locking(); |
| 206 | 214 |
| 207 base::File::Error err; | 215 base::File::Error err; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 if (statement.Succeeded()) { | 268 if (statement.Succeeded()) { |
| 261 NotifyLoadResult(runner, callback, OfflinePageMetadataStore::LOAD_SUCCEEDED, | 269 NotifyLoadResult(runner, callback, OfflinePageMetadataStore::LOAD_SUCCEEDED, |
| 262 result); | 270 result); |
| 263 } else { | 271 } else { |
| 264 result.clear(); | 272 result.clear(); |
| 265 NotifyLoadResult(runner, callback, | 273 NotifyLoadResult(runner, callback, |
| 266 OfflinePageMetadataStore::STORE_LOAD_FAILED, result); | 274 OfflinePageMetadataStore::STORE_LOAD_FAILED, result); |
| 267 } | 275 } |
| 268 } | 276 } |
| 269 | 277 |
| 270 void AddOrUpdateOfflinePageSync( | 278 void AddOrUpdateOfflinePageSync( |
|
dewittj
2016/09/13 21:43:51
nit: I'd avoid moving these functions just because
fgorski
2016/09/13 22:08:59
Move had to happen to clean up the interface and b
| |
| 271 const OfflinePageItem& offline_page, | 279 const OfflinePageItem& offline_page, |
| 272 sql::Connection* db, | 280 sql::Connection* db, |
| 273 scoped_refptr<base::SingleThreadTaskRunner> runner, | 281 scoped_refptr<base::SingleThreadTaskRunner> runner, |
| 274 const OfflinePageMetadataStore::UpdateCallback& callback) { | 282 const OfflinePageMetadataStore::UpdateCallback& callback) { |
| 275 // TODO(bburns): add UMA metrics here (and for levelDB). | 283 // TODO(bburns): add UMA metrics here (and for levelDB). |
|
dewittj
2016/09/13 21:43:51
But if you do move the functions, it might be wise
fgorski
2016/09/13 22:08:59
I'll get to that later.
| |
| 276 bool ok = InsertOrReplace(db, offline_page); | 284 bool ok = InsertOrReplace(db, offline_page); |
| 277 runner->PostTask(FROM_HERE, base::Bind(callback, ok)); | 285 runner->PostTask(FROM_HERE, base::Bind(callback, ok)); |
| 278 } | 286 } |
| 279 | 287 |
| 280 void RemoveOfflinePagesSync( | 288 void RemoveOfflinePagesSync( |
| 281 const std::vector<int64_t>& offline_ids, | 289 const std::vector<int64_t>& offline_ids, |
| 282 sql::Connection* db, | 290 sql::Connection* db, |
| 283 scoped_refptr<base::SingleThreadTaskRunner> runner, | 291 scoped_refptr<base::SingleThreadTaskRunner> runner, |
| 284 const OfflinePageMetadataStore::UpdateCallback& callback) { | 292 const OfflinePageMetadataStore::UpdateCallback& callback) { |
| 285 // TODO(bburns): add UMA metrics here (and for levelDB). | 293 // TODO(bburns): add UMA metrics here (and for levelDB). |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 425 DCHECK(db_.get()); | 433 DCHECK(db_.get()); |
| 426 if (!db_.get()) { | 434 if (!db_.get()) { |
| 427 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | 435 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
| 428 base::Bind(callback)); | 436 base::Bind(callback)); |
| 429 return false; | 437 return false; |
| 430 } | 438 } |
| 431 return true; | 439 return true; |
| 432 } | 440 } |
| 433 | 441 |
| 434 } // namespace offline_pages | 442 } // namespace offline_pages |
| OLD | NEW |