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

Unified Diff: components/history/core/browser/download_database.cc

Issue 2665243003: add a download slices table into history download db (Closed)
Patch Set: add test file to BUILD.gn 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/history/core/browser/download_database.h ('k') | components/history/core/browser/download_row.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/history/core/browser/download_database.cc
diff --git a/components/history/core/browser/download_database.cc b/components/history/core/browser/download_database.cc
index 5994bf5e2564fcf5b8d27d9ef830866cedaa29d0..e82f3947ed5efa17502afe183d3b168f3f747ddc 100644
--- a/components/history/core/browser/download_database.cc
+++ b/components/history/core/browser/download_database.cc
@@ -22,6 +22,7 @@
#include "build/build_config.h"
#include "components/history/core/browser/download_constants.h"
#include "components/history/core/browser/download_row.h"
+#include "components/history/core/browser/download_slice_info.h"
#include "components/history/core/browser/history_types.h"
#include "sql/statement.h"
@@ -312,15 +313,32 @@ bool DownloadDatabase::InitDownloadTable() {
"url LONGVARCHAR NOT NULL, " // URL.
"PRIMARY KEY (id, chain_index) )";
+ const char kSlicesSchema[] =
+ "CREATE TABLE downloads_slices ("
+ "download_id INTEGER NOT NULL," // downloads.id.
+ "offset INTEGER NOT NULL," // Offset in the target file.
+ "received_bytes INTEGER NOT NULL," // Total bytes downloaded.
+ "PRIMARY KEY (download_id, offset) )";
+
+ bool ret;
if (GetDB().DoesTableExist("downloads")) {
- return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
- EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
+ // If the "downloads" table exists, "downloads_url_chain" might not be there
+ // as it is introduced in version 24. A migration function will be run to
+ // create it later.
+ ret = EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
+ EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
} else {
- // If the "downloads" table doesn't exist, the downloads_url_chain
- // table better not.
- return (!GetDB().DoesTableExist("downloads_url_chain") &&
- GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema));
+ // If the "downloads" table doesn't exist, neither should the
+ // "downloads_url_chain" table.
+ ret = !GetDB().DoesTableExist("downloads_url_chain");
+ // Recreate the "downloads" and "downloads_url_chain" table.
+ ret = ret && GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema);
}
+
+ // Making sure the "downloads_slices" table is created as it is introduced in
+ // version 33. This table doesn't require migration of existing tables.
+ return ret && (GetDB().DoesTableExist("downloads_slices") ||
+ GetDB().Execute(kSlicesSchema));
}
uint32_t DownloadDatabase::GetNextDownloadId() {
@@ -356,7 +374,7 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
results->clear();
std::set<uint32_t> ids;
- std::map<uint32_t, DownloadRow*> info_map;
+ DownloadRowMap info_map;
sql::Statement statement_main(GetDB().GetCachedStatement(
SQL_FROM_HERE,
@@ -374,7 +392,7 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
// |id|s instead of casting them to very large uint32s, which would break
// the max(id) logic in GetNextDownloadId().
int64_t signed_id = statement_main.ColumnInt64(column++);
- info->id = IntToDownloadId(signed_id);
+ bool valid = ConvertIntToDownloadId(signed_id, &(info->id));
info->guid = statement_main.ColumnString(column++);
info->current_path = ColumnFilePath(statement_main, column++);
info->target_path = ColumnFilePath(statement_main, column++);
@@ -409,7 +427,7 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
// If the record is corrupted, note that and drop it.
// http://crbug.com/251269
DroppedReason dropped_reason = DROPPED_REASON_MAX;
- if (signed_id <= static_cast<int64_t>(kInvalidDownloadId)) {
+ if (!valid) {
// SQLITE doesn't have unsigned integers.
dropped_reason = DROPPED_REASON_BAD_ID;
} else if (!ids.insert(info->id).second) {
@@ -442,9 +460,9 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
int64_t signed_id = statement_chain.ColumnInt64(column++);
int chain_index = statement_chain.ColumnInt(column++);
- if (signed_id <= static_cast<int64_t>(kInvalidDownloadId))
+ DownloadId id = kInvalidDownloadId;
+ if (!ConvertIntToDownloadId(signed_id, &id))
continue;
- uint32_t id = IntToDownloadId(signed_id);
// Note that these DCHECKs may trip as a result of corrupted databases.
// We have them because in debug builds the chances are higher there's
@@ -473,8 +491,10 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
url_chain->push_back(GURL(statement_chain.ColumnString(2)));
}
- for (std::map<uint32_t, DownloadRow*>::iterator it = info_map.begin();
- it != info_map.end(); ++it) {
+ QueryDownloadSlices(&info_map);
+
+ for (DownloadRowMap::iterator it = info_map.begin(); it != info_map.end();
+ ++it) {
DownloadRow* row = it->second;
bool empty_url_chain = row->url_chain.empty();
UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain);
@@ -533,7 +553,19 @@ bool DownloadDatabase::UpdateDownload(const DownloadRow& data) {
statement.BindString(column++, data.last_modified);
statement.BindInt(column++, DownloadIdToInt(data.id));
- return statement.Run();
+ if (!statement.Run())
+ return false;
+
+ if (data.download_slice_info.size() == 0) {
+ RemoveDownloadSlices(data.id);
+ } else {
+ for (size_t i = 0; i < data.download_slice_info.size(); ++i) {
+ if (!CreateOrUpdateDownloadSlice(data.download_slice_info[i]))
+ return false;
+ }
+ }
+
+ return true;
}
void DownloadDatabase::EnsureInProgressEntriesCleanedUp() {
@@ -650,10 +682,18 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
}
statement_insert_chain.Reset(true);
}
+
+ for (size_t i = 0; i < info.download_slice_info.size(); ++i) {
+ if (!CreateOrUpdateDownloadSlice(info.download_slice_info[i])) {
+ RemoveDownload(info.id);
+ return false;
+ }
+ }
+
return true;
}
-void DownloadDatabase::RemoveDownload(uint32_t id) {
+void DownloadDatabase::RemoveDownload(DownloadId id) {
EnsureInProgressEntriesCleanedUp();
sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
@@ -665,9 +705,10 @@ void DownloadDatabase::RemoveDownload(uint32_t id) {
return;
}
RemoveDownloadURLs(id);
+ RemoveDownloadSlices(id);
}
-void DownloadDatabase::RemoveDownloadURLs(uint32_t id) {
+void DownloadDatabase::RemoveDownloadURLs(DownloadId id) {
sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
"DELETE FROM downloads_url_chains WHERE id=?"));
urlchain_statement.BindInt(0, id);
@@ -686,4 +727,63 @@ size_t DownloadDatabase::CountDownloads() {
return statement.ColumnInt(0);
}
+bool DownloadDatabase::CreateOrUpdateDownloadSlice(
+ const DownloadSliceInfo& info) {
+ // If the slice has no data, there is no need to insert it into the db. Note
+ // that for each slice, |received_bytes| can only go up. So if a slice is
+ // already in the db, its |received_bytes| should always be larger than 0.
+ if (info.received_bytes == 0)
+ return true;
+ sql::Statement statement_replace(GetDB().GetCachedStatement(
+ SQL_FROM_HERE,
+ "REPLACE INTO downloads_slices "
+ "(download_id, offset, received_bytes) "
+ "VALUES (?, ?, ?)"));
+ int column = 0;
+ statement_replace.BindInt(column++, info.download_id);
+ statement_replace.BindInt64(column++, info.offset);
+ statement_replace.BindInt64(column++, info.received_bytes);
+ return statement_replace.Run();
+}
+
+void DownloadDatabase::RemoveDownloadSlices(DownloadId id) {
+ sql::Statement statement_delete(GetDB().GetCachedStatement(SQL_FROM_HERE,
+ "DELETE FROM downloads_slices WHERE download_id=?"));
+ statement_delete.BindInt(0, id);
+ statement_delete.Run();
+}
+
+void DownloadDatabase::QueryDownloadSlices(DownloadRowMap* download_row_map) {
+ DCHECK(download_row_map);
+ sql::Statement statement_query(GetDB().GetCachedStatement(
+ SQL_FROM_HERE,
+ "SELECT download_id, offset, received_bytes "
+ "FROM downloads_slices "
+ "ORDER BY download_id, offset"));
+
+ while (statement_query.Step()) {
+ int column = 0;
+ DownloadSliceInfo info;
+ // Convert signed integer from sqlite to unsigned DownloadId.
+ int64_t signed_id = statement_query.ColumnInt64(column++);
+ bool success = ConvertIntToDownloadId(signed_id, &info.download_id);
+ DCHECK(success) << "Invalid download ID found in downloads_slices table "
+ << signed_id;
+ info.offset = statement_query.ColumnInt64(column++);
+ info.received_bytes = statement_query.ColumnInt64(column++);
+
+ // Confirm the download_id has already been seen--if it hasn't, discard the
+ // record.
+ DownloadRowMap::iterator it = download_row_map->find(info.download_id);
+ bool found = (it != download_row_map->end());
+ UMA_HISTOGRAM_BOOLEAN(
+ "Download.DatabaseDownloadExistsForDownloadSlice", found);
+ if (!found) {
+ RemoveDownloadSlices(info.download_id);
+ continue;
+ }
+ it->second->download_slice_info.push_back(info);
+ }
+}
+
} // namespace history
« no previous file with comments | « components/history/core/browser/download_database.h ('k') | components/history/core/browser/download_row.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698