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 |