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