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