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. 4 5 #include "chrome/browser/sync_file_system/sync_task_manager.h" 6 7 #include "base/debug/trace_event.h" 8 #include "base/location.h" 9 #include "chrome/browser/sync_file_system/sync_file_metadata.h" 10 11 using fileapi::FileSystemURL; 12 13 namespace sync_file_system { 14 15 class SyncTaskManager::TaskToken { 16 public: 17 explicit TaskToken(const base::WeakPtr<SyncTaskManager>& manager) 18 : manager_(manager) { 19 } 20 21 void UpdateTask(const tracked_objects::Location& location) { 22 location_ = location; 23 DVLOG(2) << "Token updated: " << location_.ToString(); 24 } 25 26 const tracked_objects::Location& location() const { return location_; } 27 28 ~TaskToken() { 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()) { 35 NOTREACHED() 36 << "Unexpected TaskToken deletion from: " << location_.ToString(); 37 38 // Reinitializes the token. 39 manager_->NotifyTaskDone( 40 make_scoped_ptr(new TaskToken(manager_)), 41 SyncStatusCallback(), 42 SYNC_STATUS_OK); 43 } 44 } 45 46 private: 47 base::WeakPtr<SyncTaskManager> manager_; 48 tracked_objects::Location location_; 49 50 DISALLOW_COPY_AND_ASSIGN(TaskToken); 51 }; 52 53 SyncTaskManager::SyncTaskManager( 54 base::WeakPtr<Client> client) 55 : client_(client), 56 last_operation_status_(SYNC_STATUS_OK) { 57 } 58 59 SyncTaskManager::~SyncTaskManager() { 60 client_.reset(); 61 token_.reset(); 62 } 63 64 void SyncTaskManager::Initialize(SyncStatusCode status) { 65 DCHECK(!token_); 66 NotifyTaskDone(make_scoped_ptr(new TaskToken(AsWeakPtr())), 67 SyncStatusCallback(), 68 status); 69 } 70 71 void SyncTaskManager::ScheduleTask( 72 const Task& task, 73 const SyncStatusCallback& callback) { 74 scoped_ptr<TaskToken> token(GetToken(FROM_HERE)); 75 if (!token) { 76 pending_tasks_.push_back(base::Bind( 77 &SyncTaskManager::ScheduleTask, AsWeakPtr(), task, callback)); 78 return; 79 } 80 task.Run(CreateCompletionCallback(token.Pass(), callback)); 81 } 82 83 void SyncTaskManager::ScheduleTaskIfIdle(const Task& task) { 84 scoped_ptr<TaskToken> token(GetToken(FROM_HERE)); 85 if (!token) 86 return; 87 task.Run(CreateCompletionCallback(token.Pass(), SyncStatusCallback())); 88 } 89 90 void SyncTaskManager::NotifyTaskDone( 91 scoped_ptr<TaskToken> token, 92 const SyncStatusCallback& callback, 93 SyncStatusCode status) { 94 DCHECK(token); 95 last_operation_status_ = status; 96 token_ = token.Pass(); 97 TRACE_EVENT_ASYNC_END0("Sync FileSystem", "GetToken", this); 98 99 DVLOG(3) << "NotifyTaskDone: " << "finished with status=" << status 100 << " (" << SyncStatusCodeToString(status) << ")" 101 << " " << token_->location().ToString(); 102 103 client_->NotifyLastOperationStatus(last_operation_status_); 104 105 if (!callback.is_null()) 106 callback.Run(status); 107 108 if (!pending_tasks_.empty()) { 109 base::Closure closure = pending_tasks_.front(); 110 pending_tasks_.pop_front(); 111 closure.Run(); 112 return; 113 } 114 115 client_->MaybeScheduleNextTask(); 116 } 117 118 scoped_ptr<SyncTaskManager::TaskToken> SyncTaskManager::GetToken( 119 const tracked_objects::Location& from_here) { 120 if (!token_) 121 return scoped_ptr<TaskToken>(); 122 TRACE_EVENT_ASYNC_BEGIN1("Sync FileSystem", "GetToken", this, 123 "where", from_here.ToString()); 124 token_->UpdateTask(from_here); 125 return token_.Pass(); 126 } 127 128 SyncStatusCallback SyncTaskManager::CreateCompletionCallback( 129 scoped_ptr<TaskToken> token, 130 const SyncStatusCallback& callback) { 131 DCHECK(token); 132 return base::Bind(&SyncTaskManager::NotifyTaskDone, 133 AsWeakPtr(), base::Passed(&token), callback); 134 } 135 136 } // namespace sync_file_system 137