| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_SYNC_TASK_MANAGER_H_ |
| #define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_SYNC_TASK_MANAGER_H_ |
| |
| #include <queue> |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/containers/scoped_ptr_hash_map.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/sequence_checker.h" |
| #include "chrome/browser/sync_file_system/drive_backend/task_dependency_manager.h" |
| #include "chrome/browser/sync_file_system/sync_callbacks.h" |
| #include "chrome/browser/sync_file_system/sync_status_code.h" |
| #include "chrome/browser/sync_file_system/task_logger.h" |
| |
| namespace base { |
| class SequencedTaskRunner; |
| } |
| |
| namespace tracked_objects { |
| class Location; |
| } |
| |
| namespace sync_file_system { |
| namespace drive_backend { |
| |
| class SyncTask; |
| class SyncTaskToken; |
| struct TaskBlocker; |
| |
| // This class manages asynchronous tasks for Sync FileSystem. Each task must be |
| // either a Task or a SyncTask. |
| // The instance runs single task as the foreground task, and multiple tasks as |
| // background tasks. Running background task has a TaskBlocker that |
| // describes which task can run in parallel. When a task start running as a |
| // background task, SyncTaskManager checks if any running background task |
| // doesn't block the new background task, and queues it up if it can't run. |
| class SyncTaskManager { |
| public: |
| typedef base::Callback<void(const SyncStatusCallback& callback)> Task; |
| typedef base::Callback<void(scoped_ptr<SyncTaskToken> token)> Continuation; |
| |
| enum Priority { |
| PRIORITY_LOW, |
| PRIORITY_MED, |
| PRIORITY_HIGH, |
| }; |
| |
| class Client { |
| public: |
| virtual ~Client() {} |
| |
| // Called when the manager is idle. |
| virtual void MaybeScheduleNextTask() = 0; |
| |
| // Called when the manager is notified a task is done. |
| virtual void NotifyLastOperationStatus( |
| SyncStatusCode last_operation_status, |
| bool last_operation_used_network) = 0; |
| |
| virtual void RecordTaskLog(scoped_ptr<TaskLogger::TaskLog> task_log) = 0; |
| }; |
| |
| // Runs at most |maximum_background_tasks| parallel as background tasks. |
| // If |maximum_background_tasks| is zero, all task runs as foreground task. |
| SyncTaskManager(base::WeakPtr<Client> client, |
| size_t maximum_background_task, |
| const scoped_refptr<base::SequencedTaskRunner>& task_runner); |
| virtual ~SyncTaskManager(); |
| |
| // This needs to be called to start task scheduling. |
| // If |status| is not SYNC_STATUS_OK calling this may change the |
| // service status. This should not be called more than once. |
| void Initialize(SyncStatusCode status); |
| |
| // Schedules a task at the given priority. |
| void ScheduleTask(const tracked_objects::Location& from_here, |
| const Task& task, |
| Priority priority, |
| const SyncStatusCallback& callback); |
| void ScheduleSyncTask(const tracked_objects::Location& from_here, |
| scoped_ptr<SyncTask> task, |
| Priority priority, |
| const SyncStatusCallback& callback); |
| |
| // Runs the posted task only when we're idle. Returns true if tha task is |
| // scheduled. |
| bool ScheduleTaskIfIdle(const tracked_objects::Location& from_here, |
| const Task& task, |
| const SyncStatusCallback& callback); |
| bool ScheduleSyncTaskIfIdle(const tracked_objects::Location& from_here, |
| scoped_ptr<SyncTask> task, |
| const SyncStatusCallback& callback); |
| |
| // Notifies SyncTaskManager that the task associated to |token| has finished |
| // with |status|. |
| static void NotifyTaskDone(scoped_ptr<SyncTaskToken> token, |
| SyncStatusCode status); |
| |
| // Updates |task_blocker| associated to the current task by specified |
| // |task_blocker| and turns the current task to a background task if |
| // the current task is running as a foreground task. |
| // If specified |task_blocker| is blocked by any other blocking factor |
| // associated to an existing background task, this function waits for the |
| // existing background task to finish. |
| // Upon the task is ready to run as a background task, calls |continuation| |
| // with new SyncTaskToken. |
| // Note that this function once releases previous |task_blocker| before |
| // applying new |task_blocker|. So, any other task may be run before |
| // invocation of |continuation|. |
| static void UpdateTaskBlocker(scoped_ptr<SyncTaskToken> current_task_token, |
| scoped_ptr<TaskBlocker> task_blocker, |
| const Continuation& continuation); |
| |
| bool IsRunningTask(int64 task_token_id) const; |
| |
| void DetachFromSequence(); |
| |
| private: |
| struct PendingTask { |
| base::Closure task; |
| Priority priority; |
| int64 seq; |
| |
| PendingTask(); |
| PendingTask(const base::Closure& task, Priority pri, int seq); |
| ~PendingTask(); |
| }; |
| |
| struct PendingTaskComparator { |
| bool operator()(const PendingTask& left, |
| const PendingTask& right) const; |
| }; |
| |
| // Non-static version of NotifyTaskDone. |
| void NotifyTaskDoneBody(scoped_ptr<SyncTaskToken> token, |
| SyncStatusCode status); |
| |
| // Non-static version of UpdateTaskBlocker. |
| void UpdateTaskBlockerBody(scoped_ptr<SyncTaskToken> foreground_task_token, |
| scoped_ptr<SyncTaskToken> background_task_token, |
| scoped_ptr<TaskLogger::TaskLog> task_log, |
| scoped_ptr<TaskBlocker> task_blocker, |
| const Continuation& continuation); |
| |
| // This should be called when an async task needs to get a task token. |
| scoped_ptr<SyncTaskToken> GetToken(const tracked_objects::Location& from_here, |
| const SyncStatusCallback& callback); |
| |
| scoped_ptr<SyncTaskToken> GetTokenForBackgroundTask( |
| const tracked_objects::Location& from_here, |
| const SyncStatusCallback& callback, |
| scoped_ptr<TaskBlocker> task_blocker); |
| |
| void PushPendingTask(const base::Closure& closure, Priority priority); |
| |
| void RunTask(scoped_ptr<SyncTaskToken> token, |
| scoped_ptr<SyncTask> task); |
| |
| // Runs a pending task as a foreground task if possible. |
| // If |token| is non-nullptr, put |token| back to |token_| beforehand. |
| void MaybeStartNextForegroundTask(scoped_ptr<SyncTaskToken> token); |
| |
| base::WeakPtr<Client> client_; |
| |
| // Owns running SyncTask to cancel the task on SyncTaskManager deletion. |
| scoped_ptr<SyncTask> running_foreground_task_; |
| |
| // Owns running backgrounded SyncTask to cancel the task on SyncTaskManager |
| // deletion. |
| base::ScopedPtrHashMap<int64, SyncTask> running_background_tasks_; |
| |
| size_t maximum_background_task_; |
| |
| // Holds pending continuation to move task to background. |
| base::Closure pending_backgrounding_task_; |
| |
| std::priority_queue<PendingTask, std::vector<PendingTask>, |
| PendingTaskComparator> pending_tasks_; |
| int64 pending_task_seq_; |
| int64 task_token_seq_; |
| |
| // Absence of |token_| implies a task is running. Incoming tasks should |
| // wait for the task to finish in |pending_tasks_| if |token_| is null. |
| // Each task must take TaskToken instance from |token_| and must hold it |
| // until it finished. And the task must return the instance through |
| // NotifyTaskDone when the task finished. |
| scoped_ptr<SyncTaskToken> token_; |
| |
| TaskDependencyManager dependency_manager_; |
| |
| scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| base::SequenceChecker sequence_checker_; |
| |
| base::WeakPtrFactory<SyncTaskManager> weak_ptr_factory_;; |
| |
| DISALLOW_COPY_AND_ASSIGN(SyncTaskManager); |
| }; |
| |
| } // namespace drive_backend |
| } // namespace sync_file_system |
| |
| #endif // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_SYNC_TASK_MANAGER_H_ |