OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/syncable/syncable.h" | 5 #include "chrome/browser/sync/syncable/syncable.h" |
6 | 6 |
7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
8 | 8 |
9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
10 #if defined(OS_POSIX) | 10 #if defined(OS_POSIX) |
(...skipping 18 matching lines...) Expand all Loading... |
29 | 29 |
30 #include "base/hash_tables.h" | 30 #include "base/hash_tables.h" |
31 #include "base/file_util.h" | 31 #include "base/file_util.h" |
32 #include "base/logging.h" | 32 #include "base/logging.h" |
33 #include "base/memory/scoped_ptr.h" | 33 #include "base/memory/scoped_ptr.h" |
34 #include "base/perftimer.h" | 34 #include "base/perftimer.h" |
35 #include "base/string_number_conversions.h" | 35 #include "base/string_number_conversions.h" |
36 #include "base/string_util.h" | 36 #include "base/string_util.h" |
37 #include "base/stl_util-inl.h" | 37 #include "base/stl_util-inl.h" |
38 #include "base/time.h" | 38 #include "base/time.h" |
| 39 #include "base/tracked.h" |
39 #include "base/utf_string_conversions.h" | 40 #include "base/utf_string_conversions.h" |
40 #include "base/values.h" | 41 #include "base/values.h" |
41 #include "chrome/browser/sync/engine/syncer.h" | 42 #include "chrome/browser/sync/engine/syncer.h" |
42 #include "chrome/browser/sync/engine/syncer_util.h" | 43 #include "chrome/browser/sync/engine/syncer_util.h" |
43 #include "chrome/browser/sync/protocol/proto_value_conversions.h" | 44 #include "chrome/browser/sync/protocol/proto_value_conversions.h" |
44 #include "chrome/browser/sync/protocol/service_constants.h" | 45 #include "chrome/browser/sync/protocol/service_constants.h" |
45 #include "chrome/browser/sync/syncable/directory_backing_store.h" | 46 #include "chrome/browser/sync/syncable/directory_backing_store.h" |
46 #include "chrome/browser/sync/syncable/directory_change_listener.h" | 47 #include "chrome/browser/sync/syncable/directory_change_delegate.h" |
47 #include "chrome/browser/sync/syncable/directory_manager.h" | 48 #include "chrome/browser/sync/syncable/directory_manager.h" |
48 #include "chrome/browser/sync/syncable/model_type.h" | 49 #include "chrome/browser/sync/syncable/model_type.h" |
49 #include "chrome/browser/sync/syncable/syncable-inl.h" | 50 #include "chrome/browser/sync/syncable/syncable-inl.h" |
50 #include "chrome/browser/sync/syncable/syncable_changes_version.h" | 51 #include "chrome/browser/sync/syncable/syncable_changes_version.h" |
51 #include "chrome/browser/sync/syncable/syncable_columns.h" | 52 #include "chrome/browser/sync/syncable/syncable_columns.h" |
52 #include "chrome/browser/sync/syncable/syncable_enum_conversions.h" | 53 #include "chrome/browser/sync/syncable/syncable_enum_conversions.h" |
| 54 #include "chrome/browser/sync/syncable/transaction_observer.h" |
| 55 #include "chrome/browser/sync/util/logging.h" |
53 #include "chrome/common/deprecated/event_sys-inl.h" | 56 #include "chrome/common/deprecated/event_sys-inl.h" |
54 #include "net/base/escape.h" | 57 #include "net/base/escape.h" |
55 | 58 |
56 namespace { | 59 namespace { |
57 enum InvariantCheckLevel { | 60 enum InvariantCheckLevel { |
58 OFF = 0, | 61 OFF = 0, |
59 VERIFY_IN_MEMORY = 1, | 62 VERIFY_IN_MEMORY = 1, |
60 FULL_DB_VERIFICATION = 2 | 63 FULL_DB_VERIFICATION = 2 |
61 }; | 64 }; |
62 | 65 |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 SetFieldValues(*this, kernel_info, | 319 SetFieldValues(*this, kernel_info, |
317 &GetBitTempString, &Value::CreateBooleanValue, | 320 &GetBitTempString, &Value::CreateBooleanValue, |
318 BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1); | 321 BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1); |
319 | 322 |
320 return kernel_info; | 323 return kernel_info; |
321 } | 324 } |
322 | 325 |
323 /////////////////////////////////////////////////////////////////////////// | 326 /////////////////////////////////////////////////////////////////////////// |
324 // Directory | 327 // Directory |
325 | 328 |
326 void Directory::init_kernel(const std::string& name) { | 329 void Directory::InitKernel(const std::string& name, |
| 330 DirectoryChangeDelegate* delegate) { |
327 DCHECK(kernel_ == NULL); | 331 DCHECK(kernel_ == NULL); |
328 kernel_ = new Kernel(FilePath(), name, KernelLoadInfo()); | 332 kernel_ = new Kernel(FilePath(), name, KernelLoadInfo(), delegate); |
329 } | 333 } |
330 | 334 |
331 Directory::PersistedKernelInfo::PersistedKernelInfo() | 335 Directory::PersistedKernelInfo::PersistedKernelInfo() |
332 : next_id(0) { | 336 : next_id(0) { |
333 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | 337 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { |
334 reset_download_progress(ModelTypeFromInt(i)); | 338 reset_download_progress(ModelTypeFromInt(i)); |
335 } | 339 } |
336 autofill_migration_state = NOT_DETERMINED; | 340 autofill_migration_state = NOT_DETERMINED; |
337 memset(&autofill_migration_debug_info, 0, | 341 memset(&autofill_migration_debug_info, 0, |
338 sizeof(autofill_migration_debug_info)); | 342 sizeof(autofill_migration_debug_info)); |
(...skipping 10 matching lines...) Expand all Loading... |
349 } | 353 } |
350 | 354 |
351 Directory::SaveChangesSnapshot::SaveChangesSnapshot() | 355 Directory::SaveChangesSnapshot::SaveChangesSnapshot() |
352 : kernel_info_status(KERNEL_SHARE_INFO_INVALID) { | 356 : kernel_info_status(KERNEL_SHARE_INFO_INVALID) { |
353 } | 357 } |
354 | 358 |
355 Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {} | 359 Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {} |
356 | 360 |
357 Directory::Kernel::Kernel(const FilePath& db_path, | 361 Directory::Kernel::Kernel(const FilePath& db_path, |
358 const string& name, | 362 const string& name, |
359 const KernelLoadInfo& info) | 363 const KernelLoadInfo& info, |
| 364 DirectoryChangeDelegate* delegate) |
360 : db_path(db_path), | 365 : db_path(db_path), |
361 refcount(1), | 366 refcount(1), |
362 name(name), | 367 name(name), |
363 metahandles_index(new Directory::MetahandlesIndex), | 368 metahandles_index(new Directory::MetahandlesIndex), |
364 ids_index(new Directory::IdsIndex), | 369 ids_index(new Directory::IdsIndex), |
365 parent_id_child_index(new Directory::ParentIdChildIndex), | 370 parent_id_child_index(new Directory::ParentIdChildIndex), |
366 client_tag_index(new Directory::ClientTagIndex), | 371 client_tag_index(new Directory::ClientTagIndex), |
367 unapplied_update_metahandles(new MetahandleSet), | 372 unapplied_update_metahandles(new MetahandleSet), |
368 unsynced_metahandles(new MetahandleSet), | 373 unsynced_metahandles(new MetahandleSet), |
369 dirty_metahandles(new MetahandleSet), | 374 dirty_metahandles(new MetahandleSet), |
370 metahandles_to_purge(new MetahandleSet), | 375 metahandles_to_purge(new MetahandleSet), |
371 channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)), | 376 channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)), |
372 info_status(Directory::KERNEL_SHARE_INFO_VALID), | 377 info_status(Directory::KERNEL_SHARE_INFO_VALID), |
373 persisted_info(info.kernel_info), | 378 persisted_info(info.kernel_info), |
374 cache_guid(info.cache_guid), | 379 cache_guid(info.cache_guid), |
375 next_metahandle(info.max_metahandle + 1) { | 380 next_metahandle(info.max_metahandle + 1), |
| 381 delegate(delegate), |
| 382 observers(new ObserverListThreadSafe<TransactionObserver>()) { |
| 383 DCHECK(delegate); |
376 } | 384 } |
377 | 385 |
378 void Directory::Kernel::AddRef() { | 386 void Directory::Kernel::AddRef() { |
379 base::subtle::NoBarrier_AtomicIncrement(&refcount, 1); | 387 base::subtle::NoBarrier_AtomicIncrement(&refcount, 1); |
380 } | 388 } |
381 | 389 |
382 void Directory::Kernel::Release() { | 390 void Directory::Kernel::Release() { |
383 if (!base::subtle::NoBarrier_AtomicIncrement(&refcount, -1)) | 391 if (!base::subtle::NoBarrier_AtomicIncrement(&refcount, -1)) |
384 delete this; | 392 delete this; |
385 } | 393 } |
386 | 394 |
387 void Directory::Kernel::AddChangeListener( | |
388 DirectoryChangeListener* listener) { | |
389 base::AutoLock lock(change_listeners_lock_); | |
390 change_listeners_.AddObserver(listener); | |
391 } | |
392 | |
393 void Directory::Kernel::RemoveChangeListener( | |
394 DirectoryChangeListener* listener) { | |
395 base::AutoLock lock(change_listeners_lock_); | |
396 change_listeners_.RemoveObserver(listener); | |
397 } | |
398 | |
399 // Note: it is possible that a listener will remove itself after we | |
400 // have made a copy, but before the copy is consumed. This could | |
401 // theoretically result in accessing a garbage pointer, but can only | |
402 // occur when an about:sync window is closed in the middle of a | |
403 // notification. See crbug.com/85481. | |
404 void Directory::Kernel::CopyChangeListeners( | |
405 ObserverList<DirectoryChangeListener>* change_listeners) { | |
406 DCHECK_EQ(0U, change_listeners->size()); | |
407 base::AutoLock lock(change_listeners_lock_); | |
408 ObserverListBase<DirectoryChangeListener>::Iterator it(change_listeners_); | |
409 DirectoryChangeListener* obs; | |
410 while ((obs = it.GetNext()) != NULL) | |
411 change_listeners->AddObserver(obs); | |
412 } | |
413 | |
414 Directory::Kernel::~Kernel() { | 395 Directory::Kernel::~Kernel() { |
415 CHECK_EQ(0, refcount); | 396 CHECK_EQ(0, refcount); |
416 delete channel; | 397 delete channel; |
417 delete unsynced_metahandles; | 398 delete unsynced_metahandles; |
418 delete unapplied_update_metahandles; | 399 delete unapplied_update_metahandles; |
419 delete dirty_metahandles; | 400 delete dirty_metahandles; |
420 delete metahandles_to_purge; | 401 delete metahandles_to_purge; |
421 delete parent_id_child_index; | 402 delete parent_id_child_index; |
422 delete client_tag_index; | 403 delete client_tag_index; |
423 delete ids_index; | 404 delete ids_index; |
424 STLDeleteElements(metahandles_index); | 405 STLDeleteElements(metahandles_index); |
425 delete metahandles_index; | 406 delete metahandles_index; |
426 } | 407 } |
427 | 408 |
428 Directory::Directory() : kernel_(NULL), store_(NULL) { | 409 Directory::Directory() : kernel_(NULL), store_(NULL) { |
429 } | 410 } |
430 | 411 |
431 Directory::~Directory() { | 412 Directory::~Directory() { |
432 Close(); | 413 Close(); |
433 } | 414 } |
434 | 415 |
435 DirOpenResult Directory::Open(const FilePath& file_path, const string& name) { | 416 DirOpenResult Directory::Open(const FilePath& file_path, const string& name, |
436 const DirOpenResult result = OpenImpl(file_path, name); | 417 DirectoryChangeDelegate* delegate) { |
| 418 const DirOpenResult result = OpenImpl(file_path, name, delegate); |
437 if (OPENED != result) | 419 if (OPENED != result) |
438 Close(); | 420 Close(); |
439 return result; | 421 return result; |
440 } | 422 } |
441 | 423 |
442 void Directory::InitializeIndices() { | 424 void Directory::InitializeIndices() { |
443 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); | 425 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); |
444 for (; it != kernel_->metahandles_index->end(); ++it) { | 426 for (; it != kernel_->metahandles_index->end(); ++it) { |
445 EntryKernel* entry = *it; | 427 EntryKernel* entry = *it; |
446 InitializeIndexEntry<ParentIdAndHandleIndexer>(entry, | 428 InitializeIndexEntry<ParentIdAndHandleIndexer>(entry, |
447 kernel_->parent_id_child_index); | 429 kernel_->parent_id_child_index); |
448 InitializeIndexEntry<IdIndexer>(entry, kernel_->ids_index); | 430 InitializeIndexEntry<IdIndexer>(entry, kernel_->ids_index); |
449 InitializeIndexEntry<ClientTagIndexer>(entry, kernel_->client_tag_index); | 431 InitializeIndexEntry<ClientTagIndexer>(entry, kernel_->client_tag_index); |
450 if (entry->ref(IS_UNSYNCED)) | 432 if (entry->ref(IS_UNSYNCED)) |
451 kernel_->unsynced_metahandles->insert(entry->ref(META_HANDLE)); | 433 kernel_->unsynced_metahandles->insert(entry->ref(META_HANDLE)); |
452 if (entry->ref(IS_UNAPPLIED_UPDATE)) | 434 if (entry->ref(IS_UNAPPLIED_UPDATE)) |
453 kernel_->unapplied_update_metahandles->insert(entry->ref(META_HANDLE)); | 435 kernel_->unapplied_update_metahandles->insert(entry->ref(META_HANDLE)); |
454 DCHECK(!entry->is_dirty()); | 436 DCHECK(!entry->is_dirty()); |
455 } | 437 } |
456 } | 438 } |
457 | 439 |
458 DirectoryBackingStore* Directory::CreateBackingStore( | 440 DirectoryBackingStore* Directory::CreateBackingStore( |
459 const string& dir_name, const FilePath& backing_filepath) { | 441 const string& dir_name, const FilePath& backing_filepath) { |
460 return new DirectoryBackingStore(dir_name, backing_filepath); | 442 return new DirectoryBackingStore(dir_name, backing_filepath); |
461 } | 443 } |
462 | 444 |
463 DirOpenResult Directory::OpenImpl(const FilePath& file_path, | 445 DirOpenResult Directory::OpenImpl(const FilePath& file_path, |
464 const string& name) { | 446 const string& name, |
| 447 DirectoryChangeDelegate* delegate) { |
465 DCHECK_EQ(static_cast<DirectoryBackingStore*>(NULL), store_); | 448 DCHECK_EQ(static_cast<DirectoryBackingStore*>(NULL), store_); |
466 FilePath db_path(file_path); | 449 FilePath db_path(file_path); |
467 file_util::AbsolutePath(&db_path); | 450 file_util::AbsolutePath(&db_path); |
468 store_ = CreateBackingStore(name, db_path); | 451 store_ = CreateBackingStore(name, db_path); |
469 | 452 |
470 KernelLoadInfo info; | 453 KernelLoadInfo info; |
471 // Temporary indices before kernel_ initialized in case Load fails. We 0(1) | 454 // Temporary indices before kernel_ initialized in case Load fails. We 0(1) |
472 // swap these later. | 455 // swap these later. |
473 MetahandlesIndex metas_bucket; | 456 MetahandlesIndex metas_bucket; |
474 DirOpenResult result = store_->Load(&metas_bucket, &info); | 457 DirOpenResult result = store_->Load(&metas_bucket, &info); |
475 if (OPENED != result) | 458 if (OPENED != result) |
476 return result; | 459 return result; |
477 | 460 |
478 kernel_ = new Kernel(db_path, name, info); | 461 kernel_ = new Kernel(db_path, name, info, delegate); |
479 kernel_->metahandles_index->swap(metas_bucket); | 462 kernel_->metahandles_index->swap(metas_bucket); |
480 InitializeIndices(); | 463 InitializeIndices(); |
481 return OPENED; | 464 return OPENED; |
482 } | 465 } |
483 | 466 |
484 void Directory::Close() { | 467 void Directory::Close() { |
485 if (store_) | 468 if (store_) |
486 delete store_; | 469 delete store_; |
487 store_ = NULL; | 470 store_ = NULL; |
488 if (kernel_) { | 471 if (kernel_) { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 CHECK_EQ(kernel_->dirty_metahandles->count(handle), 0U); | 647 CHECK_EQ(kernel_->dirty_metahandles->count(handle), 0U); |
665 // TODO(tim): Bug 49278. | 648 // TODO(tim): Bug 49278. |
666 CHECK(!kernel_->unsynced_metahandles->count(handle)); | 649 CHECK(!kernel_->unsynced_metahandles->count(handle)); |
667 CHECK(!kernel_->unapplied_update_metahandles->count(handle)); | 650 CHECK(!kernel_->unapplied_update_metahandles->count(handle)); |
668 } | 651 } |
669 | 652 |
670 return safe; | 653 return safe; |
671 } | 654 } |
672 | 655 |
673 void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) { | 656 void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) { |
674 ReadTransaction trans(this, __FILE__, __LINE__); | 657 ReadTransaction trans(this, FROM_HERE); |
675 ScopedKernelLock lock(this); | 658 ScopedKernelLock lock(this); |
676 // Deep copy dirty entries from kernel_->metahandles_index into snapshot and | 659 // Deep copy dirty entries from kernel_->metahandles_index into snapshot and |
677 // clear dirty flags. | 660 // clear dirty flags. |
678 | 661 |
679 for (MetahandleSet::const_iterator i = kernel_->dirty_metahandles->begin(); | 662 for (MetahandleSet::const_iterator i = kernel_->dirty_metahandles->begin(); |
680 i != kernel_->dirty_metahandles->end(); ++i) { | 663 i != kernel_->dirty_metahandles->end(); ++i) { |
681 EntryKernel* entry = GetEntryByHandle(*i, &lock); | 664 EntryKernel* entry = GetEntryByHandle(*i, &lock); |
682 if (!entry) | 665 if (!entry) |
683 continue; | 666 continue; |
684 // Skip over false positives; it happens relatively infrequently. | 667 // Skip over false positives; it happens relatively infrequently. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 // Handle success or failure. | 705 // Handle success or failure. |
723 if (success) | 706 if (success) |
724 VacuumAfterSaveChanges(snapshot); | 707 VacuumAfterSaveChanges(snapshot); |
725 else | 708 else |
726 HandleSaveChangesFailure(snapshot); | 709 HandleSaveChangesFailure(snapshot); |
727 return success; | 710 return success; |
728 } | 711 } |
729 | 712 |
730 void Directory::VacuumAfterSaveChanges(const SaveChangesSnapshot& snapshot) { | 713 void Directory::VacuumAfterSaveChanges(const SaveChangesSnapshot& snapshot) { |
731 // Need a write transaction as we are about to permanently purge entries. | 714 // Need a write transaction as we are about to permanently purge entries. |
732 WriteTransaction trans(this, VACUUM_AFTER_SAVE, __FILE__, __LINE__); | 715 WriteTransaction trans(this, VACUUM_AFTER_SAVE, FROM_HERE); |
733 ScopedKernelLock lock(this); | 716 ScopedKernelLock lock(this); |
734 kernel_->flushed_metahandles.Push(0); // Begin flush marker | 717 kernel_->flushed_metahandles.Push(0); // Begin flush marker |
735 // Now drop everything we can out of memory. | 718 // Now drop everything we can out of memory. |
736 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin(); | 719 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin(); |
737 i != snapshot.dirty_metas.end(); ++i) { | 720 i != snapshot.dirty_metas.end(); ++i) { |
738 kernel_->needle.put(META_HANDLE, i->ref(META_HANDLE)); | 721 kernel_->needle.put(META_HANDLE, i->ref(META_HANDLE)); |
739 MetahandlesIndex::iterator found = | 722 MetahandlesIndex::iterator found = |
740 kernel_->metahandles_index->find(&kernel_->needle); | 723 kernel_->metahandles_index->find(&kernel_->needle); |
741 EntryKernel* entry = (found == kernel_->metahandles_index->end() ? | 724 EntryKernel* entry = (found == kernel_->metahandles_index->end() ? |
742 NULL : *found); | 725 NULL : *found); |
(...skipping 20 matching lines...) Expand all Loading... |
763 void Directory::PurgeEntriesWithTypeIn(const std::set<ModelType>& types) { | 746 void Directory::PurgeEntriesWithTypeIn(const std::set<ModelType>& types) { |
764 if (types.count(UNSPECIFIED) != 0U || types.count(TOP_LEVEL_FOLDER) != 0U) { | 747 if (types.count(UNSPECIFIED) != 0U || types.count(TOP_LEVEL_FOLDER) != 0U) { |
765 NOTREACHED() << "Don't support purging unspecified or top level entries."; | 748 NOTREACHED() << "Don't support purging unspecified or top level entries."; |
766 return; | 749 return; |
767 } | 750 } |
768 | 751 |
769 if (types.empty()) | 752 if (types.empty()) |
770 return; | 753 return; |
771 | 754 |
772 { | 755 { |
773 WriteTransaction trans(this, PURGE_ENTRIES, __FILE__, __LINE__); | 756 WriteTransaction trans(this, PURGE_ENTRIES, FROM_HERE); |
774 { | 757 { |
775 ScopedKernelLock lock(this); | 758 ScopedKernelLock lock(this); |
776 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); | 759 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); |
777 while (it != kernel_->metahandles_index->end()) { | 760 while (it != kernel_->metahandles_index->end()) { |
778 const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS); | 761 const sync_pb::EntitySpecifics& local_specifics = (*it)->ref(SPECIFICS); |
779 const sync_pb::EntitySpecifics& server_specifics = | 762 const sync_pb::EntitySpecifics& server_specifics = |
780 (*it)->ref(SERVER_SPECIFICS); | 763 (*it)->ref(SERVER_SPECIFICS); |
781 ModelType local_type = GetModelTypeFromSpecifics(local_specifics); | 764 ModelType local_type = GetModelTypeFromSpecifics(local_specifics); |
782 ModelType server_type = GetModelTypeFromSpecifics(server_specifics); | 765 ModelType server_type = GetModelTypeFromSpecifics(server_specifics); |
783 | 766 |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1179 int64 elapsed_ms = check_timer.Elapsed().InMilliseconds(); | 1162 int64 elapsed_ms = check_timer.Elapsed().InMilliseconds(); |
1180 if (elapsed_ms > max_ms) { | 1163 if (elapsed_ms > max_ms) { |
1181 VLOG(1) << "Cutting Invariant check short after " << elapsed_ms | 1164 VLOG(1) << "Cutting Invariant check short after " << elapsed_ms |
1182 << "ms. Processed " << entries_done << "/" << handles.size() | 1165 << "ms. Processed " << entries_done << "/" << handles.size() |
1183 << " entries"; | 1166 << " entries"; |
1184 return; | 1167 return; |
1185 } | 1168 } |
1186 } | 1169 } |
1187 } | 1170 } |
1188 | 1171 |
1189 void Directory::AddChangeListener(DirectoryChangeListener* listener) { | 1172 void Directory::AddTransactionObserver(TransactionObserver* observer) { |
1190 kernel_->AddChangeListener(listener); | 1173 kernel_->observers->AddObserver(observer); |
1191 } | 1174 } |
1192 | 1175 |
1193 void Directory::RemoveChangeListener(DirectoryChangeListener* listener) { | 1176 void Directory::RemoveTransactionObserver(TransactionObserver* observer) { |
1194 kernel_->RemoveChangeListener(listener); | 1177 kernel_->observers->RemoveObserver(observer); |
1195 } | 1178 } |
1196 | 1179 |
1197 /////////////////////////////////////////////////////////////////////////////// | 1180 /////////////////////////////////////////////////////////////////////////////// |
1198 // ScopedKernelLock | 1181 // ScopedKernelLock |
1199 | 1182 |
1200 ScopedKernelLock::ScopedKernelLock(const Directory* dir) | 1183 ScopedKernelLock::ScopedKernelLock(const Directory* dir) |
1201 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) { | 1184 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) { |
1202 } | 1185 } |
1203 | 1186 |
1204 /////////////////////////////////////////////////////////////////////////// | 1187 /////////////////////////////////////////////////////////////////////////// |
1205 // Transactions | 1188 // Transactions |
1206 | 1189 |
1207 // Helper functions/macros to do logging with a source file/line. | |
1208 | |
1209 namespace { | |
1210 | |
1211 bool VlogIsOn(const char* source_file, int verbose_level) { | |
1212 return (verbose_level <= | |
1213 logging::GetVlogLevelHelper(source_file, ::strlen(source_file))); | |
1214 } | |
1215 | |
1216 } // namespace | |
1217 | |
1218 #define VLOG_SRC_STREAM(source_file, line, verbose_level) \ | |
1219 logging::LogMessage(source_file, line, -verbose_level).stream() | |
1220 | |
1221 #define VLOG_SRC(source_file, line, verbose_level) \ | |
1222 LAZY_STREAM(VLOG_SRC_STREAM(source_file, line, verbose_level), \ | |
1223 VLOG_IS_ON(verbose_level) || \ | |
1224 VlogIsOn(source_file, verbose_level)) | |
1225 | |
1226 void BaseTransaction::Lock() { | 1190 void BaseTransaction::Lock() { |
1227 base::TimeTicks start_time = base::TimeTicks::Now(); | 1191 base::TimeTicks start_time = base::TimeTicks::Now(); |
1228 | 1192 |
1229 dirkernel_->transaction_mutex.Acquire(); | 1193 dirkernel_->transaction_mutex.Acquire(); |
1230 | 1194 |
1231 time_acquired_ = base::TimeTicks::Now(); | 1195 time_acquired_ = base::TimeTicks::Now(); |
1232 const base::TimeDelta elapsed = time_acquired_ - start_time; | 1196 const base::TimeDelta elapsed = time_acquired_ - start_time; |
1233 VLOG_SRC(source_file_, line_, 1) | 1197 VLOG_LOC(from_here_, 1) |
1234 << name_ << " transaction waited " | 1198 << name_ << " transaction waited " |
1235 << elapsed.InSecondsF() << " seconds."; | 1199 << elapsed.InSecondsF() << " seconds."; |
1236 } | 1200 } |
1237 | 1201 |
1238 BaseTransaction::BaseTransaction(Directory* directory, const char* name, | 1202 BaseTransaction::BaseTransaction( |
1239 const char* source_file, int line, WriterTag writer) | 1203 Directory* directory, const char* name, |
| 1204 const tracked_objects::Location& from_here, WriterTag writer) |
1240 : directory_(directory), dirkernel_(directory->kernel_), name_(name), | 1205 : directory_(directory), dirkernel_(directory->kernel_), name_(name), |
1241 source_file_(source_file), line_(line), writer_(writer) { | 1206 from_here_(from_here), writer_(writer) { |
| 1207 dirkernel_->observers->Notify( |
| 1208 &TransactionObserver::OnTransactionStart, from_here_, writer_); |
1242 Lock(); | 1209 Lock(); |
1243 } | 1210 } |
1244 | 1211 |
1245 BaseTransaction::BaseTransaction(Directory* directory) | 1212 BaseTransaction::~BaseTransaction() { |
1246 : directory_(directory), | 1213 dirkernel_->observers->Notify( |
1247 dirkernel_(NULL), | 1214 &TransactionObserver::OnTransactionEnd, from_here_, writer_); |
1248 name_(NULL), | |
1249 source_file_(NULL), | |
1250 line_(0), | |
1251 writer_(INVALID) { | |
1252 } | 1215 } |
1253 | 1216 |
1254 BaseTransaction::~BaseTransaction() {} | |
1255 | |
1256 void BaseTransaction::UnlockAndLog(OriginalEntries* entries) { | 1217 void BaseTransaction::UnlockAndLog(OriginalEntries* entries) { |
1257 // Work while trasnaction mutex is held | 1218 // Work while transaction mutex is held |
1258 ModelTypeBitSet models_with_changes; | 1219 ModelTypeBitSet models_with_changes; |
1259 if (!NotifyTransactionChangingAndEnding(entries, &models_with_changes)) | 1220 if (!NotifyTransactionChangingAndEnding(entries, &models_with_changes)) |
1260 return; | 1221 return; |
1261 | 1222 |
1262 // Work after mutex is relased. | 1223 // Work after mutex is relased. |
1263 NotifyTransactionComplete(models_with_changes); | 1224 NotifyTransactionComplete(models_with_changes); |
1264 } | 1225 } |
1265 | 1226 |
1266 bool BaseTransaction::NotifyTransactionChangingAndEnding( | 1227 bool BaseTransaction::NotifyTransactionChangingAndEnding( |
1267 OriginalEntries* entries, | 1228 OriginalEntries* entries, |
1268 ModelTypeBitSet* models_with_changes) { | 1229 ModelTypeBitSet* models_with_changes) { |
1269 dirkernel_->transaction_mutex.AssertAcquired(); | 1230 dirkernel_->transaction_mutex.AssertAcquired(); |
1270 | 1231 |
1271 scoped_ptr<OriginalEntries> originals(entries); | 1232 scoped_ptr<OriginalEntries> originals(entries); |
1272 const base::TimeDelta elapsed = base::TimeTicks::Now() - time_acquired_; | 1233 const base::TimeDelta elapsed = base::TimeTicks::Now() - time_acquired_; |
1273 VLOG_SRC(source_file_, line_, 1) | 1234 VLOG_LOC(from_here_, 1) |
1274 << name_ << " transaction completed in " << elapsed.InSecondsF() | 1235 << name_ << " transaction completed in " << elapsed.InSecondsF() |
1275 << " seconds."; | 1236 << " seconds."; |
1276 | 1237 |
1277 ObserverList<DirectoryChangeListener> change_listeners; | 1238 if (NULL == originals.get() || originals->empty()) { |
1278 dirkernel_->CopyChangeListeners(&change_listeners); | |
1279 | |
1280 if (NULL == originals.get() || originals->empty() || | |
1281 (change_listeners.size() == 0)) { | |
1282 dirkernel_->transaction_mutex.Release(); | 1239 dirkernel_->transaction_mutex.Release(); |
1283 return false; | 1240 return false; |
1284 } | 1241 } |
1285 | 1242 |
| 1243 DirectoryChangeDelegate* const delegate = dirkernel_->delegate; |
1286 if (writer_ == syncable::SYNCAPI) { | 1244 if (writer_ == syncable::SYNCAPI) { |
1287 FOR_EACH_OBSERVER(DirectoryChangeListener, | 1245 delegate->HandleCalculateChangesChangeEventFromSyncApi(*originals, this); |
1288 change_listeners, | |
1289 HandleCalculateChangesChangeEventFromSyncApi( | |
1290 *originals.get(), | |
1291 writer_, | |
1292 this)); | |
1293 } else { | 1246 } else { |
1294 FOR_EACH_OBSERVER(DirectoryChangeListener, | 1247 delegate->HandleCalculateChangesChangeEventFromSyncer(*originals, this); |
1295 change_listeners, | |
1296 HandleCalculateChangesChangeEventFromSyncer( | |
1297 *originals.get(), | |
1298 writer_, | |
1299 this)); | |
1300 } | 1248 } |
1301 | 1249 |
1302 // Set |*models_with_changes| to the union of the return values of | 1250 *models_with_changes = delegate->HandleTransactionEndingChangeEvent(this); |
1303 // the HandleTransactionEndingChangeEvent call to each | 1251 |
1304 // DirectoryChangeListener. | 1252 dirkernel_->observers->Notify( |
1305 { | 1253 &TransactionObserver::OnTransactionMutate, |
1306 ObserverList<DirectoryChangeListener>::Iterator it(change_listeners); | 1254 from_here_, writer_, *originals, *models_with_changes); |
1307 DirectoryChangeListener* obs = NULL; | |
1308 while ((obs = it.GetNext()) != NULL) { | |
1309 *models_with_changes |= obs->HandleTransactionEndingChangeEvent(this); | |
1310 } | |
1311 }; | |
1312 | 1255 |
1313 // Release the transaction. Note, once the transaction is released this thread | 1256 // Release the transaction. Note, once the transaction is released this thread |
1314 // can be interrupted by another that was waiting for the transaction, | 1257 // can be interrupted by another that was waiting for the transaction, |
1315 // resulting in this code possibly being interrupted with another thread | 1258 // resulting in this code possibly being interrupted with another thread |
1316 // performing following the same code path. From this point foward, only | 1259 // performing following the same code path. From this point forward, only |
1317 // local state can be touched. | 1260 // local state can be touched. |
1318 dirkernel_->transaction_mutex.Release(); | 1261 dirkernel_->transaction_mutex.Release(); |
1319 return true; | 1262 return true; |
1320 } | 1263 } |
1321 | 1264 |
1322 void BaseTransaction::NotifyTransactionComplete( | 1265 void BaseTransaction::NotifyTransactionComplete( |
1323 ModelTypeBitSet models_with_changes) { | 1266 ModelTypeBitSet models_with_changes) { |
1324 ObserverList<DirectoryChangeListener> change_listeners; | 1267 dirkernel_->delegate->HandleTransactionCompleteChangeEvent( |
1325 dirkernel_->CopyChangeListeners(&change_listeners); | 1268 models_with_changes); |
1326 FOR_EACH_OBSERVER(DirectoryChangeListener, | |
1327 change_listeners, | |
1328 HandleTransactionCompleteChangeEvent( | |
1329 models_with_changes)); | |
1330 } | 1269 } |
1331 | 1270 |
1332 #undef VLOG_SRC | 1271 #undef VLOG_LOC |
1333 | 1272 |
1334 #undef VLOG_SRC_STREAM | 1273 #undef VLOG_LOC_STREAM |
1335 | 1274 |
1336 ReadTransaction::ReadTransaction(Directory* directory, const char* file, | 1275 ReadTransaction::ReadTransaction(Directory* directory, |
1337 int line) | 1276 const tracked_objects::Location& location) |
1338 : BaseTransaction(directory, "Read", file, line, INVALID) { | 1277 : BaseTransaction(directory, "Read", location, INVALID) { |
1339 } | 1278 } |
1340 | 1279 |
1341 ReadTransaction::ReadTransaction(const ScopedDirLookup& scoped_dir, | 1280 ReadTransaction::ReadTransaction(const ScopedDirLookup& scoped_dir, |
1342 const char* file, int line) | 1281 const tracked_objects::Location& location) |
1343 : BaseTransaction(scoped_dir.operator -> (), "Read", file, line, INVALID) { | 1282 : BaseTransaction(scoped_dir.operator -> (), "Read", location, INVALID) { |
1344 } | 1283 } |
1345 | 1284 |
1346 ReadTransaction::~ReadTransaction() { | 1285 ReadTransaction::~ReadTransaction() { |
1347 UnlockAndLog(NULL); | 1286 UnlockAndLog(NULL); |
1348 } | 1287 } |
1349 | 1288 |
1350 WriteTransaction::WriteTransaction(Directory* directory, WriterTag writer, | 1289 WriteTransaction::WriteTransaction(Directory* directory, WriterTag writer, |
1351 const char* file, int line) | 1290 const tracked_objects::Location& location) |
1352 : BaseTransaction(directory, "Write", file, line, writer), | 1291 : BaseTransaction(directory, "Write", location, writer), |
1353 originals_(new OriginalEntries) { | 1292 originals_(new OriginalEntries) { |
1354 } | 1293 } |
1355 | 1294 |
1356 WriteTransaction::WriteTransaction(const ScopedDirLookup& scoped_dir, | 1295 WriteTransaction::WriteTransaction(const ScopedDirLookup& scoped_dir, |
1357 WriterTag writer, const char* file, int line) | 1296 WriterTag writer, |
1358 : BaseTransaction(scoped_dir.operator -> (), "Write", file, line, writer), | 1297 const tracked_objects::Location& location) |
| 1298 : BaseTransaction(scoped_dir.operator -> (), "Write", location, writer), |
1359 originals_(new OriginalEntries) { | 1299 originals_(new OriginalEntries) { |
1360 } | 1300 } |
1361 | 1301 |
1362 WriteTransaction::WriteTransaction(Directory *directory) | |
1363 : BaseTransaction(directory), | |
1364 originals_(new OriginalEntries) { | |
1365 } | |
1366 | |
1367 void WriteTransaction::SaveOriginal(EntryKernel* entry) { | 1302 void WriteTransaction::SaveOriginal(EntryKernel* entry) { |
1368 if (NULL == entry) | 1303 if (NULL == entry) |
1369 return; | 1304 return; |
1370 OriginalEntries::iterator i = originals_->lower_bound(*entry); | 1305 OriginalEntries::iterator i = originals_->lower_bound(*entry); |
1371 if (i == originals_->end() || | 1306 if (i == originals_->end() || |
1372 i->ref(META_HANDLE) != entry->ref(META_HANDLE)) { | 1307 i->ref(META_HANDLE) != entry->ref(META_HANDLE)) { |
1373 originals_->insert(i, *entry); | 1308 originals_->insert(i, *entry); |
1374 } | 1309 } |
1375 } | 1310 } |
1376 | 1311 |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2045 CHECK(result); | 1980 CHECK(result); |
2046 for (iterator i = GetParentChildIndexLowerBound(lock, parent_id), | 1981 for (iterator i = GetParentChildIndexLowerBound(lock, parent_id), |
2047 end = GetParentChildIndexUpperBound(lock, parent_id); | 1982 end = GetParentChildIndexUpperBound(lock, parent_id); |
2048 i != end; ++i) { | 1983 i != end; ++i) { |
2049 DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID)); | 1984 DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID)); |
2050 result->push_back((*i)->ref(META_HANDLE)); | 1985 result->push_back((*i)->ref(META_HANDLE)); |
2051 } | 1986 } |
2052 } | 1987 } |
2053 | 1988 |
2054 } // namespace syncable | 1989 } // namespace syncable |
OLD | NEW |