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 "base/threading/non_thread_safe.h" 17 #include "chrome/browser/sync_file_system/drive_backend/task_dependency_manager.h" 18 #include "chrome/browser/sync_file_system/sync_callbacks.h" 19 #include "chrome/browser/sync_file_system/sync_status_code.h" 20 #include "chrome/browser/sync_file_system/task_logger.h" 21 22 namespace base { 23 class SequencedTaskRunner; 24 } 25 26 namespace tracked_objects { 27 class Location; 28 } 29 30 namespace sync_file_system { 31 namespace drive_backend { 32 33 class SyncTask; 34 class SyncTaskToken; 35 struct BlockingFactor; 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 BlockingFactor 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 base::NonThreadSafe, 46 public base::SupportsWeakPtr<SyncTaskManager> { 47 public: 48 typedef base::Callback<void(const SyncStatusCallback& callback)> Task; 49 typedef base::Callback<void(scoped_ptr<SyncTaskToken> token)> Continuation; 50 51 enum Priority { 52 PRIORITY_LOW, 53 PRIORITY_MED, 54 PRIORITY_HIGH, 55 }; 56 57 class Client { 58 public: 59 virtual ~Client() {} 60 61 // Called when the manager is idle. 62 virtual void MaybeScheduleNextTask() = 0; 63 64 // Called when the manager is notified a task is done. 65 virtual void NotifyLastOperationStatus( 66 SyncStatusCode last_operation_status, 67 bool last_operation_used_network) = 0; 68 69 virtual void RecordTaskLog(scoped_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 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 tracked_objects::Location& from_here, 86 const Task& task, 87 Priority priority, 88 const SyncStatusCallback& callback); 89 void ScheduleSyncTask(const tracked_objects::Location& from_here, 90 scoped_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 tracked_objects::Location& from_here, 97 const Task& task, 98 const SyncStatusCallback& callback); 99 bool ScheduleSyncTaskIfIdle(const tracked_objects::Location& from_here, 100 scoped_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(scoped_ptr<SyncTaskToken> token, 106 SyncStatusCode status); 107 108 // Updates |blocking_factor| associated to the current task by specified 109 // |blocking_factor| and turns the current task to a background task if 110 // the current task is running as a foreground task. 111 // If specified |blocking_factor| 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 |blocking_factor| before 117 // applying new |blocking_factor|. So, any other task may be run before 118 // invocation of |continuation|. 119 static void UpdateBlockingFactor(scoped_ptr<SyncTaskToken> current_task_token, 120 scoped_ptr<BlockingFactor> blocking_factor, 121 const Continuation& continuation); 122 123 bool IsRunningTask(int64 task_token_id) const; 124 125 void DetachFromSequence(); 126 127 private: 128 struct PendingTask { 129 base::Closure task; 130 Priority priority; 131 int64 seq; 132 133 PendingTask(); 134 PendingTask(const base::Closure& task, Priority pri, int seq); 135 ~PendingTask(); 136 }; 137 138 struct PendingTaskComparator { 139 bool operator()(const PendingTask& left, 140 const PendingTask& right) const; 141 }; 142 143 // Non-static version of NotifyTaskDone. 144 void NotifyTaskDoneBody(scoped_ptr<SyncTaskToken> token, 145 SyncStatusCode status); 146 147 // Non-static version of UpdateBlockingFactor. 148 void UpdateBlockingFactorBody(scoped_ptr<SyncTaskToken> foreground_task_token, 149 scoped_ptr<SyncTaskToken> background_task_token, 150 scoped_ptr<TaskLogger::TaskLog> task_log, 151 scoped_ptr<BlockingFactor> blocking_factor, 152 const Continuation& continuation); 153 154 // This should be called when an async task needs to get a task token. 155 scoped_ptr<SyncTaskToken> GetToken(const tracked_objects::Location& from_here, 156 const SyncStatusCallback& callback); 157 158 scoped_ptr<SyncTaskToken> GetTokenForBackgroundTask( 159 const tracked_objects::Location& from_here, 160 const SyncStatusCallback& callback, 161 scoped_ptr<BlockingFactor> blocking_factor); 162 163 void PushPendingTask(const base::Closure& closure, Priority priority); 164 165 void RunTask(scoped_ptr<SyncTaskToken> token, 166 scoped_ptr<SyncTask> task); 167 168 // Runs a pending task as a foreground task if possible. 169 // If |token| is non-NULL, put |token| back to |token_| beforehand. 170 void MaybeStartNextForegroundTask(scoped_ptr<SyncTaskToken> token); 171 172 base::WeakPtr<Client> client_; 173 174 // Owns running SyncTask to cancel the task on SyncTaskManager deletion. 175 scoped_ptr<SyncTask> running_foreground_task_; 176 177 // Owns running backgrounded SyncTask to cancel the task on SyncTaskManager 178 // deletion. 179 base::ScopedPtrHashMap<int64, SyncTask> running_background_tasks_; 180 181 size_t maximum_background_task_; 182 183 // Holds pending continuation to move task to background. 184 base::Closure pending_backgrounding_task_; 185 186 std::priority_queue<PendingTask, std::vector<PendingTask>, 187 PendingTaskComparator> pending_tasks_; 188 int64 pending_task_seq_; 189 int64 task_token_seq_; 190 191 // Absence of |token_| implies a task is running. Incoming tasks should 192 // wait for the task to finish in |pending_tasks_| if |token_| is null. 193 // Each task must take TaskToken instance from |token_| and must hold it 194 // until it finished. And the task must return the instance through 195 // NotifyTaskDone when the task finished. 196 scoped_ptr<SyncTaskToken> token_; 197 198 TaskDependencyManager dependency_manager_; 199 200 scoped_refptr<base::SequencedTaskRunner> task_runner_; 201 base::SequenceChecker sequence_checker_; 202 203 DISALLOW_COPY_AND_ASSIGN(SyncTaskManager); 204 }; 205 206 } // namespace drive_backend 207 } // namespace sync_file_system 208 209 #endif // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_SYNC_TASK_MANAGER_H_ 210