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 ScheduleSyncTaskAtPriority(task
.Pass(), PRIORITY_MED
, callback
);
98 void SyncTaskManager::ScheduleTaskAtPriority(
101 const SyncStatusCallback
& callback
) {
102 scoped_ptr
<TaskToken
> token(GetToken(FROM_HERE
));
105 base::Bind(&SyncTaskManager::ScheduleTask
, AsWeakPtr(),
110 task
.Run(CreateCompletionCallback(token
.Pass(), callback
));
113 void SyncTaskManager::ScheduleSyncTaskAtPriority(
114 scoped_ptr
<SyncTask
> task
,
116 const SyncStatusCallback
& callback
) {
117 scoped_ptr
<TaskToken
> token(GetToken(FROM_HERE
));
120 base::Bind(&SyncTaskManager::ScheduleSyncTask
,
121 AsWeakPtr(), base::Passed(&task
), callback
),
125 DCHECK(!running_task_
);
126 running_task_
= task
.Pass();
127 running_task_
->Run(CreateCompletionCallback(token
.Pass(), callback
));
130 bool SyncTaskManager::ScheduleTaskIfIdle(const Task
& task
,
131 const SyncStatusCallback
& callback
) {
132 scoped_ptr
<TaskToken
> token(GetToken(FROM_HERE
));
135 task
.Run(CreateCompletionCallback(token
.Pass(), callback
));
139 bool SyncTaskManager::ScheduleSyncTaskIfIdle(
140 scoped_ptr
<SyncTask
> task
,
141 const SyncStatusCallback
& callback
) {
142 scoped_ptr
<TaskToken
> token(GetToken(FROM_HERE
));
145 DCHECK(!running_task_
);
146 running_task_
= task
.Pass();
147 running_task_
->Run(CreateCompletionCallback(token
.Pass(),
152 void SyncTaskManager::NotifyTaskDone(
153 scoped_ptr
<TaskToken
> token
,
154 SyncStatusCode status
) {
156 last_operation_status_
= status
;
157 token_
= token
.Pass();
158 scoped_ptr
<SyncTask
> task
= running_task_
.Pass();
159 TRACE_EVENT_ASYNC_END0("Sync FileSystem", "GetToken", this);
161 DVLOG(3) << "NotifyTaskDone: " << "finished with status=" << status
162 << " (" << SyncStatusCodeToString(status
) << ")"
163 << " " << token_
->location().ToString();
165 bool task_used_network
= false;
167 task_used_network
= task
->used_network();
170 client_
->NotifyLastOperationStatus(last_operation_status_
,
173 if (!current_callback_
.is_null()) {
174 SyncStatusCallback callback
= current_callback_
;
175 current_callback_
.Reset();
176 callback
.Run(status
);
179 if (!pending_tasks_
.empty()) {
180 base::Closure closure
= pending_tasks_
.top().task
;
181 pending_tasks_
.pop();
187 client_
->MaybeScheduleNextTask();
190 scoped_ptr
<SyncTaskManager::TaskToken
> SyncTaskManager::GetToken(
191 const tracked_objects::Location
& from_here
) {
193 return scoped_ptr
<TaskToken
>();
194 TRACE_EVENT_ASYNC_BEGIN1("Sync FileSystem", "GetToken", this,
195 "where", from_here
.ToString());
196 token_
->UpdateTask(from_here
);
197 return token_
.Pass();
200 SyncStatusCallback
SyncTaskManager::CreateCompletionCallback(
201 scoped_ptr
<TaskToken
> token
,
202 const SyncStatusCallback
& callback
) {
204 DCHECK(current_callback_
.is_null());
205 current_callback_
= callback
;
206 return base::Bind(&SyncTaskManager::NotifyTaskDone
,
207 AsWeakPtr(), base::Passed(&token
));
210 void SyncTaskManager::PushPendingTask(
211 const base::Closure
& closure
, Priority priority
) {
212 pending_tasks_
.push(PendingTask(closure
, priority
, pending_task_seq_
++));
215 } // namespace sync_file_system