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 |