Chromium Code Reviews| 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/sync_client.h" | 5 #include "chrome/browser/chromeos/drive/sync_client.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
| 11 #include "chrome/browser/chromeos/drive/drive.pb.h" | 11 #include "chrome/browser/chromeos/drive/drive.pb.h" |
| 12 #include "chrome/browser/chromeos/drive/file_cache.h" | 12 #include "chrome/browser/chromeos/drive/file_cache.h" |
| 13 #include "chrome/browser/chromeos/drive/file_system/download_operation.h" | 13 #include "chrome/browser/chromeos/drive/file_system/download_operation.h" |
| 14 #include "chrome/browser/chromeos/drive/file_system/update_operation.h" | 14 #include "chrome/browser/chromeos/drive/file_system/update_operation.h" |
| 15 #include "chrome/browser/chromeos/drive/file_system_util.h" | 15 #include "chrome/browser/chromeos/drive/file_system_util.h" |
| 16 #include "chrome/browser/chromeos/drive/sync/remove_performer.h" | |
| 16 #include "chrome/browser/google_apis/task_util.h" | 17 #include "chrome/browser/google_apis/task_util.h" |
| 17 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 18 | 19 |
| 19 using content::BrowserThread; | 20 using content::BrowserThread; |
| 20 | 21 |
| 21 namespace drive { | 22 namespace drive { |
| 22 namespace internal { | 23 namespace internal { |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 // The delay constant is used to delay processing a sync task. We should not | 27 // The delay constant is used to delay processing a sync task. We should not |
| 27 // process SyncTasks immediately for the following reasons: | 28 // process SyncTasks immediately for the following reasons: |
| 28 // | 29 // |
| 29 // 1) For fetching, the user may accidentally click on "Make available | 30 // 1) For fetching, the user may accidentally click on "Make available |
| 30 // offline" checkbox on a file, and immediately cancel it in a second. | 31 // offline" checkbox on a file, and immediately cancel it in a second. |
| 31 // It's a waste to fetch the file in this case. | 32 // It's a waste to fetch the file in this case. |
| 32 // | 33 // |
| 33 // 2) For uploading, file writing via HTML5 file system API is performed in | 34 // 2) For uploading, file writing via HTML5 file system API is performed in |
| 34 // two steps: 1) truncate a file to 0 bytes, 2) write contents. We | 35 // two steps: 1) truncate a file to 0 bytes, 2) write contents. We |
| 35 // shouldn't start uploading right after the step 1). Besides, the user | 36 // shouldn't start uploading right after the step 1). Besides, the user |
| 36 // may edit the same file repeatedly in a short period of time. | 37 // may edit the same file repeatedly in a short period of time. |
| 37 // | 38 // |
| 38 // TODO(satorux): We should find a way to handle the upload case more nicely, | 39 // TODO(satorux): We should find a way to handle the upload case more nicely, |
| 39 // and shorten the delay. crbug.com/134774 | 40 // and shorten the delay. crbug.com/134774 |
| 40 const int kDelaySeconds = 5; | 41 const int kDelaySeconds = 5; |
| 41 | 42 |
| 42 // The delay constant is used to delay retrying a sync task on server errors. | 43 // The delay constant is used to delay retrying a sync task on server errors. |
| 43 const int kLongDelaySeconds = 600; | 44 const int kLongDelaySeconds = 600; |
| 44 | 45 |
| 45 // Iterates cache entries and appends IDs to |to_fetch| if the file is pinned | 46 // Iterates entries and appends IDs to |to_fetch| if the file is pinned but not |
| 46 // but not fetched (not present locally), or to |to_upload| if the file is dirty | 47 // fetched (not present locally), to |to_upload| if the file is dirty but not |
| 47 // but not uploaded. | 48 // uploaded, or to |to_remove| if the entry is locally deleted. |
| 48 void CollectBacklog(FileCache* cache, | 49 void CollectBacklog(ResourceMetadata* metadata, |
| 49 std::vector<std::string>* to_fetch, | 50 std::vector<std::string>* to_fetch, |
| 50 std::vector<std::string>* to_upload) { | 51 std::vector<std::string>* to_upload, |
| 52 std::vector<std::string>* to_remove) { | |
| 51 DCHECK(to_fetch); | 53 DCHECK(to_fetch); |
| 52 DCHECK(to_upload); | 54 DCHECK(to_upload); |
| 55 DCHECK(to_remove); | |
| 53 | 56 |
| 54 scoped_ptr<FileCache::Iterator> it = cache->GetIterator(); | 57 scoped_ptr<ResourceMetadata::Iterator> it = metadata->GetIterator(); |
| 55 for (; !it->IsAtEnd(); it->Advance()) { | 58 for (; !it->IsAtEnd(); it->Advance()) { |
| 56 const FileCacheEntry& cache_entry = it->GetValue(); | |
| 57 const std::string& local_id = it->GetID(); | 59 const std::string& local_id = it->GetID(); |
| 58 if (cache_entry.is_pinned() && !cache_entry.is_present()) | 60 const ResourceEntry& entry = it->GetValue(); |
| 59 to_fetch->push_back(local_id); | 61 if (entry.parent_local_id() == util::kDriveOtherDirLocalId && |
| 62 entry.deleted()) | |
| 63 to_remove->push_back(local_id); | |
|
kinaba
2013/11/12 06:21:29
Probably we don't want to, say, fetch a pinned and
hashimoto
2013/11/25 10:13:58
Done.
| |
| 60 | 64 |
| 61 if (cache_entry.is_dirty()) | 65 FileCacheEntry cache_entry; |
| 62 to_upload->push_back(local_id); | 66 if (it->GetCacheEntry(&cache_entry)) { |
| 67 if (cache_entry.is_pinned() && !cache_entry.is_present()) | |
| 68 to_fetch->push_back(local_id); | |
| 69 | |
| 70 if (cache_entry.is_dirty()) | |
| 71 to_upload->push_back(local_id); | |
| 72 } | |
| 63 } | 73 } |
| 64 DCHECK(!it->HasError()); | 74 DCHECK(!it->HasError()); |
| 65 } | 75 } |
| 66 | 76 |
| 67 // Iterates cache entries and collects IDs of ones with obsolete cache files. | 77 // Iterates cache entries and collects IDs of ones with obsolete cache files. |
| 68 void CheckExistingPinnedFiles(ResourceMetadata* metadata, | 78 void CheckExistingPinnedFiles(ResourceMetadata* metadata, |
| 69 FileCache* cache, | 79 FileCache* cache, |
| 70 std::vector<std::string>* local_ids) { | 80 std::vector<std::string>* local_ids) { |
| 71 scoped_ptr<FileCache::Iterator> it = cache->GetIterator(); | 81 scoped_ptr<FileCache::Iterator> it = cache->GetIterator(); |
| 72 for (; !it->IsAtEnd(); it->Advance()) { | 82 for (; !it->IsAtEnd(); it->Advance()) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 observer, | 132 observer, |
| 123 scheduler, | 133 scheduler, |
| 124 metadata, | 134 metadata, |
| 125 cache, | 135 cache, |
| 126 temporary_file_directory)), | 136 temporary_file_directory)), |
| 127 update_operation_(new file_system::UpdateOperation(blocking_task_runner, | 137 update_operation_(new file_system::UpdateOperation(blocking_task_runner, |
| 128 observer, | 138 observer, |
| 129 scheduler, | 139 scheduler, |
| 130 metadata, | 140 metadata, |
| 131 cache)), | 141 cache)), |
| 142 remove_performer_(new RemovePerformer(blocking_task_runner, | |
| 143 scheduler, | |
| 144 metadata)), | |
| 132 delay_(base::TimeDelta::FromSeconds(kDelaySeconds)), | 145 delay_(base::TimeDelta::FromSeconds(kDelaySeconds)), |
| 133 long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)), | 146 long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)), |
| 134 weak_ptr_factory_(this) { | 147 weak_ptr_factory_(this) { |
| 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 136 } | 149 } |
| 137 | 150 |
| 138 SyncClient::~SyncClient() { | 151 SyncClient::~SyncClient() { |
| 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 140 } | 153 } |
| 141 | 154 |
| 142 void SyncClient::StartProcessingBacklog() { | 155 void SyncClient::StartProcessingBacklog() { |
| 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 144 | 157 |
| 145 std::vector<std::string>* to_fetch = new std::vector<std::string>; | 158 std::vector<std::string>* to_fetch = new std::vector<std::string>; |
| 146 std::vector<std::string>* to_upload = new std::vector<std::string>; | 159 std::vector<std::string>* to_upload = new std::vector<std::string>; |
| 160 std::vector<std::string>* to_remove = new std::vector<std::string>; | |
| 147 blocking_task_runner_->PostTaskAndReply( | 161 blocking_task_runner_->PostTaskAndReply( |
| 148 FROM_HERE, | 162 FROM_HERE, |
| 149 base::Bind(&CollectBacklog, cache_, to_fetch, to_upload), | 163 base::Bind(&CollectBacklog, metadata_, to_fetch, to_upload, to_remove), |
| 150 base::Bind(&SyncClient::OnGetLocalIdsOfBacklog, | 164 base::Bind(&SyncClient::OnGetLocalIdsOfBacklog, |
| 151 weak_ptr_factory_.GetWeakPtr(), | 165 weak_ptr_factory_.GetWeakPtr(), |
| 152 base::Owned(to_fetch), | 166 base::Owned(to_fetch), |
| 153 base::Owned(to_upload))); | 167 base::Owned(to_upload), |
| 168 base::Owned(to_remove))); | |
| 154 } | 169 } |
| 155 | 170 |
| 156 void SyncClient::StartCheckingExistingPinnedFiles() { | 171 void SyncClient::StartCheckingExistingPinnedFiles() { |
| 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 158 | 173 |
| 159 std::vector<std::string>* local_ids = new std::vector<std::string>; | 174 std::vector<std::string>* local_ids = new std::vector<std::string>; |
| 160 blocking_task_runner_->PostTaskAndReply( | 175 blocking_task_runner_->PostTaskAndReply( |
| 161 FROM_HERE, | 176 FROM_HERE, |
| 162 base::Bind(&CheckExistingPinnedFiles, | 177 base::Bind(&CheckExistingPinnedFiles, |
| 163 metadata_, | 178 metadata_, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 180 // TODO(kinaba): Cancel tasks in JobScheduler as well. crbug.com/248856 | 195 // TODO(kinaba): Cancel tasks in JobScheduler as well. crbug.com/248856 |
| 181 pending_fetch_list_.erase(local_id); | 196 pending_fetch_list_.erase(local_id); |
| 182 } | 197 } |
| 183 | 198 |
| 184 void SyncClient::AddUploadTask(const std::string& local_id) { | 199 void SyncClient::AddUploadTask(const std::string& local_id) { |
| 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 186 | 201 |
| 187 AddTaskToQueue(UPLOAD, local_id, delay_); | 202 AddTaskToQueue(UPLOAD, local_id, delay_); |
| 188 } | 203 } |
| 189 | 204 |
| 205 void SyncClient::AddRemoveTask(const std::string& local_id) { | |
| 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 207 | |
| 208 DVLOG(1) << "Removing " << local_id; | |
| 209 remove_performer_->Remove(local_id, | |
| 210 base::Bind(&SyncClient::OnRemoveComplete, | |
| 211 weak_ptr_factory_.GetWeakPtr(), | |
| 212 local_id)); | |
| 213 } | |
| 214 | |
| 190 void SyncClient::AddTaskToQueue(SyncType type, | 215 void SyncClient::AddTaskToQueue(SyncType type, |
| 191 const std::string& local_id, | 216 const std::string& local_id, |
| 192 const base::TimeDelta& delay) { | 217 const base::TimeDelta& delay) { |
| 193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 194 | 219 |
| 195 // If the same task is already queued, ignore this task. | 220 // If the same task is already queued, ignore this task. |
| 196 switch (type) { | 221 switch (type) { |
| 197 case FETCH: | 222 case FETCH: |
| 198 if (fetch_list_.find(local_id) == fetch_list_.end()) { | 223 if (fetch_list_.find(local_id) == fetch_list_.end()) { |
| 199 fetch_list_.insert(local_id); | 224 fetch_list_.insert(local_id); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 : file_system::UpdateOperation::NO_CONTENT_CHECK, | 277 : file_system::UpdateOperation::NO_CONTENT_CHECK, |
| 253 base::Bind(&SyncClient::OnUploadFileComplete, | 278 base::Bind(&SyncClient::OnUploadFileComplete, |
| 254 weak_ptr_factory_.GetWeakPtr(), | 279 weak_ptr_factory_.GetWeakPtr(), |
| 255 local_id)); | 280 local_id)); |
| 256 break; | 281 break; |
| 257 } | 282 } |
| 258 } | 283 } |
| 259 | 284 |
| 260 void SyncClient::OnGetLocalIdsOfBacklog( | 285 void SyncClient::OnGetLocalIdsOfBacklog( |
| 261 const std::vector<std::string>* to_fetch, | 286 const std::vector<std::string>* to_fetch, |
| 262 const std::vector<std::string>* to_upload) { | 287 const std::vector<std::string>* to_upload, |
| 288 const std::vector<std::string>* to_remove) { | |
| 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 264 | 290 |
| 265 // Give priority to upload tasks over fetch tasks, so that dirty files are | 291 // Give priority to upload tasks over fetch tasks, so that dirty files are |
| 266 // uploaded as soon as possible. | 292 // uploaded as soon as possible. |
| 267 for (size_t i = 0; i < to_upload->size(); ++i) { | 293 for (size_t i = 0; i < to_upload->size(); ++i) { |
| 268 const std::string& local_id = (*to_upload)[i]; | 294 const std::string& local_id = (*to_upload)[i]; |
| 269 DVLOG(1) << "Queuing to upload: " << local_id; | 295 DVLOG(1) << "Queuing to upload: " << local_id; |
| 270 AddTaskToQueue(UPLOAD_NO_CONTENT_CHECK, local_id, delay_); | 296 AddTaskToQueue(UPLOAD_NO_CONTENT_CHECK, local_id, delay_); |
| 271 } | 297 } |
| 272 | 298 |
| 273 for (size_t i = 0; i < to_fetch->size(); ++i) { | 299 for (size_t i = 0; i < to_fetch->size(); ++i) { |
| 274 const std::string& local_id = (*to_fetch)[i]; | 300 const std::string& local_id = (*to_fetch)[i]; |
| 275 DVLOG(1) << "Queuing to fetch: " << local_id; | 301 DVLOG(1) << "Queuing to fetch: " << local_id; |
| 276 AddTaskToQueue(FETCH, local_id, delay_); | 302 AddTaskToQueue(FETCH, local_id, delay_); |
| 277 } | 303 } |
| 304 | |
| 305 for (size_t i = 0; i < to_remove->size(); ++i) { | |
| 306 const std::string& local_id = (*to_remove)[i]; | |
| 307 DVLOG(1) << "Queuing to remove: " << local_id; | |
| 308 AddRemoveTask(local_id); | |
| 309 } | |
| 278 } | 310 } |
| 279 | 311 |
| 280 void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) { | 312 void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) { |
| 281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 282 | 314 |
| 283 for (size_t i = 0; i < local_ids->size(); ++i) | 315 for (size_t i = 0; i < local_ids->size(); ++i) |
| 284 AddFetchTask((*local_ids)[i]); | 316 AddFetchTask((*local_ids)[i]); |
| 285 } | 317 } |
| 286 | 318 |
| 287 void SyncClient::OnFetchFileComplete(const std::string& local_id, | 319 void SyncClient::OnFetchFileComplete(const std::string& local_id, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 // Re-queue the task so that we'll retry once the service is back. | 367 // Re-queue the task so that we'll retry once the service is back. |
| 336 AddTaskToQueue(UPLOAD_NO_CONTENT_CHECK, local_id, long_delay_); | 368 AddTaskToQueue(UPLOAD_NO_CONTENT_CHECK, local_id, long_delay_); |
| 337 break; | 369 break; |
| 338 default: | 370 default: |
| 339 LOG(WARNING) << "Failed to upload " << local_id << ": " | 371 LOG(WARNING) << "Failed to upload " << local_id << ": " |
| 340 << FileErrorToString(error); | 372 << FileErrorToString(error); |
| 341 } | 373 } |
| 342 } | 374 } |
| 343 } | 375 } |
| 344 | 376 |
| 377 void SyncClient::OnRemoveComplete(const std::string& local_id, | |
| 378 FileError error) { | |
| 379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 380 | |
| 381 if (error == FILE_ERROR_OK) { | |
| 382 DVLOG(1) << "Removed " << local_id; | |
| 383 } else { | |
| 384 switch (error) { | |
| 385 case FILE_ERROR_NO_CONNECTION: | |
| 386 // Re-queue the task so that we'll retry once the connection is back. | |
| 387 AddRemoveTask(local_id); | |
| 388 break; | |
| 389 case FILE_ERROR_SERVICE_UNAVAILABLE: | |
| 390 // Re-queue the task so that we'll retry once the service is back. | |
| 391 AddRemoveTask(local_id); | |
|
kinaba
2013/11/12 06:21:29
AddTaskToQueue posts the task after a long_delay_,
hashimoto
2013/11/25 10:13:58
Done.
| |
| 392 break; | |
| 393 default: | |
| 394 LOG(WARNING) << "Failed to remove " << local_id << ": " | |
| 395 << FileErrorToString(error); | |
| 396 } | |
| 397 } | |
| 398 } | |
| 399 | |
| 345 } // namespace internal | 400 } // namespace internal |
| 346 } // namespace drive | 401 } // namespace drive |
| OLD | NEW |