| 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 |