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> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> | 10 #include <memory> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 16 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
| 17 #include "sql/meta_table.h" | |
| 17 #include "sql/statement.h" | 18 #include "sql/statement.h" |
| 19 #include "sql/transaction.h" | |
| 18 | 20 |
| 19 using content::BrowserThread; | 21 using content::BrowserThread; |
| 20 using sql::Statement; | 22 using sql::Statement; |
| 21 | 23 |
| 22 namespace { | 24 namespace { |
| 23 | 25 |
| 24 using ResourceRow = predictors::ResourcePrefetchPredictorTables::ResourceRow; | 26 using ResourceRow = predictors::ResourcePrefetchPredictorTables::ResourceRow; |
| 25 | 27 |
| 28 const char kMetadataTableName[] = "resource_prefetch_predictor_metadata"; | |
| 26 const char kUrlResourceTableName[] = "resource_prefetch_predictor_url"; | 29 const char kUrlResourceTableName[] = "resource_prefetch_predictor_url"; |
| 27 const char kUrlMetadataTableName[] = "resource_prefetch_predictor_url_metadata"; | 30 const char kUrlMetadataTableName[] = "resource_prefetch_predictor_url_metadata"; |
| 28 const char kHostResourceTableName[] = "resource_prefetch_predictor_host"; | 31 const char kHostResourceTableName[] = "resource_prefetch_predictor_host"; |
| 29 const char kHostMetadataTableName[] = | 32 const char kHostMetadataTableName[] = |
| 30 "resource_prefetch_predictor_host_metadata"; | 33 "resource_prefetch_predictor_host_metadata"; |
| 31 | 34 |
| 35 const char kCreateGlobalMetadataStatementTemplate[] = | |
| 36 "CREATE TABLE %s ( " | |
| 37 "key TEXT, value INTEGER, " | |
| 38 "PRIMARY KEY (key))"; | |
| 39 const char kCreateResourceTableStatementTemplate[] = | |
| 40 "CREATE TABLE %s ( " | |
| 41 "main_page_url TEXT, " | |
| 42 "resource_url TEXT, " | |
| 43 "proto BLOB, " | |
| 44 "PRIMARY KEY(main_page_url, resource_url))"; | |
| 45 const char kCreateMetadataTableStatementTemplate[] = | |
| 46 "CREATE TABLE %s ( " | |
| 47 "main_page_url TEXT, " | |
| 48 "last_visit_time INTEGER, " | |
| 49 "PRIMARY KEY(main_page_url))"; | |
| 50 | |
| 32 const char kInsertResourceTableStatementTemplate[] = | 51 const char kInsertResourceTableStatementTemplate[] = |
| 33 "INSERT INTO %s (main_page_url, resource_url, proto) VALUES (?,?,?)"; | 52 "INSERT INTO %s (main_page_url, resource_url, proto) VALUES (?,?,?)"; |
| 34 const char kInsertMetadataTableStatementTemplate[] = | 53 const char kInsertMetadataTableStatementTemplate[] = |
| 35 "INSERT INTO %s (main_page_url, last_visit_time) VALUES (?,?)"; | 54 "INSERT INTO %s (main_page_url, last_visit_time) VALUES (?,?)"; |
| 36 const char kDeleteStatementTemplate[] = "DELETE FROM %s WHERE main_page_url=?"; | 55 const char kDeleteStatementTemplate[] = "DELETE FROM %s WHERE main_page_url=?"; |
| 37 | 56 |
| 57 // Database version. Always increment it when any change is made to the data | |
| 58 // schema (including the .proto). | |
|
pasko
2016/08/26 14:37:18
is this mandatory? We might be OK with default bac
Benoit L
2016/08/26 14:52:39
I prefer to err on the side of caution.
| |
| 59 const int kDatabaseVersion = 1; | |
| 60 | |
| 38 void BindResourceRowToStatement(const ResourceRow& row, | 61 void BindResourceRowToStatement(const ResourceRow& row, |
| 39 const std::string& primary_key, | 62 const std::string& primary_key, |
| 40 Statement* statement) { | 63 Statement* statement) { |
| 41 chrome_browser_predictors::ResourceData proto; | 64 chrome_browser_predictors::ResourceData proto; |
| 42 row.ToProto(&proto); | 65 row.ToProto(&proto); |
| 43 int size = proto.ByteSize(); | 66 int size = proto.ByteSize(); |
| 44 std::vector<char> proto_buffer(size); | 67 std::vector<char> proto_buffer(size); |
| 45 proto.SerializeToArray(&proto_buffer[0], size); | 68 proto.SerializeToArray(&proto_buffer[0], size); |
| 46 | 69 |
| 47 statement->BindString(0, primary_key); | 70 statement->BindString(0, primary_key); |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 428 return false; | 451 return false; |
| 429 | 452 |
| 430 for (ResourceRows::const_iterator it = data.resources.begin(); | 453 for (ResourceRows::const_iterator it = data.resources.begin(); |
| 431 it != data.resources.end(); ++it) { | 454 it != data.resources.end(); ++it) { |
| 432 if (it->resource_url.spec().length() > kMaxStringLength) | 455 if (it->resource_url.spec().length() > kMaxStringLength) |
| 433 return false; | 456 return false; |
| 434 } | 457 } |
| 435 return true; | 458 return true; |
| 436 } | 459 } |
| 437 | 460 |
| 461 // static | |
| 438 bool ResourcePrefetchPredictorTables::DropTablesIfOutdated( | 462 bool ResourcePrefetchPredictorTables::DropTablesIfOutdated( |
| 439 sql::Connection* db) { | 463 sql::Connection* db) { |
| 464 int tables_version = 0; | |
| 465 if (db->DoesTableExist(kMetadataTableName)) { | |
| 466 sql::Statement statement(db->GetUniqueStatement( | |
| 467 base::StringPrintf("SELECT value FROM %s WHERE key='version'", | |
| 468 kMetadataTableName) | |
| 469 .c_str())); | |
| 470 if (statement.Step()) | |
| 471 tables_version = statement.ColumnInt(0); | |
| 472 } | |
| 473 | |
| 440 bool success = true; | 474 bool success = true; |
| 441 for (const char* table_name : | 475 // Too new is also a problem. |
| 442 {kUrlResourceTableName, kHostResourceTableName}) { | 476 bool incompatible_version = tables_version != kDatabaseVersion; |
| 443 if (db->DoesTableExist(table_name) && | 477 |
| 444 !db->DoesColumnExist(table_name, "proto")) { | 478 if (incompatible_version) { |
| 445 success &= | 479 for (const char* table_name : |
| 446 db->Execute(base::StringPrintf("DROP TABLE %s", table_name).c_str()); | 480 {kMetadataTableName, kUrlResourceTableName, kHostResourceTableName, |
| 481 kUrlMetadataTableName, kHostMetadataTableName}) { | |
| 482 success &= db->Execute( | |
| 483 base::StringPrintf("DROP TABLE IF EXISTS %s", table_name).c_str()); | |
| 447 } | 484 } |
| 448 } | 485 } |
| 486 | |
| 487 if (incompatible_version) { | |
| 488 success &= | |
| 489 db->Execute(base::StringPrintf(kCreateGlobalMetadataStatementTemplate, | |
| 490 kMetadataTableName) | |
| 491 .c_str()); | |
| 492 | |
| 493 sql::Statement statement(db->GetUniqueStatement( | |
| 494 base::StringPrintf( | |
| 495 "INSERT OR REPLACE INTO %s (key,value) VALUES ('version',%d)", | |
| 496 kMetadataTableName, kDatabaseVersion) | |
| 497 .c_str())); | |
| 498 success &= statement.Run(); | |
| 499 } | |
| 500 | |
| 449 return success; | 501 return success; |
| 450 } | 502 } |
| 451 | 503 |
| 452 void ResourcePrefetchPredictorTables::CreateTableIfNonExistent() { | 504 void ResourcePrefetchPredictorTables::CreateTableIfNonExistent() { |
| 453 DCHECK_CURRENTLY_ON(BrowserThread::DB); | 505 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 454 if (CantAccessDatabase()) | 506 if (CantAccessDatabase()) |
| 455 return; | 507 return; |
| 456 | 508 |
| 457 const char resource_table_creator[] = | 509 // Database initialization is all-or-nothing. |
| 458 "CREATE TABLE %s ( " | 510 sql::Connection* db = DB(); |
| 459 "main_page_url TEXT, " | 511 sql::Transaction transaction{db}; |
| 460 "resource_url TEXT, " | 512 bool success = transaction.Begin(); |
| 461 "proto BLOB, " | |
| 462 "PRIMARY KEY(main_page_url, resource_url))"; | |
| 463 const char* metadata_table_creator = | |
| 464 "CREATE TABLE %s ( " | |
| 465 "main_page_url TEXT, " | |
| 466 "last_visit_time INTEGER, " | |
| 467 "PRIMARY KEY(main_page_url))"; | |
| 468 | 513 |
| 469 sql::Connection* db = DB(); | 514 success &= DropTablesIfOutdated(db); |
| 470 bool success = DropTablesIfOutdated(db) && | 515 |
| 471 (db->DoesTableExist(kUrlResourceTableName) || | 516 success &= |
| 472 db->Execute(base::StringPrintf(resource_table_creator, | 517 (db->DoesTableExist(kUrlResourceTableName) || |
|
pasko
2016/08/26 14:37:18
what if we decided to drop the table because its v
Benoit L
2016/08/26 14:52:39
We are within the transaction, so it's fine.
| |
| 473 kUrlResourceTableName) | 518 db->Execute(base::StringPrintf(kCreateResourceTableStatementTemplate, |
| 474 .c_str())) && | 519 kUrlResourceTableName) |
| 475 (db->DoesTableExist(kUrlMetadataTableName) || | 520 .c_str())) && |
| 476 db->Execute(base::StringPrintf(metadata_table_creator, | 521 (db->DoesTableExist(kUrlMetadataTableName) || |
| 477 kUrlMetadataTableName) | 522 db->Execute(base::StringPrintf(kCreateMetadataTableStatementTemplate, |
| 478 .c_str())) && | 523 kUrlMetadataTableName) |
| 479 (db->DoesTableExist(kHostResourceTableName) || | 524 .c_str())) && |
| 480 db->Execute(base::StringPrintf(resource_table_creator, | 525 (db->DoesTableExist(kHostResourceTableName) || |
| 481 kHostResourceTableName) | 526 db->Execute(base::StringPrintf(kCreateResourceTableStatementTemplate, |
| 482 .c_str())) && | 527 kHostResourceTableName) |
| 483 (db->DoesTableExist(kHostMetadataTableName) || | 528 .c_str())) && |
| 484 db->Execute(base::StringPrintf(metadata_table_creator, | 529 (db->DoesTableExist(kHostMetadataTableName) || |
| 485 kHostMetadataTableName) | 530 db->Execute(base::StringPrintf(kCreateMetadataTableStatementTemplate, |
| 486 .c_str())); | 531 kHostMetadataTableName) |
| 532 .c_str())); | |
| 533 | |
| 534 if (success) { | |
| 535 success = transaction.Commit(); | |
| 536 } else { | |
| 537 transaction.Rollback(); | |
| 538 } | |
|
pasko
2016/08/26 14:37:18
nit: I think chromium style suggests no braces in
Benoit L
2016/08/26 14:52:39
Done.
| |
| 487 | 539 |
| 488 if (!success) | 540 if (!success) |
| 489 ResetDB(); | 541 ResetDB(); |
| 490 } | 542 } |
| 491 | 543 |
| 492 void ResourcePrefetchPredictorTables::LogDatabaseStats() { | 544 void ResourcePrefetchPredictorTables::LogDatabaseStats() { |
| 493 DCHECK_CURRENTLY_ON(BrowserThread::DB); | 545 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 494 if (CantAccessDatabase()) | 546 if (CantAccessDatabase()) |
| 495 return; | 547 return; |
| 496 | 548 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 } | 618 } |
| 567 | 619 |
| 568 Statement* ResourcePrefetchPredictorTables::GetHostMetadataUpdateStatement() { | 620 Statement* ResourcePrefetchPredictorTables::GetHostMetadataUpdateStatement() { |
| 569 return new Statement(DB()->GetCachedStatement( | 621 return new Statement(DB()->GetCachedStatement( |
| 570 SQL_FROM_HERE, base::StringPrintf(kInsertMetadataTableStatementTemplate, | 622 SQL_FROM_HERE, base::StringPrintf(kInsertMetadataTableStatementTemplate, |
| 571 kHostMetadataTableName) | 623 kHostMetadataTableName) |
| 572 .c_str())); | 624 .c_str())); |
| 573 } | 625 } |
| 574 | 626 |
| 575 } // namespace predictors | 627 } // namespace predictors |
| OLD | NEW |