blob: acd51ae0dd89df5db1de08265bdbc2a3fb5b4c35 [file] [log] [blame]
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001// 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
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01008#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"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010015#include "chrome/browser/chromeos/drive/job_queue.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010016#include "chrome/browser/drive/drive_service_interface.h"
17#include "chrome/browser/drive/drive_uploader.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010018#include "net/base/network_change_notifier.h"
19
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010020class PrefService;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010021
Ben Murdocheb525c52013-07-10 11:40:50 +010022namespace base {
23class SeqencedTaskRunner;
24}
25
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010026namespace drive {
27
28// The JobScheduler is responsible for queuing and scheduling drive
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010029// 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.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010050class JobScheduler
51 : public net::NetworkChangeNotifier::ConnectionTypeObserver,
52 public JobListInterface {
53 public:
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010054 JobScheduler(PrefService* pref_service,
Ben Murdocheb525c52013-07-10 11:40:50 +010055 DriveServiceInterface* drive_service,
56 base::SequencedTaskRunner* blocking_task_runner);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010057 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
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010066 // 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(
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010097 const GURL& next_url,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010098 const google_apis::GetResourceListCallback& callback);
99
100 // Adds a GetResourceEntry operation to the queue.
101 void GetResourceEntry(const std::string& resource_id,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100102 const ClientContext& context,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100103 const google_apis::GetResourceEntryCallback& callback);
104
Ben Murdochbbcdd452013-07-25 10:06:34 +0100105 // 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);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100110
111 // Adds a DeleteResource operation to the queue.
112 void DeleteResource(const std::string& resource_id,
113 const google_apis::EntryActionCallback& callback);
114
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100115 // Adds a CopyResource operation to the queue.
116 void CopyResource(
117 const std::string& resource_id,
118 const std::string& parent_resource_id,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100119 const std::string& new_title,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100120 const google_apis::GetResourceEntryCallback& callback);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100121
122 // Adds a CopyHostedDocument operation to the queue.
123 void CopyHostedDocument(
124 const std::string& resource_id,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100125 const std::string& new_title,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100126 const google_apis::GetResourceEntryCallback& callback);
127
128 // Adds a RenameResource operation to the queue.
129 void RenameResource(const std::string& resource_id,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100130 const std::string& new_title,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100131 const google_apis::EntryActionCallback& callback);
132
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100133 // 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
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100139 // 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,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100152 const std::string& directory_title,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100153 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,
Ben Murdocheb525c52013-07-10 11:40:50 +0100159 const std::string& resource_id,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100160 const ClientContext& context,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100161 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,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100170 const ClientContext& context,
171 const google_apis::GetResourceEntryCallback& callback);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100172
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,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100180 const ClientContext& context,
181 const google_apis::GetResourceEntryCallback& callback);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100182
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,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100188 const ClientContext& context,
189 const google_apis::GetResourceEntryCallback& callback);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100190
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
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100202 // Represents a single entry in the job map.
203 struct JobEntry {
204 explicit JobEntry(JobType type);
205 ~JobEntry();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100206
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100207 // General user-visible information on the job.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100208 JobInfo job_info;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100209
210 // Context of the job.
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100211 ClientContext context;
212
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100213 // The number of times the jobs is retried due to server errors.
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100214 int retry_count;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100215
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100216 // 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;
Ben Murdocheb525c52013-07-10 11:40:50 +0100221
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;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100225 };
226
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100227 // Parameters for DriveUploader::ResumeUploadFile.
228 struct ResumeUploadParams;
229
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100230 // Creates a new job and add it to the job map.
231 JobEntry* CreateNewJob(JobType type);
232
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100233 // Adds the specified job to the queue and starts the job loop for the queue
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100234 // if needed.
235 void StartJob(JobEntry* job);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100236
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100237 // Adds the specified job to the queue.
238 void QueueJob(JobID job_id);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100239
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100240 // Determines the next job that should run, and starts it.
241 void DoJobLoop(QueueType queue_type);
242
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100243 // 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);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100246
Ben Murdochbb1529c2013-08-08 10:24:53 +0100247 // Updates |wait_until_| to throttle requests.
248 void UpdateWait();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100249
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100250 // Retries the job if needed and returns false. Otherwise returns true.
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100251 bool OnJobDone(JobID job_id, google_apis::GDataErrorCode error);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100252
253 // Callback for job finishing with a GetResourceListCallback.
254 void OnGetResourceListJobDone(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100255 JobID job_id,
256 const google_apis::GetResourceListCallback& callback,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100257 google_apis::GDataErrorCode error,
258 scoped_ptr<google_apis::ResourceList> resource_list);
259
260 // Callback for job finishing with a GetResourceEntryCallback.
261 void OnGetResourceEntryJobDone(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100262 JobID job_id,
263 const google_apis::GetResourceEntryCallback& callback,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100264 google_apis::GDataErrorCode error,
265 scoped_ptr<google_apis::ResourceEntry> entry);
266
267 // Callback for job finishing with a GetAboutResourceCallback.
268 void OnGetAboutResourceJobDone(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100269 JobID job_id,
270 const google_apis::GetAboutResourceCallback& callback,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100271 google_apis::GDataErrorCode error,
272 scoped_ptr<google_apis::AboutResource> about_resource);
273
Ben Murdochbbcdd452013-07-25 10:06:34 +0100274 // 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
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100281 // Callback for job finishing with a GetAppListCallback.
282 void OnGetAppListJobDone(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100283 JobID job_id,
284 const google_apis::GetAppListCallback& callback,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100285 google_apis::GDataErrorCode error,
286 scoped_ptr<google_apis::AppList> app_list);
287
288 // Callback for job finishing with a EntryActionCallback.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100289 void OnEntryActionJobDone(JobID job_id,
290 const google_apis::EntryActionCallback& callback,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100291 google_apis::GDataErrorCode error);
292
293 // Callback for job finishing with a DownloadActionCallback.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100294 void OnDownloadActionJobDone(
295 JobID job_id,
296 const google_apis::DownloadActionCallback& callback,
297 google_apis::GDataErrorCode error,
298 const base::FilePath& temp_file);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100299
300 // Callback for job finishing with a UploadCompletionCallback.
301 void OnUploadCompletionJobDone(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100302 JobID job_id,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100303 const ResumeUploadParams& resume_params,
304 const google_apis::GetResourceEntryCallback& callback,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100305 google_apis::GDataErrorCode error,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100306 const GURL& upload_location,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100307 scoped_ptr<google_apis::ResourceEntry> resource_entry);
308
Ben Murdoch32409262013-08-07 11:04:47 +0100309 // 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
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100318 // 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
Ben Murdocheb525c52013-07-10 11:40:50 +0100331 // Aborts a job which is not in STATE_RUNNING.
332 void AbortNotRunningJob(JobEntry* job, google_apis::GDataErrorCode error);
333
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100334 // Notifies updates to observers.
335 void NotifyJobAdded(const JobInfo& job_info);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100336 void NotifyJobDone(const JobInfo& job_info,
337 google_apis::GDataErrorCode error);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100338 void NotifyJobUpdated(const JobInfo& job_info);
339
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100340 // 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
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100346 // 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
Ben Murdochbb1529c2013-08-08 10:24:53 +0100351 // Jobs should not start running until this time. Used for throttling.
352 base::Time wait_until_;
353
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100354 // Disables throttling for testing.
355 bool disable_throttling_;
356
357 // The queues of jobs.
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100358 scoped_ptr<JobQueue> queue_[NUM_QUEUES];
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100359
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100360 // The list of queued job info indexed by job IDs.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100361 typedef IDMap<JobEntry, IDMapOwnPointer> JobIDMap;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100362 JobIDMap job_map_;
363
364 // The list of observers for the scheduler.
365 ObserverList<JobListObserver> observer_list_;
366
Ben Murdocheb525c52013-07-10 11:40:50 +0100367 DriveServiceInterface* drive_service_;
368 scoped_ptr<DriveUploaderInterface> uploader_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100369
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100370 PrefService* pref_service_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100371
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_