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