1 // Copyright 2013 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.
5 #include "chrome/browser/sync_file_system/sync_task_manager.h"
7 #include "base/debug/trace_event.h"
8 #include "base/location.h"
9 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
11 using fileapi::FileSystemURL;
13 namespace sync_file_system {
15 class SyncTaskManager::TaskToken {
17 explicit TaskToken(const base::WeakPtr<SyncTaskManager>& manager)
21 void UpdateTask(const tracked_objects::Location& location) {
23 DVLOG(2) << "Token updated: " << location_.ToString();
26 const tracked_objects::Location& location() const { return location_; }
29 // All task on Client must hold TaskToken instance to ensure
30 // no other tasks are running. Also, as soon as a task finishes to work,
31 // it must return the token to TaskManager.
32 // Destroying a token with valid |client| indicates the token was
33 // dropped by a task without returning.
34 if (manager_.get() && manager_->client_.get()) {
36 << "Unexpected TaskToken deletion from: " << location_.ToString();
38 // Reinitializes the token.
39 manager_->NotifyTaskDone(
40 make_scoped_ptr(new TaskToken(manager_)),
46 base::WeakPtr<SyncTaskManager> manager_;
47 tracked_objects::Location location_;
49 DISALLOW_COPY_AND_ASSIGN(TaskToken);
52 SyncTaskManager::PendingTask::PendingTask() {}
54 SyncTaskManager::PendingTask::PendingTask(
55 const base::Closure& task, Priority pri, int seq)
56 : task(task), priority(pri), seq(seq) {}
58 SyncTaskManager::PendingTask::~PendingTask() {}
60 bool SyncTaskManager::PendingTaskComparator::operator()(
61 const PendingTask& left,
62 const PendingTask& right) const {
63 if (left.priority != right.priority)
64 return left.priority < right.priority;
65 return left.seq > right.seq;
68 SyncTaskManager::SyncTaskManager(
69 base::WeakPtr<Client> client)
71 last_operation_status_(SYNC_STATUS_OK),
72 pending_task_seq_(0) {
75 SyncTaskManager::~SyncTaskManager() {
80 void SyncTaskManager::Initialize(SyncStatusCode status) {
82 NotifyTaskDone(make_scoped_ptr(new TaskToken(AsWeakPtr())),
86 void SyncTaskManager::ScheduleTask(
88 const SyncStatusCallback& callback) {
89 ScheduleTaskAtPriority(task, PRIORITY_MED, callback);
92 void SyncTaskManager::ScheduleSyncTask(
93 scoped_ptr<SyncTask> task,
94 const SyncStatusCallback& callback) {
95 scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
98 base::Bind(&SyncTaskManager::ScheduleSyncTask,
99 AsWeakPtr(), base::Passed(&task), callback),
103 DCHECK(!running_task_);
104 running_task_ = task.Pass();
105 running_task_->Run(CreateCompletionCallback(token.Pass(), callback));
108 void SyncTaskManager::ScheduleTaskAtPriority(
111 const SyncStatusCallback& callback) {
112 scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
115 base::Bind(&SyncTaskManager::ScheduleTask, AsWeakPtr(),
120 task.Run(CreateCompletionCallback(token.Pass(), callback));
123 bool SyncTaskManager::ScheduleTaskIfIdle(const Task& task) {
124 scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
127 task.Run(CreateCompletionCallback(token.Pass(), SyncStatusCallback()));
131 bool SyncTaskManager::ScheduleSyncTaskIfIdle(scoped_ptr<SyncTask> task) {
132 scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
135 DCHECK(!running_task_);
136 running_task_ = task.Pass();
137 running_task_->Run(CreateCompletionCallback(token.Pass(),
138 SyncStatusCallback()));
142 void SyncTaskManager::NotifyTaskDone(
143 scoped_ptr<TaskToken> token,
144 SyncStatusCode status) {
146 last_operation_status_ = status;
147 token_ = token.Pass();
148 scoped_ptr<SyncTask> task = running_task_.Pass();
149 TRACE_EVENT_ASYNC_END0("Sync FileSystem", "GetToken", this);
151 DVLOG(3) << "NotifyTaskDone: " << "finished with status=" << status
152 << " (" << SyncStatusCodeToString(status) << ")"
153 << " " << token_->location().ToString();
156 client_->NotifyLastOperationStatus(last_operation_status_);
158 if (!current_callback_.is_null()) {
159 SyncStatusCallback callback = current_callback_;
160 current_callback_.Reset();
161 callback.Run(status);
164 if (!pending_tasks_.empty()) {
165 base::Closure closure = pending_tasks_.top().task;
166 pending_tasks_.pop();
172 client_->MaybeScheduleNextTask();
175 scoped_ptr<SyncTaskManager::TaskToken> SyncTaskManager::GetToken(
176 const tracked_objects::Location& from_here) {
178 return scoped_ptr<TaskToken>();
179 TRACE_EVENT_ASYNC_BEGIN1("Sync FileSystem", "GetToken", this,
180 "where", from_here.ToString());
181 token_->UpdateTask(from_here);
182 return token_.Pass();
185 SyncStatusCallback SyncTaskManager::CreateCompletionCallback(
186 scoped_ptr<TaskToken> token,
187 const SyncStatusCallback& callback) {
189 DCHECK(current_callback_.is_null());
190 current_callback_ = callback;
191 return base::Bind(&SyncTaskManager::NotifyTaskDone,
192 AsWeakPtr(), base::Passed(&token));
195 void SyncTaskManager::PushPendingTask(
196 const base::Closure& closure, Priority priority) {
197 pending_tasks_.push(PendingTask(closure, priority, pending_task_seq_++));
200 } // namespace sync_file_system