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 3// found in the LICENSE file. 4 5#include "chrome/browser/sync/glue/history_model_worker.h" 6 7#include "base/memory/ref_counted.h" 8#include "base/message_loop/message_loop.h" 9#include "base/synchronization/waitable_event.h" 10#include "content/public/browser/browser_thread.h" 11 12using base::WaitableEvent; 13using content::BrowserThread; 14 15namespace browser_sync { 16 17class WorkerTask : public history::HistoryDBTask { 18 public: 19 WorkerTask( 20 const syncer::WorkCallback& work, 21 WaitableEvent* done, 22 syncer::SyncerError* error) 23 : work_(work), done_(done), error_(error) {} 24 25 virtual bool RunOnDBThread(history::HistoryBackend* backend, 26 history::HistoryDatabase* db) OVERRIDE { 27 *error_ = work_.Run(); 28 done_->Signal(); 29 return true; 30 } 31 32 // Since the DoWorkAndWaitUntilDone() is synchronous, we don't need to run 33 // any code asynchronously on the main thread after completion. 34 virtual void DoneRunOnMainThread() OVERRIDE {} 35 36 protected: 37 virtual ~WorkerTask() {} 38 39 syncer::WorkCallback work_; 40 WaitableEvent* done_; 41 syncer::SyncerError* error_; 42}; 43 44class AddDBThreadObserverTask : public history::HistoryDBTask { 45 public: 46 explicit AddDBThreadObserverTask(base::Closure register_callback) 47 : register_callback_(register_callback) {} 48 49 virtual bool RunOnDBThread(history::HistoryBackend* backend, 50 history::HistoryDatabase* db) OVERRIDE { 51 register_callback_.Run(); 52 return true; 53 } 54 55 virtual void DoneRunOnMainThread() OVERRIDE {} 56 57 private: 58 virtual ~AddDBThreadObserverTask() {} 59 60 base::Closure register_callback_; 61}; 62 63namespace { 64 65// Post the work task on |history_service|'s DB thread from the UI 66// thread. 67void PostWorkerTask(const base::WeakPtr<HistoryService>& history_service, 68 const syncer::WorkCallback& work, 69 base::CancelableTaskTracker* cancelable_tracker, 70 WaitableEvent* done, 71 syncer::SyncerError* error) { 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 73 if (history_service.get()) { 74 scoped_ptr<history::HistoryDBTask> task(new WorkerTask(work, done, error)); 75 history_service->ScheduleDBTask(task.Pass(), cancelable_tracker); 76 } else { 77 *error = syncer::CANNOT_DO_WORK; 78 done->Signal(); 79 } 80} 81 82} // namespace 83 84HistoryModelWorker::HistoryModelWorker( 85 const base::WeakPtr<HistoryService>& history_service, 86 syncer::WorkerLoopDestructionObserver* observer) 87 : syncer::ModelSafeWorker(observer), 88 history_service_(history_service) { 89 CHECK(history_service.get()); 90 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 91 cancelable_tracker_.reset(new base::CancelableTaskTracker); 92} 93 94void HistoryModelWorker::RegisterForLoopDestruction() { 95 CHECK(history_service_.get()); 96 history_service_->ScheduleDBTask( 97 scoped_ptr<history::HistoryDBTask>(new AddDBThreadObserverTask( 98 base::Bind(&HistoryModelWorker::RegisterOnDBThread, this))), 99 cancelable_tracker_.get()); 100} 101 102void HistoryModelWorker::RegisterOnDBThread() { 103 SetWorkingLoopToCurrent(); 104} 105 106syncer::SyncerError HistoryModelWorker::DoWorkAndWaitUntilDoneImpl( 107 const syncer::WorkCallback& work) { 108 syncer::SyncerError error = syncer::UNSET; 109 if (BrowserThread::PostTask(BrowserThread::UI, 110 FROM_HERE, 111 base::Bind(&PostWorkerTask, 112 history_service_, 113 work, 114 cancelable_tracker_.get(), 115 work_done_or_stopped(), 116 &error))) { 117 work_done_or_stopped()->Wait(); 118 } else { 119 error = syncer::CANNOT_DO_WORK; 120 } 121 return error; 122} 123 124syncer::ModelSafeGroup HistoryModelWorker::GetModelSafeGroup() { 125 return syncer::GROUP_HISTORY; 126} 127 128HistoryModelWorker::~HistoryModelWorker() { 129 // The base::CancelableTaskTracker class is not thread-safe and must only be 130 // used from a single thread but the current object may not be destroyed from 131 // the UI thread, so delete it from the UI thread. 132 BrowserThread::DeleteOnUIThread::Destruct(cancelable_tracker_.release()); 133} 134 135} // namespace browser_sync 136