Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: chrome/browser/sync/syncable/syncable.cc

Issue 7190001: [Sync] Split DirectoryChangeListener for thread-safety (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix copyright Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/sync/syncable/syncable.h ('k') | chrome/browser/sync/syncable/syncable_mock.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/sync/syncable/syncable.h ('k') | chrome/browser/sync/syncable/syncable_mock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698