| Index: components/history/core/browser/history_backend.cc
|
| diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
|
| index f3a489a3343522a535eedb5608098f2704b69985..08cacf54212abaa3b3639e655f75878563e0b986 100644
|
| --- a/components/history/core/browser/history_backend.cc
|
| +++ b/components/history/core/browser/history_backend.cc
|
| @@ -114,6 +114,44 @@
|
| return mv;
|
| }
|
|
|
| +// This task is run on a timer so that commits happen at regular intervals
|
| +// so they are batched together. The important thing about this class is that
|
| +// it supports canceling of the task so the reference to the backend will be
|
| +// freed. The problem is that when history is shutting down, there is likely
|
| +// to be one of these commits still pending and holding a reference.
|
| +//
|
| +// The backend can call Cancel to have this task release the reference. The
|
| +// task will still run (if we ever get to processing the event before
|
| +// shutdown), but it will not do anything.
|
| +//
|
| +// Note that this is a refcounted object and is not a task in itself. It should
|
| +// be assigned to a RunnableMethod.
|
| +//
|
| +// TODO(brettw): bug 1165182: This should be replaced with a
|
| +// base::WeakPtrFactory which will handle everything automatically (like we do
|
| +// in ExpireHistoryBackend).
|
| +class CommitLaterTask : public base::RefCounted<CommitLaterTask> {
|
| + public:
|
| + explicit CommitLaterTask(HistoryBackend* history_backend)
|
| + : history_backend_(history_backend) {}
|
| +
|
| + // The backend will call this function if it is being destroyed so that we
|
| + // release our reference.
|
| + void Cancel() { history_backend_ = nullptr; }
|
| +
|
| + void RunCommit() {
|
| + if (history_backend_)
|
| + history_backend_->Commit();
|
| + }
|
| +
|
| + private:
|
| + friend class base::RefCounted<CommitLaterTask>;
|
| +
|
| + ~CommitLaterTask() {}
|
| +
|
| + scoped_refptr<HistoryBackend> history_backend_;
|
| +};
|
| +
|
| QueuedHistoryDBTask::QueuedHistoryDBTask(
|
| std::unique_ptr<HistoryDBTask> task,
|
| scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
|
| @@ -179,7 +217,7 @@
|
| task_runner_(task_runner) {}
|
|
|
| HistoryBackend::~HistoryBackend() {
|
| - DCHECK(scheduled_commit_.IsCancelled()) << "Deleting without cleanup";
|
| + DCHECK(!scheduled_commit_) << "Deleting without cleanup";
|
| queued_history_db_tasks_.clear();
|
|
|
| // Release stashed embedder object before cleaning up the databases.
|
| @@ -2204,21 +2242,20 @@
|
| }
|
|
|
| void HistoryBackend::ScheduleCommit() {
|
| - // Non-cancelled means there's an already scheduled commit. Note that
|
| - // CancelableClosure starts cancelled with the default constructor.
|
| - if (!scheduled_commit_.IsCancelled())
|
| - return;
|
| -
|
| - scheduled_commit_.Reset(
|
| - base::Bind(&HistoryBackend::Commit, base::Unretained(this)));
|
| -
|
| + if (scheduled_commit_)
|
| + return;
|
| + scheduled_commit_ = new CommitLaterTask(this);
|
| task_runner_->PostDelayedTask(
|
| - FROM_HERE, scheduled_commit_.callback(),
|
| + FROM_HERE,
|
| + base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_),
|
| base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
|
| }
|
|
|
| void HistoryBackend::CancelScheduledCommit() {
|
| - scheduled_commit_.Cancel();
|
| + if (scheduled_commit_) {
|
| + scheduled_commit_->Cancel();
|
| + scheduled_commit_ = nullptr;
|
| + }
|
| }
|
|
|
| void HistoryBackend::ProcessDBTaskImpl() {
|
|
|