- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / sync_task_manager.cc
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           SYNC_STATUS_OK);
42     }
43   }
44
45  private:
46   base::WeakPtr<SyncTaskManager> manager_;
47   tracked_objects::Location location_;
48
49   DISALLOW_COPY_AND_ASSIGN(TaskToken);
50 };
51
52 SyncTaskManager::PendingTask::PendingTask() {}
53
54 SyncTaskManager::PendingTask::PendingTask(
55     const base::Closure& task, Priority pri, int seq)
56     : task(task), priority(pri), seq(seq) {}
57
58 SyncTaskManager::PendingTask::~PendingTask() {}
59
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;
66 }
67
68 SyncTaskManager::SyncTaskManager(
69     base::WeakPtr<Client> client)
70     : client_(client),
71       last_operation_status_(SYNC_STATUS_OK),
72       pending_task_seq_(0) {
73 }
74
75 SyncTaskManager::~SyncTaskManager() {
76   client_.reset();
77   token_.reset();
78 }
79
80 void SyncTaskManager::Initialize(SyncStatusCode status) {
81   DCHECK(!token_);
82   NotifyTaskDone(make_scoped_ptr(new TaskToken(AsWeakPtr())),
83                  status);
84 }
85
86 void SyncTaskManager::ScheduleTask(
87     const Task& task,
88     const SyncStatusCallback& callback) {
89   ScheduleTaskAtPriority(task, PRIORITY_MED, callback);
90 }
91
92 void SyncTaskManager::ScheduleSyncTask(
93     scoped_ptr<SyncTask> task,
94     const SyncStatusCallback& callback) {
95   scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
96   if (!token) {
97     PushPendingTask(
98         base::Bind(&SyncTaskManager::ScheduleSyncTask,
99                    AsWeakPtr(), base::Passed(&task), callback),
100         PRIORITY_MED);
101     return;
102   }
103   DCHECK(!running_task_);
104   running_task_ = task.Pass();
105   running_task_->Run(CreateCompletionCallback(token.Pass(), callback));
106 }
107
108 void SyncTaskManager::ScheduleTaskAtPriority(
109     const Task& task,
110     Priority priority,
111     const SyncStatusCallback& callback) {
112   scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
113   if (!token) {
114     PushPendingTask(
115         base::Bind(&SyncTaskManager::ScheduleTask, AsWeakPtr(),
116                    task, callback),
117         priority);
118     return;
119   }
120   task.Run(CreateCompletionCallback(token.Pass(), callback));
121 }
122
123 bool SyncTaskManager::ScheduleTaskIfIdle(const Task& task) {
124   scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
125   if (!token)
126     return false;
127   task.Run(CreateCompletionCallback(token.Pass(), SyncStatusCallback()));
128   return true;
129 }
130
131 bool SyncTaskManager::ScheduleSyncTaskIfIdle(scoped_ptr<SyncTask> task) {
132   scoped_ptr<TaskToken> token(GetToken(FROM_HERE));
133   if (!token)
134     return false;
135   DCHECK(!running_task_);
136   running_task_ = task.Pass();
137   running_task_->Run(CreateCompletionCallback(token.Pass(),
138                                               SyncStatusCallback()));
139   return true;
140 }
141
142 void SyncTaskManager::NotifyTaskDone(
143     scoped_ptr<TaskToken> token,
144     SyncStatusCode status) {
145   DCHECK(token);
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);
150
151   DVLOG(3) << "NotifyTaskDone: " << "finished with status=" << status
152            << " (" << SyncStatusCodeToString(status) << ")"
153            << " " << token_->location().ToString();
154
155   if (client_)
156     client_->NotifyLastOperationStatus(last_operation_status_);
157
158   if (!current_callback_.is_null()) {
159     SyncStatusCallback callback = current_callback_;
160     current_callback_.Reset();
161     callback.Run(status);
162   }
163
164   if (!pending_tasks_.empty()) {
165     base::Closure closure = pending_tasks_.top().task;
166     pending_tasks_.pop();
167     closure.Run();
168     return;
169   }
170
171   if (client_)
172     client_->MaybeScheduleNextTask();
173 }
174
175 scoped_ptr<SyncTaskManager::TaskToken> SyncTaskManager::GetToken(
176     const tracked_objects::Location& from_here) {
177   if (!token_)
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();
183 }
184
185 SyncStatusCallback SyncTaskManager::CreateCompletionCallback(
186     scoped_ptr<TaskToken> token,
187     const SyncStatusCallback& callback) {
188   DCHECK(token);
189   DCHECK(current_callback_.is_null());
190   current_callback_ = callback;
191   return base::Bind(&SyncTaskManager::NotifyTaskDone,
192                     AsWeakPtr(), base::Passed(&token));
193 }
194
195 void SyncTaskManager::PushPendingTask(
196     const base::Closure& closure, Priority priority) {
197   pending_tasks_.push(PendingTask(closure, priority, pending_task_seq_++));
198 }
199
200 }  // namespace sync_file_system