summaryrefslogtreecommitdiff
path: root/sync
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2013-07-23 11:17:05 +0100
committerBen Murdoch <benm@google.com>2013-07-23 11:17:05 +0100
commitca12bfac764ba476d6cd062bf1dde12cc64c3f40 (patch)
tree1cd09db25ea5de98e73c8efbe572e103daee8b2b /sync
parentfcb3e05bdd21d752df9c3dff28b6bbf29b5b733b (diff)
downloadchromium_org-ca12bfac764ba476d6cd062bf1dde12cc64c3f40.tar.gz
Merge from Chromium at DEPS revision r213057
This commit was generated by merge_to_master.py. Change-Id: I3e2e2506eb9b0080157e9c5f133559df3e600388
Diffstat (limited to 'sync')
-rw-r--r--sync/engine/sync_scheduler_impl.cc3
-rw-r--r--sync/engine/sync_scheduler_unittest.cc1
-rw-r--r--sync/engine/syncer.cc19
-rw-r--r--sync/engine/syncer_unittest.cc1
-rw-r--r--sync/internal_api/internal_components_factory_impl.cc2
-rw-r--r--sync/internal_api/public/base/invalidation.cc15
-rw-r--r--sync/internal_api/public/base/invalidation.h6
-rw-r--r--sync/internal_api/public/base/model_type.h8
-rw-r--r--sync/internal_api/public/internal_components_factory.h11
-rw-r--r--sync/internal_api/public/util/experiments.h1
-rw-r--r--sync/internal_api/sync_manager_impl.cc11
-rw-r--r--sync/internal_api/test/test_internal_components_factory.cc2
-rw-r--r--sync/notifier/object_id_invalidation_map.cc3
-rw-r--r--sync/notifier/object_id_invalidation_map.h5
-rw-r--r--sync/notifier/p2p_invalidator.cc6
-rw-r--r--sync/notifier/p2p_invalidator_unittest.cc7
-rw-r--r--sync/notifier/sync_invalidation_listener.cc22
-rw-r--r--sync/notifier/sync_invalidation_listener.h2
-rw-r--r--sync/notifier/sync_invalidation_listener_unittest.cc34
-rw-r--r--sync/protocol/experiments_specifics.proto6
-rw-r--r--sync/protocol/proto_value_conversions.cc1
-rw-r--r--sync/sessions/data_type_tracker.cc12
-rw-r--r--sync/sessions/data_type_tracker.h4
-rw-r--r--sync/sessions/nudge_tracker.cc10
-rw-r--r--sync/sessions/nudge_tracker.h4
-rw-r--r--sync/sessions/nudge_tracker_unittest.cc65
-rw-r--r--sync/sessions/sync_session_context.cc6
-rw-r--r--sync/sessions/sync_session_context.h19
-rw-r--r--sync/sessions/sync_session_unittest.cc1
-rw-r--r--sync/syncable/model_type.cc24
-rw-r--r--sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java14
-rw-r--r--sync/test/engine/syncer_command_test.h1
-rw-r--r--sync/tools/testserver/chromiumsync.py30
-rwxr-xr-xsync/tools/testserver/sync_testserver.py16
34 files changed, 338 insertions, 34 deletions
diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc
index fe377d4019..3a904d1dc5 100644
--- a/sync/engine/sync_scheduler_impl.cc
+++ b/sync/engine/sync_scheduler_impl.cc
@@ -616,7 +616,8 @@ void SyncSchedulerImpl::UpdateNudgeTimeRecords(ModelTypeSet types) {
void SyncSchedulerImpl::AdjustPolling(PollAdjustType type) {
DCHECK(CalledOnValidThread());
- TimeDelta poll = (!session_context_->notifications_enabled()) ?
+ TimeDelta poll = (!session_context_->notifications_enabled() ||
+ !session_context_->ShouldFetchUpdatesBeforeCommit()) ?
syncer_short_poll_interval_seconds_ :
syncer_long_poll_interval_seconds_;
bool rate_changed = !poll_timer_.IsRunning() ||
diff --git a/sync/engine/sync_scheduler_unittest.cc b/sync/engine/sync_scheduler_unittest.cc
index a55eb7f1bb..3fb2042fe0 100644
--- a/sync/engine/sync_scheduler_unittest.cc
+++ b/sync/engine/sync_scheduler_unittest.cc
@@ -150,6 +150,7 @@ class SyncSchedulerTest : public testing::Test {
&extensions_activity_monitor_,
std::vector<SyncEngineEventListener*>(), NULL, NULL,
true, // enable keystore encryption
+ false, // force enable pre-commit GU avoidance
"fake_invalidator_client_id"));
context_->set_routing_info(routing_info_);
context_->set_notifications_enabled(true);
diff --git a/sync/engine/syncer.cc b/sync/engine/syncer.cc
index 8ebbff1170..8005459fb8 100644
--- a/sync/engine/syncer.cc
+++ b/sync/engine/syncer.cc
@@ -64,14 +64,17 @@ bool Syncer::NormalSyncShare(ModelTypeSet request_types,
SyncSession* session) {
HandleCycleBegin(session);
VLOG(1) << "Downloading types " << ModelTypeSetToString(request_types);
- if (!DownloadAndApplyUpdates(
- session,
- base::Bind(&NormalDownloadUpdates,
- session,
- kCreateMobileBookmarksFolder,
- request_types,
- base::ConstRef(nudge_tracker)))) {
- return HandleCycleEnd(session);
+ if (nudge_tracker.IsGetUpdatesRequired() ||
+ session->context()->ShouldFetchUpdatesBeforeCommit()) {
+ if (!DownloadAndApplyUpdates(
+ session,
+ base::Bind(&NormalDownloadUpdates,
+ session,
+ kCreateMobileBookmarksFolder,
+ request_types,
+ base::ConstRef(nudge_tracker)))) {
+ return HandleCycleEnd(session);
+ }
}
VLOG(1) << "Committing from types " << ModelTypeSetToString(request_types);
diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc
index 61f7f9b838..a2ccccfb23 100644
--- a/sync/engine/syncer_unittest.cc
+++ b/sync/engine/syncer_unittest.cc
@@ -239,6 +239,7 @@ class SyncerTest : public testing::Test,
&extensions_activity_monitor_,
listeners, NULL, &traffic_recorder_,
true, // enable keystore encryption
+ false, // force enable pre-commit GU avoidance experiment
"fake_invalidator_client_id"));
context_->set_routing_info(routing_info);
syncer_ = new Syncer();
diff --git a/sync/internal_api/internal_components_factory_impl.cc b/sync/internal_api/internal_components_factory_impl.cc
index f4fd94232e..1cc3b112c6 100644
--- a/sync/internal_api/internal_components_factory_impl.cc
+++ b/sync/internal_api/internal_components_factory_impl.cc
@@ -48,6 +48,8 @@ InternalComponentsFactoryImpl::BuildContext(
listeners, debug_info_getter,
traffic_recorder,
switches_.encryption_method == ENCRYPTION_KEYSTORE,
+ switches_.pre_commit_updates_policy ==
+ FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE,
invalidation_client_id));
}
diff --git a/sync/internal_api/public/base/invalidation.cc b/sync/internal_api/public/base/invalidation.cc
index 472fad2c3c..b503d07c4a 100644
--- a/sync/internal_api/public/base/invalidation.cc
+++ b/sync/internal_api/public/base/invalidation.cc
@@ -64,19 +64,23 @@ AckHandle::AckHandle(const std::string& state, base::Time timestamp)
AckHandle::~AckHandle() {
}
+const int64 Invalidation::kUnknownVersion = -1;
+
Invalidation::Invalidation()
- : ack_handle(AckHandle::InvalidAckHandle()) {
+ : version(kUnknownVersion), ack_handle(AckHandle::InvalidAckHandle()) {
}
Invalidation::~Invalidation() {
}
bool Invalidation::Equals(const Invalidation& other) const {
- return (payload == other.payload) && ack_handle.Equals(other.ack_handle);
+ return (version == other.version) && (payload == other.payload) &&
+ ack_handle.Equals(other.ack_handle);
}
scoped_ptr<base::DictionaryValue> Invalidation::ToValue() const {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
+ value->SetString("version", base::Int64ToString(version));
value->SetString("payload", payload);
value->Set("ackHandle", ack_handle.ToValue().release());
return value.Pass();
@@ -84,6 +88,13 @@ scoped_ptr<base::DictionaryValue> Invalidation::ToValue() const {
bool Invalidation::ResetFromValue(const base::DictionaryValue& value) {
const base::DictionaryValue* ack_handle_value = NULL;
+ std::string version_as_string;
+ if (value.GetString("version", &version_as_string)) {
+ if (!base::StringToInt64(version_as_string, &version))
+ return false;
+ } else {
+ version = kUnknownVersion;
+ }
return
value.GetString("payload", &payload) &&
value.GetDictionary("ackHandle", &ack_handle_value) &&
diff --git a/sync/internal_api/public/base/invalidation.h b/sync/internal_api/public/base/invalidation.h
index e1e274ed13..851dbed747 100644
--- a/sync/internal_api/public/base/invalidation.h
+++ b/sync/internal_api/public/base/invalidation.h
@@ -43,11 +43,14 @@ class SYNC_EXPORT AckHandle {
};
// Represents a local invalidation, and is roughly analogous to
-// invalidation::Invalidation. It contains a payload (which may be empty) and an
+// invalidation::Invalidation. It contains a version (which may be
+// kUnknownVersion), a payload (which may be empty) and an
// associated ack handle that an InvalidationHandler implementation can use to
// acknowledge receipt of the invalidation. It does not embed the object ID,
// since it is typically associated with it through ObjectIdInvalidationMap.
struct SYNC_EXPORT Invalidation {
+ static const int64 kUnknownVersion;
+
Invalidation();
~Invalidation();
@@ -56,6 +59,7 @@ struct SYNC_EXPORT Invalidation {
scoped_ptr<base::DictionaryValue> ToValue() const;
bool ResetFromValue(const base::DictionaryValue& value);
+ int64 version;
std::string payload;
AckHandle ack_handle;
};
diff --git a/sync/internal_api/public/base/model_type.h b/sync/internal_api/public/base/model_type.h
index 59f970fd86..247d351375 100644
--- a/sync/internal_api/public/base/model_type.h
+++ b/sync/internal_api/public/base/model_type.h
@@ -207,6 +207,14 @@ SYNC_EXPORT ModelTypeSet ControlTypes();
// See comment above for more information on what makes these types special.
SYNC_EXPORT bool IsControlType(ModelType model_type);
+// Core types are those data types used by sync's core functionality (i.e. not
+// user data types). These types are always enabled, and include ControlTypes().
+//
+// The set of all core types.
+SYNC_EXPORT ModelTypeSet CoreTypes();
+// Those core types that have high priority (includes ControlTypes()).
+SYNC_EXPORT ModelTypeSet PriorityCoreTypes();
+
// Determine a model type from the field number of its associated
// EntitySpecifics field. Returns UNSPECIFIED if the field number is
// not recognized.
diff --git a/sync/internal_api/public/internal_components_factory.h b/sync/internal_api/public/internal_components_factory.h
index 6b79ddd2f9..96fd640737 100644
--- a/sync/internal_api/public/internal_components_factory.h
+++ b/sync/internal_api/public/internal_components_factory.h
@@ -50,6 +50,16 @@ class SYNC_EXPORT InternalComponentsFactory {
BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE
};
+ enum PreCommitUpdatesPolicy {
+ // By default, the server will enable or disable this experiment through the
+ // sync protocol's experiments data type.
+ SERVER_CONTROLLED_PRE_COMMIT_UPDATE_AVOIANCE,
+
+ // This flag overrides the server's decision and enables the pre-commit
+ // update avoidance experiment.
+ FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE,
+ };
+
// Configuration options for internal components. This struct is expected
// to grow and shrink over time with transient features / experiments,
// roughly following command line flags in chrome. Implementations of
@@ -58,6 +68,7 @@ class SYNC_EXPORT InternalComponentsFactory {
struct Switches {
EncryptionMethod encryption_method;
BackoffOverride backoff_override;
+ PreCommitUpdatesPolicy pre_commit_updates_policy;
};
virtual ~InternalComponentsFactory() {}
diff --git a/sync/internal_api/public/util/experiments.h b/sync/internal_api/public/util/experiments.h
index 6c53e30120..144687d968 100644
--- a/sync/internal_api/public/util/experiments.h
+++ b/sync/internal_api/public/util/experiments.h
@@ -11,6 +11,7 @@ namespace syncer {
const char kAutofillCullingTag[] = "autofill_culling";
const char kFaviconSyncTag[] = "favicon_sync";
+const char kPreCommitUpdateAvoidanceTag[] = "pre_commit_update_avoidance";
// A structure to hold the enable status of experimental sync features.
struct Experiments {
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index e9eeea1832..3d6158d8a1 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -1295,6 +1295,17 @@ bool SyncManagerImpl::ReceivedExperiment(Experiments* experiments) {
found_experiment = true;
}
+ ReadNode pre_commit_update_avoidance_node(&trans);
+ if (pre_commit_update_avoidance_node.InitByClientTagLookup(
+ syncer::EXPERIMENTS,
+ syncer::kPreCommitUpdateAvoidanceTag) == BaseNode::INIT_OK) {
+ session_context_->set_server_enabled_pre_commit_update_avoidance(
+ pre_commit_update_avoidance_node.GetExperimentsSpecifics().
+ pre_commit_update_avoidance().enabled());
+ // We don't bother setting found_experiment. The frontend doesn't need to
+ // know about this.
+ }
+
return found_experiment;
}
diff --git a/sync/internal_api/test/test_internal_components_factory.cc b/sync/internal_api/test/test_internal_components_factory.cc
index beb249e743..154c58cc99 100644
--- a/sync/internal_api/test/test_internal_components_factory.cc
+++ b/sync/internal_api/test/test_internal_components_factory.cc
@@ -45,6 +45,8 @@ TestInternalComponentsFactory::BuildContext(
empty_listeners, debug_info_getter,
traffic_recorder,
switches_.encryption_method == ENCRYPTION_KEYSTORE,
+ switches_.pre_commit_updates_policy ==
+ FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE,
invalidator_client_id));
}
diff --git a/sync/notifier/object_id_invalidation_map.cc b/sync/notifier/object_id_invalidation_map.cc
index 47b08e684a..3dc7514b97 100644
--- a/sync/notifier/object_id_invalidation_map.cc
+++ b/sync/notifier/object_id_invalidation_map.cc
@@ -22,10 +22,11 @@ ObjectIdSet ObjectIdInvalidationMapToSet(
}
ObjectIdInvalidationMap ObjectIdSetToInvalidationMap(
- const ObjectIdSet& ids, const std::string& payload) {
+ const ObjectIdSet& ids, int64 version, const std::string& payload) {
ObjectIdInvalidationMap invalidation_map;
for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
// TODO(dcheng): Do we need to provide a way to set AckHandle?
+ invalidation_map[*it].version = version;
invalidation_map[*it].payload = payload;
}
return invalidation_map;
diff --git a/sync/notifier/object_id_invalidation_map.h b/sync/notifier/object_id_invalidation_map.h
index 6560b3b51a..0a6a95ede4 100644
--- a/sync/notifier/object_id_invalidation_map.h
+++ b/sync/notifier/object_id_invalidation_map.h
@@ -8,6 +8,7 @@
#include <map>
#include <string>
+#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "google/cacheinvalidation/include/types.h"
#include "sync/base/sync_export.h"
@@ -29,7 +30,7 @@ typedef std::map<invalidation::ObjectId,
ObjectIdSet ObjectIdInvalidationMapToSet(
const ObjectIdInvalidationMap& invalidation_map);
SYNC_EXPORT ObjectIdInvalidationMap ObjectIdSetToInvalidationMap(
- const ObjectIdSet& ids, const std::string& payload);
+ const ObjectIdSet& ids, int64 version, const std::string& payload);
SYNC_EXPORT bool ObjectIdInvalidationMapEquals(
const ObjectIdInvalidationMap& invalidation_map1,
@@ -51,4 +52,4 @@ SYNC_EXPORT ObjectIdInvalidationMap
} // namespace syncer
-#endif // HOME_DCHENG_SRC_CHROMIUM_SRC_SYNC_NOTIFIER_OBJECT_ID_STATE_MAP_H_
+#endif // SYNC_NOTIFIER_OBJECT_ID_INVALIDATION_MAP_H_
diff --git a/sync/notifier/p2p_invalidator.cc b/sync/notifier/p2p_invalidator.cc
index 8b54c0417e..05ec183537 100644
--- a/sync/notifier/p2p_invalidator.cc
+++ b/sync/notifier/p2p_invalidator.cc
@@ -173,7 +173,9 @@ void P2PInvalidator::UpdateRegisteredIds(InvalidationHandler* handler,
const P2PNotificationData notification_data(
invalidator_client_id_,
NOTIFY_SELF,
- ObjectIdSetToInvalidationMap(new_ids, std::string()));
+ ObjectIdSetToInvalidationMap(new_ids,
+ Invalidation::kUnknownVersion,
+ std::string()));
SendNotificationData(notification_data);
}
@@ -228,6 +230,7 @@ void P2PInvalidator::OnNotificationsEnabled() {
invalidator_client_id_,
NOTIFY_SELF,
ObjectIdSetToInvalidationMap(registrar_.GetAllRegisteredIds(),
+ Invalidation::kUnknownVersion,
std::string()));
SendNotificationData(notification_data);
}
@@ -263,6 +266,7 @@ void P2PInvalidator::OnIncomingNotification(
invalidator_client_id_,
NOTIFY_ALL,
ObjectIdSetToInvalidationMap(registrar_.GetAllRegisteredIds(),
+ Invalidation::kUnknownVersion,
std::string()));
}
if (!notification_data.IsTargeted(invalidator_client_id_)) {
diff --git a/sync/notifier/p2p_invalidator_unittest.cc b/sync/notifier/p2p_invalidator_unittest.cc
index 6acc3d1703..be9ee3f970 100644
--- a/sync/notifier/p2p_invalidator_unittest.cc
+++ b/sync/notifier/p2p_invalidator_unittest.cc
@@ -180,6 +180,7 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) {
const ObjectIdInvalidationMap& invalidation_map =
ObjectIdSetToInvalidationMap(
ModelTypeSetToObjectIdSet(ModelTypeSet(BOOKMARKS, THEMES)),
+ Invalidation::kUnknownVersion,
std::string());
const P2PNotificationData notification_data(
"sender", NOTIFY_ALL, invalidation_map);
@@ -193,10 +194,10 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) {
"{\"idInvalidationMap\":["
"{\"objectId\":{\"name\":\"BOOKMARK\",\"source\":1004},"
"\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"},"
- "\"payload\":\"\"}},"
+ "\"payload\":\"\",\"version\":\"-1\"}},"
"{\"objectId\":{\"name\":\"THEME\",\"source\":1004},"
"\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"},"
- "\"payload\":\"\"}}"
+ "\"payload\":\"\",\"version\":\"-1\"}}"
"],\"notificationType\":\"notifyAll\","
"\"senderId\":\"sender\"}", notification_data_str);
@@ -249,6 +250,7 @@ TEST_F(P2PInvalidatorTest, NotificationsBasic) {
const ObjectIdInvalidationMap& invalidation_map =
ObjectIdSetToInvalidationMap(
ModelTypeSetToObjectIdSet(ModelTypeSet(THEMES, APPS)),
+ Invalidation::kUnknownVersion,
std::string());
invalidator->SendInvalidation(invalidation_map);
}
@@ -267,6 +269,7 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
const ObjectIdInvalidationMap& invalidation_map =
ObjectIdSetToInvalidationMap(ModelTypeSetToObjectIdSet(changed_types),
+ Invalidation::kUnknownVersion,
std::string());
P2PInvalidator* const invalidator = delegate_.GetInvalidator();
diff --git a/sync/notifier/sync_invalidation_listener.cc b/sync/notifier/sync_invalidation_listener.cc
index ddb9e35184..ed07f2070b 100644
--- a/sync/notifier/sync_invalidation_listener.cc
+++ b/sync/notifier/sync_invalidation_listener.cc
@@ -205,7 +205,7 @@ void SyncInvalidationListener::Invalidate(
ObjectIdSet ids;
ids.insert(id);
- PrepareInvalidation(ids, payload, client, ack_handle);
+ PrepareInvalidation(ids, invalidation.version(), payload, client, ack_handle);
}
void SyncInvalidationListener::InvalidateUnknownVersion(
@@ -218,7 +218,12 @@ void SyncInvalidationListener::InvalidateUnknownVersion(
ObjectIdSet ids;
ids.insert(object_id);
- PrepareInvalidation(ids, std::string(), client, ack_handle);
+ PrepareInvalidation(
+ ids,
+ Invalidation::kUnknownVersion,
+ std::string(),
+ client,
+ ack_handle);
}
// This should behave as if we got an invalidation with version
@@ -230,11 +235,17 @@ void SyncInvalidationListener::InvalidateAll(
DCHECK_EQ(client, invalidation_client_.get());
DVLOG(1) << "InvalidateAll";
- PrepareInvalidation(registered_ids_, std::string(), client, ack_handle);
+ PrepareInvalidation(
+ registered_ids_,
+ Invalidation::kUnknownVersion,
+ std::string(),
+ client,
+ ack_handle);
}
void SyncInvalidationListener::PrepareInvalidation(
const ObjectIdSet& ids,
+ int64 version,
const std::string& payload,
invalidation::InvalidationClient* client,
const invalidation::AckHandle& ack_handle) {
@@ -250,6 +261,7 @@ void SyncInvalidationListener::PrepareInvalidation(
base::Bind(&SyncInvalidationListener::EmitInvalidation,
weak_ptr_factory_.GetWeakPtr(),
ids,
+ version,
payload,
client,
ack_handle));
@@ -257,13 +269,14 @@ void SyncInvalidationListener::PrepareInvalidation(
void SyncInvalidationListener::EmitInvalidation(
const ObjectIdSet& ids,
+ int64 version,
const std::string& payload,
invalidation::InvalidationClient* client,
const invalidation::AckHandle& ack_handle,
const AckHandleMap& local_ack_handles) {
DCHECK(CalledOnValidThread());
ObjectIdInvalidationMap invalidation_map =
- ObjectIdSetToInvalidationMap(ids, payload);
+ ObjectIdSetToInvalidationMap(ids, version, payload);
for (AckHandleMap::const_iterator it = local_ack_handles.begin();
it != local_ack_handles.end(); ++it) {
// Update in-memory copy of the invalidation state.
@@ -280,6 +293,7 @@ void SyncInvalidationListener::OnTimeout(const ObjectIdSet& ids) {
for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
Invalidation invalidation;
invalidation.ack_handle = invalidation_state_map_[*it].expected;
+ invalidation.version = invalidation_state_map_[*it].version;
invalidation.payload = invalidation_state_map_[*it].payload;
invalidation_map.insert(std::make_pair(*it, invalidation));
}
diff --git a/sync/notifier/sync_invalidation_listener.h b/sync/notifier/sync_invalidation_listener.h
index 3613551460..d280e2e5c6 100644
--- a/sync/notifier/sync_invalidation_listener.h
+++ b/sync/notifier/sync_invalidation_listener.h
@@ -151,10 +151,12 @@ class SYNC_EXPORT_PRIVATE SyncInvalidationListener
void EmitStateChange();
void PrepareInvalidation(const ObjectIdSet& ids,
+ int64 version,
const std::string& payload,
invalidation::InvalidationClient* client,
const invalidation::AckHandle& ack_handle);
void EmitInvalidation(const ObjectIdSet& ids,
+ int64 version,
const std::string& payload,
invalidation::InvalidationClient* client,
const invalidation::AckHandle& ack_handle,
diff --git a/sync/notifier/sync_invalidation_listener_unittest.cc b/sync/notifier/sync_invalidation_listener_unittest.cc
index 3dee40cd08..d3aa712b7d 100644
--- a/sync/notifier/sync_invalidation_listener_unittest.cc
+++ b/sync/notifier/sync_invalidation_listener_unittest.cc
@@ -146,6 +146,11 @@ class FakeDelegate : public SyncInvalidationListener::Delegate {
return (it == invalidation_counts_.end()) ? 0 : it->second;
}
+ int64 GetVersion(const ObjectId& id) const {
+ ObjectIdInvalidationMap::const_iterator it = invalidations_.find(id);
+ return (it == invalidations_.end()) ? 0 : it->second.version;
+ }
+
std::string GetPayload(const ObjectId& id) const {
ObjectIdInvalidationMap::const_iterator it = invalidations_.find(id);
return (it == invalidations_.end()) ? std::string() : it->second.payload;
@@ -295,6 +300,10 @@ class SyncInvalidationListenerTest : public testing::Test {
return fake_delegate_.GetInvalidationCount(id);
}
+ int64 GetVersion(const ObjectId& id) const {
+ return fake_delegate_.GetVersion(id);
+ }
+
std::string GetPayload(const ObjectId& id) const {
return fake_delegate_.GetPayload(id);
}
@@ -437,6 +446,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateNoPayload) {
FireInvalidate(id, kVersion1, NULL);
EXPECT_EQ(1, GetInvalidationCount(id));
+ EXPECT_EQ(kVersion1, GetVersion(id));
EXPECT_EQ("", GetPayload(id));
EXPECT_EQ(kVersion1, GetMaxVersion(id));
AcknowledgeAndVerify(id);
@@ -451,6 +461,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateEmptyPayload) {
FireInvalidate(id, kVersion1, "");
EXPECT_EQ(1, GetInvalidationCount(id));
+ EXPECT_EQ(kVersion1, GetVersion(id));
EXPECT_EQ("", GetPayload(id));
EXPECT_EQ(kVersion1, GetMaxVersion(id));
AcknowledgeAndVerify(id);
@@ -464,6 +475,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateWithPayload) {
FireInvalidate(id, kVersion1, kPayload1);
EXPECT_EQ(1, GetInvalidationCount(id));
+ EXPECT_EQ(kVersion1, GetVersion(id));
EXPECT_EQ(kPayload1, GetPayload(id));
EXPECT_EQ(kVersion1, GetMaxVersion(id));
AcknowledgeAndVerify(id);
@@ -483,6 +495,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateUnregisteredWithPayload) {
FireInvalidate(id, kVersion1, "unregistered payload");
EXPECT_EQ(1, GetInvalidationCount(id));
+ EXPECT_EQ(kVersion1, GetVersion(id));
EXPECT_EQ("unregistered payload", GetPayload(id));
EXPECT_EQ(kVersion1, GetMaxVersion(id));
AcknowledgeAndVerify(id);
@@ -497,6 +510,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateVersion) {
FireInvalidate(id, kVersion2, kPayload2);
EXPECT_EQ(1, GetInvalidationCount(id));
+ EXPECT_EQ(kVersion2, GetVersion(id));
EXPECT_EQ(kPayload2, GetPayload(id));
EXPECT_EQ(kVersion2, GetMaxVersion(id));
AcknowledgeAndVerify(id);
@@ -504,6 +518,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateVersion) {
FireInvalidate(id, kVersion1, kPayload1);
EXPECT_EQ(1, GetInvalidationCount(id));
+ EXPECT_EQ(kVersion2, GetVersion(id));
EXPECT_EQ(kPayload2, GetPayload(id));
EXPECT_EQ(kVersion2, GetMaxVersion(id));
VerifyAcknowledged(id);
@@ -518,6 +533,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateUnknownVersion) {
FireInvalidateUnknownVersion(id);
EXPECT_EQ(1, GetInvalidationCount(id));
+ EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(id));
EXPECT_EQ("", GetPayload(id));
EXPECT_EQ(kMinVersion, GetMaxVersion(id));
AcknowledgeAndVerify(id);
@@ -525,6 +541,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateUnknownVersion) {
FireInvalidateUnknownVersion(id);
EXPECT_EQ(2, GetInvalidationCount(id));
+ EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(id));
EXPECT_EQ("", GetPayload(id));
EXPECT_EQ(kMinVersion, GetMaxVersion(id));
AcknowledgeAndVerify(id);
@@ -538,6 +555,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateAll) {
for (ObjectIdSet::const_iterator it = registered_ids_.begin();
it != registered_ids_.end(); ++it) {
EXPECT_EQ(1, GetInvalidationCount(*it));
+ EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(*it));
EXPECT_EQ("", GetPayload(*it));
EXPECT_EQ(kMinVersion, GetMaxVersion(*it));
AcknowledgeAndVerify(*it);
@@ -549,6 +567,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) {
FireInvalidate(kBookmarksId_, 3, NULL);
EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_));
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
AcknowledgeAndVerify(kBookmarksId_);
@@ -556,6 +575,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) {
FireInvalidate(kExtensionsId_, 2, NULL);
EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_));
+ EXPECT_EQ(2, GetVersion(kExtensionsId_));
EXPECT_EQ("", GetPayload(kExtensionsId_));
EXPECT_EQ(2, GetMaxVersion(kExtensionsId_));
AcknowledgeAndVerify(kExtensionsId_);
@@ -565,12 +585,14 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) {
FireInvalidate(kBookmarksId_, 1, NULL);
EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_));
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
FireInvalidate(kExtensionsId_, 1, NULL);
EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_));
+ EXPECT_EQ(2, GetVersion(kExtensionsId_));
EXPECT_EQ("", GetPayload(kExtensionsId_));
EXPECT_EQ(2, GetMaxVersion(kExtensionsId_));
@@ -579,11 +601,13 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) {
FireInvalidateAll();
EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_));
+ EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
AcknowledgeAndVerify(kBookmarksId_);
EXPECT_EQ(1, GetInvalidationCount(kPreferencesId_));
+ EXPECT_EQ(Invalidation::kUnknownVersion, GetVersion(kPreferencesId_));
EXPECT_EQ("", GetPayload(kPreferencesId_));
EXPECT_EQ(kMinVersion, GetMaxVersion(kPreferencesId_));
AcknowledgeAndVerify(kPreferencesId_);
@@ -591,6 +615,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) {
// Note that kExtensionsId_ is not registered, so InvalidateAll() shouldn't
// affect it.
EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_));
+ EXPECT_EQ(2, GetVersion(kExtensionsId_));
EXPECT_EQ("", GetPayload(kExtensionsId_));
EXPECT_EQ(2, GetMaxVersion(kExtensionsId_));
VerifyAcknowledged(kExtensionsId_);
@@ -599,18 +624,21 @@ TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) {
FireInvalidate(kPreferencesId_, 5, NULL);
EXPECT_EQ(2, GetInvalidationCount(kPreferencesId_));
+ EXPECT_EQ(5, GetVersion(kPreferencesId_));
EXPECT_EQ("", GetPayload(kPreferencesId_));
EXPECT_EQ(5, GetMaxVersion(kPreferencesId_));
AcknowledgeAndVerify(kPreferencesId_);
FireInvalidate(kExtensionsId_, 3, NULL);
EXPECT_EQ(2, GetInvalidationCount(kExtensionsId_));
+ EXPECT_EQ(3, GetVersion(kExtensionsId_));
EXPECT_EQ("", GetPayload(kExtensionsId_));
EXPECT_EQ(3, GetMaxVersion(kExtensionsId_));
AcknowledgeAndVerify(kExtensionsId_);
FireInvalidate(kBookmarksId_, 4, NULL);
EXPECT_EQ(3, GetInvalidationCount(kBookmarksId_));
+ EXPECT_EQ(4, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(4, GetMaxVersion(kBookmarksId_));
AcknowledgeAndVerify(kBookmarksId_);
@@ -628,6 +656,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateOneTimeout) {
// Trigger the initial invalidation.
FireInvalidate(kBookmarksId_, 3, NULL);
EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_));
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
VerifyUnacknowledged(kBookmarksId_);
@@ -638,6 +667,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidateOneTimeout) {
tick_clock_.NowTicks()));
EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_));
// Other properties should remain the same.
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
@@ -655,6 +685,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) {
FireInvalidate(kBookmarksId_, 3, NULL);
EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_));
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
@@ -664,6 +695,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) {
tick_clock_.NowTicks()));
EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_));
// Other properties should remain the same.
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
@@ -676,6 +708,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) {
// The bookmark invalidation state should not have changed.
EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_));
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
@@ -685,6 +718,7 @@ TEST_F(SyncInvalidationListenerTest, InvalidationTimeoutRestart) {
tick_clock_.NowTicks()));
EXPECT_EQ(3, GetInvalidationCount(kBookmarksId_));
// Other properties should remain the same.
+ EXPECT_EQ(3, GetVersion(kBookmarksId_));
EXPECT_EQ("", GetPayload(kBookmarksId_));
EXPECT_EQ(3, GetMaxVersion(kBookmarksId_));
diff --git a/sync/protocol/experiments_specifics.proto b/sync/protocol/experiments_specifics.proto
index f834cb91c0..1e8732fd02 100644
--- a/sync/protocol/experiments_specifics.proto
+++ b/sync/protocol/experiments_specifics.proto
@@ -34,6 +34,11 @@ message FaviconSyncFlags {
optional int32 favicon_sync_limit = 2 [default = 200];
}
+// Flags for enabling the experimental no-precommit GU feature.
+message PreCommitUpdateAvoidanceFlags {
+ optional bool enabled = 1;
+}
+
// Contains one flag or set of related flags. Each node of the experiments type
// will have a unique_client_tag identifying which flags it contains. By
// convention, the tag name should match the sub-message name.
@@ -42,4 +47,5 @@ message ExperimentsSpecifics {
optional HistoryDeleteDirectives history_delete_directives = 2;
optional AutofillCullingFlags autofill_culling = 3;
optional FaviconSyncFlags favicon_sync = 4;
+ optional PreCommitUpdateAvoidanceFlags pre_commit_update_avoidance = 5;
}
diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc
index f0a2011c27..9ccc5eb0c8 100644
--- a/sync/protocol/proto_value_conversions.cc
+++ b/sync/protocol/proto_value_conversions.cc
@@ -352,6 +352,7 @@ base::DictionaryValue* ExperimentsSpecificsToValue(
SET_EXPERIMENT_ENABLED_FIELD(keystore_encryption);
SET_EXPERIMENT_ENABLED_FIELD(history_delete_directives);
SET_EXPERIMENT_ENABLED_FIELD(autofill_culling);
+ SET_EXPERIMENT_ENABLED_FIELD(pre_commit_update_avoidance);
if (proto.has_favicon_sync())
SET(favicon_sync, FaviconSyncFlagsToValue);
return value;
diff --git a/sync/sessions/data_type_tracker.cc b/sync/sessions/data_type_tracker.cc
index 3eabbbe758..a061679839 100644
--- a/sync/sessions/data_type_tracker.cc
+++ b/sync/sessions/data_type_tracker.cc
@@ -59,7 +59,17 @@ bool DataTypeTracker::IsSyncRequired() const {
return !IsThrottled() &&
(local_nudge_count_ > 0 ||
local_refresh_request_count_ > 0 ||
- !pending_payloads_.empty());
+ HasPendingInvalidation() ||
+ local_payload_overflow_ ||
+ server_payload_overflow_);
+}
+
+bool DataTypeTracker::IsGetUpdatesRequired() const {
+ return !IsThrottled() &&
+ (local_refresh_request_count_ > 0 ||
+ HasPendingInvalidation() ||
+ local_payload_overflow_ ||
+ server_payload_overflow_);
}
bool DataTypeTracker::HasLocalChangePending() const {
diff --git a/sync/sessions/data_type_tracker.h b/sync/sessions/data_type_tracker.h
index 6488f8e105..30bc3b6dbb 100644
--- a/sync/sessions/data_type_tracker.h
+++ b/sync/sessions/data_type_tracker.h
@@ -49,6 +49,10 @@ class DataTypeTracker {
// cycle. That's for the scheduler to decide.
bool IsSyncRequired() const;
+ // Returns true if there is a good reason to fetch updates for this type as
+ // part of the next sync cycle.
+ bool IsGetUpdatesRequired() const;
+
// Returns true if there is an uncommitted local change.
bool HasLocalChangePending() const;
diff --git a/sync/sessions/nudge_tracker.cc b/sync/sessions/nudge_tracker.cc
index 144860b1a8..f9b90386f5 100644
--- a/sync/sessions/nudge_tracker.cc
+++ b/sync/sessions/nudge_tracker.cc
@@ -38,6 +38,16 @@ bool NudgeTracker::IsSyncRequired() const {
return false;
}
+bool NudgeTracker::IsGetUpdatesRequired() const {
+ for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
+ it != type_trackers_.end(); ++it) {
+ if (it->second.IsGetUpdatesRequired()) {
+ return true;
+ }
+ }
+ return false;
+}
+
void NudgeTracker::RecordSuccessfulSyncCycle() {
updates_source_ = sync_pb::GetUpdatesCallerInfo::UNKNOWN;
diff --git a/sync/sessions/nudge_tracker.h b/sync/sessions/nudge_tracker.h
index 0e8ab51202..f8109a42d3 100644
--- a/sync/sessions/nudge_tracker.h
+++ b/sync/sessions/nudge_tracker.h
@@ -34,6 +34,10 @@ class SYNC_EXPORT_PRIVATE NudgeTracker {
// perform a sync cycle; that's the scheduler's job.
bool IsSyncRequired() const;
+ // Returns true if there is a good reason for performing a get updates
+ // request as part of the next sync cycle.
+ bool IsGetUpdatesRequired() const;
+
// Tells this class that all required update fetching and committing has
// completed successfully.
void RecordSuccessfulSyncCycle();
diff --git a/sync/sessions/nudge_tracker_unittest.cc b/sync/sessions/nudge_tracker_unittest.cc
index 8439af1d82..598a3e6b43 100644
--- a/sync/sessions/nudge_tracker_unittest.cc
+++ b/sync/sessions/nudge_tracker_unittest.cc
@@ -61,6 +61,7 @@ TEST_F(NudgeTrackerTest, EmptyNudgeTracker) {
NudgeTracker nudge_tracker;
EXPECT_FALSE(nudge_tracker.IsSyncRequired());
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN,
nudge_tracker.updates_source());
@@ -300,6 +301,33 @@ TEST_F(NudgeTrackerTest, IsSyncRequired) {
EXPECT_FALSE(nudge_tracker.IsSyncRequired());
}
+// Basic tests for the IsGetUpdatesRequired() flag.
+TEST_F(NudgeTrackerTest, IsGetUpdatesRequired) {
+ NudgeTracker nudge_tracker;
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+
+ // Local changes.
+ nudge_tracker.RecordLocalChange(ModelTypeSet(SESSIONS));
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+ nudge_tracker.RecordSuccessfulSyncCycle();
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+
+ // Refresh requests.
+ nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
+ EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+ nudge_tracker.RecordSuccessfulSyncCycle();
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+
+ // Invalidations.
+ ModelTypeInvalidationMap invalidation_map =
+ ModelTypeSetToInvalidationMap(ModelTypeSet(PREFERENCES),
+ std::string("hint"));
+ nudge_tracker.RecordRemoteInvalidation(invalidation_map);
+ EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+ nudge_tracker.RecordSuccessfulSyncCycle();
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+}
+
// Test IsSyncRequired() responds correctly to data type throttling.
TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) {
NudgeTracker nudge_tracker;
@@ -320,7 +348,7 @@ TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) {
EXPECT_FALSE(nudge_tracker.IsSyncRequired());
// A refresh request for bookmarks means we have reason to sync again.
- nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
+ nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS));
EXPECT_TRUE(nudge_tracker.IsSyncRequired());
// A successful sync cycle means we took care of bookmarks.
@@ -335,6 +363,41 @@ TEST_F(NudgeTrackerTest, IsSyncRequired_Throttling) {
EXPECT_TRUE(nudge_tracker.IsSyncRequired());
}
+// Test IsGetUpdatesRequired() responds correctly to data type throttling.
+TEST_F(NudgeTrackerTest, IsGetUpdatesRequired_Throttling) {
+ NudgeTracker nudge_tracker;
+ const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234);
+ const base::TimeDelta throttle_length = base::TimeDelta::FromMinutes(10);
+ const base::TimeTicks t1 = t0 + throttle_length;
+
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+
+ // A refresh request to sessions enables the flag.
+ nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(SESSIONS));
+ EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+
+ // But the throttling of sessions unsets it.
+ nudge_tracker.SetTypesThrottledUntil(ModelTypeSet(SESSIONS),
+ throttle_length,
+ t0);
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+
+ // A refresh request for bookmarks means we have reason to sync again.
+ nudge_tracker.RecordLocalRefreshRequest(ModelTypeSet(BOOKMARKS));
+ EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+
+ // A successful sync cycle means we took care of bookmarks.
+ nudge_tracker.RecordSuccessfulSyncCycle();
+ EXPECT_FALSE(nudge_tracker.IsGetUpdatesRequired());
+
+ // But we still haven't dealt with sessions. We'll need to remember
+ // that sessions are out of sync and re-enable the flag when their
+ // throttling interval expires.
+ nudge_tracker.UpdateTypeThrottlingState(t1);
+ EXPECT_FALSE(nudge_tracker.IsTypeThrottled(SESSIONS));
+ EXPECT_TRUE(nudge_tracker.IsGetUpdatesRequired());
+}
+
// Tests throttling-related getter functions when no types are throttled.
TEST_F(NudgeTrackerTest, NoTypesThrottled) {
NudgeTracker nudge_tracker;
diff --git a/sync/sessions/sync_session_context.cc b/sync/sessions/sync_session_context.cc
index 9043db3cba..c48c32b31e 100644
--- a/sync/sessions/sync_session_context.cc
+++ b/sync/sessions/sync_session_context.cc
@@ -22,6 +22,7 @@ SyncSessionContext::SyncSessionContext(
DebugInfoGetter* debug_info_getter,
TrafficRecorder* traffic_recorder,
bool keystore_encryption_enabled,
+ bool client_enabled_pre_commit_update_avoidance,
const std::string& invalidator_client_id)
: connection_manager_(connection_manager),
directory_(directory),
@@ -31,7 +32,10 @@ SyncSessionContext::SyncSessionContext(
debug_info_getter_(debug_info_getter),
traffic_recorder_(traffic_recorder),
keystore_encryption_enabled_(keystore_encryption_enabled),
- invalidator_client_id_(invalidator_client_id) {
+ invalidator_client_id_(invalidator_client_id),
+ server_enabled_pre_commit_update_avoidance_(false),
+ client_enabled_pre_commit_update_avoidance_(
+ client_enabled_pre_commit_update_avoidance) {
for (size_t i = 0u; i < workers.size(); ++i)
workers_.push_back(workers[i]);
diff --git a/sync/sessions/sync_session_context.h b/sync/sessions/sync_session_context.h
index b694162c15..76170958ec 100644
--- a/sync/sessions/sync_session_context.h
+++ b/sync/sessions/sync_session_context.h
@@ -55,6 +55,7 @@ class SYNC_EXPORT_PRIVATE SyncSessionContext {
DebugInfoGetter* debug_info_getter,
TrafficRecorder* traffic_recorder,
bool keystore_encryption_enabled,
+ bool client_enabled_pre_commit_update_avoidance,
const std::string& invalidator_client_id);
~SyncSessionContext();
@@ -129,6 +130,15 @@ class SYNC_EXPORT_PRIVATE SyncSessionContext {
return invalidator_client_id_;
}
+ bool ShouldFetchUpdatesBeforeCommit() const {
+ return !(server_enabled_pre_commit_update_avoidance_ ||
+ client_enabled_pre_commit_update_avoidance_);
+ }
+
+ void set_server_enabled_pre_commit_update_avoidance(bool value) {
+ server_enabled_pre_commit_update_avoidance_ = value;
+ }
+
private:
// Rather than force clients to set and null-out various context members, we
// extend our encapsulation boundary to scoped helpers that take care of this
@@ -181,6 +191,15 @@ class SYNC_EXPORT_PRIVATE SyncSessionContext {
// prevent us from receiving notifications of changes we make ourselves.
const std::string invalidator_client_id_;
+ // Flag to enable or disable the no pre-commit GetUpdates experiment. When
+ // this flag is set to false, the syncer has the option of not performing at
+ // GetUpdates request when there is nothing to fetch.
+ bool server_enabled_pre_commit_update_avoidance_;
+
+ // If true, indicates that we've been passed a command-line flag to force
+ // enable the pre-commit update avoidance experiment described above.
+ const bool client_enabled_pre_commit_update_avoidance_;
+
DISALLOW_COPY_AND_ASSIGN(SyncSessionContext);
};
diff --git a/sync/sessions/sync_session_unittest.cc b/sync/sessions/sync_session_unittest.cc
index c98b63923f..4acee569fe 100644
--- a/sync/sessions/sync_session_unittest.cc
+++ b/sync/sessions/sync_session_unittest.cc
@@ -65,6 +65,7 @@ class SyncSessionTest : public testing::Test,
NULL,
NULL,
true, // enable keystore encryption
+ false, // force enable pre-commit GU avoidance experiment
"fake_invalidator_client_id"));
context_->set_routing_info(routes_);
diff --git a/sync/syncable/model_type.cc b/sync/syncable/model_type.cc
index 5e227948b7..b9dacbecf1 100644
--- a/sync/syncable/model_type.cc
+++ b/sync/syncable/model_type.cc
@@ -367,7 +367,7 @@ ModelTypeSet EncryptableUserTypes() {
encryptable_user_types.Remove(SYNCED_NOTIFICATIONS);
// Priority preferences are not encrypted because they might be synced before
// encryption is ready.
- encryptable_user_types.RemoveAll(PriorityUserTypes());
+ encryptable_user_types.Remove(PRIORITY_PREFERENCES);
// Managed user settings are not encrypted since they are set server-side.
encryptable_user_types.Remove(MANAGED_USER_SETTINGS);
// Managed users are not encrypted since they are managed server-side.
@@ -380,7 +380,7 @@ ModelTypeSet EncryptableUserTypes() {
}
ModelTypeSet PriorityUserTypes() {
- return ModelTypeSet(PRIORITY_PREFERENCES, MANAGED_USERS);
+ return ModelTypeSet(PRIORITY_PREFERENCES);
}
ModelTypeSet ControlTypes() {
@@ -405,6 +405,26 @@ bool IsControlType(ModelType model_type) {
return ControlTypes().Has(model_type);
}
+ModelTypeSet CoreTypes() {
+ syncer::ModelTypeSet result;
+ result.PutAll(PriorityCoreTypes());
+
+ // The following are low priority core types.
+ result.Put(SYNCED_NOTIFICATIONS);
+
+ return result;
+}
+
+ModelTypeSet PriorityCoreTypes() {
+ syncer::ModelTypeSet result;
+ result.PutAll(ControlTypes());
+
+ // The following are non-control core types.
+ result.Put(MANAGED_USERS);
+
+ return result;
+}
+
const char* ModelTypeToString(ModelType model_type) {
// This is used in serialization routines as well as for displaying debug
// information. Do not attempt to change these string values unless you know
diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java
index b79abcf5d5..da16fae2ae 100644
--- a/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java
+++ b/sync/test/android/javatests/src/org/chromium/sync/test/util/MockAccountManager.java
@@ -238,7 +238,8 @@ public class MockAccountManager implements AccountManagerDelegate {
} else {
Log.d(TAG, "getAuthTokenFuture: Account " + ah.getAccount() +
" is asking for permission for " + authTokenType);
- final Intent intent = newGrantCredentialsPermissionIntent(true, account, authTokenType);
+ final Intent intent = newGrantCredentialsPermissionIntent(
+ activity != null, account, authTokenType);
return runTask(mExecutor,
new AccountManagerAuthTokenTask(activity, handler, callback,
account, authTokenType,
@@ -495,10 +496,13 @@ public class MockAccountManager implements AccountManagerDelegate {
try {
Bundle bundle = mCallable.call();
Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
- if (intent != null && mActivity != null) {
- // Since the user provided an Activity we will silently start intents we see.
- // Starting activity and waiting for it to finish.
- waitForActivity(mActivity, intent);
+ if (intent != null) {
+ // Start the intent activity and wait for it to finish.
+ if (mActivity != null) {
+ waitForActivity(mActivity, intent);
+ } else {
+ waitForActivity(mContext, intent);
+ }
if (mAccountAuthTokenPreparation == null) {
throw new IllegalStateException("No account preparation ready for " +
mAccount + ", authTokenType = " + mAuthTokenType +
diff --git a/sync/test/engine/syncer_command_test.h b/sync/test/engine/syncer_command_test.h
index c292fe0b96..93106b9933 100644
--- a/sync/test/engine/syncer_command_test.h
+++ b/sync/test/engine/syncer_command_test.h
@@ -136,6 +136,7 @@ class SyncerCommandTestBase : public testing::Test,
&mock_debug_info_getter_,
&traffic_recorder_,
true, // enable keystore encryption
+ false, // force enable pre-commit GU avoidance experiment
"fake_invalidator_client_id"));
context_->set_routing_info(routing_info_);
context_->set_account_name(directory()->name());
diff --git a/sync/tools/testserver/chromiumsync.py b/sync/tools/testserver/chromiumsync.py
index 7aac4deeaa..834765ff71 100644
--- a/sync/tools/testserver/chromiumsync.py
+++ b/sync/tools/testserver/chromiumsync.py
@@ -129,8 +129,9 @@ UNIX_TIME_EPOCH = (1970, 1, 1, 0, 0, 0, 3, 1, 0)
# The number of characters in the server-generated encryption key.
KEYSTORE_KEY_LENGTH = 16
-# The hashed client tag for the keystore encryption experiment node.
+# The hashed client tags for some experiment nodes.
KEYSTORE_ENCRYPTION_EXPERIMENT_TAG = "pis8ZRzh98/MKLtVEio2mr42LQA="
+PRE_COMMIT_GU_AVOIDANCE_EXPERIMENT_TAG = "Z1xgeh3QUBa50vdEPd8C/4c7jfE="
class Error(Exception):
"""Error class for this module."""
@@ -1101,6 +1102,25 @@ class SyncDataModel(object):
user.specifics.managed_user.acknowledged = True
self._SaveEntry(user)
+ def TriggerEnablePreCommitGetUpdateAvoidance(self):
+ """Sets the experiment to enable pre-commit GetUpdate avoidance."""
+ experiment_id = self._ServerTagToId("google_chrome_experiments")
+ pre_commit_gu_avoidance_id = self._ClientTagToId(
+ EXPERIMENTS,
+ PRE_COMMIT_GU_AVOIDANCE_EXPERIMENT_TAG)
+ entry = self._entries.get(pre_commit_gu_avoidance_id)
+ if entry is None:
+ entry = sync_pb2.SyncEntity()
+ entry.id_string = pre_commit_gu_avoidance_id
+ entry.name = "Pre-commit GU avoidance"
+ entry.client_defined_unique_tag = PRE_COMMIT_GU_AVOIDANCE_EXPERIMENT_TAG
+ entry.folder = False
+ entry.deleted = False
+ entry.specifics.CopyFrom(GetDefaultEntitySpecifics(EXPERIMENTS))
+ self._WritePosition(entry, experiment_id)
+ entry.specifics.experiments.pre_commit_update_avoidance.enabled = True
+ self._SaveEntry(entry)
+
def SetInducedError(self, error, error_frequency,
sync_count_before_errors):
self.induced_error = error
@@ -1281,6 +1301,14 @@ class TestServer(object):
'<html><title>Enable Managed User Acknowledgement</title>'
'<h1>Enable Managed User Acknowledgement</h1></html>')
+ def HandleEnablePreCommitGetUpdateAvoidance(self):
+ """Enables the pre-commit GU avoidance experiment."""
+ self.account.TriggerEnablePreCommitGetUpdateAvoidance()
+ return (
+ 200,
+ '<html><title>Enable pre-commit GU avoidance</title>'
+ '<H1>Enable pre-commit GU avoidance</H1></html>')
+
def HandleCommand(self, query, raw_request):
"""Decode and handle a sync command from a raw input of bytes.
diff --git a/sync/tools/testserver/sync_testserver.py b/sync/tools/testserver/sync_testserver.py
index 4fbfdaf9ac..53532cb5b7 100755
--- a/sync/tools/testserver/sync_testserver.py
+++ b/sync/tools/testserver/sync_testserver.py
@@ -150,7 +150,8 @@ class SyncPageHandler(testserver_base.BasePageHandler):
self.ChromiumSyncCreateSyncedBookmarksOpHandler,
self.ChromiumSyncEnableKeystoreEncryptionOpHandler,
self.ChromiumSyncRotateKeystoreKeysOpHandler,
- self.ChromiumSyncEnableManagedUserAcknowledgementHandler]
+ self.ChromiumSyncEnableManagedUserAcknowledgementHandler,
+ self.ChromiumSyncEnablePreCommitGetUpdateAvoidanceHandler]
post_handlers = [self.ChromiumSyncCommandHandler,
self.ChromiumSyncTimeHandler]
@@ -427,6 +428,19 @@ class SyncPageHandler(testserver_base.BasePageHandler):
self.wfile.write(raw_reply)
return True
+ def ChromiumSyncEnablePreCommitGetUpdateAvoidanceHandler(self):
+ test_name = "/chromiumsync/enableprecommitgetupdateavoidance"
+ if not self._ShouldHandleRequest(test_name):
+ return False
+ result, raw_reply = (
+ self.server._sync_handler.HandleEnablePreCommitGetUpdateAvoidance())
+ self.send_response(result)
+ self.send_header('Content-Type', 'text/html')
+ self.send_header('Content-Length', len(raw_reply))
+ self.end_headers()
+ self.wfile.write(raw_reply)
+ return True
+
class SyncServerRunner(testserver_base.TestServerRunner):
"""TestServerRunner for the net test servers."""