OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/sync_file_system/local/local_file_change_tracker.h" | 5 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h" |
6 | 6 |
7 #include <queue> | 7 #include <queue> |
8 | 8 |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 | 72 |
73 // LocalFileChangeTracker ------------------------------------------------------ | 73 // LocalFileChangeTracker ------------------------------------------------------ |
74 | 74 |
75 LocalFileChangeTracker::LocalFileChangeTracker( | 75 LocalFileChangeTracker::LocalFileChangeTracker( |
76 const base::FilePath& base_path, | 76 const base::FilePath& base_path, |
77 leveldb::Env* env_override, | 77 leveldb::Env* env_override, |
78 base::SequencedTaskRunner* file_task_runner) | 78 base::SequencedTaskRunner* file_task_runner) |
79 : initialized_(false), | 79 : initialized_(false), |
80 file_task_runner_(file_task_runner), | 80 file_task_runner_(file_task_runner), |
81 tracker_db_(new TrackerDB(base_path, env_override)), | 81 tracker_db_(new TrackerDB(base_path, env_override)), |
82 current_change_seq_(0), | 82 current_change_seq_number_(0), |
83 num_changes_(0) { | 83 num_changes_(0) { |
84 } | 84 } |
85 | 85 |
86 LocalFileChangeTracker::~LocalFileChangeTracker() { | 86 LocalFileChangeTracker::~LocalFileChangeTracker() { |
87 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 87 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
88 tracker_db_.reset(); | 88 tracker_db_.reset(); |
89 } | 89 } |
90 | 90 |
91 void LocalFileChangeTracker::OnStartUpdate(const FileSystemURL& url) { | 91 void LocalFileChangeTracker::OnStartUpdate(const FileSystemURL& url) { |
92 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 92 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
93 if (ContainsKey(changes_, url)) | 93 if (ContainsKey(changes_, url) || ContainsKey(demoted_changes_, url)) |
94 return; | 94 return; |
95 // TODO(nhiroki): propagate the error code (see http://crbug.com/152127). | 95 // TODO(nhiroki): propagate the error code (see http://crbug.com/152127). |
96 MarkDirtyOnDatabase(url); | 96 MarkDirtyOnDatabase(url); |
97 } | 97 } |
98 | 98 |
99 void LocalFileChangeTracker::OnEndUpdate(const FileSystemURL& url) {} | 99 void LocalFileChangeTracker::OnEndUpdate(const FileSystemURL& url) {} |
100 | 100 |
101 void LocalFileChangeTracker::OnCreateFile(const FileSystemURL& url) { | 101 void LocalFileChangeTracker::OnCreateFile(const FileSystemURL& url) { |
102 RecordChange(url, FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, | 102 RecordChange(url, FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, |
103 SYNC_FILE_TYPE_FILE)); | 103 SYNC_FILE_TYPE_FILE)); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 } | 179 } |
180 | 180 |
181 void LocalFileChangeTracker::RemoveMirrorAndCommitChangesForURL( | 181 void LocalFileChangeTracker::RemoveMirrorAndCommitChangesForURL( |
182 const fileapi::FileSystemURL& url) { | 182 const fileapi::FileSystemURL& url) { |
183 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 183 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
184 FileChangeMap::iterator found = mirror_changes_.find(url); | 184 FileChangeMap::iterator found = mirror_changes_.find(url); |
185 if (found == mirror_changes_.end()) | 185 if (found == mirror_changes_.end()) |
186 return; | 186 return; |
187 mirror_changes_.erase(found); | 187 mirror_changes_.erase(found); |
188 | 188 |
189 if (ContainsKey(changes_, url)) | 189 if (ContainsKey(changes_, url) || ContainsKey(demoted_changes_, url)) |
190 MarkDirtyOnDatabase(url); | 190 MarkDirtyOnDatabase(url); |
191 else | 191 else |
192 ClearDirtyOnDatabase(url); | 192 ClearDirtyOnDatabase(url); |
193 UpdateNumChanges(); | 193 UpdateNumChanges(); |
194 } | 194 } |
195 | 195 |
196 void LocalFileChangeTracker::ResetToMirrorAndCommitChangesForURL( | 196 void LocalFileChangeTracker::ResetToMirrorAndCommitChangesForURL( |
197 const fileapi::FileSystemURL& url) { | 197 const fileapi::FileSystemURL& url) { |
198 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 198 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
199 FileChangeMap::iterator found = mirror_changes_.find(url); | 199 FileChangeMap::iterator found = mirror_changes_.find(url); |
200 if (found == mirror_changes_.end() || found->second.change_list.empty()) { | 200 if (found == mirror_changes_.end() || found->second.change_list.empty()) { |
201 ClearChangesForURL(url); | 201 ClearChangesForURL(url); |
202 return; | 202 return; |
203 } | 203 } |
204 const ChangeInfo& info = found->second; | 204 const ChangeInfo& info = found->second; |
205 change_seqs_[info.change_seq] = url; | 205 if (ContainsKey(demoted_changes_, url)) { |
206 changes_[url] = info; | 206 DCHECK(!ContainsKey(changes_, url)); |
| 207 demoted_changes_[url] = info; |
| 208 } else { |
| 209 DCHECK(!ContainsKey(demoted_changes_, url)); |
| 210 change_seqs_[info.change_seq] = url; |
| 211 changes_[url] = info; |
| 212 } |
207 RemoveMirrorAndCommitChangesForURL(url); | 213 RemoveMirrorAndCommitChangesForURL(url); |
208 } | 214 } |
209 | 215 |
210 void LocalFileChangeTracker::DemoteChangesForURL( | 216 void LocalFileChangeTracker::DemoteChangesForURL( |
211 const fileapi::FileSystemURL& url) { | 217 const fileapi::FileSystemURL& url) { |
212 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 218 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
| 219 |
213 FileChangeMap::iterator found = changes_.find(url); | 220 FileChangeMap::iterator found = changes_.find(url); |
214 if (found == changes_.end()) | 221 if (found == changes_.end()) |
215 return; | 222 return; |
216 FileChangeList changes = found->second.change_list; | 223 DCHECK(!ContainsKey(demoted_changes_, url)); |
217 | |
218 mirror_changes_.erase(url); | |
219 change_seqs_.erase(found->second.change_seq); | 224 change_seqs_.erase(found->second.change_seq); |
| 225 demoted_changes_.insert(*found); |
220 changes_.erase(found); | 226 changes_.erase(found); |
221 | |
222 FileChangeList::List change_list = changes.list(); | |
223 while (!change_list.empty()) { | |
224 RecordChangeToChangeMaps(url, change_list.front(), 0, | |
225 &demoted_changes_, NULL); | |
226 change_list.pop_front(); | |
227 } | |
228 UpdateNumChanges(); | 227 UpdateNumChanges(); |
229 } | 228 } |
230 | 229 |
231 void LocalFileChangeTracker::PromoteDemotedChangesForURL( | 230 void LocalFileChangeTracker::PromoteDemotedChangesForURL( |
232 const fileapi::FileSystemURL& url) { | 231 const fileapi::FileSystemURL& url) { |
233 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 232 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
234 | 233 |
235 FileChangeMap::iterator iter = demoted_changes_.find(url); | 234 FileChangeMap::iterator iter = demoted_changes_.find(url); |
236 if (iter == demoted_changes_.end()) | 235 if (iter == demoted_changes_.end()) |
237 return; | 236 return; |
238 | 237 |
239 FileChangeList::List change_list = iter->second.change_list.list(); | 238 FileChangeList::List change_list = iter->second.change_list.list(); |
240 // Make sure that this URL is in no queues. | 239 // Make sure that this URL is in no queues. |
| 240 DCHECK(!ContainsKey(change_seqs_, iter->second.change_seq)); |
241 DCHECK(!ContainsKey(changes_, url)); | 241 DCHECK(!ContainsKey(changes_, url)); |
242 DCHECK(!ContainsKey(mirror_changes_, url)); | |
243 | 242 |
| 243 change_seqs_[iter->second.change_seq] = url; |
| 244 changes_.insert(*iter); |
244 demoted_changes_.erase(iter); | 245 demoted_changes_.erase(iter); |
245 | |
246 while (!change_list.empty()) { | |
247 RecordChange(url, change_list.front()); | |
248 change_list.pop_front(); | |
249 } | |
250 } | 246 } |
251 | 247 |
252 bool LocalFileChangeTracker::PromoteDemotedChanges() { | 248 bool LocalFileChangeTracker::PromoteDemotedChanges() { |
253 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 249 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
254 if (demoted_changes_.empty()) | 250 if (demoted_changes_.empty()) |
255 return false; | 251 return false; |
256 while (!demoted_changes_.empty()) { | 252 while (!demoted_changes_.empty()) { |
257 fileapi::FileSystemURL url = demoted_changes_.begin()->first; | 253 fileapi::FileSystemURL url = demoted_changes_.begin()->first; |
258 PromoteDemotedChangesForURL(url); | 254 PromoteDemotedChangesForURL(url); |
259 } | 255 } |
(...skipping 14 matching lines...) Expand all Loading... |
274 } | 270 } |
275 | 271 |
276 void LocalFileChangeTracker::ResetForFileSystem( | 272 void LocalFileChangeTracker::ResetForFileSystem( |
277 const GURL& origin, | 273 const GURL& origin, |
278 fileapi::FileSystemType type) { | 274 fileapi::FileSystemType type) { |
279 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 275 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
280 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); | 276 scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); |
281 for (FileChangeMap::iterator iter = changes_.begin(); | 277 for (FileChangeMap::iterator iter = changes_.begin(); |
282 iter != changes_.end();) { | 278 iter != changes_.end();) { |
283 fileapi::FileSystemURL url = iter->first; | 279 fileapi::FileSystemURL url = iter->first; |
284 if (url.origin() != origin || url.type() != type) { | 280 int change_seq = iter->second.change_seq; |
285 ++iter; | 281 // Advance |iter| before calling ResetForURL to avoid the iterator |
286 continue; | 282 // invalidation in it. |
287 } | 283 ++iter; |
288 mirror_changes_.erase(url); | 284 if (url.origin() == origin && url.type() == type) |
289 demoted_changes_.erase(url); | 285 ResetForURL(url, change_seq, batch.get()); |
290 change_seqs_.erase(iter->second.change_seq); | 286 } |
291 changes_.erase(iter++); | |
292 | 287 |
293 std::string serialized_url; | 288 for (FileChangeMap::iterator iter = demoted_changes_.begin(); |
294 const bool should_success = | 289 iter != demoted_changes_.end();) { |
295 SerializeSyncableFileSystemURL(url, &serialized_url); | 290 fileapi::FileSystemURL url = iter->first; |
296 if (!should_success) { | 291 int change_seq = iter->second.change_seq; |
297 NOTREACHED() << "Failed to serialize: " << url.DebugString(); | 292 // Advance |iter| before calling ResetForURL to avoid the iterator |
298 continue; | 293 // invalidation in it. |
299 } | 294 ++iter; |
300 batch->Delete(serialized_url); | 295 if (url.origin() == origin && url.type() == type) |
| 296 ResetForURL(url, change_seq, batch.get()); |
301 } | 297 } |
| 298 |
302 // Fail to apply batch to database wouldn't have critical effect, they'll be | 299 // Fail to apply batch to database wouldn't have critical effect, they'll be |
303 // just marked deleted on next relaunch. | 300 // just marked deleted on next relaunch. |
304 tracker_db_->WriteBatch(batch.Pass()); | 301 tracker_db_->WriteBatch(batch.Pass()); |
305 UpdateNumChanges(); | 302 UpdateNumChanges(); |
306 } | 303 } |
307 | 304 |
308 void LocalFileChangeTracker::UpdateNumChanges() { | 305 void LocalFileChangeTracker::UpdateNumChanges() { |
309 base::AutoLock lock(num_changes_lock_); | 306 base::AutoLock lock(num_changes_lock_); |
310 num_changes_ = static_cast<int64>(change_seqs_.size()); | 307 num_changes_ = static_cast<int64>(change_seqs_.size()); |
311 } | 308 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 LOG(WARNING) << "Failed to access local file."; | 405 LOG(WARNING) << "Failed to access local file."; |
409 break; | 406 break; |
410 } | 407 } |
411 } | 408 } |
412 return SYNC_STATUS_OK; | 409 return SYNC_STATUS_OK; |
413 } | 410 } |
414 | 411 |
415 void LocalFileChangeTracker::RecordChange( | 412 void LocalFileChangeTracker::RecordChange( |
416 const FileSystemURL& url, const FileChange& change) { | 413 const FileSystemURL& url, const FileChange& change) { |
417 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); | 414 DCHECK(file_task_runner_->RunsTasksOnCurrentThread()); |
| 415 int change_seq = current_change_seq_number_++; |
418 if (ContainsKey(demoted_changes_, url)) { | 416 if (ContainsKey(demoted_changes_, url)) { |
419 RecordChangeToChangeMaps(url, change, 0, &demoted_changes_, NULL); | 417 RecordChangeToChangeMaps(url, change, change_seq, |
420 return; | 418 &demoted_changes_, NULL); |
| 419 } else { |
| 420 RecordChangeToChangeMaps(url, change, change_seq, &changes_, &change_seqs_); |
421 } | 421 } |
422 int change_seq = current_change_seq_++; | |
423 RecordChangeToChangeMaps(url, change, change_seq, &changes_, &change_seqs_); | |
424 if (ContainsKey(mirror_changes_, url)) | 422 if (ContainsKey(mirror_changes_, url)) |
425 RecordChangeToChangeMaps(url, change, change_seq, &mirror_changes_, NULL); | 423 RecordChangeToChangeMaps(url, change, change_seq, &mirror_changes_, NULL); |
426 UpdateNumChanges(); | 424 UpdateNumChanges(); |
427 } | 425 } |
428 | 426 |
429 // static | 427 // static |
430 void LocalFileChangeTracker::RecordChangeToChangeMaps( | 428 void LocalFileChangeTracker::RecordChangeToChangeMaps( |
431 const FileSystemURL& url, | 429 const FileSystemURL& url, |
432 const FileChange& change, | 430 const FileChange& change, |
433 int new_change_seq, | 431 int new_change_seq, |
434 FileChangeMap* changes, | 432 FileChangeMap* changes, |
435 ChangeSeqMap* change_seqs) { | 433 ChangeSeqMap* change_seqs) { |
436 ChangeInfo& info = (*changes)[url]; | 434 ChangeInfo& info = (*changes)[url]; |
437 if (info.change_seq >= 0 && change_seqs) | 435 if (info.change_seq >= 0 && change_seqs) |
438 change_seqs->erase(info.change_seq); | 436 change_seqs->erase(info.change_seq); |
439 info.change_list.Update(change); | 437 info.change_list.Update(change); |
440 if (info.change_list.empty()) { | 438 if (info.change_list.empty()) { |
441 changes->erase(url); | 439 changes->erase(url); |
442 return; | 440 return; |
443 } | 441 } |
444 info.change_seq = new_change_seq; | 442 info.change_seq = new_change_seq; |
445 if (change_seqs) | 443 if (change_seqs) |
446 (*change_seqs)[info.change_seq] = url; | 444 (*change_seqs)[info.change_seq] = url; |
447 } | 445 } |
448 | 446 |
| 447 void LocalFileChangeTracker::ResetForURL(const fileapi::FileSystemURL& url, |
| 448 int change_seq, |
| 449 leveldb::WriteBatch* batch) { |
| 450 mirror_changes_.erase(url); |
| 451 demoted_changes_.erase(url); |
| 452 change_seqs_.erase(change_seq); |
| 453 changes_.erase(url); |
| 454 |
| 455 std::string serialized_url; |
| 456 if (!SerializeSyncableFileSystemURL(url, &serialized_url)) { |
| 457 NOTREACHED() << "Failed to serialize: " << url.DebugString(); |
| 458 return; |
| 459 } |
| 460 batch->Delete(serialized_url); |
| 461 } |
| 462 |
449 // TrackerDB ------------------------------------------------------------------- | 463 // TrackerDB ------------------------------------------------------------------- |
450 | 464 |
451 LocalFileChangeTracker::TrackerDB::TrackerDB(const base::FilePath& base_path, | 465 LocalFileChangeTracker::TrackerDB::TrackerDB(const base::FilePath& base_path, |
452 leveldb::Env* env_override) | 466 leveldb::Env* env_override) |
453 : base_path_(base_path), | 467 : base_path_(base_path), |
454 env_override_(env_override), | 468 env_override_(env_override), |
455 db_status_(SYNC_STATUS_OK) {} | 469 db_status_(SYNC_STATUS_OK) {} |
456 | 470 |
457 SyncStatusCode LocalFileChangeTracker::TrackerDB::Init( | 471 SyncStatusCode LocalFileChangeTracker::TrackerDB::Init( |
458 RecoveryOption recovery_option) { | 472 RecoveryOption recovery_option) { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 if (!status.ok() && !status.IsNotFound()) { | 607 if (!status.ok() && !status.IsNotFound()) { |
594 HandleError(FROM_HERE, status); | 608 HandleError(FROM_HERE, status); |
595 db_status_ = LevelDBStatusToSyncStatusCode(status); | 609 db_status_ = LevelDBStatusToSyncStatusCode(status); |
596 db_.reset(); | 610 db_.reset(); |
597 return db_status_; | 611 return db_status_; |
598 } | 612 } |
599 return SYNC_STATUS_OK; | 613 return SYNC_STATUS_OK; |
600 } | 614 } |
601 | 615 |
602 } // namespace sync_file_system | 616 } // namespace sync_file_system |
OLD | NEW |