| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/drive/drive_scheduler.h" | 5 #include "chrome/browser/chromeos/drive/drive_scheduler.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/rand_util.h" | 10 #include "base/rand_util.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 DriveScheduler::JobInfo::JobInfo(JobType in_job_type, FilePath in_file_path) | 26 DriveScheduler::JobInfo::JobInfo(JobType in_job_type, FilePath in_file_path) |
| 27 : job_type(in_job_type), | 27 : job_type(in_job_type), |
| 28 job_id(-1), | 28 job_id(-1), |
| 29 completed_bytes(0), | 29 completed_bytes(0), |
| 30 total_bytes(0), | 30 total_bytes(0), |
| 31 file_path(in_file_path), | 31 file_path(in_file_path), |
| 32 state(STATE_NONE) { | 32 state(STATE_NONE) { |
| 33 } | 33 } |
| 34 | 34 |
| 35 DriveScheduler::QueueEntry::QueueEntry(JobType in_job_type, | 35 DriveScheduler::QueueEntry::QueueEntry(JobType in_job_type, |
| 36 FilePath in_file_path) | 36 FilePath in_file_path, |
| 37 : job_info(TYPE_REMOVE, in_file_path) { | 37 FileOperationCallback in_callback) |
| 38 : job_info(in_job_type, in_file_path), |
| 39 callback(in_callback), |
| 40 is_recursive(false) { |
| 38 } | 41 } |
| 39 | 42 |
| 40 DriveScheduler::QueueEntry::~QueueEntry() { | 43 DriveScheduler::QueueEntry::~QueueEntry() { |
| 41 } | 44 } |
| 42 | 45 |
| 43 DriveScheduler::RemoveJobPrivate::RemoveJobPrivate( | |
| 44 bool in_is_recursive, | |
| 45 FileOperationCallback in_callback) | |
| 46 : is_recursive(in_is_recursive), | |
| 47 callback(in_callback) { | |
| 48 } | |
| 49 | |
| 50 DriveScheduler::RemoveJobPrivate::~RemoveJobPrivate() { | |
| 51 } | |
| 52 | |
| 53 DriveScheduler::DriveScheduler(Profile* profile, | 46 DriveScheduler::DriveScheduler(Profile* profile, |
| 54 file_system::DriveOperations* drive_operations) | 47 file_system::DriveOperations* drive_operations) |
| 55 : job_loop_is_running_(false), | 48 : job_loop_is_running_(false), |
| 56 next_job_id_(0), | 49 next_job_id_(0), |
| 57 throttle_count_(0), | 50 throttle_count_(0), |
| 58 disable_throttling_(false), | 51 disable_throttling_(false), |
| 59 drive_operations_(drive_operations), | 52 drive_operations_(drive_operations), |
| 60 profile_(profile), | 53 profile_(profile), |
| 61 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 54 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
| 62 initialized_(false) { | 55 initialized_(false) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 74 | 67 |
| 75 // Initialize() may be called more than once for the lifetime when the | 68 // Initialize() may be called more than once for the lifetime when the |
| 76 // file system is remounted. | 69 // file system is remounted. |
| 77 if (initialized_) | 70 if (initialized_) |
| 78 return; | 71 return; |
| 79 | 72 |
| 80 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | 73 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| 81 initialized_ = true; | 74 initialized_ = true; |
| 82 } | 75 } |
| 83 | 76 |
| 77 void DriveScheduler::Move(const FilePath& src_file_path, |
| 78 const FilePath& dest_file_path, |
| 79 const FileOperationCallback& callback) { |
| 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 81 |
| 82 scoped_ptr<QueueEntry> new_job( |
| 83 new QueueEntry(TYPE_MOVE, src_file_path, callback)); |
| 84 new_job->dest_file_path = dest_file_path; |
| 85 |
| 86 QueueJob(new_job.Pass()); |
| 87 |
| 88 StartJobLoop(); |
| 89 } |
| 90 |
| 84 void DriveScheduler::Remove(const FilePath& file_path, | 91 void DriveScheduler::Remove(const FilePath& file_path, |
| 85 bool is_recursive, | 92 bool is_recursive, |
| 86 const FileOperationCallback& callback) { | 93 const FileOperationCallback& callback) { |
| 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 88 | 95 |
| 89 QueueEntry* new_job = new QueueEntry(TYPE_REMOVE, file_path); | 96 scoped_ptr<QueueEntry> new_job( |
| 90 new_job->remove_private.reset(new RemoveJobPrivate(is_recursive, callback)); | 97 new QueueEntry(TYPE_REMOVE, file_path, callback)); |
| 98 new_job->is_recursive = is_recursive; |
| 91 | 99 |
| 92 QueueJob(new_job); | 100 QueueJob(new_job.Pass()); |
| 93 | 101 |
| 94 StartJobLoop(); | 102 StartJobLoop(); |
| 95 } | 103 } |
| 96 | 104 |
| 97 int DriveScheduler::QueueJob(QueueEntry* job) { | 105 int DriveScheduler::QueueJob(scoped_ptr<QueueEntry> job) { |
| 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 99 | 107 |
| 100 int job_id = next_job_id_; | 108 int job_id = next_job_id_; |
| 101 job->job_info.job_id = job_id; | 109 job->job_info.job_id = job_id; |
| 102 next_job_id_++; | 110 next_job_id_++; |
| 103 | 111 |
| 104 queue_.push_back(job_id); | 112 queue_.push_back(job_id); |
| 105 | 113 |
| 106 DCHECK(job_info_.find(job_id) == job_info_.end()); | 114 DCHECK(job_info_map_.find(job_id) == job_info_map_.end()); |
| 107 job_info_[job_id] = make_linked_ptr(job); | 115 job_info_map_[job_id] = make_linked_ptr(job.release()); |
| 108 | 116 |
| 109 return job_id; | 117 return job_id; |
| 110 } | 118 } |
| 111 | 119 |
| 112 void DriveScheduler::StartJobLoop() { | 120 void DriveScheduler::StartJobLoop() { |
| 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 114 | 122 |
| 115 if (!job_loop_is_running_) | 123 if (!job_loop_is_running_) |
| 116 DoJobLoop(); | 124 DoJobLoop(); |
| 117 } | 125 } |
| 118 | 126 |
| 119 void DriveScheduler::DoJobLoop() { | 127 void DriveScheduler::DoJobLoop() { |
| 120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 121 | 129 |
| 122 if (queue_.empty() || ShouldStopJobLoop()) { | 130 if (queue_.empty() || ShouldStopJobLoop()) { |
| 123 // Note that |queue_| is not cleared so the sync loop can resume. | 131 // Note that |queue_| is not cleared so the sync loop can resume. |
| 124 job_loop_is_running_ = false; | 132 job_loop_is_running_ = false; |
| 125 return; | 133 return; |
| 126 } | 134 } |
| 127 job_loop_is_running_ = true; | 135 job_loop_is_running_ = true; |
| 128 | 136 |
| 129 // Should copy before calling queue_.pop_front(). | 137 // Should copy before calling queue_.pop_front(). |
| 130 int job_id = queue_.front(); | 138 int job_id = queue_.front(); |
| 131 queue_.pop_front(); | 139 queue_.pop_front(); |
| 132 | 140 |
| 133 JobMap::iterator job_iter = job_info_.find(job_id); | 141 JobMap::iterator job_iter = job_info_map_.find(job_id); |
| 134 DCHECK(job_iter != job_info_.end()); | 142 DCHECK(job_iter != job_info_map_.end()); |
| 135 | 143 |
| 136 JobInfo& job_info = job_iter->second->job_info; | 144 JobInfo& job_info = job_iter->second->job_info; |
| 137 job_info.state = STATE_RUNNING; | 145 job_info.state = STATE_RUNNING; |
| 138 | 146 |
| 139 switch (job_info.job_type) { | 147 switch (job_info.job_type) { |
| 140 case TYPE_REMOVE: { | 148 case TYPE_MOVE: { |
| 141 DCHECK(job_iter->second->remove_private.get()); | 149 drive_operations_->Move( |
| 142 | |
| 143 drive_operations_->Remove( | |
| 144 job_info.file_path, | 150 job_info.file_path, |
| 145 job_iter->second->remove_private->is_recursive, | 151 job_iter->second->dest_file_path, |
| 146 base::Bind(&DriveScheduler::OnRemoveDone, | 152 base::Bind(&DriveScheduler::OnJobDone, |
| 147 weak_ptr_factory_.GetWeakPtr(), | 153 weak_ptr_factory_.GetWeakPtr(), |
| 148 job_id)); | 154 job_id)); |
| 149 } | 155 } |
| 150 break; | 156 break; |
| 157 |
| 158 case TYPE_REMOVE: { |
| 159 drive_operations_->Remove( |
| 160 job_info.file_path, |
| 161 job_iter->second->is_recursive, |
| 162 base::Bind(&DriveScheduler::OnJobDone, |
| 163 weak_ptr_factory_.GetWeakPtr(), |
| 164 job_id)); |
| 165 } |
| 166 break; |
| 167 |
| 168 // There is no default case so that there will be a compiler error if a type |
| 169 // is added but unhandled. |
| 151 } | 170 } |
| 152 | |
| 153 } | 171 } |
| 154 | 172 |
| 155 bool DriveScheduler::ShouldStopJobLoop() { | 173 bool DriveScheduler::ShouldStopJobLoop() { |
| 156 // Should stop if the gdata feature was disabled while running the fetch | 174 // Should stop if the gdata feature was disabled while running the fetch |
| 157 // loop. | 175 // loop. |
| 158 if (profile_->GetPrefs()->GetBoolean(prefs::kDisableDrive)) | 176 if (profile_->GetPrefs()->GetBoolean(prefs::kDisableDrive)) |
| 159 return true; | 177 return true; |
| 160 | 178 |
| 161 // Should stop if the network is not online. | 179 // Should stop if the network is not online. |
| 162 if (net::NetworkChangeNotifier::IsOffline()) | 180 if (net::NetworkChangeNotifier::IsOffline()) |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 DCHECK(posted); | 214 DCHECK(posted); |
| 197 } | 215 } |
| 198 | 216 |
| 199 void DriveScheduler::ResetThrottleAndContinueJobLoop() { | 217 void DriveScheduler::ResetThrottleAndContinueJobLoop() { |
| 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 201 | 219 |
| 202 throttle_count_ = 0; | 220 throttle_count_ = 0; |
| 203 DoJobLoop(); | 221 DoJobLoop(); |
| 204 } | 222 } |
| 205 | 223 |
| 206 void DriveScheduler::OnRemoveDone(int job_id, DriveFileError error) { | 224 void DriveScheduler::OnJobDone(int job_id, DriveFileError error) { |
| 207 JobMap::iterator job_iter = job_info_.find(job_id); | 225 JobMap::iterator job_iter = job_info_map_.find(job_id); |
| 208 DCHECK(job_iter != job_info_.end()); | 226 DCHECK(job_iter != job_info_map_.end()); |
| 209 | 227 |
| 210 // Retry, depending on the error. | 228 // Retry, depending on the error. |
| 211 if (error == DRIVE_FILE_ERROR_THROTTLED || | 229 if (error == DRIVE_FILE_ERROR_THROTTLED || |
| 212 error == DRIVE_FILE_ERROR_NO_CONNECTION) { | 230 error == DRIVE_FILE_ERROR_NO_CONNECTION) { |
| 213 job_iter->second->job_info.state = STATE_RETRY; | 231 job_iter->second->job_info.state = STATE_RETRY; |
| 214 | 232 |
| 215 // Requeue the job. | 233 // Requeue the job. |
| 216 queue_.push_back(job_id); | 234 queue_.push_back(job_id); |
| 217 ThrottleAndContinueJobLoop(); | 235 ThrottleAndContinueJobLoop(); |
| 218 } else { | 236 } else { |
| 219 DCHECK(job_iter->second->remove_private.get()); | |
| 220 | |
| 221 // Handle the callback. | 237 // Handle the callback. |
| 222 if (!job_iter->second->remove_private->callback.is_null()) { | 238 if (!job_iter->second->callback.is_null()) { |
| 223 MessageLoop::current()->PostTask(FROM_HERE, | 239 MessageLoop::current()->PostTask(FROM_HERE, |
| 224 base::Bind(job_iter->second->remove_private->callback, error)); | 240 base::Bind(job_iter->second->callback, error)); |
| 225 } | 241 } |
| 226 | 242 |
| 227 // Delete the job. | 243 // Delete the job. |
| 228 job_info_.erase(job_id); | 244 job_info_map_.erase(job_id); |
| 229 ResetThrottleAndContinueJobLoop(); | 245 ResetThrottleAndContinueJobLoop(); |
| 230 } | 246 } |
| 231 } | 247 } |
| 232 | 248 |
| 233 void DriveScheduler::OnConnectionTypeChanged( | 249 void DriveScheduler::OnConnectionTypeChanged( |
| 234 net::NetworkChangeNotifier::ConnectionType type) { | 250 net::NetworkChangeNotifier::ConnectionType type) { |
| 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 236 | 252 |
| 237 // Resume the job loop if the network is back online. Note that we don't | 253 // Resume the job loop if the network is back online. Note that we don't |
| 238 // need to check the type of the network as it will be checked in | 254 // need to check the type of the network as it will be checked in |
| 239 // ShouldStopJobLoop() as soon as the loop is resumed. | 255 // ShouldStopJobLoop() as soon as the loop is resumed. |
| 240 if (!net::NetworkChangeNotifier::IsOffline()) | 256 if (!net::NetworkChangeNotifier::IsOffline()) |
| 241 StartJobLoop(); | 257 StartJobLoop(); |
| 242 } | 258 } |
| 243 | 259 |
| 244 } // namespace drive | 260 } // namespace drive |
| OLD | NEW |