| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/engine/syncer_thread.h" | 5 #include "chrome/browser/sync/engine/syncer_thread.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | |
| 9 #include <queue> | 8 #include <queue> |
| 9 #include <string> |
| 10 #include <vector> |
| 10 | 11 |
| 11 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
| 12 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 13 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| 13 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 14 #include "chrome/browser/sync/engine/model_safe_worker.h" | 15 #include "chrome/browser/sync/engine/model_safe_worker.h" |
| 15 #include "chrome/browser/sync/engine/net/server_connection_manager.h" | 16 #include "chrome/browser/sync/engine/net/server_connection_manager.h" |
| 16 #include "chrome/browser/sync/engine/syncer.h" | 17 #include "chrome/browser/sync/engine/syncer.h" |
| 17 #include "chrome/browser/sync/sessions/sync_session.h" | 18 #include "chrome/browser/sync/sessions/sync_session.h" |
| 18 #include "jingle/notifier/listener/notification_constants.h" | 19 #include "jingle/notifier/listener/notification_constants.h" |
| 19 | 20 |
| 20 #if defined(OS_MACOSX) | 21 #if defined(OS_MACOSX) |
| 21 #include <CoreFoundation/CFNumber.h> | 22 #include <CoreFoundation/CFNumber.h> |
| 22 #include <IOKit/IOTypes.h> | 23 #include <IOKit/IOTypes.h> |
| 23 #include <IOKit/IOKitLib.h> | 24 #include <IOKit/IOKitLib.h> |
| 24 #endif | 25 #endif |
| 25 | 26 |
| 26 using std::priority_queue; | 27 using std::priority_queue; |
| 27 using std::min; | 28 using std::min; |
| 28 using base::Time; | 29 using base::Time; |
| 29 using base::TimeDelta; | 30 using base::TimeDelta; |
| 30 using base::TimeTicks; | 31 using base::TimeTicks; |
| 31 | 32 |
| 32 namespace browser_sync { | 33 namespace browser_sync { |
| 33 | 34 |
| 34 using sessions::SyncSession; | 35 using sessions::SyncSession; |
| 35 using sessions::SyncSessionSnapshot; | 36 using sessions::SyncSessionSnapshot; |
| 36 using sessions::SyncSourceInfo; | 37 using sessions::SyncSourceInfo; |
| 38 using sessions::TypePayloadMap; |
| 37 | 39 |
| 38 // We use high values here to ensure that failure to receive poll updates from | 40 // We use high values here to ensure that failure to receive poll updates from |
| 39 // the server doesn't result in rapid-fire polling from the client due to low | 41 // the server doesn't result in rapid-fire polling from the client due to low |
| 40 // local limits. | 42 // local limits. |
| 41 const int SyncerThread::kDefaultShortPollIntervalSeconds = 3600 * 8; | 43 const int SyncerThread::kDefaultShortPollIntervalSeconds = 3600 * 8; |
| 42 const int SyncerThread::kDefaultLongPollIntervalSeconds = 3600 * 12; | 44 const int SyncerThread::kDefaultLongPollIntervalSeconds = 3600 * 12; |
| 43 | 45 |
| 44 // TODO(tim): This is used to regulate the short poll (when notifications are | 46 // TODO(tim): This is used to regulate the short poll (when notifications are |
| 45 // disabled) based on user idle time. If it is set to a smaller value than | 47 // disabled) based on user idle time. If it is set to a smaller value than |
| 46 // the short poll interval, it basically does nothing; for now, this is what | 48 // the short poll interval, it basically does nothing; for now, this is what |
| 47 // we want and allows stronger control over the poll rate from the server. We | 49 // we want and allows stronger control over the poll rate from the server. We |
| 48 // should probably re-visit this code later and figure out if user idle time | 50 // should probably re-visit this code later and figure out if user idle time |
| 49 // is really something we want and make sure it works, if it is. | 51 // is really something we want and make sure it works, if it is. |
| 50 const int SyncerThread::kDefaultMaxPollIntervalMs = 30 * 60 * 1000; | 52 const int SyncerThread::kDefaultMaxPollIntervalMs = 30 * 60 * 1000; |
| 51 | 53 |
| 52 // Backoff interval randomization factor. | 54 // Backoff interval randomization factor. |
| 53 static const int kBackoffRandomizationFactor = 2; | 55 static const int kBackoffRandomizationFactor = 2; |
| 54 | 56 |
| 55 const int SyncerThread::kMaxBackoffSeconds = 60 * 60 * 4; // 4 hours. | 57 const int SyncerThread::kMaxBackoffSeconds = 60 * 60 * 4; // 4 hours. |
| 56 | 58 |
| 59 void SyncerThread::NudgeSyncerWithPayloads( |
| 60 int milliseconds_from_now, |
| 61 NudgeSource source, |
| 62 const TypePayloadMap& model_types_with_payloads) { |
| 63 base::AutoLock lock(lock_); |
| 64 if (vault_.syncer_ == NULL) { |
| 65 return; |
| 66 } |
| 67 |
| 68 NudgeSyncImpl(milliseconds_from_now, source, model_types_with_payloads); |
| 69 } |
| 70 |
| 57 void SyncerThread::NudgeSyncerWithDataTypes( | 71 void SyncerThread::NudgeSyncerWithDataTypes( |
| 58 int milliseconds_from_now, | 72 int milliseconds_from_now, |
| 59 NudgeSource source, | 73 NudgeSource source, |
| 60 const syncable::ModelTypeBitSet& model_types) { | 74 const syncable::ModelTypeBitSet& model_types) { |
| 61 base::AutoLock lock(lock_); | 75 base::AutoLock lock(lock_); |
| 62 if (vault_.syncer_ == NULL) { | 76 if (vault_.syncer_ == NULL) { |
| 63 return; | 77 return; |
| 64 } | 78 } |
| 65 | 79 |
| 66 NudgeSyncImpl(milliseconds_from_now, source, model_types); | 80 TypePayloadMap model_types_with_payloads = |
| 81 sessions::ModelTypeBitSetToTypePayloadMap(model_types, std::string()); |
| 82 NudgeSyncImpl(milliseconds_from_now, source, model_types_with_payloads); |
| 67 } | 83 } |
| 68 | 84 |
| 69 void SyncerThread::NudgeSyncer( | 85 void SyncerThread::NudgeSyncer( |
| 70 int milliseconds_from_now, | 86 int milliseconds_from_now, |
| 71 NudgeSource source) { | 87 NudgeSource source) { |
| 72 base::AutoLock lock(lock_); | 88 base::AutoLock lock(lock_); |
| 73 if (vault_.syncer_ == NULL) { | 89 if (vault_.syncer_ == NULL) { |
| 74 return; | 90 return; |
| 75 } | 91 } |
| 76 | 92 |
| 77 syncable::ModelTypeBitSet model_types; // All false by default. | 93 // Set all enabled datatypes. |
| 78 NudgeSyncImpl(milliseconds_from_now, source, model_types); | 94 ModelSafeRoutingInfo routes; |
| 95 session_context_->registrar()->GetModelSafeRoutingInfo(&routes); |
| 96 TypePayloadMap model_types_with_payloads = |
| 97 sessions::RoutingInfoToTypePayloadMap(routes, std::string()); |
| 98 NudgeSyncImpl(milliseconds_from_now, source, model_types_with_payloads); |
| 79 } | 99 } |
| 80 | 100 |
| 81 SyncerThread::SyncerThread(sessions::SyncSessionContext* context) | 101 SyncerThread::SyncerThread(sessions::SyncSessionContext* context) |
| 82 : thread_main_started_(false, false), | 102 : thread_main_started_(false, false), |
| 83 thread_("SyncEngine_SyncerThread"), | 103 thread_("SyncEngine_SyncerThread"), |
| 84 vault_field_changed_(&lock_), | 104 vault_field_changed_(&lock_), |
| 85 conn_mgr_hookup_(NULL), | 105 conn_mgr_hookup_(NULL), |
| 86 syncer_short_poll_interval_seconds_(kDefaultShortPollIntervalSeconds), | 106 syncer_short_poll_interval_seconds_(kDefaultShortPollIntervalSeconds), |
| 87 syncer_long_poll_interval_seconds_(kDefaultLongPollIntervalSeconds), | 107 syncer_long_poll_interval_seconds_(kDefaultLongPollIntervalSeconds), |
| 88 syncer_polling_interval_(kDefaultShortPollIntervalSeconds), | 108 syncer_polling_interval_(kDefaultShortPollIntervalSeconds), |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 // event. This will also update the source of the following SyncMain call. | 355 // event. This will also update the source of the following SyncMain call. |
| 336 VLOG(1) << "Calling Sync Main at time " << Time::Now().ToInternalValue(); | 356 VLOG(1) << "Calling Sync Main at time " << Time::Now().ToInternalValue(); |
| 337 bool nudged = false; | 357 bool nudged = false; |
| 338 scoped_ptr<SyncSession> session; | 358 scoped_ptr<SyncSession> session; |
| 339 session.reset(SyncMain(vault_.syncer_, | 359 session.reset(SyncMain(vault_.syncer_, |
| 340 throttled, continue_sync_cycle, &initial_sync_for_thread, &nudged)); | 360 throttled, continue_sync_cycle, &initial_sync_for_thread, &nudged)); |
| 341 | 361 |
| 342 // Update timing information for how often these datatypes are triggering | 362 // Update timing information for how often these datatypes are triggering |
| 343 // nudges. | 363 // nudges. |
| 344 base::TimeTicks now = TimeTicks::Now(); | 364 base::TimeTicks now = TimeTicks::Now(); |
| 345 for (size_t i = syncable::FIRST_REAL_MODEL_TYPE; | 365 if (!last_sync_time.is_null()) { |
| 346 i < session->source().second.size(); | 366 TypePayloadMap::const_iterator iter; |
| 347 ++i) { | 367 for (iter = session->source().types.begin(); |
| 348 if (session->source().second[i]) { | 368 iter != session->source().types.end(); |
| 349 syncable::PostTimeToTypeHistogram(syncable::ModelType(i), | 369 ++iter) { |
| 370 syncable::PostTimeToTypeHistogram(iter->first, |
| 350 now - last_sync_time); | 371 now - last_sync_time); |
| 351 } | 372 } |
| 352 } | 373 } |
| 353 | 374 |
| 354 last_sync_time = now; | 375 last_sync_time = now; |
| 355 | 376 |
| 356 VLOG(1) << "Updating the next polling time after SyncMain"; | 377 VLOG(1) << "Updating the next polling time after SyncMain"; |
| 357 vault_.current_wait_interval_ = CalculatePollingWaitTime( | 378 vault_.current_wait_interval_ = CalculatePollingWaitTime( |
| 358 static_cast<int>(vault_.current_wait_interval_.poll_delta.InSeconds()), | 379 static_cast<int>(vault_.current_wait_interval_.poll_delta.InSeconds()), |
| 359 &user_idle_milliseconds, &continue_sync_cycle, nudged); | 380 &user_idle_milliseconds, &continue_sync_cycle, nudged); |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 VLOG(1) << "Done calling SyncShare."; | 588 VLOG(1) << "Done calling SyncShare."; |
| 568 return session.release(); | 589 return session.release(); |
| 569 } | 590 } |
| 570 | 591 |
| 571 SyncSourceInfo SyncerThread::GetAndResetNudgeSource(bool was_throttled, | 592 SyncSourceInfo SyncerThread::GetAndResetNudgeSource(bool was_throttled, |
| 572 bool continue_sync_cycle, | 593 bool continue_sync_cycle, |
| 573 bool* initial_sync, | 594 bool* initial_sync, |
| 574 bool* was_nudged) { | 595 bool* was_nudged) { |
| 575 bool nudged = false; | 596 bool nudged = false; |
| 576 NudgeSource nudge_source = kUnknown; | 597 NudgeSource nudge_source = kUnknown; |
| 577 syncable::ModelTypeBitSet model_types; | 598 TypePayloadMap model_types_with_payloads; |
| 578 // Has the previous sync cycle completed? | 599 // Has the previous sync cycle completed? |
| 579 if (continue_sync_cycle) | 600 if (continue_sync_cycle) |
| 580 nudge_source = kContinuation; | 601 nudge_source = kContinuation; |
| 581 // Update the nudge source if a new nudge has come through during the | 602 // Update the nudge source if a new nudge has come through during the |
| 582 // previous sync cycle. | 603 // previous sync cycle. |
| 583 if (!vault_.pending_nudge_time_.is_null()) { | 604 if (!vault_.pending_nudge_time_.is_null()) { |
| 584 if (!was_throttled) { | 605 if (!was_throttled) { |
| 585 nudge_source = vault_.pending_nudge_source_; | 606 nudge_source = vault_.pending_nudge_source_; |
| 586 model_types = vault_.pending_nudge_types_; | 607 model_types_with_payloads = vault_.pending_nudge_types_; |
| 587 nudged = true; | 608 nudged = true; |
| 588 } | 609 } |
| 589 VLOG(1) << "Clearing pending nudge from " << vault_.pending_nudge_source_ | 610 VLOG(1) << "Clearing pending nudge from " << vault_.pending_nudge_source_ |
| 590 << " at tick " << vault_.pending_nudge_time_.ToInternalValue(); | 611 << " at tick " << vault_.pending_nudge_time_.ToInternalValue(); |
| 591 vault_.pending_nudge_source_ = kUnknown; | 612 vault_.pending_nudge_source_ = kUnknown; |
| 592 vault_.pending_nudge_types_.reset(); | 613 vault_.pending_nudge_types_.clear(); |
| 593 vault_.pending_nudge_time_ = base::TimeTicks(); | 614 vault_.pending_nudge_time_ = base::TimeTicks(); |
| 594 } | 615 } |
| 595 | 616 |
| 596 *was_nudged = nudged; | 617 *was_nudged = nudged; |
| 597 | 618 |
| 598 // TODO(tim): Hack for bug 64136 to correctly tag continuations that result | 619 // TODO(tim): Hack for bug 64136 to correctly tag continuations that result |
| 599 // from syncer having more work to do. This will be handled properly with | 620 // from syncer having more work to do. This will be handled properly with |
| 600 // the message loop based syncer thread, bug 26339. | 621 // the message loop based syncer thread, bug 26339. |
| 601 return MakeSyncSourceInfo(nudged || nudge_source == kContinuation, | 622 return MakeSyncSourceInfo(nudged || nudge_source == kContinuation, |
| 602 nudge_source, model_types, initial_sync); | 623 nudge_source, model_types_with_payloads, initial_sync); |
| 603 } | 624 } |
| 604 | 625 |
| 605 SyncSourceInfo SyncerThread::MakeSyncSourceInfo(bool nudged, | 626 SyncSourceInfo SyncerThread::MakeSyncSourceInfo(bool nudged, |
| 606 NudgeSource nudge_source, const syncable::ModelTypeBitSet& nudge_types, | 627 NudgeSource nudge_source, |
| 628 const TypePayloadMap& model_types_with_payloads, |
| 607 bool* initial_sync) { | 629 bool* initial_sync) { |
| 608 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source = | 630 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source = |
| 609 sync_pb::GetUpdatesCallerInfo::UNKNOWN; | 631 sync_pb::GetUpdatesCallerInfo::UNKNOWN; |
| 610 if (*initial_sync) { | 632 if (*initial_sync) { |
| 611 updates_source = sync_pb::GetUpdatesCallerInfo::FIRST_UPDATE; | 633 updates_source = sync_pb::GetUpdatesCallerInfo::FIRST_UPDATE; |
| 612 *initial_sync = false; | 634 *initial_sync = false; |
| 613 } else if (!nudged) { | 635 } else if (!nudged) { |
| 614 updates_source = sync_pb::GetUpdatesCallerInfo::PERIODIC; | 636 updates_source = sync_pb::GetUpdatesCallerInfo::PERIODIC; |
| 615 } else { | 637 } else { |
| 616 switch (nudge_source) { | 638 switch (nudge_source) { |
| 617 case kNotification: | 639 case kNotification: |
| 618 updates_source = sync_pb::GetUpdatesCallerInfo::NOTIFICATION; | 640 updates_source = sync_pb::GetUpdatesCallerInfo::NOTIFICATION; |
| 619 break; | 641 break; |
| 620 case kLocal: | 642 case kLocal: |
| 621 updates_source = sync_pb::GetUpdatesCallerInfo::LOCAL; | 643 updates_source = sync_pb::GetUpdatesCallerInfo::LOCAL; |
| 622 break; | 644 break; |
| 623 case kContinuation: | 645 case kContinuation: |
| 624 updates_source = sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION; | 646 updates_source = sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION; |
| 625 break; | 647 break; |
| 626 case kClearPrivateData: | 648 case kClearPrivateData: |
| 627 updates_source = sync_pb::GetUpdatesCallerInfo::CLEAR_PRIVATE_DATA; | 649 updates_source = sync_pb::GetUpdatesCallerInfo::CLEAR_PRIVATE_DATA; |
| 628 break; | 650 break; |
| 629 case kUnknown: | 651 case kUnknown: |
| 630 default: | 652 default: |
| 631 updates_source = sync_pb::GetUpdatesCallerInfo::UNKNOWN; | 653 updates_source = sync_pb::GetUpdatesCallerInfo::UNKNOWN; |
| 632 break; | 654 break; |
| 633 } | 655 } |
| 634 } | 656 } |
| 635 return SyncSourceInfo(updates_source, nudge_types); | 657 |
| 658 TypePayloadMap sync_source_types; |
| 659 if (model_types_with_payloads.empty()) { |
| 660 // No datatypes requested. This must be a poll so set all enabled datatypes. |
| 661 ModelSafeRoutingInfo routes; |
| 662 session_context_->registrar()->GetModelSafeRoutingInfo(&routes); |
| 663 sync_source_types = sessions::RoutingInfoToTypePayloadMap(routes, |
| 664 std::string()); |
| 665 } else { |
| 666 sync_source_types = model_types_with_payloads; |
| 667 } |
| 668 |
| 669 return SyncSourceInfo(updates_source, sync_source_types); |
| 636 } | 670 } |
| 637 | 671 |
| 638 void SyncerThread::CreateSyncer(const std::string& dirname) { | 672 void SyncerThread::CreateSyncer(const std::string& dirname) { |
| 639 base::AutoLock lock(lock_); | 673 base::AutoLock lock(lock_); |
| 640 VLOG(1) << "Creating syncer up for: " << dirname; | 674 VLOG(1) << "Creating syncer up for: " << dirname; |
| 641 // The underlying database structure is ready, and we should create | 675 // The underlying database structure is ready, and we should create |
| 642 // the syncer. | 676 // the syncer. |
| 643 CHECK(vault_.syncer_ == NULL); | 677 CHECK(vault_.syncer_ == NULL); |
| 644 session_context_->set_account_name(dirname); | 678 session_context_->set_account_name(dirname); |
| 645 vault_.syncer_ = new Syncer(); | 679 vault_.syncer_ = new Syncer(); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 727 // rate. | 761 // rate. |
| 728 if (idle >= kPollBackoffThresholdMultiplier * syncer_polling_interval_ms) { | 762 if (idle >= kPollBackoffThresholdMultiplier * syncer_polling_interval_ms) { |
| 729 next_wait = std::min(GetRecommendedDelaySeconds( | 763 next_wait = std::min(GetRecommendedDelaySeconds( |
| 730 last_interval / 1000), syncer_max_interval_ / 1000) * 1000; | 764 last_interval / 1000), syncer_max_interval_ / 1000) * 1000; |
| 731 } | 765 } |
| 732 | 766 |
| 733 return next_wait; | 767 return next_wait; |
| 734 } | 768 } |
| 735 | 769 |
| 736 // Called with mutex_ already locked. | 770 // Called with mutex_ already locked. |
| 737 void SyncerThread::NudgeSyncImpl(int milliseconds_from_now, | 771 void SyncerThread::NudgeSyncImpl( |
| 738 NudgeSource source, | 772 int milliseconds_from_now, |
| 739 const syncable::ModelTypeBitSet& model_types) { | 773 NudgeSource source, |
| 774 const TypePayloadMap& model_types_with_payloads) { |
| 740 // TODO(sync): Add the option to reset the backoff state machine. | 775 // TODO(sync): Add the option to reset the backoff state machine. |
| 741 // This is needed so nudges that are a result of the user's desire | 776 // This is needed so nudges that are a result of the user's desire |
| 742 // to download updates for a new data type can be satisfied quickly. | 777 // to download updates for a new data type can be satisfied quickly. |
| 743 if (vault_.current_wait_interval_.mode == WaitInterval::THROTTLED || | 778 if (vault_.current_wait_interval_.mode == WaitInterval::THROTTLED || |
| 744 vault_.current_wait_interval_.had_nudge_during_backoff) { | 779 vault_.current_wait_interval_.had_nudge_during_backoff) { |
| 745 // Drop nudges on the floor if we've already had one since starting this | 780 // Drop nudges on the floor if we've already had one since starting this |
| 746 // stage of exponential backoff or we are throttled. | 781 // stage of exponential backoff or we are throttled. |
| 747 return; | 782 return; |
| 748 } | 783 } |
| 749 | 784 |
| 750 // Union the current bitset with any from nudges that may have already | 785 // Union the current TypePayloadMap with any from nudges that may have already |
| 751 // posted (coalesce the nudge datatype information). | 786 // posted (coalesce the nudge datatype information). |
| 752 // TODO(tim): It seems weird to do this if the sources don't match up (e.g. | 787 // TODO(tim): It seems weird to do this if the sources don't match up (e.g. |
| 753 // if pending_source is kLocal and |source| is kClearPrivateData). | 788 // if pending_source is kLocal and |source| is kClearPrivateData). |
| 754 vault_.pending_nudge_types_ |= model_types; | 789 sessions::CoalescePayloads(&vault_.pending_nudge_types_, |
| 790 model_types_with_payloads); |
| 755 | 791 |
| 756 const TimeTicks nudge_time = TimeTicks::Now() + | 792 const TimeTicks nudge_time = TimeTicks::Now() + |
| 757 TimeDelta::FromMilliseconds(milliseconds_from_now); | 793 TimeDelta::FromMilliseconds(milliseconds_from_now); |
| 758 if (nudge_time <= vault_.pending_nudge_time_) { | 794 if (nudge_time <= vault_.pending_nudge_time_) { |
| 759 VLOG(1) << "Nudge for source " << source | 795 VLOG(1) << "Nudge for source " << source |
| 760 << " dropped due to existing later pending nudge"; | 796 << " dropped due to existing later pending nudge"; |
| 761 return; | 797 return; |
| 762 } | 798 } |
| 763 | 799 |
| 764 VLOG(1) << "Replacing pending nudge for source " << source | 800 VLOG(1) << "Replacing pending nudge for source " << source |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 842 was_logged = true; | 878 was_logged = true; |
| 843 VLOG(1) << "UserIdleTime unimplemented on this platform, synchronization " | 879 VLOG(1) << "UserIdleTime unimplemented on this platform, synchronization " |
| 844 "will not throttle when user idle"; | 880 "will not throttle when user idle"; |
| 845 } | 881 } |
| 846 #endif | 882 #endif |
| 847 | 883 |
| 848 return 0; | 884 return 0; |
| 849 } | 885 } |
| 850 | 886 |
| 851 } // namespace browser_sync | 887 } // namespace browser_sync |
| OLD | NEW |