| 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 in the trash. |
| 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::kDriveTrashDirLocalId) { |
| 62 to_remove->push_back(local_id); |
| 63 continue; |
| 64 } |
| 60 | 65 |
| 61 if (cache_entry.is_dirty()) | 66 FileCacheEntry cache_entry; |
| 62 to_upload->push_back(local_id); | 67 if (it->GetCacheEntry(&cache_entry)) { |
| 68 if (cache_entry.is_pinned() && !cache_entry.is_present()) |
| 69 to_fetch->push_back(local_id); |
| 70 |
| 71 if (cache_entry.is_dirty()) |
| 72 to_upload->push_back(local_id); |
| 73 } |
| 63 } | 74 } |
| 64 DCHECK(!it->HasError()); | 75 DCHECK(!it->HasError()); |
| 65 } | 76 } |
| 66 | 77 |
| 67 // Iterates cache entries and collects IDs of ones with obsolete cache files. | 78 // Iterates cache entries and collects IDs of ones with obsolete cache files. |
| 68 void CheckExistingPinnedFiles(ResourceMetadata* metadata, | 79 void CheckExistingPinnedFiles(ResourceMetadata* metadata, |
| 69 FileCache* cache, | 80 FileCache* cache, |
| 70 std::vector<std::string>* local_ids) { | 81 std::vector<std::string>* local_ids) { |
| 71 scoped_ptr<FileCache::Iterator> it = cache->GetIterator(); | 82 scoped_ptr<FileCache::Iterator> it = cache->GetIterator(); |
| 72 for (; !it->IsAtEnd(); it->Advance()) { | 83 for (; !it->IsAtEnd(); it->Advance()) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 observer, | 133 observer, |
| 123 scheduler, | 134 scheduler, |
| 124 metadata, | 135 metadata, |
| 125 cache, | 136 cache, |
| 126 temporary_file_directory)), | 137 temporary_file_directory)), |
| 127 update_operation_(new file_system::UpdateOperation(blocking_task_runner, | 138 update_operation_(new file_system::UpdateOperation(blocking_task_runner, |
| 128 observer, | 139 observer, |
| 129 scheduler, | 140 scheduler, |
| 130 metadata, | 141 metadata, |
| 131 cache)), | 142 cache)), |
| 143 remove_performer_(new RemovePerformer(blocking_task_runner, |
| 144 scheduler, |
| 145 metadata)), |
| 132 delay_(base::TimeDelta::FromSeconds(kDelaySeconds)), | 146 delay_(base::TimeDelta::FromSeconds(kDelaySeconds)), |
| 133 long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)), | 147 long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)), |
| 134 weak_ptr_factory_(this) { | 148 weak_ptr_factory_(this) { |
| 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 136 } | 150 } |
| 137 | 151 |
| 138 SyncClient::~SyncClient() { | 152 SyncClient::~SyncClient() { |
| 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 140 } | 154 } |
| 141 | 155 |
| 142 void SyncClient::StartProcessingBacklog() { | 156 void SyncClient::StartProcessingBacklog() { |
| 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 144 | 158 |
| 145 std::vector<std::string>* to_fetch = new std::vector<std::string>; | 159 std::vector<std::string>* to_fetch = new std::vector<std::string>; |
| 146 std::vector<std::string>* to_upload = new std::vector<std::string>; | 160 std::vector<std::string>* to_upload = new std::vector<std::string>; |
| 161 std::vector<std::string>* to_remove = new std::vector<std::string>; |
| 147 blocking_task_runner_->PostTaskAndReply( | 162 blocking_task_runner_->PostTaskAndReply( |
| 148 FROM_HERE, | 163 FROM_HERE, |
| 149 base::Bind(&CollectBacklog, cache_, to_fetch, to_upload), | 164 base::Bind(&CollectBacklog, metadata_, to_fetch, to_upload, to_remove), |
| 150 base::Bind(&SyncClient::OnGetLocalIdsOfBacklog, | 165 base::Bind(&SyncClient::OnGetLocalIdsOfBacklog, |
| 151 weak_ptr_factory_.GetWeakPtr(), | 166 weak_ptr_factory_.GetWeakPtr(), |
| 152 base::Owned(to_fetch), | 167 base::Owned(to_fetch), |
| 153 base::Owned(to_upload))); | 168 base::Owned(to_upload), |
| 169 base::Owned(to_remove))); |
| 154 } | 170 } |
| 155 | 171 |
| 156 void SyncClient::StartCheckingExistingPinnedFiles() { | 172 void SyncClient::StartCheckingExistingPinnedFiles() { |
| 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 158 | 174 |
| 159 std::vector<std::string>* local_ids = new std::vector<std::string>; | 175 std::vector<std::string>* local_ids = new std::vector<std::string>; |
| 160 blocking_task_runner_->PostTaskAndReply( | 176 blocking_task_runner_->PostTaskAndReply( |
| 161 FROM_HERE, | 177 FROM_HERE, |
| 162 base::Bind(&CheckExistingPinnedFiles, | 178 base::Bind(&CheckExistingPinnedFiles, |
| 163 metadata_, | 179 metadata_, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 181 pending_fetch_list_.erase(local_id); | 197 pending_fetch_list_.erase(local_id); |
| 182 } | 198 } |
| 183 | 199 |
| 184 void SyncClient::AddUploadTask(const ClientContext& context, | 200 void SyncClient::AddUploadTask(const ClientContext& context, |
| 185 const std::string& local_id) { | 201 const std::string& local_id) { |
| 186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 187 | 203 |
| 188 AddTaskToQueue(UPLOAD, context, local_id, delay_); | 204 AddTaskToQueue(UPLOAD, context, local_id, delay_); |
| 189 } | 205 } |
| 190 | 206 |
| 207 void SyncClient::AddRemoveTask(const std::string& local_id) { |
| 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 209 |
| 210 DVLOG(1) << "Removing " << local_id; |
| 211 remove_performer_->Remove(local_id, |
| 212 base::Bind(&SyncClient::OnRemoveComplete, |
| 213 weak_ptr_factory_.GetWeakPtr(), |
| 214 local_id)); |
| 215 } |
| 216 |
| 191 void SyncClient::AddTaskToQueue(SyncType type, | 217 void SyncClient::AddTaskToQueue(SyncType type, |
| 192 const ClientContext& context, | 218 const ClientContext& context, |
| 193 const std::string& local_id, | 219 const std::string& local_id, |
| 194 const base::TimeDelta& delay) { | 220 const base::TimeDelta& delay) { |
| 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 196 | 222 |
| 197 // If the same task is already queued, ignore this task. | 223 // If the same task is already queued, ignore this task. |
| 198 switch (type) { | 224 switch (type) { |
| 199 case FETCH: | 225 case FETCH: |
| 200 if (fetch_list_.find(local_id) == fetch_list_.end()) { | 226 if (fetch_list_.find(local_id) == fetch_list_.end()) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 check_mode, | 287 check_mode, |
| 262 base::Bind(&SyncClient::OnUploadFileComplete, | 288 base::Bind(&SyncClient::OnUploadFileComplete, |
| 263 weak_ptr_factory_.GetWeakPtr(), | 289 weak_ptr_factory_.GetWeakPtr(), |
| 264 local_id)); | 290 local_id)); |
| 265 break; | 291 break; |
| 266 } | 292 } |
| 267 } | 293 } |
| 268 | 294 |
| 269 void SyncClient::OnGetLocalIdsOfBacklog( | 295 void SyncClient::OnGetLocalIdsOfBacklog( |
| 270 const std::vector<std::string>* to_fetch, | 296 const std::vector<std::string>* to_fetch, |
| 271 const std::vector<std::string>* to_upload) { | 297 const std::vector<std::string>* to_upload, |
| 298 const std::vector<std::string>* to_remove) { |
| 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 273 | 300 |
| 274 // Give priority to upload tasks over fetch tasks, so that dirty files are | 301 // Give priority to upload tasks over fetch tasks, so that dirty files are |
| 275 // uploaded as soon as possible. | 302 // uploaded as soon as possible. |
| 276 for (size_t i = 0; i < to_upload->size(); ++i) { | 303 for (size_t i = 0; i < to_upload->size(); ++i) { |
| 277 const std::string& local_id = (*to_upload)[i]; | 304 const std::string& local_id = (*to_upload)[i]; |
| 278 DVLOG(1) << "Queuing to upload: " << local_id; | 305 DVLOG(1) << "Queuing to upload: " << local_id; |
| 279 AddTaskToQueue(UPLOAD_RETRY, ClientContext(BACKGROUND), local_id, delay_); | 306 AddTaskToQueue(UPLOAD_RETRY, ClientContext(BACKGROUND), local_id, delay_); |
| 280 } | 307 } |
| 281 | 308 |
| 282 for (size_t i = 0; i < to_fetch->size(); ++i) { | 309 for (size_t i = 0; i < to_fetch->size(); ++i) { |
| 283 const std::string& local_id = (*to_fetch)[i]; | 310 const std::string& local_id = (*to_fetch)[i]; |
| 284 DVLOG(1) << "Queuing to fetch: " << local_id; | 311 DVLOG(1) << "Queuing to fetch: " << local_id; |
| 285 AddTaskToQueue(FETCH, ClientContext(BACKGROUND), local_id, delay_); | 312 AddTaskToQueue(FETCH, ClientContext(BACKGROUND), local_id, delay_); |
| 286 } | 313 } |
| 314 |
| 315 for (size_t i = 0; i < to_remove->size(); ++i) { |
| 316 const std::string& local_id = (*to_remove)[i]; |
| 317 DVLOG(1) << "Queuing to remove: " << local_id; |
| 318 AddRemoveTask(local_id); |
| 319 } |
| 287 } | 320 } |
| 288 | 321 |
| 289 void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) { | 322 void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) { |
| 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 291 | 324 |
| 292 for (size_t i = 0; i < local_ids->size(); ++i) | 325 for (size_t i = 0; i < local_ids->size(); ++i) |
| 293 AddFetchTask((*local_ids)[i]); | 326 AddFetchTask((*local_ids)[i]); |
| 294 } | 327 } |
| 295 | 328 |
| 296 void SyncClient::OnFetchFileComplete(const std::string& local_id, | 329 void SyncClient::OnFetchFileComplete(const std::string& local_id, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 AddTaskToQueue(UPLOAD_RETRY, ClientContext(BACKGROUND), local_id, | 379 AddTaskToQueue(UPLOAD_RETRY, ClientContext(BACKGROUND), local_id, |
| 347 long_delay_); | 380 long_delay_); |
| 348 break; | 381 break; |
| 349 default: | 382 default: |
| 350 LOG(WARNING) << "Failed to upload " << local_id << ": " | 383 LOG(WARNING) << "Failed to upload " << local_id << ": " |
| 351 << FileErrorToString(error); | 384 << FileErrorToString(error); |
| 352 } | 385 } |
| 353 } | 386 } |
| 354 } | 387 } |
| 355 | 388 |
| 389 void SyncClient::OnRemoveComplete(const std::string& local_id, |
| 390 FileError error) { |
| 391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 392 |
| 393 if (error == FILE_ERROR_OK) { |
| 394 DVLOG(1) << "Removed " << local_id; |
| 395 } else { |
| 396 switch (error) { |
| 397 case FILE_ERROR_NO_CONNECTION: |
| 398 // Re-queue the task so that we'll retry once the connection is back. |
| 399 AddRemoveTask(local_id); |
| 400 break; |
| 401 case FILE_ERROR_SERVICE_UNAVAILABLE: |
| 402 // Re-queue the task so that we'll retry once the service is back. |
| 403 base::MessageLoopProxy::current()->PostDelayedTask( |
| 404 FROM_HERE, |
| 405 base::Bind(&SyncClient::AddRemoveTask, |
| 406 weak_ptr_factory_.GetWeakPtr(), |
| 407 local_id), |
| 408 long_delay_); |
| 409 break; |
| 410 default: |
| 411 LOG(WARNING) << "Failed to remove " << local_id << ": " |
| 412 << FileErrorToString(error); |
| 413 } |
| 414 } |
| 415 } |
| 416 |
| 356 } // namespace internal | 417 } // namespace internal |
| 357 } // namespace drive | 418 } // namespace drive |
| OLD | NEW |