Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/browser/predictors/resource_prefetch_predictor_tables.h" | 5 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h" |
| 6 | 6 |
| 7 #include <stdint.h> | |
| 8 | |
| 9 #include <algorithm> | 7 #include <algorithm> |
| 10 #include <memory> | |
| 11 #include <utility> | 8 #include <utility> |
| 12 | 9 |
| 13 #include "base/logging.h" | 10 #include "base/memory/ptr_util.h" |
| 14 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
| 15 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 16 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
| 17 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
| 18 #include "sql/meta_table.h" | |
| 19 #include "sql/statement.h" | 15 #include "sql/statement.h" |
| 20 #include "sql/transaction.h" | |
| 21 | 16 |
| 22 using content::BrowserThread; | 17 using google::protobuf::MessageLite; |
| 23 using sql::Statement; | |
|
Benoit L
2016/11/04 15:03:10
Why?
alexilin
2016/11/04 15:29:47
sql::Statement is more readable than just Statemen
| |
| 24 | 18 |
| 25 namespace { | 19 namespace { |
| 26 | 20 |
| 27 using PrefetchData = predictors::PrefetchData; | |
| 28 using RedirectData = predictors::RedirectData; | |
| 29 using ::google::protobuf::MessageLite; | |
| 30 | |
| 31 const char kMetadataTableName[] = "resource_prefetch_predictor_metadata"; | 21 const char kMetadataTableName[] = "resource_prefetch_predictor_metadata"; |
| 32 const char kUrlResourceTableName[] = "resource_prefetch_predictor_url"; | 22 const char kUrlResourceTableName[] = "resource_prefetch_predictor_url"; |
| 33 const char kUrlRedirectTableName[] = "resource_prefetch_predictor_url_redirect"; | 23 const char kUrlRedirectTableName[] = "resource_prefetch_predictor_url_redirect"; |
| 34 const char kHostResourceTableName[] = "resource_prefetch_predictor_host"; | 24 const char kHostResourceTableName[] = "resource_prefetch_predictor_host"; |
| 35 const char kHostRedirectTableName[] = | 25 const char kHostRedirectTableName[] = |
| 36 "resource_prefetch_predictor_host_redirect"; | 26 "resource_prefetch_predictor_host_redirect"; |
| 37 | 27 |
| 38 const char kCreateGlobalMetadataStatementTemplate[] = | 28 const char kCreateGlobalMetadataStatementTemplate[] = |
| 39 "CREATE TABLE %s ( " | 29 "CREATE TABLE %s ( " |
| 40 "key TEXT, value INTEGER, " | 30 "key TEXT, value INTEGER, " |
| 41 "PRIMARY KEY (key))"; | 31 "PRIMARY KEY (key))"; |
| 42 const char kCreateProtoTableStatementTemplate[] = | 32 const char kCreateProtoTableStatementTemplate[] = |
| 43 "CREATE TABLE %s ( " | 33 "CREATE TABLE %s ( " |
| 44 "key TEXT, " | 34 "key TEXT, " |
| 45 "proto BLOB, " | 35 "proto BLOB, " |
| 46 "PRIMARY KEY(key))"; | 36 "PRIMARY KEY(key))"; |
| 47 const char kInsertProtoTableStatementTemplate[] = | 37 const char kInsertProtoTableStatementTemplate[] = |
| 48 "INSERT INTO %s (key, proto) VALUES (?,?)"; | 38 "INSERT INTO %s (key, proto) VALUES (?,?)"; |
| 49 const char kDeleteProtoTableStatementTemplate[] = "DELETE FROM %s WHERE key=?"; | 39 const char kDeleteProtoTableStatementTemplate[] = "DELETE FROM %s WHERE key=?"; |
| 50 | 40 |
| 51 void BindProtoDataToStatement(const std::string& key, | 41 void BindProtoDataToStatement(const std::string& key, |
| 52 const MessageLite& data, | 42 const MessageLite& data, |
| 53 Statement* statement) { | 43 sql::Statement* statement) { |
| 54 int size = data.ByteSize(); | 44 int size = data.ByteSize(); |
| 55 DCHECK_GT(size, 0); | 45 DCHECK_GT(size, 0); |
| 56 std::vector<char> proto_buffer(size); | 46 std::vector<char> proto_buffer(size); |
| 57 data.SerializeToArray(&proto_buffer[0], size); | 47 data.SerializeToArray(&proto_buffer[0], size); |
| 58 | 48 |
| 59 statement->BindString(0, key); | 49 statement->BindString(0, key); |
| 60 statement->BindBlob(1, &proto_buffer[0], size); | 50 statement->BindBlob(1, &proto_buffer[0], size); |
| 61 } | 51 } |
| 62 | 52 |
| 63 bool StepAndInitializeProtoData(Statement* statement, | 53 bool StepAndInitializeProtoData(sql::Statement* statement, |
| 64 std::string* key, | 54 std::string* key, |
| 65 MessageLite* data) { | 55 MessageLite* data) { |
| 66 if (!statement->Step()) | 56 if (!statement->Step()) |
| 67 return false; | 57 return false; |
| 68 | 58 |
| 69 *key = statement->ColumnString(0); | 59 *key = statement->ColumnString(0); |
| 70 | 60 |
| 71 int size = statement->ColumnByteLength(1); | 61 int size = statement->ColumnByteLength(1); |
| 72 const void* blob = statement->ColumnBlob(1); | 62 const void* blob = statement->ColumnBlob(1); |
| 73 DCHECK(blob); | 63 DCHECK(blob); |
| 74 data->ParseFromArray(blob, size); | 64 data->ParseFromArray(blob, size); |
| 75 | 65 |
| 76 return true; | 66 return true; |
| 77 } | 67 } |
| 78 | 68 |
| 79 } // namespace | 69 } // namespace |
| 80 | 70 |
| 81 namespace predictors { | 71 namespace predictors { |
| 82 | 72 |
| 83 // static | 73 using content::BrowserThread; |
| 84 void ResourcePrefetchPredictorTables::TrimResources( | |
| 85 PrefetchData* data, | |
| 86 size_t max_consecutive_misses) { | |
| 87 auto new_end = std::remove_if( | |
| 88 data->mutable_resources()->begin(), data->mutable_resources()->end(), | |
| 89 [max_consecutive_misses](const ResourceData& x) { | |
| 90 return x.consecutive_misses() >= max_consecutive_misses; | |
| 91 }); | |
| 92 data->mutable_resources()->erase(new_end, data->mutable_resources()->end()); | |
| 93 } | |
| 94 | |
| 95 // static | |
| 96 void ResourcePrefetchPredictorTables::SortResources(PrefetchData* data) { | |
| 97 std::sort(data->mutable_resources()->begin(), | |
| 98 data->mutable_resources()->end(), | |
| 99 [](const ResourceData& x, const ResourceData& y) { | |
| 100 // Decreasing score ordering. | |
| 101 return ComputeResourceScore(x) > ComputeResourceScore(y); | |
| 102 }); | |
| 103 } | |
| 104 | |
| 105 // static | |
| 106 void ResourcePrefetchPredictorTables::TrimRedirects( | |
| 107 RedirectData* data, | |
| 108 size_t max_consecutive_misses) { | |
| 109 auto new_end = | |
| 110 std::remove_if(data->mutable_redirect_endpoints()->begin(), | |
| 111 data->mutable_redirect_endpoints()->end(), | |
| 112 [max_consecutive_misses](const RedirectStat& x) { | |
| 113 return x.consecutive_misses() >= max_consecutive_misses; | |
| 114 }); | |
| 115 data->mutable_redirect_endpoints()->erase( | |
| 116 new_end, data->mutable_redirect_endpoints()->end()); | |
| 117 } | |
| 118 | 74 |
| 119 void ResourcePrefetchPredictorTables::GetAllData( | 75 void ResourcePrefetchPredictorTables::GetAllData( |
| 120 PrefetchDataMap* url_data_map, | 76 PrefetchDataMap* url_data_map, |
| 121 PrefetchDataMap* host_data_map, | 77 PrefetchDataMap* host_data_map, |
| 122 RedirectDataMap* url_redirect_data_map, | 78 RedirectDataMap* url_redirect_data_map, |
| 123 RedirectDataMap* host_redirect_data_map) { | 79 RedirectDataMap* host_redirect_data_map) { |
| 124 TRACE_EVENT0("browser", "ResourcePrefetchPredictor::GetAllData"); | 80 TRACE_EVENT0("browser", "ResourcePrefetchPredictor::GetAllData"); |
| 125 DCHECK_CURRENTLY_ON(BrowserThread::DB); | 81 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 126 if (CantAccessDatabase()) | 82 if (CantAccessDatabase()) |
| 127 return; | 83 return; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 return; | 180 return; |
| 225 | 181 |
| 226 DeleteDataHelper(key_type, PrefetchDataType::REDIRECT, {key}); | 182 DeleteDataHelper(key_type, PrefetchDataType::REDIRECT, {key}); |
| 227 } | 183 } |
| 228 | 184 |
| 229 void ResourcePrefetchPredictorTables::DeleteAllData() { | 185 void ResourcePrefetchPredictorTables::DeleteAllData() { |
| 230 DCHECK_CURRENTLY_ON(BrowserThread::DB); | 186 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 231 if (CantAccessDatabase()) | 187 if (CantAccessDatabase()) |
| 232 return; | 188 return; |
| 233 | 189 |
| 234 Statement deleter; | 190 sql::Statement deleter; |
| 235 for (const char* table_name : | 191 for (const char* table_name : |
| 236 {kUrlResourceTableName, kUrlRedirectTableName, kHostResourceTableName, | 192 {kUrlResourceTableName, kUrlRedirectTableName, kHostResourceTableName, |
| 237 kHostRedirectTableName}) { | 193 kHostRedirectTableName}) { |
| 238 deleter.Assign(DB()->GetUniqueStatement( | 194 deleter.Assign(DB()->GetUniqueStatement( |
| 239 base::StringPrintf("DELETE FROM %s", table_name).c_str())); | 195 base::StringPrintf("DELETE FROM %s", table_name).c_str())); |
| 240 deleter.Run(); | 196 deleter.Run(); |
| 241 } | 197 } |
| 242 } | 198 } |
| 243 | 199 |
| 244 ResourcePrefetchPredictorTables::ResourcePrefetchPredictorTables() | 200 // static |
| 245 : PredictorTableBase() {} | 201 void ResourcePrefetchPredictorTables::TrimResources( |
| 202 PrefetchData* data, | |
| 203 size_t max_consecutive_misses) { | |
| 204 auto new_end = std::remove_if( | |
| 205 data->mutable_resources()->begin(), data->mutable_resources()->end(), | |
| 206 [max_consecutive_misses](const ResourceData& x) { | |
| 207 return x.consecutive_misses() >= max_consecutive_misses; | |
| 208 }); | |
| 209 data->mutable_resources()->erase(new_end, data->mutable_resources()->end()); | |
| 210 } | |
| 211 | |
| 212 // static | |
| 213 void ResourcePrefetchPredictorTables::SortResources(PrefetchData* data) { | |
| 214 std::sort(data->mutable_resources()->begin(), | |
| 215 data->mutable_resources()->end(), | |
| 216 [](const ResourceData& x, const ResourceData& y) { | |
| 217 // Decreasing score ordering. | |
| 218 return ComputeResourceScore(x) > ComputeResourceScore(y); | |
| 219 }); | |
| 220 } | |
| 221 | |
| 222 // static | |
| 223 float ResourcePrefetchPredictorTables::ComputeResourceScore( | |
| 224 const ResourceData& data) { | |
| 225 // The ranking is done by considering, in this order: | |
| 226 // 1. Resource Priority | |
| 227 // 2. Request resource type | |
| 228 // 3. Finally, the average position, giving a higher priotity to earlier | |
| 229 // resources. | |
| 230 | |
| 231 int priority_multiplier; | |
| 232 switch (data.priority()) { | |
| 233 case ResourceData::REQUEST_PRIORITY_HIGHEST: | |
| 234 priority_multiplier = 3; | |
| 235 break; | |
| 236 case ResourceData::REQUEST_PRIORITY_MEDIUM: | |
| 237 priority_multiplier = 2; | |
| 238 break; | |
| 239 case ResourceData::REQUEST_PRIORITY_LOW: | |
| 240 case ResourceData::REQUEST_PRIORITY_LOWEST: | |
| 241 case ResourceData::REQUEST_PRIORITY_IDLE: | |
| 242 default: | |
| 243 priority_multiplier = 1; | |
| 244 break; | |
| 245 } | |
| 246 | |
| 247 int type_multiplier; | |
| 248 switch (data.resource_type()) { | |
| 249 case ResourceData::RESOURCE_TYPE_STYLESHEET: | |
| 250 case ResourceData::RESOURCE_TYPE_SCRIPT: | |
| 251 type_multiplier = 3; | |
| 252 break; | |
| 253 case ResourceData::RESOURCE_TYPE_FONT_RESOURCE: | |
| 254 type_multiplier = 2; | |
| 255 break; | |
| 256 case ResourceData::RESOURCE_TYPE_IMAGE: | |
| 257 default: | |
| 258 type_multiplier = 1; | |
| 259 } | |
| 260 | |
| 261 constexpr int kMaxResourcesPerType = 100; | |
| 262 return kMaxResourcesPerType * | |
| 263 (priority_multiplier * 100 + type_multiplier * 10) - | |
| 264 data.average_position(); | |
| 265 } | |
| 266 | |
| 267 // static | |
| 268 void ResourcePrefetchPredictorTables::TrimRedirects( | |
| 269 RedirectData* data, | |
| 270 size_t max_consecutive_misses) { | |
| 271 auto new_end = | |
| 272 std::remove_if(data->mutable_redirect_endpoints()->begin(), | |
| 273 data->mutable_redirect_endpoints()->end(), | |
| 274 [max_consecutive_misses](const RedirectStat& x) { | |
| 275 return x.consecutive_misses() >= max_consecutive_misses; | |
| 276 }); | |
| 277 data->mutable_redirect_endpoints()->erase( | |
| 278 new_end, data->mutable_redirect_endpoints()->end()); | |
| 279 } | |
| 280 | |
| 281 ResourcePrefetchPredictorTables::ResourcePrefetchPredictorTables() {} | |
| 246 | 282 |
| 247 ResourcePrefetchPredictorTables::~ResourcePrefetchPredictorTables() {} | 283 ResourcePrefetchPredictorTables::~ResourcePrefetchPredictorTables() {} |
| 248 | 284 |
| 249 void ResourcePrefetchPredictorTables::GetAllResourceDataHelper( | 285 void ResourcePrefetchPredictorTables::GetAllResourceDataHelper( |
| 250 PrefetchKeyType key_type, | 286 PrefetchKeyType key_type, |
| 251 PrefetchDataMap* data_map) { | 287 PrefetchDataMap* data_map) { |
| 252 // Read the resources table and organize it per primary key. | 288 // Read the resources table and organize it per primary key. |
| 253 const char* table_name = GetTableName(key_type, PrefetchDataType::RESOURCE); | 289 const char* table_name = GetTableName(key_type, PrefetchDataType::RESOURCE); |
| 254 Statement resource_reader(DB()->GetUniqueStatement( | 290 sql::Statement resource_reader(DB()->GetUniqueStatement( |
| 255 base::StringPrintf("SELECT * FROM %s", table_name).c_str())); | 291 base::StringPrintf("SELECT * FROM %s", table_name).c_str())); |
| 256 | 292 |
| 257 PrefetchData data; | 293 PrefetchData data; |
| 258 std::string key; | 294 std::string key; |
| 259 while (StepAndInitializeProtoData(&resource_reader, &key, &data)) { | 295 while (StepAndInitializeProtoData(&resource_reader, &key, &data)) { |
| 260 data_map->insert(std::make_pair(key, data)); | 296 data_map->insert(std::make_pair(key, data)); |
| 261 DCHECK_EQ(data.primary_key(), key); | 297 DCHECK_EQ(data.primary_key(), key); |
| 262 } | 298 } |
| 263 | 299 |
| 264 // Sort each of the resource vectors by score. | 300 // Sort each of the resource vectors by score. |
| 265 for (auto& kv : *data_map) { | 301 for (auto& kv : *data_map) { |
| 266 SortResources(&(kv.second)); | 302 SortResources(&(kv.second)); |
| 267 } | 303 } |
| 268 } | 304 } |
| 269 | 305 |
| 270 void ResourcePrefetchPredictorTables::GetAllRedirectDataHelper( | 306 void ResourcePrefetchPredictorTables::GetAllRedirectDataHelper( |
| 271 PrefetchKeyType key_type, | 307 PrefetchKeyType key_type, |
| 272 RedirectDataMap* data_map) { | 308 RedirectDataMap* data_map) { |
| 273 // Read the redirects table and organize it per primary key. | 309 // Read the redirects table and organize it per primary key. |
| 274 const char* table_name = GetTableName(key_type, PrefetchDataType::REDIRECT); | 310 const char* table_name = GetTableName(key_type, PrefetchDataType::REDIRECT); |
| 275 Statement redirect_reader(DB()->GetUniqueStatement( | 311 sql::Statement redirect_reader(DB()->GetUniqueStatement( |
| 276 base::StringPrintf("SELECT * FROM %s", table_name).c_str())); | 312 base::StringPrintf("SELECT * FROM %s", table_name).c_str())); |
| 277 | 313 |
| 278 RedirectData data; | 314 RedirectData data; |
| 279 std::string key; | 315 std::string key; |
| 280 while (StepAndInitializeProtoData(&redirect_reader, &key, &data)) { | 316 while (StepAndInitializeProtoData(&redirect_reader, &key, &data)) { |
| 281 data_map->insert(std::make_pair(key, data)); | 317 data_map->insert(std::make_pair(key, data)); |
| 282 DCHECK_EQ(data.primary_key(), key); | 318 DCHECK_EQ(data.primary_key(), key); |
| 283 } | 319 } |
| 284 } | 320 } |
| 285 | 321 |
| 286 bool ResourcePrefetchPredictorTables::UpdateDataHelper( | 322 bool ResourcePrefetchPredictorTables::UpdateDataHelper( |
| 287 PrefetchKeyType key_type, | 323 PrefetchKeyType key_type, |
| 288 PrefetchDataType data_type, | 324 PrefetchDataType data_type, |
| 289 const std::string& key, | 325 const std::string& key, |
| 290 const MessageLite& data) { | 326 const MessageLite& data) { |
| 291 // Delete the older data from the table. | 327 // Delete the older data from the table. |
| 292 std::unique_ptr<Statement> deleter( | 328 std::unique_ptr<sql::Statement> deleter( |
| 293 GetTableUpdateStatement(key_type, data_type, TableOperationType::REMOVE)); | 329 GetTableUpdateStatement(key_type, data_type, TableOperationType::REMOVE)); |
| 294 deleter->BindString(0, key); | 330 deleter->BindString(0, key); |
| 295 if (!deleter->Run()) | 331 if (!deleter->Run()) |
| 296 return false; | 332 return false; |
| 297 | 333 |
| 298 // Add the new data to the table. | 334 // Add the new data to the table. |
| 299 std::unique_ptr<Statement> inserter( | 335 std::unique_ptr<sql::Statement> inserter( |
| 300 GetTableUpdateStatement(key_type, data_type, TableOperationType::INSERT)); | 336 GetTableUpdateStatement(key_type, data_type, TableOperationType::INSERT)); |
| 301 BindProtoDataToStatement(key, data, inserter.get()); | 337 BindProtoDataToStatement(key, data, inserter.get()); |
| 302 return inserter->Run(); | 338 return inserter->Run(); |
| 303 } | 339 } |
| 304 | 340 |
| 305 void ResourcePrefetchPredictorTables::DeleteDataHelper( | 341 void ResourcePrefetchPredictorTables::DeleteDataHelper( |
| 306 PrefetchKeyType key_type, | 342 PrefetchKeyType key_type, |
| 307 PrefetchDataType data_type, | 343 PrefetchDataType data_type, |
| 308 const std::vector<std::string>& keys) { | 344 const std::vector<std::string>& keys) { |
| 309 for (const std::string& key : keys) { | 345 for (const std::string& key : keys) { |
| 310 std::unique_ptr<Statement> deleter(GetTableUpdateStatement( | 346 std::unique_ptr<sql::Statement> deleter(GetTableUpdateStatement( |
| 311 key_type, data_type, TableOperationType::REMOVE)); | 347 key_type, data_type, TableOperationType::REMOVE)); |
| 312 deleter->BindString(0, key); | 348 deleter->BindString(0, key); |
| 313 deleter->Run(); | 349 deleter->Run(); |
| 314 } | 350 } |
| 315 } | 351 } |
| 316 | 352 |
| 317 // static | 353 void ResourcePrefetchPredictorTables::CreateTableIfNonExistent() { |
| 318 float ResourcePrefetchPredictorTables::ComputeResourceScore( | 354 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 319 const ResourceData& data) { | 355 if (CantAccessDatabase()) |
| 320 // The ranking is done by considering, in this order: | 356 return; |
| 321 // 1. Resource Priority | |
| 322 // 2. Request resource type | |
| 323 // 3. Finally, the average position, giving a higher priotity to earlier | |
| 324 // resources. | |
| 325 | 357 |
| 326 int priority_multiplier; | 358 // Database initialization is all-or-nothing. |
| 327 switch (data.priority()) { | 359 bool success = DB()->BeginTransaction(); |
| 328 case ResourceData::REQUEST_PRIORITY_HIGHEST: | 360 |
| 329 priority_multiplier = 3; | 361 success = success && DropTablesIfOutdated(); |
| 330 break; | 362 |
| 331 case ResourceData::REQUEST_PRIORITY_MEDIUM: | 363 for (const char* table_name : |
| 332 priority_multiplier = 2; | 364 {kUrlResourceTableName, kHostResourceTableName, kUrlRedirectTableName, |
| 333 break; | 365 kHostRedirectTableName}) { |
| 334 case ResourceData::REQUEST_PRIORITY_LOW: | 366 success = success && |
| 335 case ResourceData::REQUEST_PRIORITY_LOWEST: | 367 (DB()->DoesTableExist(table_name) || |
| 336 case ResourceData::REQUEST_PRIORITY_IDLE: | 368 DB()->Execute(base::StringPrintf( |
| 337 default: | 369 kCreateProtoTableStatementTemplate, table_name) |
| 338 priority_multiplier = 1; | 370 .c_str())); |
| 339 break; | |
| 340 } | 371 } |
| 341 | 372 |
| 342 int type_multiplier; | 373 if (success) |
| 343 switch (data.resource_type()) { | 374 success = DB()->CommitTransaction(); |
| 344 case ResourceData::RESOURCE_TYPE_STYLESHEET: | 375 else |
| 345 case ResourceData::RESOURCE_TYPE_SCRIPT: | 376 DB()->RollbackTransaction(); |
| 346 type_multiplier = 3; | |
| 347 break; | |
| 348 case ResourceData::RESOURCE_TYPE_FONT_RESOURCE: | |
| 349 type_multiplier = 2; | |
| 350 break; | |
| 351 case ResourceData::RESOURCE_TYPE_IMAGE: | |
| 352 default: | |
| 353 type_multiplier = 1; | |
| 354 } | |
| 355 | 377 |
| 356 constexpr int kMaxResourcesPerType = 100; | 378 if (!success) |
| 357 return kMaxResourcesPerType * | 379 ResetDB(); |
| 358 (priority_multiplier * 100 + type_multiplier * 10) - | |
| 359 data.average_position(); | |
| 360 } | 380 } |
| 361 | 381 |
| 362 // static | 382 void ResourcePrefetchPredictorTables::LogDatabaseStats() { |
| 363 bool ResourcePrefetchPredictorTables::DropTablesIfOutdated( | 383 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 364 sql::Connection* db) { | 384 if (CantAccessDatabase()) |
| 365 int version = GetDatabaseVersion(db); | 385 return; |
| 366 bool success = true; | 386 |
| 387 sql::Statement statement(DB()->GetUniqueStatement( | |
| 388 base::StringPrintf("SELECT count(*) FROM %s", kUrlResourceTableName) | |
| 389 .c_str())); | |
| 390 if (statement.Step()) | |
| 391 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableRowCount", | |
| 392 statement.ColumnInt(0)); | |
| 393 | |
| 394 statement.Assign(DB()->GetUniqueStatement( | |
| 395 base::StringPrintf("SELECT count(*) FROM %s", kHostResourceTableName) | |
| 396 .c_str())); | |
| 397 if (statement.Step()) | |
| 398 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HostTableRowCount", | |
| 399 statement.ColumnInt(0)); | |
| 400 } | |
| 401 | |
| 402 bool ResourcePrefetchPredictorTables::DropTablesIfOutdated() { | |
| 403 int version = GetDatabaseVersion(); | |
| 367 // Too new is also a problem. | 404 // Too new is also a problem. |
| 368 bool incompatible_version = version != kDatabaseVersion; | 405 bool incompatible_version = version != kDatabaseVersion; |
| 369 | 406 |
| 370 // These are deprecated tables but they still have to be removed if present. | 407 // These are deprecated tables but they still have to be removed if present. |
| 371 const char kUrlMetadataTableName[] = | 408 static const char kUrlMetadataTableName[] = |
| 372 "resource_prefetch_predictor_url_metadata"; | 409 "resource_prefetch_predictor_url_metadata"; |
| 373 const char kHostMetadataTableName[] = | 410 static const char kHostMetadataTableName[] = |
| 374 "resource_prefetch_predictor_host_metadata"; | 411 "resource_prefetch_predictor_host_metadata"; |
| 375 | 412 |
| 413 bool success = true; | |
| 376 if (incompatible_version) { | 414 if (incompatible_version) { |
| 377 for (const char* table_name : | 415 for (const char* table_name : |
| 378 {kMetadataTableName, kUrlResourceTableName, kHostResourceTableName, | 416 {kMetadataTableName, kUrlResourceTableName, kHostResourceTableName, |
| 379 kUrlRedirectTableName, kHostRedirectTableName, kUrlMetadataTableName, | 417 kUrlRedirectTableName, kHostRedirectTableName, kUrlMetadataTableName, |
| 380 kHostMetadataTableName}) { | 418 kHostMetadataTableName}) { |
| 381 success = | 419 success = success && |
| 382 success && | 420 DB()->Execute( |
| 383 db->Execute(base::StringPrintf("DROP TABLE IF EXISTS %s", table_name) | 421 base::StringPrintf("DROP TABLE IF EXISTS %s", table_name) |
| 384 .c_str()); | 422 .c_str()); |
| 385 } | 423 } |
| 386 } | |
| 387 | 424 |
| 388 if (incompatible_version) { | |
| 389 success = | 425 success = |
| 390 success && | 426 success && |
| 391 db->Execute(base::StringPrintf(kCreateGlobalMetadataStatementTemplate, | 427 DB()->Execute(base::StringPrintf(kCreateGlobalMetadataStatementTemplate, |
| 392 kMetadataTableName) | 428 kMetadataTableName) |
| 393 .c_str()); | 429 .c_str()); |
| 394 success = success && SetDatabaseVersion(db, kDatabaseVersion); | 430 success = success && SetDatabaseVersion(kDatabaseVersion); |
| 395 } | 431 } |
| 396 | 432 |
| 397 return success; | 433 return success; |
| 398 } | 434 } |
| 399 | 435 |
| 400 // static | 436 int ResourcePrefetchPredictorTables::GetDatabaseVersion() { |
| 401 int ResourcePrefetchPredictorTables::GetDatabaseVersion(sql::Connection* db) { | |
| 402 int version = 0; | 437 int version = 0; |
| 403 if (db->DoesTableExist(kMetadataTableName)) { | 438 if (DB()->DoesTableExist(kMetadataTableName)) { |
| 404 sql::Statement statement(db->GetUniqueStatement( | 439 sql::Statement statement(DB()->GetUniqueStatement( |
| 405 base::StringPrintf("SELECT value FROM %s WHERE key='version'", | 440 base::StringPrintf("SELECT value FROM %s WHERE key='version'", |
| 406 kMetadataTableName) | 441 kMetadataTableName) |
| 407 .c_str())); | 442 .c_str())); |
| 408 if (statement.Step()) | 443 if (statement.Step()) |
| 409 version = statement.ColumnInt(0); | 444 version = statement.ColumnInt(0); |
| 410 } | 445 } |
| 411 return version; | 446 return version; |
| 412 } | 447 } |
| 413 | 448 |
| 414 // static | 449 bool ResourcePrefetchPredictorTables::SetDatabaseVersion(int version) { |
| 415 bool ResourcePrefetchPredictorTables::SetDatabaseVersion(sql::Connection* db, | 450 sql::Statement statement(DB()->GetUniqueStatement( |
| 416 int version) { | |
| 417 sql::Statement statement(db->GetUniqueStatement( | |
| 418 base::StringPrintf( | 451 base::StringPrintf( |
| 419 "INSERT OR REPLACE INTO %s (key,value) VALUES ('version',%d)", | 452 "INSERT OR REPLACE INTO %s (key,value) VALUES ('version',%d)", |
| 420 kMetadataTableName, version) | 453 kMetadataTableName, version) |
| 421 .c_str())); | 454 .c_str())); |
| 422 return statement.Run(); | 455 return statement.Run(); |
| 423 } | 456 } |
| 424 | 457 |
| 425 void ResourcePrefetchPredictorTables::CreateTableIfNonExistent() { | 458 std::unique_ptr<sql::Statement> |
| 426 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 427 if (CantAccessDatabase()) | |
| 428 return; | |
| 429 | |
| 430 // Database initialization is all-or-nothing. | |
| 431 sql::Connection* db = DB(); | |
| 432 sql::Transaction transaction{db}; | |
| 433 bool success = transaction.Begin(); | |
| 434 | |
| 435 success = success && DropTablesIfOutdated(db); | |
| 436 | |
| 437 for (const char* table_name : | |
| 438 {kUrlResourceTableName, kHostResourceTableName, kUrlRedirectTableName, | |
| 439 kHostRedirectTableName}) { | |
| 440 success = success && | |
| 441 (db->DoesTableExist(table_name) || | |
| 442 db->Execute(base::StringPrintf( | |
| 443 kCreateProtoTableStatementTemplate, table_name) | |
| 444 .c_str())); | |
| 445 } | |
| 446 | |
| 447 if (success) | |
| 448 success = transaction.Commit(); | |
| 449 else | |
| 450 transaction.Rollback(); | |
| 451 | |
| 452 if (!success) | |
| 453 ResetDB(); | |
| 454 } | |
| 455 | |
| 456 void ResourcePrefetchPredictorTables::LogDatabaseStats() { | |
| 457 DCHECK_CURRENTLY_ON(BrowserThread::DB); | |
| 458 if (CantAccessDatabase()) | |
| 459 return; | |
| 460 | |
| 461 Statement statement(DB()->GetUniqueStatement( | |
| 462 base::StringPrintf("SELECT count(*) FROM %s", | |
| 463 kUrlResourceTableName).c_str())); | |
| 464 if (statement.Step()) | |
| 465 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableRowCount", | |
| 466 statement.ColumnInt(0)); | |
| 467 | |
| 468 statement.Assign(DB()->GetUniqueStatement( | |
| 469 base::StringPrintf("SELECT count(*) FROM %s", | |
| 470 kHostResourceTableName).c_str())); | |
| 471 if (statement.Step()) | |
| 472 UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HostTableRowCount", | |
| 473 statement.ColumnInt(0)); | |
| 474 } | |
| 475 | |
| 476 std::unique_ptr<Statement> | |
| 477 ResourcePrefetchPredictorTables::GetTableUpdateStatement( | 459 ResourcePrefetchPredictorTables::GetTableUpdateStatement( |
| 478 PrefetchKeyType key_type, | 460 PrefetchKeyType key_type, |
| 479 PrefetchDataType data_type, | 461 PrefetchDataType data_type, |
| 480 TableOperationType op_type) { | 462 TableOperationType op_type) { |
| 481 sql::StatementID id(__FILE__, key_type | (static_cast<int>(data_type) << 1) | | 463 sql::StatementID id(__FILE__, key_type | (static_cast<int>(data_type) << 1) | |
| 482 (static_cast<int>(op_type) << 2)); | 464 (static_cast<int>(op_type) << 2)); |
| 483 const char* statement_template = (op_type == TableOperationType::REMOVE | 465 const char* statement_template = (op_type == TableOperationType::REMOVE |
| 484 ? kDeleteProtoTableStatementTemplate | 466 ? kDeleteProtoTableStatementTemplate |
| 485 : kInsertProtoTableStatementTemplate); | 467 : kInsertProtoTableStatementTemplate); |
| 486 const char* table_name = GetTableName(key_type, data_type); | 468 const char* table_name = GetTableName(key_type, data_type); |
| 487 return base::MakeUnique<Statement>(DB()->GetCachedStatement( | 469 return base::MakeUnique<sql::Statement>(DB()->GetCachedStatement( |
| 488 id, base::StringPrintf(statement_template, table_name).c_str())); | 470 id, base::StringPrintf(statement_template, table_name).c_str())); |
| 489 } | 471 } |
| 490 | 472 |
| 491 // static | 473 // static |
| 492 const char* ResourcePrefetchPredictorTables::GetTableName( | 474 const char* ResourcePrefetchPredictorTables::GetTableName( |
| 493 PrefetchKeyType key_type, | 475 PrefetchKeyType key_type, |
| 494 PrefetchDataType data_type) { | 476 PrefetchDataType data_type) { |
| 495 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; | 477 bool is_host = key_type == PREFETCH_KEY_TYPE_HOST; |
| 496 switch (data_type) { | 478 switch (data_type) { |
| 497 case PrefetchDataType::RESOURCE: | 479 case PrefetchDataType::RESOURCE: |
| 498 return is_host ? kHostResourceTableName : kUrlResourceTableName; | 480 return is_host ? kHostResourceTableName : kUrlResourceTableName; |
| 499 case PrefetchDataType::REDIRECT: | 481 case PrefetchDataType::REDIRECT: |
| 500 return is_host ? kHostRedirectTableName : kUrlRedirectTableName; | 482 return is_host ? kHostRedirectTableName : kUrlRedirectTableName; |
| 501 } | 483 } |
| 502 | 484 |
| 503 NOTREACHED(); | 485 NOTREACHED(); |
| 504 return nullptr; | 486 return nullptr; |
| 505 } | 487 } |
| 506 | 488 |
| 507 } // namespace predictors | 489 } // namespace predictors |
| OLD | NEW |