Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(330)

Side by Side Diff: components/history/core/browser/download_database.cc

Issue 2665243003: add a download slices table into history download db (Closed)
Patch Set: addressing comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/history/core/browser/download_database.h" 5 #include "components/history/core/browser/download_database.h"
6 6
7 #include <inttypes.h> 7 #include <inttypes.h>
8 8
9 #include <limits> 9 #include <limits>
10 #include <memory> 10 #include <memory>
11 #include <string> 11 #include <string>
12 #include <vector> 12 #include <vector>
13 13
14 #include "base/debug/alias.h" 14 #include "base/debug/alias.h"
15 #include "base/files/file_path.h" 15 #include "base/files/file_path.h"
16 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
17 #include "base/rand_util.h" 17 #include "base/rand_util.h"
18 #include "base/stl_util.h" 18 #include "base/stl_util.h"
19 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h" 20 #include "base/strings/utf_string_conversions.h"
21 #include "base/time/time.h" 21 #include "base/time/time.h"
22 #include "build/build_config.h" 22 #include "build/build_config.h"
23 #include "components/history/core/browser/download_constants.h" 23 #include "components/history/core/browser/download_constants.h"
24 #include "components/history/core/browser/download_job_info.h"
24 #include "components/history/core/browser/download_row.h" 25 #include "components/history/core/browser/download_row.h"
25 #include "components/history/core/browser/history_types.h" 26 #include "components/history/core/browser/history_types.h"
26 #include "sql/statement.h" 27 #include "sql/statement.h"
27 28
28 namespace history { 29 namespace history {
29 30
30 namespace { 31 namespace {
31 32
32 // Reason for dropping a particular record. Used for UMA. 33 // Reason for dropping a particular record. Used for UMA.
33 enum DroppedReason { 34 enum DroppedReason {
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 306
306 const char kUrlChainSchema[] = 307 const char kUrlChainSchema[] =
307 "CREATE TABLE downloads_url_chains (" 308 "CREATE TABLE downloads_url_chains ("
308 "id INTEGER NOT NULL," // downloads.id. 309 "id INTEGER NOT NULL," // downloads.id.
309 "chain_index INTEGER NOT NULL," // Index of url in chain 310 "chain_index INTEGER NOT NULL," // Index of url in chain
310 // 0 is initial target, 311 // 0 is initial target,
311 // MAX is target after redirects. 312 // MAX is target after redirects.
312 "url LONGVARCHAR NOT NULL, " // URL. 313 "url LONGVARCHAR NOT NULL, " // URL.
313 "PRIMARY KEY (id, chain_index) )"; 314 "PRIMARY KEY (id, chain_index) )";
314 315
316 const char kJobsSchema[] =
317 "CREATE TABLE downloads_jobs ("
318 "download_id INTEGER NOT NULL," // downloads.id.
319 "job_id INTEGER NOT NULL," // Download job id.
320 "start_position INTEGER NOT NULL," // The start request position of the
321 // download job.
322 "length INTEGER NOT NULL," // Length of the request, -1
323 // if not specified
324 "received_bytes INTEGER NOT NULL," // Total bytes downloaded.
325 "state INTEGER NOT NULL," // State of the download job.
326 "interrupt_reason INTEGER NOT NULL, " // DownloadInterruptReason
327 "PRIMARY KEY (download_id, job_id) )";
328
329 bool ret;
315 if (GetDB().DoesTableExist("downloads")) { 330 if (GetDB().DoesTableExist("downloads")) {
316 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && 331 ret = EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
317 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); 332 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
318 } else { 333 } else {
319 // If the "downloads" table doesn't exist, the downloads_url_chain 334 // If the "downloads" table doesn't exist, the downloads_url_chain
320 // table better not. 335 // table better not.
321 return (!GetDB().DoesTableExist("downloads_url_chain") && 336 ret = (!GetDB().DoesTableExist("downloads_url_chain") &&
322 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema)); 337 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema));
323 } 338 }
339
340 return ret && (GetDB().DoesTableExist("downloads_jobs") ||
341 GetDB().Execute(kJobsSchema));
324 } 342 }
325 343
326 uint32_t DownloadDatabase::GetNextDownloadId() { 344 uint32_t DownloadDatabase::GetNextDownloadId() {
327 sql::Statement select_max_id(GetDB().GetUniqueStatement( 345 sql::Statement select_max_id(GetDB().GetUniqueStatement(
328 "SELECT max(id) FROM downloads")); 346 "SELECT max(id) FROM downloads"));
329 bool result = select_max_id.Step(); 347 bool result = select_max_id.Step();
330 DCHECK(result); 348 DCHECK(result);
331 // If there are zero records in the downloads table, then max(id) will 349 // If there are zero records in the downloads table, then max(id) will
332 // return 0 = kInvalidDownloadId, so GetNextDownloadId() will set 350 // return 0 = kInvalidDownloadId, so GetNextDownloadId() will set
333 // *id = kInvalidDownloadId + 1. 351 // *id = kInvalidDownloadId + 1.
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 url_chain->push_back(GURL()); 484 url_chain->push_back(GURL());
467 current_chain_size++; 485 current_chain_size++;
468 } 486 }
469 if (current_chain_size > chain_index) 487 if (current_chain_size > chain_index)
470 continue; 488 continue;
471 489
472 // Save the record. 490 // Save the record.
473 url_chain->push_back(GURL(statement_chain.ColumnString(2))); 491 url_chain->push_back(GURL(statement_chain.ColumnString(2)));
474 } 492 }
475 493
494 QueryDownloadJobs(&info_map);
495
476 for (std::map<uint32_t, DownloadRow*>::iterator it = info_map.begin(); 496 for (std::map<uint32_t, DownloadRow*>::iterator it = info_map.begin();
477 it != info_map.end(); ++it) { 497 it != info_map.end(); ++it) {
478 DownloadRow* row = it->second; 498 DownloadRow* row = it->second;
479 bool empty_url_chain = row->url_chain.empty(); 499 bool empty_url_chain = row->url_chain.empty();
480 UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain); 500 UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain);
481 if (empty_url_chain) { 501 if (empty_url_chain) {
482 RemoveDownload(row->id); 502 RemoveDownload(row->id);
483 } else { 503 } else {
484 // Copy the contents of the stored info. 504 // Copy the contents of the stored info.
485 results->push_back(*row); 505 results->push_back(*row);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
526 statement.BindBlob(column++, data.hash.data(), data.hash.size()); 546 statement.BindBlob(column++, data.hash.data(), data.hash.size());
527 statement.BindInt64(column++, data.end_time.ToInternalValue()); 547 statement.BindInt64(column++, data.end_time.ToInternalValue());
528 statement.BindInt64(column++, data.total_bytes); 548 statement.BindInt64(column++, data.total_bytes);
529 statement.BindInt(column++, (data.opened ? 1 : 0)); 549 statement.BindInt(column++, (data.opened ? 1 : 0));
530 statement.BindString(column++, data.by_ext_id); 550 statement.BindString(column++, data.by_ext_id);
531 statement.BindString(column++, data.by_ext_name); 551 statement.BindString(column++, data.by_ext_name);
532 statement.BindString(column++, data.etag); 552 statement.BindString(column++, data.etag);
533 statement.BindString(column++, data.last_modified); 553 statement.BindString(column++, data.last_modified);
534 statement.BindInt(column++, DownloadIdToInt(data.id)); 554 statement.BindInt(column++, DownloadIdToInt(data.id));
535 555
536 return statement.Run(); 556 if (!statement.Run())
557 return false;
558 for (size_t i = 0; i < data.download_job_info.size(); ++i) {
559 if (!UpdateDownloadJob(data.download_job_info[i]) &&
560 !CreateDownloadJob(data.download_job_info[i])) {
561 return false;
562 }
563 }
564
565 return true;
537 } 566 }
538 567
539 void DownloadDatabase::EnsureInProgressEntriesCleanedUp() { 568 void DownloadDatabase::EnsureInProgressEntriesCleanedUp() {
540 if (in_progress_entry_cleanup_completed_) 569 if (in_progress_entry_cleanup_completed_)
541 return; 570 return;
542 571
543 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 572 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
544 "UPDATE downloads SET state=?, interrupt_reason=? WHERE state=?")); 573 "UPDATE downloads SET state=?, interrupt_reason=? WHERE state=?"));
545 statement.BindInt(0, DownloadStateToInt(DownloadState::INTERRUPTED)); 574 statement.BindInt(0, DownloadStateToInt(DownloadState::INTERRUPTED));
546 statement.BindInt( 575 statement.BindInt(
547 1, DownloadInterruptReasonToInt(download_interrupt_reason_crash_)); 576 1, DownloadInterruptReasonToInt(download_interrupt_reason_crash_));
548 statement.BindInt(2, DownloadStateToInt(DownloadState::IN_PROGRESS)); 577 statement.BindInt(2, DownloadStateToInt(DownloadState::IN_PROGRESS));
549 578
550 statement.Run(); 579 statement.Run();
580
581 sql::Statement statement_download_job(GetDB().GetCachedStatement(
582 SQL_FROM_HERE,
583 "UPDATE downloads_jobs SET state=?, interrupt_reason=? WHERE state=?"));
584 statement_download_job.BindInt(
585 0, DownloadStateToInt(DownloadState::INTERRUPTED));
586 statement_download_job.BindInt(
587 1, DownloadInterruptReasonToInt(download_interrupt_reason_crash_));
588 statement_download_job.BindInt(
589 2, DownloadStateToInt(DownloadState::IN_PROGRESS));
590 statement_download_job.Run();
551 in_progress_entry_cleanup_completed_ = true; 591 in_progress_entry_cleanup_completed_ = true;
552 } 592 }
553 593
554 bool DownloadDatabase::CreateDownload(const DownloadRow& info) { 594 bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
555 DCHECK_NE(kInvalidDownloadId, info.id); 595 DCHECK_NE(kInvalidDownloadId, info.id);
556 DCHECK(!info.guid.empty()); 596 DCHECK(!info.guid.empty());
557 SCOPED_UMA_HISTOGRAM_TIMER("Download.Database.CreateDownloadDuration"); 597 SCOPED_UMA_HISTOGRAM_TIMER("Download.Database.CreateDownloadDuration");
558 EnsureInProgressEntriesCleanedUp(); 598 EnsureInProgressEntriesCleanedUp();
559 599
560 if (info.url_chain.empty()) 600 if (info.url_chain.empty())
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 statement_insert_chain.BindInt(1, static_cast<int>(i)); 683 statement_insert_chain.BindInt(1, static_cast<int>(i));
644 statement_insert_chain.BindString(2, info.url_chain[i].spec()); 684 statement_insert_chain.BindString(2, info.url_chain[i].spec());
645 if (!statement_insert_chain.Run()) { 685 if (!statement_insert_chain.Run()) {
646 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainInsertError", 686 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainInsertError",
647 GetDB().GetErrorCode() & 0xff, 50); 687 GetDB().GetErrorCode() & 0xff, 50);
648 RemoveDownload(info.id); 688 RemoveDownload(info.id);
649 return false; 689 return false;
650 } 690 }
651 statement_insert_chain.Reset(true); 691 statement_insert_chain.Reset(true);
652 } 692 }
693
694 for (size_t i = 0; i < info.download_job_info.size(); ++i) {
695 if (!CreateDownloadJob(info.download_job_info[i])) {
696 RemoveDownload(info.id);
697 return false;
698 }
699 }
700
653 return true; 701 return true;
654 } 702 }
655 703
656 void DownloadDatabase::RemoveDownload(uint32_t id) { 704 void DownloadDatabase::RemoveDownload(uint32_t id) {
657 EnsureInProgressEntriesCleanedUp(); 705 EnsureInProgressEntriesCleanedUp();
658 706
659 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 707 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
660 "DELETE FROM downloads WHERE id=?")); 708 "DELETE FROM downloads WHERE id=?"));
661 downloads_statement.BindInt(0, id); 709 downloads_statement.BindInt(0, id);
662 if (!downloads_statement.Run()) { 710 if (!downloads_statement.Run()) {
663 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainDeleteError", 711 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainDeleteError",
664 GetDB().GetErrorCode() & 0xff, 50); 712 GetDB().GetErrorCode() & 0xff, 50);
665 return; 713 return;
666 } 714 }
667 RemoveDownloadURLs(id); 715 RemoveDownloadURLs(id);
716 RemoveDownloadJobs(id);
668 } 717 }
669 718
670 void DownloadDatabase::RemoveDownloadURLs(uint32_t id) { 719 void DownloadDatabase::RemoveDownloadURLs(uint32_t id) {
671 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 720 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
672 "DELETE FROM downloads_url_chains WHERE id=?")); 721 "DELETE FROM downloads_url_chains WHERE id=?"));
673 urlchain_statement.BindInt(0, id); 722 urlchain_statement.BindInt(0, id);
674 if (!urlchain_statement.Run()) { 723 if (!urlchain_statement.Run()) {
675 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainDeleteError", 724 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainDeleteError",
676 GetDB().GetErrorCode() & 0xff, 50); 725 GetDB().GetErrorCode() & 0xff, 50);
677 } 726 }
678 } 727 }
679 728
680 size_t DownloadDatabase::CountDownloads() { 729 size_t DownloadDatabase::CountDownloads() {
681 EnsureInProgressEntriesCleanedUp(); 730 EnsureInProgressEntriesCleanedUp();
682 731
683 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 732 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
684 "SELECT count(*) from downloads")); 733 "SELECT count(*) from downloads"));
685 statement.Step(); 734 statement.Step();
686 return statement.ColumnInt(0); 735 return statement.ColumnInt(0);
687 } 736 }
688 737
738 bool DownloadDatabase::CreateDownloadJob(const DownloadJobInfo& info) {
739 sql::Statement statement_insert(GetDB().GetCachedStatement(
740 SQL_FROM_HERE,
741 "INSERT INTO downloads_jobs "
742 "(download_id, job_id, start_position, length, received_bytes, state, "
743 "interrupt_reason) "
744 "VALUES (?, ?, ?, ?, ?, ?, ?)"));
745 int column = 0;
746 statement_insert.BindInt(column++, info.download_id);
747 statement_insert.BindInt(column++, info.job_id);
748 statement_insert.BindInt64(column++, info.start_position);
749 statement_insert.BindInt64(column++, info.length);
750 statement_insert.BindInt64(column++, info.received_bytes);
751 statement_insert.BindInt(column++, DownloadStateToInt(info.state));
752 statement_insert.BindInt(
753 column++, DownloadInterruptReasonToInt(info.interrupt_reason));
754 return statement_insert.Run();
755 }
756
757 bool DownloadDatabase::UpdateDownloadJob(const DownloadJobInfo& info) {
758 // Need to check whether the entry exists first. Unfortunately, running an
759 // UPDATE statement will always return true even if the entry doesn't exist.
760 sql::Statement statement_query(GetDB().GetCachedStatement(
qinmin 2017/02/04 00:06:57 Unfortunately, update statement always return true
sky 2017/02/06 16:29:04 http://stackoverflow.com/questions/15277373/sqlite
qinmin 2017/02/06 16:41:53 INSERT OR IGNORE doesn't improve the performance o
qinmin 2017/02/06 19:25:02 Compared the performance of "SELECT changes" and "
761 SQL_FROM_HERE,
762 "SELECT count(*) "
763 "FROM downloads_jobs "
764 "WHERE download_id=? AND job_id=?"));
765 statement_query.BindInt(0, info.download_id);
766 statement_query.BindInt(1, info.job_id);
767 if (statement_query.Step() && statement_query.ColumnInt(0) == 0)
768 return false;
769
770 sql::Statement statement_update(GetDB().GetCachedStatement(
771 SQL_FROM_HERE,
772 "UPDATE downloads_jobs "
773 "SET start_position=?, length=?, received_bytes=?, state=?, "
774 "interrupt_reason=? "
775 "WHERE download_id=? AND job_id=?"));
776 int column = 0;
777 statement_update.BindInt64(column++, info.start_position);
778 statement_update.BindInt64(column++, info.length);
779 statement_update.BindInt64(column++, info.received_bytes);
780 statement_update.BindInt(column++, DownloadStateToInt(info.state));
781 statement_update.BindInt(
782 column++, DownloadInterruptReasonToInt(info.interrupt_reason));
783 statement_update.BindInt(column++, info.download_id);
784 statement_update.BindInt(column++, info.job_id);
785 return statement_update.Run();
786 }
787
788 void DownloadDatabase::RemoveDownloadJobs(uint32_t id) {
789 sql::Statement statement_delete(GetDB().GetCachedStatement(SQL_FROM_HERE,
790 "DELETE FROM downloads_jobs WHERE download_id=?"));
791 statement_delete.BindInt(0, id);
792 statement_delete.Run();
793 }
794
795 void DownloadDatabase::QueryDownloadJobs(
796 std::map<uint32_t, DownloadRow*>* download_row_map) {
797 sql::Statement statement_download_job(GetDB().GetCachedStatement(
798 SQL_FROM_HERE,
799 "SELECT download_id, job_id, start_position, length, received_bytes, "
800 "state, interrupt_reason FROM downloads_jobs "
801 "ORDER BY download_id, job_id"));
802
803 while (statement_download_job.Step()) {
804 int column = 0;
805 // See the comment above about SQLITE lacking unsigned integers.
806 int64_t signed_id = statement_download_job.ColumnInt64(column++);
807 if (signed_id <= static_cast<int64_t>(kInvalidDownloadId)) {
808 LOG(ERROR) << "Invalid download ID found in downloads_jobs table "
809 << signed_id;
810 continue;
811 }
812 int download_id = IntToDownloadId(signed_id);
813 // Confirm the download_id has already been seen--if it hasn't, discard the
814 // record.
815 bool found = base::ContainsKey(*download_row_map, download_id);
816 UMA_HISTOGRAM_BOOLEAN(
817 "Download.DatabaseDownloadExistsForDownloadJob", found);
818 DCHECK(found);
819 if (!found)
820 continue;
821
822 DownloadJobInfo info;
823 info.download_id = download_id;
824 info.job_id = statement_download_job.ColumnInt(column++);
825 info.start_position = statement_download_job.ColumnInt64(column++);
826 info.length = statement_download_job.ColumnInt64(column++);
827 info.received_bytes = statement_download_job.ColumnInt64(column++);
828 info.state = IntToDownloadState(
829 statement_download_job.ColumnInt(column++));
830 info.interrupt_reason = IntToDownloadInterruptReason(
831 statement_download_job.ColumnInt(column++));
832 (*download_row_map)[download_id]->download_job_info.push_back(info);
833 }
834 }
835
689 } // namespace history 836 } // namespace history
OLDNEW
« no previous file with comments | « components/history/core/browser/download_database.h ('k') | components/history/core/browser/download_job_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698