15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/sync/glue/history_model_worker.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/ref_counted.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::WaitableEvent;
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using content::BrowserThread;
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace browser_sync {
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class WorkerTask : public history::HistoryDBTask {
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WorkerTask(
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const syncer::WorkCallback& work,
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      WaitableEvent* done,
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      syncer::SyncerError* error)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : work_(work), done_(done), error_(error) {}
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual bool RunOnDBThread(history::HistoryBackend* backend,
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             history::HistoryDatabase* db) OVERRIDE {
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error_ = work_.Run();
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    done_->Signal();
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Since the DoWorkAndWaitUntilDone() is synchronous, we don't need to run
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // any code asynchronously on the main thread after completion.
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void DoneRunOnMainThread() OVERRIDE {}
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) protected:
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~WorkerTask() {}
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  syncer::WorkCallback work_;
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WaitableEvent* done_;
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  syncer::SyncerError* error_;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class AddDBThreadObserverTask : public history::HistoryDBTask {
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit AddDBThreadObserverTask(base::Closure register_callback)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     : register_callback_(register_callback) {}
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual bool RunOnDBThread(history::HistoryBackend* backend,
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             history::HistoryDatabase* db) OVERRIDE {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    register_callback_.Run();
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void DoneRunOnMainThread() OVERRIDE {}
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~AddDBThreadObserverTask() {}
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Closure register_callback_;
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Post the work task on |history_service|'s DB thread from the UI
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// thread.
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PostWorkerTask(const base::WeakPtr<HistoryService>& history_service,
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    const syncer::WorkCallback& work,
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    base::CancelableTaskTracker* cancelable_tracker,
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    WaitableEvent* done,
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    syncer::SyncerError* error) {
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (history_service.get()) {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<history::HistoryDBTask> task(new WorkerTask(work, done, error));
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    history_service->ScheduleDBTask(task.Pass(), cancelable_tracker);
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error = syncer::CANNOT_DO_WORK;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    done->Signal();
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HistoryModelWorker::HistoryModelWorker(
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::WeakPtr<HistoryService>& history_service,
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::WorkerLoopDestructionObserver* observer)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  : syncer::ModelSafeWorker(observer),
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    history_service_(history_service) {
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(history_service.get());
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  cancelable_tracker_.reset(new base::CancelableTaskTracker);
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HistoryModelWorker::RegisterForLoopDestruction() {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(history_service_.get());
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  history_service_->ScheduleDBTask(
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<history::HistoryDBTask>(new AddDBThreadObserverTask(
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(&HistoryModelWorker::RegisterOnDBThread, this))),
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      cancelable_tracker_.get());
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HistoryModelWorker::RegisterOnDBThread() {
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetWorkingLoopToCurrent();
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)syncer::SyncerError HistoryModelWorker::DoWorkAndWaitUntilDoneImpl(
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::WorkCallback& work) {
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  syncer::SyncerError error = syncer::UNSET;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (BrowserThread::PostTask(BrowserThread::UI,
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              FROM_HERE,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              base::Bind(&PostWorkerTask,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         history_service_,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         work,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         cancelable_tracker_.get(),
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         work_done_or_stopped(),
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         &error))) {
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    work_done_or_stopped()->Wait();
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    error = syncer::CANNOT_DO_WORK;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return error;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)syncer::ModelSafeGroup HistoryModelWorker::GetModelSafeGroup() {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return syncer::GROUP_HISTORY;
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HistoryModelWorker::~HistoryModelWorker() {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The base::CancelableTaskTracker class is not thread-safe and must only be
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // used from a single thread but the current object may not be destroyed from
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the UI thread, so delete it from the UI thread.
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BrowserThread::DeleteOnUIThread::Destruct(cancelable_tracker_.release());
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace browser_sync
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)