Commit f9ae18e1 authored by rdsmith@chromium.org's avatar rdsmith@chromium.org

Clean up entries left by crashes in the DownloadDB.

BUG=224385
R=benjhayden@chromium.org



Review URL: https://chromiumcodereview.appspot.com/13044019

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@192879 0039d316-1c4b-4281-b951-d872f2087c98
parent cafd0add
This diff is collapsed.
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/gtest_prod_util.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "content/public/browser/download_item.h"
#include "sql/meta_table.h" #include "sql/meta_table.h"
namespace sql { namespace sql {
...@@ -41,12 +43,6 @@ class DownloadDatabase { ...@@ -41,12 +43,6 @@ class DownloadDatabase {
// to select the row in the database table to update. // to select the row in the database table to update.
bool UpdateDownload(const DownloadRow& data); bool UpdateDownload(const DownloadRow& data);
// Fixes state of the download entries. Sometimes entries with IN_PROGRESS
// state are not updated during browser shutdown (particularly when crashing).
// On the next start such entries are considered canceled. This functions
// fixes such entries.
bool CleanUpInProgressEntries();
// Create a new database entry for one download and return its primary db id. // Create a new database entry for one download and return its primary db id.
int64 CreateDownload(const DownloadRow& info); int64 CreateDownload(const DownloadRow& info);
...@@ -79,16 +75,59 @@ class DownloadDatabase { ...@@ -79,16 +75,59 @@ class DownloadDatabase {
bool DropDownloadTable(); bool DropDownloadTable();
private: private:
FRIEND_TEST_ALL_PREFIXES(
HistoryBackendDBTest, ConfirmDownloadInProgressCleanup);
// Values used in the database for DownloadItem::State.
static const int kStateInvalid;
static const int kStateInProgress;
static const int kStateComplete;
static const int kStateCancelled;
static const int kStateBug140687;
static const int kStateInterrupted;
// Values used in the database for DownloadItem::DangerType
static const int kDangerTypeInvalid;
static const int kDangerTypeNotDangerous;
static const int kDangerTypeDangerousFile;
static const int kDangerTypeDangerousUrl;
static const int kDangerTypeDangerousContent;
static const int kDangerTypeMaybeDangerousContent;
static const int kDangerTypeUncommonContent;
static const int kDangerTypeUserValidated;
static const int kDangerTypeDangerousHost;
// Fixes state of the download entries. Sometimes entries with IN_PROGRESS
// state are not updated during browser shutdown (particularly when crashing).
// On the next start such entries are considered interrupted with
// interrupt reason |DOWNLOAD_INTERRUPT_REASON_CRASH|. This function
// fixes such entries.
void EnsureInProgressEntriesCleanedUp();
bool EnsureColumnExists(const std::string& name, const std::string& type); bool EnsureColumnExists(const std::string& name, const std::string& type);
void RemoveDownloadURLs(int64 handle); void RemoveDownloadURLs(int64 handle);
// Utility functions for conversion between DownloadItem types
// and DownloadDatabase constants.
static int StateToInt(content::DownloadItem::DownloadState state);
static content::DownloadItem::DownloadState IntToState(int state);
static int DangerTypeToInt(content::DownloadDangerType danger_type);
static content::DownloadDangerType IntToDangerType(int danger_type);
bool owning_thread_set_; bool owning_thread_set_;
base::PlatformThreadId owning_thread_; base::PlatformThreadId owning_thread_;
int next_id_; int next_id_;
int next_db_handle_; int next_db_handle_;
// Initialized to false on construction, and checked in all functional
// routines post-migration in the database for a possible call to
// CleanUpInProgressEntries(). This allows us to avoid
// doing the cleanup until after any DB migration and unless we are
// actually use the downloads database.
bool in_progress_entry_cleanup_completed_;
DISALLOW_COPY_AND_ASSIGN(DownloadDatabase); DISALLOW_COPY_AND_ASSIGN(DownloadDatabase);
}; };
......
...@@ -1312,16 +1312,6 @@ void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) { ...@@ -1312,16 +1312,6 @@ void HistoryBackend::QueryDownloads(std::vector<DownloadRow>* rows) {
db_->QueryDownloads(rows); db_->QueryDownloads(rows);
} }
// Clean up entries that has been corrupted (because of the crash, for example).
void HistoryBackend::CleanUpInProgressEntries() {
// If some "in progress" entries were not updated when Chrome exited, they
// need to be cleaned up.
if (!db_.get())
return;
db_->CleanUpInProgressEntries();
ScheduleCommit();
}
// Update a particular download entry. // Update a particular download entry.
void HistoryBackend::UpdateDownload(const history::DownloadRow& data) { void HistoryBackend::UpdateDownload(const history::DownloadRow& data) {
if (!db_.get()) if (!db_.get())
......
...@@ -308,7 +308,6 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>, ...@@ -308,7 +308,6 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
void GetNextDownloadId(int* id); void GetNextDownloadId(int* id);
void QueryDownloads(std::vector<DownloadRow>* rows); void QueryDownloads(std::vector<DownloadRow>* rows);
void CleanUpInProgressEntries();
void UpdateDownload(const DownloadRow& data); void UpdateDownload(const DownloadRow& data);
void CreateDownload(const history::DownloadRow& history_info, void CreateDownload(const history::DownloadRow& history_info,
int64* db_handle); int64* db_handle);
......
...@@ -804,14 +804,6 @@ void HistoryService::QueryDownloads( ...@@ -804,14 +804,6 @@ void HistoryService::QueryDownloads(
base::Bind(callback, base::Passed(&scoped_rows))); base::Bind(callback, base::Passed(&scoped_rows)));
} }
// Changes all IN_PROGRESS in the database entries to CANCELED.
// IN_PROGRESS entries are the corrupted entries, not updated by next function
// because of the crash or some other extremal exit.
void HistoryService::CleanUpInProgressEntries() {
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::CleanUpInProgressEntries);
}
// Handle updates for a particular download. This is a 'fire and forget' // Handle updates for a particular download. This is a 'fire and forget'
// operation, so we don't need to be called back. // operation, so we don't need to be called back.
void HistoryService::UpdateDownload(const history::DownloadRow& data) { void HistoryService::UpdateDownload(const history::DownloadRow& data) {
......
...@@ -464,10 +464,6 @@ class HistoryService : public CancelableRequestProvider, ...@@ -464,10 +464,6 @@ class HistoryService : public CancelableRequestProvider,
// download. The callback is called on the thread that calls QueryDownloads(). // download. The callback is called on the thread that calls QueryDownloads().
void QueryDownloads(const DownloadQueryCallback& callback); void QueryDownloads(const DownloadQueryCallback& callback);
// Begins a request to clean up entries that has been corrupted (because of
// the crash, for example).
void CleanUpInProgressEntries();
// Called to update the history service about the current state of a download. // Called to update the history service about the current state of a download.
// This is a 'fire and forget' query, so just pass the relevant state info to // This is a 'fire and forget' query, so just pass the relevant state info to
// the database with no need for a callback. // the database with no need for a callback.
......
...@@ -213,8 +213,6 @@ void BackendDelegate::BroadcastNotifications(int type, ...@@ -213,8 +213,6 @@ void BackendDelegate::BroadcastNotifications(int type,
delete details; delete details;
} }
namespace {
TEST_F(HistoryBackendDBTest, ClearBrowsingData_Downloads) { TEST_F(HistoryBackendDBTest, ClearBrowsingData_Downloads) {
CreateBackendAndDatabase(); CreateBackendAndDatabase();
...@@ -516,6 +514,65 @@ TEST_F(HistoryBackendDBTest, DownloadNukeRecordsMissingURLs) { ...@@ -516,6 +514,65 @@ TEST_F(HistoryBackendDBTest, DownloadNukeRecordsMissingURLs) {
} }
} }
TEST_F(HistoryBackendDBTest, ConfirmDownloadInProgressCleanup) {
// Create the DB.
CreateBackendAndDatabase();
base::Time now(base::Time::Now());
// Put an IN_PROGRESS download in the DB.
AddDownload(DownloadItem::IN_PROGRESS, now);
// Confirm that they made it into the DB unchanged.
DeleteBackend();
{
sql::Connection db;
ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
sql::Statement statement(db.GetUniqueStatement(
"Select Count(*) from downloads"));
EXPECT_TRUE(statement.Step());
EXPECT_EQ(1, statement.ColumnInt(0));
sql::Statement statement1(db.GetUniqueStatement(
"Select state, interrupt_reason from downloads"));
EXPECT_TRUE(statement1.Step());
EXPECT_EQ(DownloadDatabase::kStateInProgress, statement1.ColumnInt(0));
EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, statement1.ColumnInt(1));
EXPECT_FALSE(statement1.Step());
}
// Read in the DB through query downloads, then test that the
// right transformation was returned.
CreateBackendAndDatabase();
std::vector<DownloadRow> results;
db_->QueryDownloads(&results);
ASSERT_EQ(1u, results.size());
EXPECT_EQ(content::DownloadItem::INTERRUPTED, results[0].state);
EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH,
results[0].interrupt_reason);
// Allow the update to propagate, shut down the DB, and confirm that
// the query updated the on disk database as well.
MessageLoop::current()->RunUntilIdle();
DeleteBackend();
{
sql::Connection db;
ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
sql::Statement statement(db.GetUniqueStatement(
"Select Count(*) from downloads"));
EXPECT_TRUE(statement.Step());
EXPECT_EQ(1, statement.ColumnInt(0));
sql::Statement statement1(db.GetUniqueStatement(
"Select state, interrupt_reason from downloads"));
EXPECT_TRUE(statement1.Step());
EXPECT_EQ(DownloadDatabase::kStateInterrupted, statement1.ColumnInt(0));
EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH,
statement1.ColumnInt(1));
EXPECT_FALSE(statement1.Step());
}
}
struct InterruptReasonAssociation { struct InterruptReasonAssociation {
std::string name; std::string name;
int value; int value;
...@@ -1635,6 +1692,4 @@ TEST_F(HistoryBackendDBTest, MigratePresentations) { ...@@ -1635,6 +1692,4 @@ TEST_F(HistoryBackendDBTest, MigratePresentations) {
STLDeleteElements(&results); STLDeleteElements(&results);
} }
} // namespace
} // namespace history } // namespace history
...@@ -133,10 +133,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate, ...@@ -133,10 +133,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
bound_net_log_(bound_net_log), bound_net_log_(bound_net_log),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
delegate_->Attach(); delegate_->Attach();
if (state_ == IN_PROGRESS_INTERNAL) { DCHECK_NE(IN_PROGRESS_INTERNAL, state_);
state_ = INTERRUPTED_INTERNAL;
last_reason_ = DOWNLOAD_INTERRUPT_REASON_CRASH;
}
Init(false /* not actively downloading */, SRC_HISTORY_IMPORT); Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
} }
......
...@@ -76,7 +76,7 @@ class MockDownloadItemImpl : public DownloadItemImpl { ...@@ -76,7 +76,7 @@ class MockDownloadItemImpl : public DownloadItemImpl {
base::Time(), base::Time(),
0, 0,
0, 0,
DownloadItem::IN_PROGRESS, DownloadItem::COMPLETE,
DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
DOWNLOAD_INTERRUPT_REASON_NONE, DOWNLOAD_INTERRUPT_REASON_NONE,
false, false,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment