sync_task_manager.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
1// Copyright 2014 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_file_system/drive_backend/sync_task_manager.h" 6 7#include "base/bind.h" 8#include "base/location.h" 9#include "base/memory/scoped_ptr.h" 10#include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h" 11#include "chrome/browser/sync_file_system/sync_file_metadata.h" 12 13using fileapi::FileSystemURL; 14 15namespace sync_file_system { 16namespace drive_backend { 17 18namespace { 19 20class SyncTaskAdapter : public ExclusiveTask { 21 public: 22 explicit SyncTaskAdapter(const SyncTaskManager::Task& task) : task_(task) {} 23 virtual ~SyncTaskAdapter() {} 24 25 virtual void RunExclusive(const SyncStatusCallback& callback) OVERRIDE { 26 task_.Run(callback); 27 } 28 29 private: 30 SyncTaskManager::Task task_; 31 32 DISALLOW_COPY_AND_ASSIGN(SyncTaskAdapter); 33}; 34 35} // namespace 36 37SyncTaskManager::PendingTask::PendingTask() {} 38 39SyncTaskManager::PendingTask::PendingTask( 40 const base::Closure& task, Priority pri, int seq) 41 : task(task), priority(pri), seq(seq) {} 42 43SyncTaskManager::PendingTask::~PendingTask() {} 44 45bool SyncTaskManager::PendingTaskComparator::operator()( 46 const PendingTask& left, 47 const PendingTask& right) const { 48 if (left.priority != right.priority) 49 return left.priority < right.priority; 50 return left.seq > right.seq; 51} 52 53SyncTaskManager::SyncTaskManager( 54 base::WeakPtr<Client> client, 55 size_t maximum_background_task) 56 : client_(client), 57 maximum_background_task_(maximum_background_task), 58 pending_task_seq_(0), 59 task_token_seq_(SyncTaskToken::kMinimumBackgroundTaskTokenID) { 60} 61 62SyncTaskManager::~SyncTaskManager() { 63 client_.reset(); 64 token_.reset(); 65} 66 67void SyncTaskManager::Initialize(SyncStatusCode status) { 68 DCHECK(!token_); 69 NotifyTaskDone(SyncTaskToken::CreateForForegroundTask(AsWeakPtr()), 70 status); 71} 72 73void SyncTaskManager::ScheduleTask( 74 const tracked_objects::Location& from_here, 75 const Task& task, 76 Priority priority, 77 const SyncStatusCallback& callback) { 78 ScheduleSyncTask(from_here, 79 scoped_ptr<SyncTask>(new SyncTaskAdapter(task)), 80 priority, 81 callback); 82} 83 84void SyncTaskManager::ScheduleSyncTask( 85 const tracked_objects::Location& from_here, 86 scoped_ptr<SyncTask> task, 87 Priority priority, 88 const SyncStatusCallback& callback) { 89 scoped_ptr<SyncTaskToken> token(GetToken(from_here, callback)); 90 if (!token) { 91 PushPendingTask( 92 base::Bind(&SyncTaskManager::ScheduleSyncTask, AsWeakPtr(), from_here, 93 base::Passed(&task), priority, callback), 94 priority); 95 return; 96 } 97 RunTask(token.Pass(), task.Pass()); 98} 99 100bool SyncTaskManager::ScheduleTaskIfIdle( 101 const tracked_objects::Location& from_here, 102 const Task& task, 103 const SyncStatusCallback& callback) { 104 return ScheduleSyncTaskIfIdle( 105 from_here, 106 scoped_ptr<SyncTask>(new SyncTaskAdapter(task)), 107 callback); 108} 109 110bool SyncTaskManager::ScheduleSyncTaskIfIdle( 111 const tracked_objects::Location& from_here, 112 scoped_ptr<SyncTask> task, 113 const SyncStatusCallback& callback) { 114 scoped_ptr<SyncTaskToken> token(GetToken(from_here, callback)); 115 if (!token) 116 return false; 117 RunTask(token.Pass(), task.Pass()); 118 return true; 119} 120 121// static 122void SyncTaskManager::NotifyTaskDone(scoped_ptr<SyncTaskToken> token, 123 SyncStatusCode status) { 124 DCHECK(token); 125 126 SyncTaskManager* manager = token->manager(); 127 if (manager) 128 manager->NotifyTaskDoneBody(token.Pass(), status); 129} 130 131// static 132void SyncTaskManager::MoveTaskToBackground( 133 scoped_ptr<SyncTaskToken> token, 134 scoped_ptr<BlockingFactor> blocking_factor, 135 const Continuation& continuation) { 136 DCHECK(token); 137 138 SyncTaskManager* manager = token->manager(); 139 if (!manager) 140 return; 141 manager->MoveTaskToBackgroundBody(token.Pass(), blocking_factor.Pass(), 142 continuation); 143} 144 145bool SyncTaskManager::IsRunningTask(int64 token_id) const { 146 // If the client is gone, all task should be aborted. 147 if (!client_) 148 return false; 149 150 if (token_id == SyncTaskToken::kForegroundTaskTokenID) 151 return true; 152 153 return ContainsKey(running_background_task_, token_id); 154} 155 156void SyncTaskManager::NotifyTaskDoneBody(scoped_ptr<SyncTaskToken> token, 157 SyncStatusCode status) { 158 DCHECK(token); 159 160 DVLOG(3) << "NotifyTaskDone: " << "finished with status=" << status 161 << " (" << SyncStatusCodeToString(status) << ")" 162 << " " << token_->location().ToString(); 163 164 if (token->blocking_factor()) { 165 dependency_manager_.Erase(*token->blocking_factor()); 166 token->clear_blocking_factor(); 167 } 168 169 scoped_ptr<SyncTask> task; 170 SyncStatusCallback callback = token->callback(); 171 token->clear_callback(); 172 if (token->token_id() == SyncTaskToken::kForegroundTaskTokenID) { 173 token_ = token.Pass(); 174 task = running_task_.Pass(); 175 } else { 176 task = running_background_task_.take_and_erase(token->token_id()); 177 } 178 179 bool task_used_network = false; 180 if (task) 181 task_used_network = task->used_network(); 182 183 if (client_) 184 client_->NotifyLastOperationStatus(status, task_used_network); 185 186 if (!callback.is_null()) 187 callback.Run(status); 188 189 StartNextTask(); 190} 191 192void SyncTaskManager::MoveTaskToBackgroundBody( 193 scoped_ptr<SyncTaskToken> token, 194 scoped_ptr<BlockingFactor> blocking_factor, 195 const Continuation& continuation) { 196 if (!maximum_background_task_) { 197 continuation.Run(token.Pass()); 198 return; 199 } 200 201 if (running_background_task_.size() >= maximum_background_task_ || 202 !dependency_manager_.Insert(*blocking_factor)) { 203 DCHECK(!running_background_task_.empty()); 204 205 // Wait for NotifyTaskDone to release a |blocking_factor|. 206 pending_backgrounding_task_ = 207 base::Bind(&SyncTaskManager::MoveTaskToBackground, 208 base::Passed(&token), base::Passed(&blocking_factor), 209 continuation); 210 return; 211 } 212 213 tracked_objects::Location from_here = token->location(); 214 SyncStatusCallback callback = token->callback(); 215 token->clear_callback(); 216 217 scoped_ptr<SyncTaskToken> background_task_token = 218 SyncTaskToken::CreateForBackgroundTask( 219 AsWeakPtr(), task_token_seq_++, blocking_factor.Pass()); 220 background_task_token->UpdateTask(from_here, callback); 221 222 NotifyTaskBackgrounded(token.Pass(), *background_task_token); 223 continuation.Run(background_task_token.Pass()); 224} 225 226void SyncTaskManager::NotifyTaskBackgrounded( 227 scoped_ptr<SyncTaskToken> foreground_task_token, 228 const SyncTaskToken& background_task_token) { 229 token_ = foreground_task_token.Pass(); 230 running_background_task_.set(background_task_token.token_id(), 231 running_task_.Pass()); 232 233 StartNextTask(); 234} 235 236scoped_ptr<SyncTaskToken> SyncTaskManager::GetToken( 237 const tracked_objects::Location& from_here, 238 const SyncStatusCallback& callback) { 239 if (!token_) 240 return scoped_ptr<SyncTaskToken>(); 241 token_->UpdateTask(from_here, callback); 242 return token_.Pass(); 243} 244 245void SyncTaskManager::PushPendingTask( 246 const base::Closure& closure, Priority priority) { 247 pending_tasks_.push(PendingTask(closure, priority, pending_task_seq_++)); 248} 249 250void SyncTaskManager::RunTask(scoped_ptr<SyncTaskToken> token, 251 scoped_ptr<SyncTask> task) { 252 DCHECK(!running_task_); 253 running_task_ = task.Pass(); 254 running_task_->RunPreflight(token.Pass()); 255} 256 257void SyncTaskManager::StartNextTask() { 258 if (!pending_backgrounding_task_.is_null()) { 259 base::Closure closure = pending_backgrounding_task_; 260 pending_backgrounding_task_.Reset(); 261 closure.Run(); 262 return; 263 } 264 265 if (!pending_tasks_.empty()) { 266 base::Closure closure = pending_tasks_.top().task; 267 pending_tasks_.pop(); 268 closure.Run(); 269 return; 270 } 271 272 if (client_) 273 client_->MaybeScheduleNextTask(); 274} 275 276} // namespace drive_backend 277} // namespace sync_file_system 278