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