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#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_SYNC_TASK_MANAGER_H_
6#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_SYNC_TASK_MANAGER_H_
7
8#include <queue>
9#include <vector>
10
11#include "base/callback.h"
12#include "base/containers/scoped_ptr_hash_map.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/weak_ptr.h"
15#include "base/sequence_checker.h"
16#include "chrome/browser/sync_file_system/drive_backend/task_dependency_manager.h"
17#include "chrome/browser/sync_file_system/sync_callbacks.h"
18#include "chrome/browser/sync_file_system/sync_status_code.h"
19#include "chrome/browser/sync_file_system/task_logger.h"
20
21namespace base {
22class SequencedTaskRunner;
23}
24
25namespace tracked_objects {
26class Location;
27}
28
29namespace sync_file_system {
30namespace drive_backend {
31
32class SyncTask;
33class SyncTaskToken;
34struct TaskBlocker;
35
36// This class manages asynchronous tasks for Sync FileSystem.  Each task must be
37// either a Task or a SyncTask.
38// The instance runs single task as the foreground task, and multiple tasks as
39// background tasks.  Running background task has a TaskBlocker that
40// describes which task can run in parallel.  When a task start running as a
41// background task, SyncTaskManager checks if any running background task
42// doesn't block the new background task, and queues it up if it can't run.
43class SyncTaskManager : public base::SupportsWeakPtr<SyncTaskManager> {
44 public:
45  typedef base::Callback<void(const SyncStatusCallback& callback)> Task;
46  typedef base::Callback<void(scoped_ptr<SyncTaskToken> token)> Continuation;
47
48  enum Priority {
49    PRIORITY_LOW,
50    PRIORITY_MED,
51    PRIORITY_HIGH,
52  };
53
54  class Client {
55   public:
56    virtual ~Client() {}
57
58    // Called when the manager is idle.
59    virtual void MaybeScheduleNextTask() = 0;
60
61    // Called when the manager is notified a task is done.
62    virtual void NotifyLastOperationStatus(
63        SyncStatusCode last_operation_status,
64        bool last_operation_used_network) = 0;
65
66    virtual void RecordTaskLog(scoped_ptr<TaskLogger::TaskLog> task_log) = 0;
67  };
68
69  // Runs at most |maximum_background_tasks| parallel as background tasks.
70  // If |maximum_background_tasks| is zero, all task runs as foreground task.
71  SyncTaskManager(base::WeakPtr<Client> client,
72                  size_t maximum_background_task,
73                  const scoped_refptr<base::SequencedTaskRunner>& task_runner);
74  virtual ~SyncTaskManager();
75
76  // This needs to be called to start task scheduling.
77  // If |status| is not SYNC_STATUS_OK calling this may change the
78  // service status. This should not be called more than once.
79  void Initialize(SyncStatusCode status);
80
81  // Schedules a task at the given priority.
82  void ScheduleTask(const tracked_objects::Location& from_here,
83                    const Task& task,
84                    Priority priority,
85                    const SyncStatusCallback& callback);
86  void ScheduleSyncTask(const tracked_objects::Location& from_here,
87                        scoped_ptr<SyncTask> task,
88                        Priority priority,
89                        const SyncStatusCallback& callback);
90
91  // Runs the posted task only when we're idle.  Returns true if tha task is
92  // scheduled.
93  bool ScheduleTaskIfIdle(const tracked_objects::Location& from_here,
94                          const Task& task,
95                          const SyncStatusCallback& callback);
96  bool ScheduleSyncTaskIfIdle(const tracked_objects::Location& from_here,
97                              scoped_ptr<SyncTask> task,
98                              const SyncStatusCallback& callback);
99
100  // Notifies SyncTaskManager that the task associated to |token| has finished
101  // with |status|.
102  static void NotifyTaskDone(scoped_ptr<SyncTaskToken> token,
103                             SyncStatusCode status);
104
105  // Updates |task_blocker| associated to the current task by specified
106  // |task_blocker| and turns the current task to a background task if
107  // the current task is running as a foreground task.
108  // If specified |task_blocker| is blocked by any other blocking factor
109  // associated to an existing background task, this function waits for the
110  // existing background task to finish.
111  // Upon the task is ready to run as a background task, calls |continuation|
112  // with new SyncTaskToken.
113  // Note that this function once releases previous |task_blocker| before
114  // applying new |task_blocker|.  So, any other task may be run before
115  // invocation of |continuation|.
116  static void UpdateTaskBlocker(scoped_ptr<SyncTaskToken> current_task_token,
117                                scoped_ptr<TaskBlocker> task_blocker,
118                                const Continuation& continuation);
119
120  bool IsRunningTask(int64 task_token_id) const;
121
122  void DetachFromSequence();
123
124 private:
125  struct PendingTask {
126    base::Closure task;
127    Priority priority;
128    int64 seq;
129
130    PendingTask();
131    PendingTask(const base::Closure& task, Priority pri, int seq);
132    ~PendingTask();
133  };
134
135  struct PendingTaskComparator {
136    bool operator()(const PendingTask& left,
137                    const PendingTask& right) const;
138  };
139
140  // Non-static version of NotifyTaskDone.
141  void NotifyTaskDoneBody(scoped_ptr<SyncTaskToken> token,
142                          SyncStatusCode status);
143
144  // Non-static version of UpdateTaskBlocker.
145  void UpdateTaskBlockerBody(scoped_ptr<SyncTaskToken> foreground_task_token,
146                             scoped_ptr<SyncTaskToken> background_task_token,
147                             scoped_ptr<TaskLogger::TaskLog> task_log,
148                             scoped_ptr<TaskBlocker> task_blocker,
149                             const Continuation& continuation);
150
151  // This should be called when an async task needs to get a task token.
152  scoped_ptr<SyncTaskToken> GetToken(const tracked_objects::Location& from_here,
153                                     const SyncStatusCallback& callback);
154
155  scoped_ptr<SyncTaskToken> GetTokenForBackgroundTask(
156      const tracked_objects::Location& from_here,
157      const SyncStatusCallback& callback,
158      scoped_ptr<TaskBlocker> task_blocker);
159
160  void PushPendingTask(const base::Closure& closure, Priority priority);
161
162  void RunTask(scoped_ptr<SyncTaskToken> token,
163               scoped_ptr<SyncTask> task);
164
165  // Runs a pending task as a foreground task if possible.
166  // If |token| is non-NULL, put |token| back to |token_| beforehand.
167  void MaybeStartNextForegroundTask(scoped_ptr<SyncTaskToken> token);
168
169  base::WeakPtr<Client> client_;
170
171  // Owns running SyncTask to cancel the task on SyncTaskManager deletion.
172  scoped_ptr<SyncTask> running_foreground_task_;
173
174  // Owns running backgrounded SyncTask to cancel the task on SyncTaskManager
175  // deletion.
176  base::ScopedPtrHashMap<int64, SyncTask> running_background_tasks_;
177
178  size_t maximum_background_task_;
179
180  // Holds pending continuation to move task to background.
181  base::Closure pending_backgrounding_task_;
182
183  std::priority_queue<PendingTask, std::vector<PendingTask>,
184                      PendingTaskComparator> pending_tasks_;
185  int64 pending_task_seq_;
186  int64 task_token_seq_;
187
188  // Absence of |token_| implies a task is running. Incoming tasks should
189  // wait for the task to finish in |pending_tasks_| if |token_| is null.
190  // Each task must take TaskToken instance from |token_| and must hold it
191  // until it finished. And the task must return the instance through
192  // NotifyTaskDone when the task finished.
193  scoped_ptr<SyncTaskToken> token_;
194
195  TaskDependencyManager dependency_manager_;
196
197  scoped_refptr<base::SequencedTaskRunner> task_runner_;
198  base::SequenceChecker sequence_checker_;
199
200  DISALLOW_COPY_AND_ASSIGN(SyncTaskManager);
201};
202
203}  // namespace drive_backend
204}  // namespace sync_file_system
205
206#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_SYNC_TASK_MANAGER_H_
207