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 21 namespace base { 22 class SequencedTaskRunner; 23 } 24 25 namespace tracked_objects { 26 class Location; 27 } 28 29 namespace sync_file_system { 30 namespace drive_backend { 31 32 class SyncTask; 33 class SyncTaskToken; 34 struct 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. 43 class 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