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