Home | History | Annotate | Download | only in drive_backend
      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