Home | History | Annotate | Download | only in drive
      1 // Copyright (c) 2012 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_CHROMEOS_DRIVE_JOB_SCHEDULER_H_
      6 #define CHROME_BROWSER_CHROMEOS_DRIVE_JOB_SCHEDULER_H_
      7 
      8 #include <vector>
      9 
     10 #include "base/id_map.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/observer_list.h"
     13 #include "chrome/browser/chromeos/drive/file_system_interface.h"
     14 #include "chrome/browser/chromeos/drive/job_list.h"
     15 #include "chrome/browser/chromeos/drive/job_queue.h"
     16 #include "chrome/browser/drive/drive_service_interface.h"
     17 #include "chrome/browser/drive/drive_uploader.h"
     18 #include "net/base/network_change_notifier.h"
     19 
     20 class PrefService;
     21 
     22 namespace base {
     23 class SeqencedTaskRunner;
     24 }
     25 
     26 namespace drive {
     27 
     28 // The JobScheduler is responsible for queuing and scheduling drive
     29 // jobs.
     30 //
     31 // All jobs are processed in order of priority.
     32 //   - Jobs that occur as a result of a direct user action are handled
     33 //     immediately (i.e. the client context is USER_INITIATED).
     34 //   - Jobs that are done in response to state changes or server actions are run
     35 //     in the background (i.e. the client context is BACKGROUND).
     36 //
     37 // All jobs are retried a maximum of kMaxRetryCount when they fail due to
     38 // throttling or server error.  The delay before retrying a job is shared
     39 // between jobs.  It doubles in length on each failure, up to 16 seconds.
     40 //
     41 // Jobs are grouped into two types:
     42 //   - File jobs are any job that transfer the contents of files.
     43 //     By default, they are only run when connected to WiFi.
     44 //   - Metadata jobs are any jobs that operate on File metadata or
     45 //     the directory structure.  Up to kMaxJobCount[METADATA_QUEUE] jobs are run
     46 //     concurrently.
     47 //
     48 // Because jobs are executed by priority and the potential for network failures,
     49 // there is no guarantee of ordering of operations.
     50 class JobScheduler
     51     : public net::NetworkChangeNotifier::ConnectionTypeObserver,
     52       public JobListInterface {
     53  public:
     54   JobScheduler(PrefService* pref_service,
     55                DriveServiceInterface* drive_service,
     56                base::SequencedTaskRunner* blocking_task_runner);
     57   virtual ~JobScheduler();
     58 
     59   // JobListInterface overrides.
     60   virtual std::vector<JobInfo> GetJobInfoList() OVERRIDE;
     61   virtual void AddObserver(JobListObserver* observer) OVERRIDE;
     62   virtual void RemoveObserver(JobListObserver* observer) OVERRIDE;
     63   virtual void CancelJob(JobID job_id) OVERRIDE;
     64   virtual void CancelAllJobs() OVERRIDE;
     65 
     66   // Adds a GetAppList operation to the queue.
     67   // |callback| must not be null.
     68   void GetAppList(const google_apis::GetAppListCallback& callback);
     69 
     70   // Adds a GetAboutResource operation to the queue.
     71   // |callback| must not be null.
     72   void GetAboutResource(const google_apis::GetAboutResourceCallback& callback);
     73 
     74   // Adds a GetAllResourceList operation to the queue.
     75   // |callback| must not be null.
     76   void GetAllResourceList(const google_apis::GetResourceListCallback& callback);
     77 
     78   // Adds a GetResourceListInDirectory operation to the queue.
     79   // |callback| must not be null.
     80   void GetResourceListInDirectory(
     81       const std::string& directory_resource_id,
     82       const google_apis::GetResourceListCallback& callback);
     83 
     84   // Adds a Search operation to the queue.
     85   // |callback| must not be null.
     86   void Search(const std::string& search_query,
     87               const google_apis::GetResourceListCallback& callback);
     88 
     89   // Adds a GetChangeList operation to the queue.
     90   // |callback| must not be null.
     91   void GetChangeList(int64 start_changestamp,
     92                      const google_apis::GetResourceListCallback& callback);
     93 
     94   // Adds ContinueGetResourceList operation to the queue.
     95   // |callback| must not be null.
     96   void ContinueGetResourceList(
     97       const GURL& next_url,
     98       const google_apis::GetResourceListCallback& callback);
     99 
    100   // Adds a GetResourceEntry operation to the queue.
    101   void GetResourceEntry(const std::string& resource_id,
    102                         const ClientContext& context,
    103                         const google_apis::GetResourceEntryCallback& callback);
    104 
    105   // Adds a GetShareUrl operation to the queue.
    106   void GetShareUrl(const std::string& resource_id,
    107                    const GURL& embed_origin,
    108                    const ClientContext& context,
    109                    const google_apis::GetShareUrlCallback& callback);
    110 
    111   // Adds a DeleteResource operation to the queue.
    112   void DeleteResource(const std::string& resource_id,
    113                       const google_apis::EntryActionCallback& callback);
    114 
    115   // Adds a CopyResource operation to the queue.
    116   void CopyResource(
    117       const std::string& resource_id,
    118       const std::string& parent_resource_id,
    119       const std::string& new_title,
    120       const google_apis::GetResourceEntryCallback& callback);
    121 
    122   // Adds a CopyHostedDocument operation to the queue.
    123   void CopyHostedDocument(
    124       const std::string& resource_id,
    125       const std::string& new_title,
    126       const google_apis::GetResourceEntryCallback& callback);
    127 
    128   // Adds a RenameResource operation to the queue.
    129   void RenameResource(const std::string& resource_id,
    130                       const std::string& new_title,
    131                       const google_apis::EntryActionCallback& callback);
    132 
    133   // Adds a TouchResource operation to the queue.
    134   void TouchResource(const std::string& resource_id,
    135                      const base::Time& modified_date,
    136                      const base::Time& last_viewed_by_me_date,
    137                      const google_apis::GetResourceEntryCallback& callback);
    138 
    139   // Adds a AddResourceToDirectory operation to the queue.
    140   void AddResourceToDirectory(const std::string& parent_resource_id,
    141                               const std::string& resource_id,
    142                               const google_apis::EntryActionCallback& callback);
    143 
    144   // Adds a RemoveResourceFromDirectory operation to the queue.
    145   void RemoveResourceFromDirectory(
    146       const std::string& parent_resource_id,
    147       const std::string& resource_id,
    148       const google_apis::EntryActionCallback& callback);
    149 
    150   // Adds a AddNewDirectory operation to the queue.
    151   void AddNewDirectory(const std::string& parent_resource_id,
    152                        const std::string& directory_title,
    153                        const google_apis::GetResourceEntryCallback& callback);
    154 
    155   // Adds a DownloadFile operation to the queue.
    156   JobID DownloadFile(
    157       const base::FilePath& virtual_path,
    158       const base::FilePath& local_cache_path,
    159       const std::string& resource_id,
    160       const ClientContext& context,
    161       const google_apis::DownloadActionCallback& download_action_callback,
    162       const google_apis::GetContentCallback& get_content_callback);
    163 
    164   // Adds an UploadNewFile operation to the queue.
    165   void UploadNewFile(const std::string& parent_resource_id,
    166                      const base::FilePath& drive_file_path,
    167                      const base::FilePath& local_file_path,
    168                      const std::string& title,
    169                      const std::string& content_type,
    170                      const ClientContext& context,
    171                      const google_apis::GetResourceEntryCallback& callback);
    172 
    173   // Adds an UploadExistingFile operation to the queue.
    174   void UploadExistingFile(
    175       const std::string& resource_id,
    176       const base::FilePath& drive_file_path,
    177       const base::FilePath& local_file_path,
    178       const std::string& content_type,
    179       const std::string& etag,
    180       const ClientContext& context,
    181       const google_apis::GetResourceEntryCallback& callback);
    182 
    183   // Adds a CreateFile operation to the queue.
    184   void CreateFile(const std::string& parent_resource_id,
    185                   const base::FilePath& drive_file_path,
    186                   const std::string& title,
    187                   const std::string& content_type,
    188                   const ClientContext& context,
    189                   const google_apis::GetResourceEntryCallback& callback);
    190 
    191  private:
    192   friend class JobSchedulerTest;
    193 
    194   enum QueueType {
    195     METADATA_QUEUE,
    196     FILE_QUEUE,
    197     NUM_QUEUES
    198   };
    199 
    200   static const int kMaxJobCount[NUM_QUEUES];
    201 
    202   // Represents a single entry in the job map.
    203   struct JobEntry {
    204     explicit JobEntry(JobType type);
    205     ~JobEntry();
    206 
    207     // General user-visible information on the job.
    208     JobInfo job_info;
    209 
    210     // Context of the job.
    211     ClientContext context;
    212 
    213     // The number of times the jobs is retried due to server errors.
    214     int retry_count;
    215 
    216     // The callback to start the job. Called each time it is retry.
    217     base::Callback<google_apis::CancelCallback()> task;
    218 
    219     // The callback to cancel the running job. It is returned from task.Run().
    220     google_apis::CancelCallback cancel_callback;
    221 
    222     // The callback to notify an error to the client of JobScheduler.
    223     // This is used to notify cancel of a job that is not running yet.
    224     base::Callback<void(google_apis::GDataErrorCode)> abort_callback;
    225   };
    226 
    227   // Parameters for DriveUploader::ResumeUploadFile.
    228   struct ResumeUploadParams;
    229 
    230   // Creates a new job and add it to the job map.
    231   JobEntry* CreateNewJob(JobType type);
    232 
    233   // Adds the specified job to the queue and starts the job loop for the queue
    234   // if needed.
    235   void StartJob(JobEntry* job);
    236 
    237   // Adds the specified job to the queue.
    238   void QueueJob(JobID job_id);
    239 
    240   // Determines the next job that should run, and starts it.
    241   void DoJobLoop(QueueType queue_type);
    242 
    243   // Returns the lowest acceptable priority level of the operations that is
    244   // currently allowed to start for the |queue_type|.
    245   int GetCurrentAcceptedPriority(QueueType queue_type);
    246 
    247   // Updates |wait_until_| to throttle requests.
    248   void UpdateWait();
    249 
    250   // Retries the job if needed and returns false. Otherwise returns true.
    251   bool OnJobDone(JobID job_id, google_apis::GDataErrorCode error);
    252 
    253   // Callback for job finishing with a GetResourceListCallback.
    254   void OnGetResourceListJobDone(
    255       JobID job_id,
    256       const google_apis::GetResourceListCallback& callback,
    257       google_apis::GDataErrorCode error,
    258       scoped_ptr<google_apis::ResourceList> resource_list);
    259 
    260   // Callback for job finishing with a GetResourceEntryCallback.
    261   void OnGetResourceEntryJobDone(
    262       JobID job_id,
    263       const google_apis::GetResourceEntryCallback& callback,
    264       google_apis::GDataErrorCode error,
    265       scoped_ptr<google_apis::ResourceEntry> entry);
    266 
    267   // Callback for job finishing with a GetAboutResourceCallback.
    268   void OnGetAboutResourceJobDone(
    269       JobID job_id,
    270       const google_apis::GetAboutResourceCallback& callback,
    271       google_apis::GDataErrorCode error,
    272       scoped_ptr<google_apis::AboutResource> about_resource);
    273 
    274   // Callback for job finishing with a GetShareUrlCallback.
    275   void OnGetShareUrlJobDone(
    276       JobID job_id,
    277       const google_apis::GetShareUrlCallback& callback,
    278       google_apis::GDataErrorCode error,
    279       const GURL& share_url);
    280 
    281   // Callback for job finishing with a GetAppListCallback.
    282   void OnGetAppListJobDone(
    283       JobID job_id,
    284       const google_apis::GetAppListCallback& callback,
    285       google_apis::GDataErrorCode error,
    286       scoped_ptr<google_apis::AppList> app_list);
    287 
    288   // Callback for job finishing with a EntryActionCallback.
    289   void OnEntryActionJobDone(JobID job_id,
    290                             const google_apis::EntryActionCallback& callback,
    291                             google_apis::GDataErrorCode error);
    292 
    293   // Callback for job finishing with a DownloadActionCallback.
    294   void OnDownloadActionJobDone(
    295       JobID job_id,
    296       const google_apis::DownloadActionCallback& callback,
    297       google_apis::GDataErrorCode error,
    298       const base::FilePath& temp_file);
    299 
    300   // Callback for job finishing with a UploadCompletionCallback.
    301   void OnUploadCompletionJobDone(
    302       JobID job_id,
    303       const ResumeUploadParams& resume_params,
    304       const google_apis::GetResourceEntryCallback& callback,
    305       google_apis::GDataErrorCode error,
    306       const GURL& upload_location,
    307       scoped_ptr<google_apis::ResourceEntry> resource_entry);
    308 
    309   // Callback for DriveUploader::ResumeUploadFile().
    310   void OnResumeUploadFileDone(
    311       JobID job_id,
    312       const base::Callback<google_apis::CancelCallback()>& original_task,
    313       const google_apis::GetResourceEntryCallback& callback,
    314       google_apis::GDataErrorCode error,
    315       const GURL& upload_location,
    316       scoped_ptr<google_apis::ResourceEntry> resource_entry);
    317 
    318   // Updates the progress status of the specified job.
    319   void UpdateProgress(JobID job_id, int64 progress, int64 total);
    320 
    321   // net::NetworkChangeNotifier::ConnectionTypeObserver override.
    322   virtual void OnConnectionTypeChanged(
    323       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
    324 
    325   // Get the type of queue the specified job should be put in.
    326   QueueType GetJobQueueType(JobType type);
    327 
    328   // For testing only.  Disables throttling so that testing is faster.
    329   void SetDisableThrottling(bool disable) { disable_throttling_ = disable; }
    330 
    331   // Aborts a job which is not in STATE_RUNNING.
    332   void AbortNotRunningJob(JobEntry* job, google_apis::GDataErrorCode error);
    333 
    334   // Notifies updates to observers.
    335   void NotifyJobAdded(const JobInfo& job_info);
    336   void NotifyJobDone(const JobInfo& job_info,
    337                      google_apis::GDataErrorCode error);
    338   void NotifyJobUpdated(const JobInfo& job_info);
    339 
    340   // Gets information of the queue of the given type as string.
    341   std::string GetQueueInfo(QueueType type) const;
    342 
    343   // Returns a string representation of QueueType.
    344   static std::string QueueTypeToString(QueueType type);
    345 
    346   // The number of times operations have failed in a row, capped at
    347   // kMaxThrottleCount.  This is used to calculate the delay before running the
    348   // next task.
    349   int throttle_count_;
    350 
    351   // Jobs should not start running until this time. Used for throttling.
    352   base::Time wait_until_;
    353 
    354   // Disables throttling for testing.
    355   bool disable_throttling_;
    356 
    357   // The queues of jobs.
    358   scoped_ptr<JobQueue> queue_[NUM_QUEUES];
    359 
    360   // The list of queued job info indexed by job IDs.
    361   typedef IDMap<JobEntry, IDMapOwnPointer> JobIDMap;
    362   JobIDMap job_map_;
    363 
    364   // The list of observers for the scheduler.
    365   ObserverList<JobListObserver> observer_list_;
    366 
    367   DriveServiceInterface* drive_service_;
    368   scoped_ptr<DriveUploaderInterface> uploader_;
    369 
    370   PrefService* pref_service_;
    371 
    372   // Note: This should remain the last member so it'll be destroyed and
    373   // invalidate its weak pointers before any other members are destroyed.
    374   base::WeakPtrFactory<JobScheduler> weak_ptr_factory_;
    375   DISALLOW_COPY_AND_ASSIGN(JobScheduler);
    376 };
    377 
    378 }  // namespace drive
    379 
    380 #endif  // CHROME_BROWSER_CHROMEOS_DRIVE_JOB_SCHEDULER_H_
    381