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 |
35 using sessions::ModelTypeMap; | |
34 using sessions::SyncSession; | 36 using sessions::SyncSession; |
35 using sessions::SyncSessionSnapshot; | 37 using sessions::SyncSessionSnapshot; |
36 using sessions::SyncSourceInfo; | 38 using sessions::SyncSourceInfo; |
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 ModelTypeMap& 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 ModelTypeMap model_types_with_payloads; |
81 sessions::BuildModelTypeMapFromModelTypeBitSet(model_types, | |
82 std::string(), | |
83 &model_types_with_payloads); | |
84 NudgeSyncImpl(milliseconds_from_now, source, model_types_with_payloads); | |
67 } | 85 } |
68 | 86 |
69 void SyncerThread::NudgeSyncer( | 87 void SyncerThread::NudgeSyncer( |
70 int milliseconds_from_now, | 88 int milliseconds_from_now, |
71 NudgeSource source) { | 89 NudgeSource source) { |
72 base::AutoLock lock(lock_); | 90 base::AutoLock lock(lock_); |
73 if (vault_.syncer_ == NULL) { | 91 if (vault_.syncer_ == NULL) { |
74 return; | 92 return; |
75 } | 93 } |
76 | 94 |
77 syncable::ModelTypeBitSet model_types; // All false by default. | 95 // Set all enabled datatypes. |
78 NudgeSyncImpl(milliseconds_from_now, source, model_types); | 96 ModelTypeMap model_types_with_payloads; |
97 ModelSafeRoutingInfo routes; | |
98 session_context_->registrar()->GetModelSafeRoutingInfo(&routes); | |
99 sessions::BuildModelTypeMapFromModelSafeRoutingInfo( | |
100 routes, | |
101 std::string(), | |
102 &model_types_with_payloads); | |
103 NudgeSyncImpl(milliseconds_from_now, source, model_types_with_payloads); | |
79 } | 104 } |
80 | 105 |
81 SyncerThread::SyncerThread(sessions::SyncSessionContext* context) | 106 SyncerThread::SyncerThread(sessions::SyncSessionContext* context) |
82 : thread_main_started_(false, false), | 107 : thread_main_started_(false, false), |
83 thread_("SyncEngine_SyncerThread"), | 108 thread_("SyncEngine_SyncerThread"), |
84 vault_field_changed_(&lock_), | 109 vault_field_changed_(&lock_), |
85 conn_mgr_hookup_(NULL), | 110 conn_mgr_hookup_(NULL), |
86 syncer_short_poll_interval_seconds_(kDefaultShortPollIntervalSeconds), | 111 syncer_short_poll_interval_seconds_(kDefaultShortPollIntervalSeconds), |
87 syncer_long_poll_interval_seconds_(kDefaultLongPollIntervalSeconds), | 112 syncer_long_poll_interval_seconds_(kDefaultLongPollIntervalSeconds), |
88 syncer_polling_interval_(kDefaultShortPollIntervalSeconds), | 113 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. | 360 // event. This will also update the source of the following SyncMain call. |
336 VLOG(1) << "Calling Sync Main at time " << Time::Now().ToInternalValue(); | 361 VLOG(1) << "Calling Sync Main at time " << Time::Now().ToInternalValue(); |
337 bool nudged = false; | 362 bool nudged = false; |
338 scoped_ptr<SyncSession> session; | 363 scoped_ptr<SyncSession> session; |
339 session.reset(SyncMain(vault_.syncer_, | 364 session.reset(SyncMain(vault_.syncer_, |
340 throttled, continue_sync_cycle, &initial_sync_for_thread, &nudged)); | 365 throttled, continue_sync_cycle, &initial_sync_for_thread, &nudged)); |
341 | 366 |
342 // Update timing information for how often these datatypes are triggering | 367 // Update timing information for how often these datatypes are triggering |
343 // nudges. | 368 // nudges. |
344 base::TimeTicks now = TimeTicks::Now(); | 369 base::TimeTicks now = TimeTicks::Now(); |
345 for (size_t i = syncable::FIRST_REAL_MODEL_TYPE; | 370 if (!last_sync_time.is_null()) { |
346 i < session->source().second.size(); | 371 ModelTypeMap::const_iterator iter; |
347 ++i) { | 372 for (iter = session->source().types.begin(); |
348 if (session->source().second[i]) { | 373 iter != session->source().types.end(); |
349 syncable::PostTimeToTypeHistogram(syncable::ModelType(i), | 374 ++iter) { |
375 syncable::PostTimeToTypeHistogram(iter->first, | |
350 now - last_sync_time); | 376 now - last_sync_time); |
351 } | 377 } |
352 } | 378 } |
353 | 379 |
354 last_sync_time = now; | 380 last_sync_time = now; |
355 | 381 |
356 VLOG(1) << "Updating the next polling time after SyncMain"; | 382 VLOG(1) << "Updating the next polling time after SyncMain"; |
357 vault_.current_wait_interval_ = CalculatePollingWaitTime( | 383 vault_.current_wait_interval_ = CalculatePollingWaitTime( |
358 static_cast<int>(vault_.current_wait_interval_.poll_delta.InSeconds()), | 384 static_cast<int>(vault_.current_wait_interval_.poll_delta.InSeconds()), |
359 &user_idle_milliseconds, &continue_sync_cycle, nudged); | 385 &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."; | 593 VLOG(1) << "Done calling SyncShare."; |
568 return session.release(); | 594 return session.release(); |
569 } | 595 } |
570 | 596 |
571 SyncSourceInfo SyncerThread::GetAndResetNudgeSource(bool was_throttled, | 597 SyncSourceInfo SyncerThread::GetAndResetNudgeSource(bool was_throttled, |
572 bool continue_sync_cycle, | 598 bool continue_sync_cycle, |
573 bool* initial_sync, | 599 bool* initial_sync, |
574 bool* was_nudged) { | 600 bool* was_nudged) { |
575 bool nudged = false; | 601 bool nudged = false; |
576 NudgeSource nudge_source = kUnknown; | 602 NudgeSource nudge_source = kUnknown; |
577 syncable::ModelTypeBitSet model_types; | 603 ModelTypeMap model_types_with_payloads; |
578 // Has the previous sync cycle completed? | 604 // Has the previous sync cycle completed? |
579 if (continue_sync_cycle) | 605 if (continue_sync_cycle) |
580 nudge_source = kContinuation; | 606 nudge_source = kContinuation; |
581 // Update the nudge source if a new nudge has come through during the | 607 // Update the nudge source if a new nudge has come through during the |
582 // previous sync cycle. | 608 // previous sync cycle. |
583 if (!vault_.pending_nudge_time_.is_null()) { | 609 if (!vault_.pending_nudge_time_.is_null()) { |
584 if (!was_throttled) { | 610 if (!was_throttled) { |
585 nudge_source = vault_.pending_nudge_source_; | 611 nudge_source = vault_.pending_nudge_source_; |
586 model_types = vault_.pending_nudge_types_; | 612 model_types_with_payloads = vault_.pending_nudge_types_; |
587 nudged = true; | 613 nudged = true; |
588 } | 614 } |
589 VLOG(1) << "Clearing pending nudge from " << vault_.pending_nudge_source_ | 615 VLOG(1) << "Clearing pending nudge from " << vault_.pending_nudge_source_ |
590 << " at tick " << vault_.pending_nudge_time_.ToInternalValue(); | 616 << " at tick " << vault_.pending_nudge_time_.ToInternalValue(); |
591 vault_.pending_nudge_source_ = kUnknown; | 617 vault_.pending_nudge_source_ = kUnknown; |
592 vault_.pending_nudge_types_.reset(); | 618 vault_.pending_nudge_types_.clear(); |
593 vault_.pending_nudge_time_ = base::TimeTicks(); | 619 vault_.pending_nudge_time_ = base::TimeTicks(); |
594 } | 620 } |
595 | 621 |
596 *was_nudged = nudged; | 622 *was_nudged = nudged; |
597 | 623 |
598 // TODO(tim): Hack for bug 64136 to correctly tag continuations that result | 624 // 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 | 625 // from syncer having more work to do. This will be handled properly with |
600 // the message loop based syncer thread, bug 26339. | 626 // the message loop based syncer thread, bug 26339. |
601 return MakeSyncSourceInfo(nudged || nudge_source == kContinuation, | 627 return MakeSyncSourceInfo(nudged || nudge_source == kContinuation, |
602 nudge_source, model_types, initial_sync); | 628 nudge_source, model_types_with_payloads, initial_sync); |
603 } | 629 } |
604 | 630 |
605 SyncSourceInfo SyncerThread::MakeSyncSourceInfo(bool nudged, | 631 SyncSourceInfo SyncerThread::MakeSyncSourceInfo(bool nudged, |
606 NudgeSource nudge_source, const syncable::ModelTypeBitSet& nudge_types, | 632 NudgeSource nudge_source, |
633 const ModelTypeMap& model_types_with_payloads, | |
607 bool* initial_sync) { | 634 bool* initial_sync) { |
608 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source = | 635 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source = |
609 sync_pb::GetUpdatesCallerInfo::UNKNOWN; | 636 sync_pb::GetUpdatesCallerInfo::UNKNOWN; |
610 if (*initial_sync) { | 637 if (*initial_sync) { |
611 updates_source = sync_pb::GetUpdatesCallerInfo::FIRST_UPDATE; | 638 updates_source = sync_pb::GetUpdatesCallerInfo::FIRST_UPDATE; |
612 *initial_sync = false; | 639 *initial_sync = false; |
613 } else if (!nudged) { | 640 } else if (!nudged) { |
614 updates_source = sync_pb::GetUpdatesCallerInfo::PERIODIC; | 641 updates_source = sync_pb::GetUpdatesCallerInfo::PERIODIC; |
615 } else { | 642 } else { |
616 switch (nudge_source) { | 643 switch (nudge_source) { |
617 case kNotification: | 644 case kNotification: |
618 updates_source = sync_pb::GetUpdatesCallerInfo::NOTIFICATION; | 645 updates_source = sync_pb::GetUpdatesCallerInfo::NOTIFICATION; |
619 break; | 646 break; |
620 case kLocal: | 647 case kLocal: |
621 updates_source = sync_pb::GetUpdatesCallerInfo::LOCAL; | 648 updates_source = sync_pb::GetUpdatesCallerInfo::LOCAL; |
622 break; | 649 break; |
623 case kContinuation: | 650 case kContinuation: |
624 updates_source = sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION; | 651 updates_source = sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION; |
625 break; | 652 break; |
626 case kClearPrivateData: | 653 case kClearPrivateData: |
627 updates_source = sync_pb::GetUpdatesCallerInfo::CLEAR_PRIVATE_DATA; | 654 updates_source = sync_pb::GetUpdatesCallerInfo::CLEAR_PRIVATE_DATA; |
628 break; | 655 break; |
629 case kUnknown: | 656 case kUnknown: |
630 default: | 657 default: |
631 updates_source = sync_pb::GetUpdatesCallerInfo::UNKNOWN; | 658 updates_source = sync_pb::GetUpdatesCallerInfo::UNKNOWN; |
632 break; | 659 break; |
633 } | 660 } |
634 } | 661 } |
635 return SyncSourceInfo(updates_source, nudge_types); | 662 |
663 ModelTypeMap sync_source_types; | |
664 if (model_types_with_payloads.empty()) { | |
665 // No datatypes requested. This must be a poll so set all enabled datatypes. | |
666 ModelSafeRoutingInfo routes; | |
667 session_context_->registrar()->GetModelSafeRoutingInfo(&routes); | |
668 sessions::BuildModelTypeMapFromModelSafeRoutingInfo(routes, | |
669 std::string(), | |
670 &sync_source_types); | |
671 } else { | |
672 sync_source_types = model_types_with_payloads; | |
673 } | |
674 | |
675 return SyncSourceInfo(updates_source, sync_source_types); | |
636 } | 676 } |
637 | 677 |
638 void SyncerThread::CreateSyncer(const std::string& dirname) { | 678 void SyncerThread::CreateSyncer(const std::string& dirname) { |
639 base::AutoLock lock(lock_); | 679 base::AutoLock lock(lock_); |
640 VLOG(1) << "Creating syncer up for: " << dirname; | 680 VLOG(1) << "Creating syncer up for: " << dirname; |
641 // The underlying database structure is ready, and we should create | 681 // The underlying database structure is ready, and we should create |
642 // the syncer. | 682 // the syncer. |
643 CHECK(vault_.syncer_ == NULL); | 683 CHECK(vault_.syncer_ == NULL); |
644 session_context_->set_account_name(dirname); | 684 session_context_->set_account_name(dirname); |
645 vault_.syncer_ = new Syncer(); | 685 vault_.syncer_ = new Syncer(); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
727 // rate. | 767 // rate. |
728 if (idle >= kPollBackoffThresholdMultiplier * syncer_polling_interval_ms) { | 768 if (idle >= kPollBackoffThresholdMultiplier * syncer_polling_interval_ms) { |
729 next_wait = std::min(GetRecommendedDelaySeconds( | 769 next_wait = std::min(GetRecommendedDelaySeconds( |
730 last_interval / 1000), syncer_max_interval_ / 1000) * 1000; | 770 last_interval / 1000), syncer_max_interval_ / 1000) * 1000; |
731 } | 771 } |
732 | 772 |
733 return next_wait; | 773 return next_wait; |
734 } | 774 } |
735 | 775 |
736 // Called with mutex_ already locked. | 776 // Called with mutex_ already locked. |
737 void SyncerThread::NudgeSyncImpl(int milliseconds_from_now, | 777 void SyncerThread::NudgeSyncImpl( |
738 NudgeSource source, | 778 int milliseconds_from_now, |
739 const syncable::ModelTypeBitSet& model_types) { | 779 NudgeSource source, |
780 const ModelTypeMap& model_types_with_payloads) { | |
740 // TODO(sync): Add the option to reset the backoff state machine. | 781 // 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 | 782 // 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. | 783 // to download updates for a new data type can be satisfied quickly. |
743 if (vault_.current_wait_interval_.mode == WaitInterval::THROTTLED || | 784 if (vault_.current_wait_interval_.mode == WaitInterval::THROTTLED || |
744 vault_.current_wait_interval_.had_nudge_during_backoff) { | 785 vault_.current_wait_interval_.had_nudge_during_backoff) { |
745 // Drop nudges on the floor if we've already had one since starting this | 786 // Drop nudges on the floor if we've already had one since starting this |
746 // stage of exponential backoff or we are throttled. | 787 // stage of exponential backoff or we are throttled. |
747 return; | 788 return; |
748 } | 789 } |
749 | 790 |
750 // Union the current bitset with any from nudges that may have already | 791 // Union the current ModelTypeMap with any from nudges that may have already |
751 // posted (coalesce the nudge datatype information). | 792 // posted (coalesce the nudge datatype information). |
752 // TODO(tim): It seems weird to do this if the sources don't match up (e.g. | 793 // 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). | 794 // if pending_source is kLocal and |source| is kClearPrivateData). |
754 vault_.pending_nudge_types_ |= model_types; | 795 for (ModelTypeMap::const_iterator i = |
akalin
2011/01/24 22:17:29
I think this logic is tricky enough that it should
Nicolas Zea
2011/01/25 00:29:14
Done.
| |
796 model_types_with_payloads.begin(); | |
797 i != model_types_with_payloads.end(); | |
798 ++i) { | |
799 if (vault_.pending_nudge_types_.count(i->first) == 0) { | |
800 // If this datatype isn't already in our map, add it. | |
801 vault_.pending_nudge_types_[i->first] = i->second; | |
802 } else if (i->second.length() > 0) { | |
803 // If it is, we only overwrite the payload if the new one is non-empty. | |
804 vault_.pending_nudge_types_[i->first] = i->second; | |
805 } | |
806 } | |
755 | 807 |
756 const TimeTicks nudge_time = TimeTicks::Now() + | 808 const TimeTicks nudge_time = TimeTicks::Now() + |
757 TimeDelta::FromMilliseconds(milliseconds_from_now); | 809 TimeDelta::FromMilliseconds(milliseconds_from_now); |
758 if (nudge_time <= vault_.pending_nudge_time_) { | 810 if (nudge_time <= vault_.pending_nudge_time_) { |
759 VLOG(1) << "Nudge for source " << source | 811 VLOG(1) << "Nudge for source " << source |
760 << " dropped due to existing later pending nudge"; | 812 << " dropped due to existing later pending nudge"; |
761 return; | 813 return; |
762 } | 814 } |
763 | 815 |
764 VLOG(1) << "Replacing pending nudge for source " << source | 816 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; | 894 was_logged = true; |
843 VLOG(1) << "UserIdleTime unimplemented on this platform, synchronization " | 895 VLOG(1) << "UserIdleTime unimplemented on this platform, synchronization " |
844 "will not throttle when user idle"; | 896 "will not throttle when user idle"; |
845 } | 897 } |
846 #endif | 898 #endif |
847 | 899 |
848 return 0; | 900 return 0; |
849 } | 901 } |
850 | 902 |
851 } // namespace browser_sync | 903 } // namespace browser_sync |
OLD | NEW |