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

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: increase history db version 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>
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 305
306 const char kUrlChainSchema[] = 306 const char kUrlChainSchema[] =
307 "CREATE TABLE downloads_url_chains (" 307 "CREATE TABLE downloads_url_chains ("
308 "id INTEGER NOT NULL," // downloads.id. 308 "id INTEGER NOT NULL," // downloads.id.
309 "chain_index INTEGER NOT NULL," // Index of url in chain 309 "chain_index INTEGER NOT NULL," // Index of url in chain
310 // 0 is initial target, 310 // 0 is initial target,
311 // MAX is target after redirects. 311 // MAX is target after redirects.
312 "url LONGVARCHAR NOT NULL, " // URL. 312 "url LONGVARCHAR NOT NULL, " // URL.
313 "PRIMARY KEY (id, chain_index) )"; 313 "PRIMARY KEY (id, chain_index) )";
314 314
315 bool ret;
315 if (GetDB().DoesTableExist("downloads")) { 316 if (GetDB().DoesTableExist("downloads")) {
316 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && 317 ret = EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
317 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); 318 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
318 } else { 319 } else {
319 // If the "downloads" table doesn't exist, the downloads_url_chain 320 // If the "downloads" table doesn't exist, the downloads_url_chain
320 // table better not. 321 // and the downloads_jobs table better not.
321 return (!GetDB().DoesTableExist("downloads_url_chain") && 322 ret = !GetDB().DoesTableExist("downloads_url_chain") &&
322 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema)); 323 !GetDB().DoesTableExist("downloads_jobs") &&
asanka 2017/02/02 19:06:27 This condition isn't relevant here since neither k
qinmin 2017/02/02 22:31:32 Done. removed, it just feels wierd that download_j
324 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema);
323 } 325 }
326 ret = ret && EnsureDownloadJobsTableExists();
asanka 2017/02/02 19:06:27 Roll EnsureDownloadJobsTableExists here for consis
qinmin 2017/02/02 22:31:32 Done. Moved all the code here
327
328 return ret;
324 } 329 }
325 330
326 uint32_t DownloadDatabase::GetNextDownloadId() { 331 uint32_t DownloadDatabase::GetNextDownloadId() {
327 sql::Statement select_max_id(GetDB().GetUniqueStatement( 332 sql::Statement select_max_id(GetDB().GetUniqueStatement(
328 "SELECT max(id) FROM downloads")); 333 "SELECT max(id) FROM downloads"));
329 bool result = select_max_id.Step(); 334 bool result = select_max_id.Step();
330 DCHECK(result); 335 DCHECK(result);
331 // If there are zero records in the downloads table, then max(id) will 336 // If there are zero records in the downloads table, then max(id) will
332 // return 0 = kInvalidDownloadId, so GetNextDownloadId() will set 337 // return 0 = kInvalidDownloadId, so GetNextDownloadId() will set
333 // *id = kInvalidDownloadId + 1. 338 // *id = kInvalidDownloadId + 1.
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 url_chain->push_back(GURL()); 471 url_chain->push_back(GURL());
467 current_chain_size++; 472 current_chain_size++;
468 } 473 }
469 if (current_chain_size > chain_index) 474 if (current_chain_size > chain_index)
470 continue; 475 continue;
471 476
472 // Save the record. 477 // Save the record.
473 url_chain->push_back(GURL(statement_chain.ColumnString(2))); 478 url_chain->push_back(GURL(statement_chain.ColumnString(2)));
474 } 479 }
475 480
481 sql::Statement statement_download_job(GetDB().GetCachedStatement(
482 SQL_FROM_HERE,
483 "SELECT id, job_id, start_position, length, received_bytes, "
484 "state, interrupt_reason FROM downloads_jobs "
485 "ORDER BY id, job_id"));
486
487 while (statement_download_job.Step()) {
488 int column = 0;
489 // See the comment above about SQLITE lacking unsigned integers.
490 int64_t signed_id = statement_download_job.ColumnInt64(column++);
491 if (signed_id <= static_cast<int64_t>(kInvalidDownloadId))
492 continue;
493 int id = IntToDownloadId(signed_id);
494 DownloadJobInfo info;
495 info.id = IntToDownloadId(signed_id);
496 info.job_id = statement_download_job.ColumnInt(column++);
497 info.start_position = statement_download_job.ColumnInt64(column++);
498 info.length = statement_download_job.ColumnInt64(column++);
499 info.received_bytes = statement_download_job.ColumnInt64(column++);
500 info.state = IntToDownloadState(
501 statement_download_job.ColumnInt(column++));
502 info.interrupt_reason = IntToDownloadInterruptReason(
503 statement_download_job.ColumnInt(column++));
504 // Confirm the id has already been seen--if it hasn't, discard the
505 // record.
506 DCHECK(base::ContainsKey(info_map, id));
507 if (!base::ContainsKey(info_map, id))
asanka 2017/02/02 19:06:27 Might as well front load this check. There's no po
qinmin 2017/02/02 22:31:32 Done. Added a new UMA entry
508 continue;
509 info_map[id]->download_job_info.push_back(info);
510 }
511
476 for (std::map<uint32_t, DownloadRow*>::iterator it = info_map.begin(); 512 for (std::map<uint32_t, DownloadRow*>::iterator it = info_map.begin();
477 it != info_map.end(); ++it) { 513 it != info_map.end(); ++it) {
478 DownloadRow* row = it->second; 514 DownloadRow* row = it->second;
479 bool empty_url_chain = row->url_chain.empty(); 515 bool empty_url_chain = row->url_chain.empty();
480 UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain); 516 UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain);
481 if (empty_url_chain) { 517 if (empty_url_chain) {
482 RemoveDownload(row->id); 518 RemoveDownload(row->id);
483 } else { 519 } else {
484 // Copy the contents of the stored info. 520 // Copy the contents of the stored info.
485 results->push_back(*row); 521 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()); 562 statement.BindBlob(column++, data.hash.data(), data.hash.size());
527 statement.BindInt64(column++, data.end_time.ToInternalValue()); 563 statement.BindInt64(column++, data.end_time.ToInternalValue());
528 statement.BindInt64(column++, data.total_bytes); 564 statement.BindInt64(column++, data.total_bytes);
529 statement.BindInt(column++, (data.opened ? 1 : 0)); 565 statement.BindInt(column++, (data.opened ? 1 : 0));
530 statement.BindString(column++, data.by_ext_id); 566 statement.BindString(column++, data.by_ext_id);
531 statement.BindString(column++, data.by_ext_name); 567 statement.BindString(column++, data.by_ext_name);
532 statement.BindString(column++, data.etag); 568 statement.BindString(column++, data.etag);
533 statement.BindString(column++, data.last_modified); 569 statement.BindString(column++, data.last_modified);
534 statement.BindInt(column++, DownloadIdToInt(data.id)); 570 statement.BindInt(column++, DownloadIdToInt(data.id));
535 571
536 return statement.Run(); 572 if (!statement.Run())
573 return false;
574
575 for (size_t i = 0; i < data.download_job_info.size(); ++i) {
576 if (!UpdateDownloadJob(data.download_job_info[i], false))
577 return false;
578 }
579
580 return true;
537 } 581 }
538 582
539 void DownloadDatabase::EnsureInProgressEntriesCleanedUp() { 583 void DownloadDatabase::EnsureInProgressEntriesCleanedUp() {
540 if (in_progress_entry_cleanup_completed_) 584 if (in_progress_entry_cleanup_completed_)
541 return; 585 return;
542 586
543 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 587 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
544 "UPDATE downloads SET state=?, interrupt_reason=? WHERE state=?")); 588 "UPDATE downloads SET state=?, interrupt_reason=? WHERE state=?"));
545 statement.BindInt(0, DownloadStateToInt(DownloadState::INTERRUPTED)); 589 statement.BindInt(0, DownloadStateToInt(DownloadState::INTERRUPTED));
546 statement.BindInt( 590 statement.BindInt(
547 1, DownloadInterruptReasonToInt(download_interrupt_reason_crash_)); 591 1, DownloadInterruptReasonToInt(download_interrupt_reason_crash_));
548 statement.BindInt(2, DownloadStateToInt(DownloadState::IN_PROGRESS)); 592 statement.BindInt(2, DownloadStateToInt(DownloadState::IN_PROGRESS));
549 593
550 statement.Run(); 594 statement.Run();
595
596 sql::Statement statement_download_job(GetDB().GetCachedStatement(
597 SQL_FROM_HERE,
598 "UPDATE downloads_jobs SET state=?, interrupt_reason=? WHERE state=?"));
599 statement_download_job.BindInt(
600 0, DownloadStateToInt(DownloadState::INTERRUPTED));
601 statement_download_job.BindInt(
602 1, DownloadInterruptReasonToInt(download_interrupt_reason_crash_));
603 statement_download_job.BindInt(
604 2, DownloadStateToInt(DownloadState::IN_PROGRESS));
605 statement_download_job.Run();
551 in_progress_entry_cleanup_completed_ = true; 606 in_progress_entry_cleanup_completed_ = true;
552 } 607 }
553 608
554 bool DownloadDatabase::CreateDownload(const DownloadRow& info) { 609 bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
555 DCHECK_NE(kInvalidDownloadId, info.id); 610 DCHECK_NE(kInvalidDownloadId, info.id);
556 DCHECK(!info.guid.empty()); 611 DCHECK(!info.guid.empty());
557 SCOPED_UMA_HISTOGRAM_TIMER("Download.Database.CreateDownloadDuration"); 612 SCOPED_UMA_HISTOGRAM_TIMER("Download.Database.CreateDownloadDuration");
558 EnsureInProgressEntriesCleanedUp(); 613 EnsureInProgressEntriesCleanedUp();
559 614
560 if (info.url_chain.empty()) 615 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)); 698 statement_insert_chain.BindInt(1, static_cast<int>(i));
644 statement_insert_chain.BindString(2, info.url_chain[i].spec()); 699 statement_insert_chain.BindString(2, info.url_chain[i].spec());
645 if (!statement_insert_chain.Run()) { 700 if (!statement_insert_chain.Run()) {
646 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainInsertError", 701 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainInsertError",
647 GetDB().GetErrorCode() & 0xff, 50); 702 GetDB().GetErrorCode() & 0xff, 50);
648 RemoveDownload(info.id); 703 RemoveDownload(info.id);
649 return false; 704 return false;
650 } 705 }
651 statement_insert_chain.Reset(true); 706 statement_insert_chain.Reset(true);
652 } 707 }
708
709 for (size_t i = 0; i < info.download_job_info.size(); ++i) {
710 if (!UpdateDownloadJob(info.download_job_info[i], true)) {
711 RemoveDownload(info.id);
712 return false;
713 }
714 }
715
653 return true; 716 return true;
654 } 717 }
655 718
656 void DownloadDatabase::RemoveDownload(uint32_t id) { 719 void DownloadDatabase::RemoveDownload(uint32_t id) {
657 EnsureInProgressEntriesCleanedUp(); 720 EnsureInProgressEntriesCleanedUp();
658 721
659 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 722 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
660 "DELETE FROM downloads WHERE id=?")); 723 "DELETE FROM downloads WHERE id=?"));
661 downloads_statement.BindInt(0, id); 724 downloads_statement.BindInt(0, id);
662 if (!downloads_statement.Run()) { 725 if (!downloads_statement.Run()) {
663 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainDeleteError", 726 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainDeleteError",
664 GetDB().GetErrorCode() & 0xff, 50); 727 GetDB().GetErrorCode() & 0xff, 50);
665 return; 728 return;
666 } 729 }
667 RemoveDownloadURLs(id); 730 RemoveDownloadURLs(id);
731 RemoveDownloadJobs(id);
668 } 732 }
669 733
670 void DownloadDatabase::RemoveDownloadURLs(uint32_t id) { 734 void DownloadDatabase::RemoveDownloadURLs(uint32_t id) {
671 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 735 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
672 "DELETE FROM downloads_url_chains WHERE id=?")); 736 "DELETE FROM downloads_url_chains WHERE id=?"));
673 urlchain_statement.BindInt(0, id); 737 urlchain_statement.BindInt(0, id);
674 if (!urlchain_statement.Run()) { 738 if (!urlchain_statement.Run()) {
675 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainDeleteError", 739 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainDeleteError",
676 GetDB().GetErrorCode() & 0xff, 50); 740 GetDB().GetErrorCode() & 0xff, 50);
677 } 741 }
678 } 742 }
679 743
680 size_t DownloadDatabase::CountDownloads() { 744 size_t DownloadDatabase::CountDownloads() {
681 EnsureInProgressEntriesCleanedUp(); 745 EnsureInProgressEntriesCleanedUp();
682 746
683 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 747 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
684 "SELECT count(*) from downloads")); 748 "SELECT count(*) from downloads"));
685 statement.Step(); 749 statement.Step();
686 return statement.ColumnInt(0); 750 return statement.ColumnInt(0);
687 } 751 }
688 752
753 bool DownloadDatabase::EnsureDownloadJobsTableExists() {
754 // TODO(qinmin): increment the current history database version by 1 once
755 // this feature is no longer experimental.
756 const char kJobsSchema[] =
757 "CREATE TABLE downloads_jobs ("
758 "id INTEGER NOT NULL," // downloads.id.
asanka 2017/02/02 19:06:27 Probably call this |download_id| since it doesn't
qinmin 2017/02/02 22:31:32 Done.
759 "job_id INTEGER NOT NULL," // Download job id.
760 "start_position INTEGER NOT NULL," // The start request position of the
761 // download job.
762 "length INTEGER NOT NULL," // length of the request, -1
763 // if not specified
764 "received_bytes INTEGER NOT NULL," // Total bytes downloaded.
765 "state INTEGER NOT NULL," // To be determined.
766 "interrupt_reason INTEGER NOT NULL, " // DownloadInterruptReason
asanka 2017/02/02 19:06:27 How do you plan to use |state| and |interrupt_reas
qinmin 2017/02/02 22:31:32 I was thinking whether we should keep the state fo
767 "PRIMARY KEY (id, job_id) )";
768
769 return GetDB().DoesTableExist("downloads_jobs") ||
770 GetDB().Execute(kJobsSchema);
771 }
772
773 bool DownloadDatabase::UpdateDownloadJob(
774 const DownloadJobInfo& info, bool is_new_download) {
775 sql::Statement statement_query(GetDB().GetCachedStatement(
776 SQL_FROM_HERE,
777 "SELECT count(*) "
778 "FROM downloads_jobs "
779 "WHERE id=? AND job_id=?"));
780 statement_query.BindInt(0, info.id);
781 statement_query.BindInt(1, info.job_id);
782
783 bool job_exists = false;
784 if (statement_query.Step()) {
785 job_exists = statement_query.ColumnInt(0) > 0;
asanka 2017/02/02 19:06:28 Separate UpdateDownloadJob and CreateDownloadJob.
qinmin 2017/02/02 22:31:32 Done. Separated UpdateDownloadJob from CreateDownl
786 // There should not be any jobs in downloads_jobs for this id. If there
asanka 2017/02/02 19:06:27 This doesn't really follow from the (!is_new_downl
qinmin 2017/02/02 22:31:32 Done.
787 // are, we don't want them to interfere with inserting the correct jobs,
788 // so just remove them.
789 if (is_new_download && job_exists)
790 RemoveDownloadJobs(info.id);
791 }
792 int column = 0;
793
794 if (!is_new_download && job_exists) {
795 sql::Statement statement_update(GetDB().GetCachedStatement(
796 SQL_FROM_HERE,
797 "UPDATE downloads_jobs "
798 "SET start_position=?, length=?, received_bytes=?, state=?, "
799 "interrupt_reason=? "
800 "WHERE id=? AND job_id=?"));
801 statement_update.BindInt64(column++, info.start_position);
802 statement_update.BindInt64(column++, info.length);
803 statement_update.BindInt64(column++, info.received_bytes);
804 statement_update.BindInt(column++, DownloadStateToInt(info.state));
805 statement_update.BindInt(
806 column++, DownloadInterruptReasonToInt(info.interrupt_reason));
807 statement_update.BindInt(column++, info.id);
808 statement_update.BindInt(column++, info.job_id);
809 return statement_update.Run();
810 } else {
811 sql::Statement statement_insert(GetDB().GetCachedStatement(
812 SQL_FROM_HERE,
813 "INSERT INTO downloads_jobs "
814 "(id, job_id, start_position, length, received_bytes, state, "
815 "interrupt_reason) "
816 "VALUES (?, ?, ?, ?, ?, ?, ?)"));
817 statement_insert.BindInt(column++, info.id);
818 statement_insert.BindInt(column++, info.job_id);
819 statement_insert.BindInt64(column++, info.start_position);
820 statement_insert.BindInt64(column++, info.length);
821 statement_insert.BindInt64(column++, info.received_bytes);
822 statement_insert.BindInt(column++, DownloadStateToInt(info.state));
823 statement_insert.BindInt(
824 column++, DownloadInterruptReasonToInt(info.interrupt_reason));
825
826 return statement_insert.Run();
827 }
828 }
829
830 void DownloadDatabase::RemoveDownloadJobs(uint32_t id) {
831 sql::Statement statement_delete(GetDB().GetCachedStatement(SQL_FROM_HERE,
832 "DELETE FROM downloads_jobs WHERE id=?"));
833 statement_delete.BindInt(0, id);
834 statement_delete.Run();
835 }
836
689 } // namespace history 837 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698