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