diff options
18 files changed, 631 insertions, 153 deletions
diff --git a/chrome/browser/sync/invalidations/invalidator_storage.cc b/chrome/browser/sync/invalidations/invalidator_storage.cc index dd7dd9e..ebd6dbc 100644 --- a/chrome/browser/sync/invalidations/invalidator_storage.cc +++ b/chrome/browser/sync/invalidations/invalidator_storage.cc @@ -5,9 +5,13 @@ #include "chrome/browser/sync/invalidations/invalidator_storage.h" #include "base/base64.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/string_number_conversions.h" +#include "base/task_runner.h" #include "base/values.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/pref_names.h" @@ -22,35 +26,53 @@ namespace { const char kSourceKey[] = "source"; const char kNameKey[] = "name"; const char kMaxVersionKey[] = "max-version"; +const char kPayloadKey[] = "payload"; +const char kCurrentAckHandleKey[] = "current-ack"; +const char kExpectedAckHandleKey[] = "expected-ack"; bool ValueToObjectIdAndState(const DictionaryValue& value, invalidation::ObjectId* id, syncer::InvalidationState* state) { std::string source_str; - int source = 0; - std::string name; - std::string max_version_str; if (!value.GetString(kSourceKey, &source_str)) { DLOG(WARNING) << "Unable to deserialize source"; return false; } + int source = 0; + if (!base::StringToInt(source_str, &source)) { + DLOG(WARNING) << "Invalid source: " << source_str; + return false; + } + std::string name; if (!value.GetString(kNameKey, &name)) { DLOG(WARNING) << "Unable to deserialize name"; return false; } + *id = invalidation::ObjectId(source, name); + std::string max_version_str; if (!value.GetString(kMaxVersionKey, &max_version_str)) { DLOG(WARNING) << "Unable to deserialize max version"; return false; } - if (!base::StringToInt(source_str, &source)) { - DLOG(WARNING) << "Invalid source: " << source_str; - return false; - } if (!base::StringToInt64(max_version_str, &state->version)) { DLOG(WARNING) << "Invalid max invalidation version: " << max_version_str; return false; } - *id = invalidation::ObjectId(source, name); + value.GetString(kPayloadKey, &state->payload); + // The ack handle fields won't be set if upgrading from previous versions of + // Chrome. + const base::DictionaryValue* current_ack_handle_value = NULL; + if (value.GetDictionary(kCurrentAckHandleKey, ¤t_ack_handle_value)) { + state->current.ResetFromValue(*current_ack_handle_value); + } + const base::DictionaryValue* expected_ack_handle_value = NULL; + if (value.GetDictionary(kExpectedAckHandleKey, &expected_ack_handle_value)) { + state->expected.ResetFromValue(*expected_ack_handle_value); + } else { + // In this case, we should never have a valid current value set. + DCHECK(!state->current.IsValid()); + state->current = syncer::AckHandle::InvalidAckHandle(); + } return true; } @@ -61,6 +83,11 @@ DictionaryValue* ObjectIdAndStateToValue( value->SetString(kSourceKey, base::IntToString(id.source())); value->SetString(kNameKey, id.name()); value->SetString(kMaxVersionKey, base::Int64ToString(state.version)); + value->SetString(kPayloadKey, state.payload); + if (state.current.IsValid()) + value->Set(kCurrentAckHandleKey, state.current.ToValue().release()); + if (state.expected.IsValid()) + value->Set(kExpectedAckHandleKey, state.expected.ToValue().release()); return value; } @@ -98,8 +125,10 @@ InvalidationStateMap InvalidatorStorage::GetAllInvalidationStates() const { return state_map; } -void InvalidatorStorage::SetMaxVersion(const invalidation::ObjectId& id, - int64 max_version) { +void InvalidatorStorage::SetMaxVersionAndPayload( + const invalidation::ObjectId& id, + int64 max_version, + const std::string& payload) { DCHECK(thread_checker_.CalledOnValidThread()); CHECK(pref_service_); InvalidationStateMap state_map = GetAllInvalidationStates(); @@ -109,6 +138,7 @@ void InvalidatorStorage::SetMaxVersion(const invalidation::ObjectId& id, return; } state_map[id].version = max_version; + state_map[id].payload = payload; base::ListValue state_map_list; SerializeToList(state_map, &state_map_list); @@ -248,4 +278,47 @@ void InvalidatorStorage::Clear() { pref_service_->ClearPref(prefs::kInvalidatorInvalidationState); } +void InvalidatorStorage::GenerateAckHandles( + const syncer::ObjectIdSet& ids, + const scoped_refptr<base::TaskRunner>& task_runner, + const base::Callback<void(const syncer::AckHandleMap&)> callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + CHECK(pref_service_); + InvalidationStateMap state_map = GetAllInvalidationStates(); + + syncer::AckHandleMap ack_handles; + for (syncer::ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); + ++it) { + state_map[*it].expected = syncer::AckHandle::CreateUnique(); + ack_handles.insert(std::make_pair(*it, state_map[*it].expected)); + } + + base::ListValue state_map_list; + SerializeToList(state_map, &state_map_list); + pref_service_->Set(prefs::kInvalidatorMaxInvalidationVersions, + state_map_list); + + ignore_result(task_runner->PostTask(FROM_HERE, + base::Bind(callback, ack_handles))); +} + +void InvalidatorStorage::Acknowledge(const invalidation::ObjectId& id, + const syncer::AckHandle& ack_handle) { + DCHECK(thread_checker_.CalledOnValidThread()); + CHECK(pref_service_); + InvalidationStateMap state_map = GetAllInvalidationStates(); + + InvalidationStateMap::iterator it = state_map.find(id); + // This could happen if the acknowledgement is delayed and Forget() has + // already been called. + if (it == state_map.end()) + return; + it->second.current = ack_handle; + + base::ListValue state_map_list; + SerializeToList(state_map, &state_map_list); + pref_service_->Set(prefs::kInvalidatorMaxInvalidationVersions, + state_map_list); +} + } // namespace browser_sync diff --git a/chrome/browser/sync/invalidations/invalidator_storage.h b/chrome/browser/sync/invalidations/invalidator_storage.h index c0f480f..1916403 100644 --- a/chrome/browser/sync/invalidations/invalidator_storage.h +++ b/chrome/browser/sync/invalidations/invalidator_storage.h @@ -43,12 +43,19 @@ class InvalidatorStorage : public base::SupportsWeakPtr<InvalidatorStorage>, // InvalidationStateTracker implementation. virtual syncer::InvalidationStateMap GetAllInvalidationStates() const OVERRIDE; - virtual void SetMaxVersion(const invalidation::ObjectId& id, - int64 max_version) OVERRIDE; + virtual void SetMaxVersionAndPayload(const invalidation::ObjectId& id, + int64 max_version, + const std::string& payload) OVERRIDE; virtual void Forget(const syncer::ObjectIdSet& ids) OVERRIDE; // TODO(tim): These are not yet used. Bug 124140. virtual void SetBootstrapData(const std::string& data) OVERRIDE; virtual std::string GetBootstrapData() const OVERRIDE; + virtual void GenerateAckHandles( + const syncer::ObjectIdSet& ids, + const scoped_refptr<base::TaskRunner>& task_runner, + base::Callback<void(const syncer::AckHandleMap&)> callback) OVERRIDE; + virtual void Acknowledge(const invalidation::ObjectId& id, + const syncer::AckHandle& ack_handle) OVERRIDE; private: FRIEND_TEST_ALL_PREFIXES(InvalidatorStorageTest, SerializeEmptyMap); @@ -61,6 +68,8 @@ class InvalidatorStorage : public base::SupportsWeakPtr<InvalidatorStorage>, FRIEND_TEST_ALL_PREFIXES(InvalidatorStorageTest, DeserializeFromEmptyList); FRIEND_TEST_ALL_PREFIXES(InvalidatorStorageTest, DeserializeFromListBasic); + FRIEND_TEST_ALL_PREFIXES(InvalidatorStorageTest, + DeserializeFromListMissingOptionalValues); FRIEND_TEST_ALL_PREFIXES(InvalidatorStorageTest, DeserializeMapOutOfRange); FRIEND_TEST_ALL_PREFIXES(InvalidatorStorageTest, DeserializeMapInvalidFormat); FRIEND_TEST_ALL_PREFIXES(InvalidatorStorageTest, diff --git a/chrome/browser/sync/invalidations/invalidator_storage_unittest.cc b/chrome/browser/sync/invalidations/invalidator_storage_unittest.cc index 850c574..8beb9a5 100644 --- a/chrome/browser/sync/invalidations/invalidator_storage_unittest.cc +++ b/chrome/browser/sync/invalidations/invalidator_storage_unittest.cc @@ -5,11 +5,14 @@ #include "chrome/browser/sync/invalidations/invalidator_storage.h" +#include "base/bind.h" #include "base/message_loop.h" +#include "base/message_loop_proxy.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_pref_service.h" +#include "sync/internal_api/public/base/invalidation_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,9 +25,17 @@ namespace { const char kSourceKey[] = "source"; const char kNameKey[] = "name"; const char kMaxVersionKey[] = "max-version"; +const char kPayloadKey[] = "payload"; +const char kCurrentAckHandleKey[] = "current-ack"; +const char kExpectedAckHandleKey[] = "expected-ack"; const int kChromeSyncSourceId = 1004; +void GenerateAckHandlesTestHelper(syncer::AckHandleMap* output, + const syncer::AckHandleMap& input) { + *output = input; +} + } // namespace class InvalidatorStorageTest : public testing::Test { @@ -43,33 +54,35 @@ class InvalidatorStorageTest : public testing::Test { const invalidation::ObjectId kAppNotificationsId_; const invalidation::ObjectId kAutofillId_; - private: MessageLoop loop_; }; -// Set max versions for various keys and verify that they are written and read -// back correctly. -TEST_F(InvalidatorStorageTest, MaxInvalidationVersions) { +// Set invalidation states for various keys and verify that they are written and +// read back correctly. +TEST_F(InvalidatorStorageTest, SetMaxVersionAndPayload) { InvalidatorStorage storage(&pref_service_); - InvalidationStateMap expected_max_versions; - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + InvalidationStateMap expected_states; + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); - expected_max_versions[kBookmarksId_].version = 2; - storage.SetMaxVersion(kBookmarksId_, 2); - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + expected_states[kBookmarksId_].version = 2; + expected_states[kBookmarksId_].payload = "hello"; + storage.SetMaxVersionAndPayload(kBookmarksId_, 2, "hello"); + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); - expected_max_versions[kPreferencesId_].version = 5; - storage.SetMaxVersion(kPreferencesId_, 5); - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + expected_states[kPreferencesId_].version = 5; + storage.SetMaxVersionAndPayload(kPreferencesId_, 5, std::string()); + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); - expected_max_versions[kAppNotificationsId_].version = 3; - storage.SetMaxVersion(kAppNotificationsId_, 3); - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + expected_states[kAppNotificationsId_].version = 3; + expected_states[kAppNotificationsId_].payload = "world"; + storage.SetMaxVersionAndPayload(kAppNotificationsId_, 3, "world"); + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); - expected_max_versions[kAppNotificationsId_].version = 4; - storage.SetMaxVersion(kAppNotificationsId_, 4); - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + expected_states[kAppNotificationsId_].version = 4; + expected_states[kAppNotificationsId_].payload = "again"; + storage.SetMaxVersionAndPayload(kAppNotificationsId_, 4, "again"); + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); } // Forgetting an entry should cause that entry to be deleted. @@ -77,18 +90,20 @@ TEST_F(InvalidatorStorageTest, Forget) { InvalidatorStorage storage(&pref_service_); EXPECT_TRUE(storage.GetAllInvalidationStates().empty()); - InvalidationStateMap expected_max_versions; - expected_max_versions[kBookmarksId_].version = 2; - expected_max_versions[kPreferencesId_].version = 5; - storage.SetMaxVersion(kBookmarksId_, 2); - storage.SetMaxVersion(kPreferencesId_, 5); - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + InvalidationStateMap expected_states; + expected_states[kBookmarksId_].version = 2; + expected_states[kBookmarksId_].payload = "a"; + expected_states[kPreferencesId_].version = 5; + expected_states[kPreferencesId_].payload = "b"; + storage.SetMaxVersionAndPayload(kBookmarksId_, 2, "a"); + storage.SetMaxVersionAndPayload(kPreferencesId_, 5, "b"); + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); - expected_max_versions.erase(kPreferencesId_); + expected_states.erase(kPreferencesId_); syncer::ObjectIdSet to_forget; to_forget.insert(kPreferencesId_); storage.Forget(to_forget); - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); } // Clearing the storage should erase all version map entries and the bootstrap @@ -101,10 +116,10 @@ TEST_F(InvalidatorStorageTest, Clear) { storage.SetBootstrapData("test"); EXPECT_EQ("test", storage.GetBootstrapData()); { - InvalidationStateMap expected_max_versions; - expected_max_versions[kAppNotificationsId_].version = 3; - storage.SetMaxVersion(kAppNotificationsId_, 3); - EXPECT_EQ(expected_max_versions, storage.GetAllInvalidationStates()); + InvalidationStateMap expected_states; + expected_states[kAppNotificationsId_].version = 3; + storage.SetMaxVersionAndPayload(kAppNotificationsId_, 3, std::string()); + EXPECT_EQ(expected_states, storage.GetAllInvalidationStates()); } storage.Clear(); @@ -227,28 +242,82 @@ TEST_F(InvalidatorStorageTest, DeserializeFromEmptyList) { EXPECT_TRUE(map.empty()); } -// Tests that deserializing a well-formed value results in the expected version +// Tests that deserializing a well-formed value results in the expected state // map. TEST_F(InvalidatorStorageTest, DeserializeFromListBasic) { InvalidationStateMap map; base::ListValue list; DictionaryValue* value; + syncer::AckHandle ack_handle_1 = syncer::AckHandle::CreateUnique(); + syncer::AckHandle ack_handle_2 = syncer::AckHandle::CreateUnique(); + + value = new DictionaryValue(); + value->SetString(kSourceKey, + base::IntToString(kAppNotificationsId_.source())); + value->SetString(kNameKey, kAppNotificationsId_.name()); + value->SetString(kMaxVersionKey, "20"); + value->SetString(kPayloadKey, "testing"); + value->Set(kCurrentAckHandleKey, ack_handle_1.ToValue().release()); + value->Set(kExpectedAckHandleKey, ack_handle_2.ToValue().release()); + list.Append(value); + + InvalidatorStorage::DeserializeFromList(list, &map); + EXPECT_EQ(1U, map.size()); + EXPECT_EQ(20, map[kAppNotificationsId_].version); + EXPECT_EQ("testing", map[kAppNotificationsId_].payload); + EXPECT_THAT(map[kAppNotificationsId_].current, Eq(ack_handle_1)); + EXPECT_THAT(map[kAppNotificationsId_].expected, Eq(ack_handle_2)); +} + +// Tests that deserializing well-formed values when optional parameters are +// omitted works. +TEST_F(InvalidatorStorageTest, DeserializeFromListMissingOptionalValues) { + InvalidationStateMap map; + base::ListValue list; + DictionaryValue* value; + syncer::AckHandle ack_handle = syncer::AckHandle::CreateUnique(); + // Payload missing because of an upgrade from a previous browser version that + // didn't set the field. value = new DictionaryValue(); value->SetString(kSourceKey, base::IntToString(kAutofillId_.source())); value->SetString(kNameKey, kAutofillId_.name()); value->SetString(kMaxVersionKey, "10"); list.Append(value); + // A crash between SetMaxVersion() and a callback from GenerateAckHandles() + // could result in this state. value = new DictionaryValue(); value->SetString(kSourceKey, base::IntToString(kBookmarksId_.source())); value->SetString(kNameKey, kBookmarksId_.name()); value->SetString(kMaxVersionKey, "15"); + value->SetString(kPayloadKey, "hello"); + list.Append(value); + // Never acknowledged, so current ack handle is unset. + value = new DictionaryValue(); + value->SetString(kSourceKey, base::IntToString(kPreferencesId_.source())); + value->SetString(kNameKey, kPreferencesId_.name()); + value->SetString(kMaxVersionKey, "20"); + value->SetString(kPayloadKey, "world"); + value->Set(kExpectedAckHandleKey, ack_handle.ToValue().release()); list.Append(value); InvalidatorStorage::DeserializeFromList(list, &map); - EXPECT_EQ(2U, map.size()); + EXPECT_EQ(3U, map.size()); + EXPECT_EQ(10, map[kAutofillId_].version); + EXPECT_EQ("", map[kAutofillId_].payload); + EXPECT_FALSE(map[kAutofillId_].current.IsValid()); + EXPECT_FALSE(map[kAutofillId_].expected.IsValid()); + EXPECT_EQ(15, map[kBookmarksId_].version); + EXPECT_EQ("hello", map[kBookmarksId_].payload); + EXPECT_FALSE(map[kBookmarksId_].current.IsValid()); + EXPECT_FALSE(map[kBookmarksId_].expected.IsValid()); + + EXPECT_EQ(20, map[kPreferencesId_].version); + EXPECT_EQ("world", map[kPreferencesId_].payload); + EXPECT_FALSE(map[kPreferencesId_].current.IsValid()); + EXPECT_THAT(map[kPreferencesId_].expected, Eq(ack_handle)); } // Tests for legacy deserialization code. @@ -340,4 +409,80 @@ TEST_F(InvalidatorStorageTest, SetGetBootstrapData) { EXPECT_EQ(mess, storage.GetBootstrapData()); } +// Test that we correctly generate ack handles, acknowledge them, and persist +// them. +TEST_F(InvalidatorStorageTest, GenerateAckHandlesAndAcknowledge) { + InvalidatorStorage storage(&pref_service_); + syncer::ObjectIdSet ids; + InvalidationStateMap state_map; + syncer::AckHandleMap ack_handle_map; + syncer::AckHandleMap::const_iterator it; + + // Test that it works as expected if the key doesn't already exist in the map, + // e.g. the first invalidation received for the object ID was not for a + // specific version. + ids.insert(kAutofillId_); + storage.GenerateAckHandles( + ids, base::MessageLoopProxy::current(), + base::Bind(&GenerateAckHandlesTestHelper, &ack_handle_map)); + loop_.RunUntilIdle(); + EXPECT_EQ(1U, ack_handle_map.size()); + it = ack_handle_map.find(kAutofillId_); + // Android STL appears to be buggy and causes gtest's IsContainerTest<> to + // treat an iterator as a STL container so we use != instead of ASSERT_NE. + ASSERT_TRUE(ack_handle_map.end() != it); + EXPECT_TRUE(it->second.IsValid()); + state_map[kAutofillId_].expected = it->second; + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); + + storage.Acknowledge(kAutofillId_, it->second); + state_map[kAutofillId_].current = it->second; + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); + + ids.clear(); + + // Test that it works as expected if the key already exists. + state_map[kBookmarksId_].version = 11; + state_map[kBookmarksId_].payload = "hello"; + storage.SetMaxVersionAndPayload(kBookmarksId_, 11, "hello"); + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); + ids.insert(kBookmarksId_); + storage.GenerateAckHandles( + ids, base::MessageLoopProxy::current(), + base::Bind(&GenerateAckHandlesTestHelper, &ack_handle_map)); + loop_.RunUntilIdle(); + EXPECT_EQ(1U, ack_handle_map.size()); + it = ack_handle_map.find(kBookmarksId_); + ASSERT_TRUE(ack_handle_map.end() != it); + EXPECT_TRUE(it->second.IsValid()); + state_map[kBookmarksId_].expected = it->second; + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); + + storage.Acknowledge(kBookmarksId_, it->second); + state_map[kBookmarksId_].current = it->second; + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); + + // Finally, test that the ack handles are updated if we're asked to generate + // another ack handle for the same object ID. + state_map[kBookmarksId_].version = 12; + state_map[kBookmarksId_].payload = "world"; + storage.SetMaxVersionAndPayload(kBookmarksId_, 12, "world"); + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); + ids.insert(kBookmarksId_); + storage.GenerateAckHandles( + ids, base::MessageLoopProxy::current(), + base::Bind(&GenerateAckHandlesTestHelper, &ack_handle_map)); + loop_.RunUntilIdle(); + EXPECT_EQ(1U, ack_handle_map.size()); + it = ack_handle_map.find(kBookmarksId_); + ASSERT_TRUE(ack_handle_map.end() != it); + EXPECT_TRUE(it->second.IsValid()); + state_map[kBookmarksId_].expected = it->second; + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); + + storage.Acknowledge(kBookmarksId_, it->second); + state_map[kBookmarksId_].current = it->second; + EXPECT_EQ(state_map, storage.GetAllInvalidationStates()); +} + } // namespace browser_sync diff --git a/sync/internal_api/public/base/invalidation.cc b/sync/internal_api/public/base/invalidation.cc index 2ddaa63..58f5cce 100644 --- a/sync/internal_api/public/base/invalidation.cc +++ b/sync/internal_api/public/base/invalidation.cc @@ -4,22 +4,67 @@ #include "sync/internal_api/public/base/invalidation.h" +#include <cstddef> +#include "base/rand_util.h" +#include "base/string_number_conversions.h" #include "base/values.h" namespace syncer { +namespace { +// Hopefully enough bytes for uniqueness. +const size_t kBytesInHandle = 16; +} // namespace + +AckHandle AckHandle::CreateUnique() { + // This isn't a valid UUID, so we don't attempt to format it like one. + uint8 random_bytes[kBytesInHandle]; + base::RandBytes(random_bytes, sizeof(random_bytes)); + return AckHandle(base::HexEncode(random_bytes, sizeof(random_bytes)), + base::Time::Now()); +} + +AckHandle AckHandle::InvalidAckHandle() { + return AckHandle(std::string(), base::Time()); +} + bool AckHandle::Equals(const AckHandle& other) const { - return true; + return state_ == other.state_ && timestamp_ == other.timestamp_; } -scoped_ptr<base::Value> AckHandle::ToValue() const { - return scoped_ptr<base::Value>(new DictionaryValue()); +scoped_ptr<base::DictionaryValue> AckHandle::ToValue() const { + scoped_ptr<DictionaryValue> value(new DictionaryValue()); + value->SetString("state", state_); + value->SetString("timestamp", + base::Int64ToString(timestamp_.ToInternalValue())); + return value.Pass(); } -bool AckHandle::ResetFromValue(const base::Value& value) { +bool AckHandle::ResetFromValue(const base::DictionaryValue& value) { + if (!value.GetString("state", &state_)) + return false; + std::string timestamp_as_string; + if (!value.GetString("timestamp", ×tamp_as_string)) + return false; + int64 timestamp_value; + if (!base::StringToInt64(timestamp_as_string, ×tamp_value)) + return false; + timestamp_ = base::Time::FromInternalValue(timestamp_value); return true; } +bool AckHandle::IsValid() const { + return !state_.empty(); +} + +AckHandle::AckHandle(const std::string& state, base::Time timestamp) + : state_(state), timestamp_(timestamp) { +} + +Invalidation::Invalidation() + : ack_handle(AckHandle::InvalidAckHandle()) { +} + bool Invalidation::Equals(const Invalidation& other) const { return (payload == other.payload) && ack_handle.Equals(other.ack_handle); } @@ -32,10 +77,10 @@ scoped_ptr<base::DictionaryValue> Invalidation::ToValue() const { } bool Invalidation::ResetFromValue(const base::DictionaryValue& value) { - const base::Value* ack_handle_value = NULL; + const DictionaryValue* ack_handle_value = NULL; return value.GetString("payload", &payload) && - value.Get("ackHandle", &ack_handle_value) && + value.GetDictionary("ackHandle", &ack_handle_value) && ack_handle.ResetFromValue(*ack_handle_value); } diff --git a/sync/internal_api/public/base/invalidation.h b/sync/internal_api/public/base/invalidation.h index fc8c361c..f25304b 100644 --- a/sync/internal_api/public/base/invalidation.h +++ b/sync/internal_api/public/base/invalidation.h @@ -7,25 +7,36 @@ #include <string> +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" +#include "base/time.h" namespace base { class DictionaryValue; -class Value; } // namespace namespace syncer { -// Opaque class that represents an ack handle. -// TODO(dcheng): This is just a refactoring change, so the class is empty for -// the moment. It will be filled once we start implementing 'reminders'. +// Opaque class that represents a local ack handle. We don't reuse the +// invalidation ack handles to avoid unnecessary dependencies. class AckHandle { public: + static AckHandle CreateUnique(); + static AckHandle InvalidAckHandle(); + bool Equals(const AckHandle& other) const; - scoped_ptr<base::Value> ToValue() const; + scoped_ptr<base::DictionaryValue> ToValue() const; + bool ResetFromValue(const base::DictionaryValue& value); + + bool IsValid() const; + + private: + // Explicitly copyable and assignable for STL containers. + AckHandle(const std::string& state, base::Time timestamp); - bool ResetFromValue(const base::Value& value); + std::string state_; + base::Time timestamp_; }; // Represents a local invalidation, and is roughly analogous to @@ -34,15 +45,15 @@ class AckHandle { // acknowledge receipt of the invalidation. It does not embed the object ID, // since it is typically associated with it through ObjectIdInvalidationMap. struct Invalidation { - std::string payload; - AckHandle ack_handle; + Invalidation(); bool Equals(const Invalidation& other) const; - // Caller owns the returned DictionaryValue. scoped_ptr<base::DictionaryValue> ToValue() const; - bool ResetFromValue(const base::DictionaryValue& value); + + std::string payload; + AckHandle ack_handle; }; } // namespace syncer diff --git a/sync/internal_api/public/base/invalidation_test_util.cc b/sync/internal_api/public/base/invalidation_test_util.cc index a95b657..3f3910b 100644 --- a/sync/internal_api/public/base/invalidation_test_util.cc +++ b/sync/internal_api/public/base/invalidation_test_util.cc @@ -5,6 +5,9 @@ #include "sync/internal_api/public/base/invalidation_test_util.h" #include "base/basictypes.h" +#include "base/json/json_writer.h" +#include "base/json/string_escape.h" +#include "base/values.h" #include "sync/internal_api/public/base/invalidation.h" namespace syncer { @@ -17,6 +20,39 @@ using ::testing::PrintToString; namespace { +class AckHandleEqMatcher + : public MatcherInterface<const AckHandle&> { + public: + explicit AckHandleEqMatcher(const AckHandle& expected); + + virtual bool MatchAndExplain(const AckHandle& actual, + MatchResultListener* listener) const; + virtual void DescribeTo(::std::ostream* os) const; + virtual void DescribeNegationTo(::std::ostream* os) const; + + private: + const AckHandle expected_; + + DISALLOW_COPY_AND_ASSIGN(AckHandleEqMatcher); +}; + +AckHandleEqMatcher::AckHandleEqMatcher(const AckHandle& expected) + : expected_(expected) { +} + +bool AckHandleEqMatcher::MatchAndExplain(const AckHandle& actual, + MatchResultListener* listener) const { + return expected_.Equals(actual); +} + +void AckHandleEqMatcher::DescribeTo(::std::ostream* os) const { + *os << " is equal to " << PrintToString(expected_); +} + +void AckHandleEqMatcher::DescribeNegationTo(::std::ostream* os) const { + *os << " isn't equal to " << PrintToString(expected_); +} + class InvalidationEqMatcher : public MatcherInterface<const Invalidation&> { public: @@ -52,8 +88,23 @@ void InvalidationEqMatcher::DescribeNegationTo(::std::ostream* os) const { } // namespace -void PrintTo(const Invalidation& invalidation, ::std::ostream* os) { - *os << "{ payload: " << invalidation.payload << " }"; +void PrintTo(const AckHandle& ack_handle, ::std::ostream* os ) { + scoped_ptr<base::Value> value(ack_handle.ToValue()); + std::string printable_ack_handle; + base::JSONWriter::Write(value.get(), &printable_ack_handle); + *os << "{ ack_handle: " << printable_ack_handle << " }"; +} + +Matcher<const AckHandle&> Eq(const AckHandle& expected) { + return MakeMatcher(new AckHandleEqMatcher(expected)); +} + +void PrintTo(const Invalidation& state, ::std::ostream* os) { + std::string printable_payload; + base::JsonDoubleQuote(state.payload, + true /* put_in_quotes */, + &printable_payload); + *os << "{ payload: " << printable_payload << " }"; } Matcher<const Invalidation&> Eq(const Invalidation& expected) { diff --git a/sync/internal_api/public/base/invalidation_test_util.h b/sync/internal_api/public/base/invalidation_test_util.h index 694081d..9376a28 100644 --- a/sync/internal_api/public/base/invalidation_test_util.h +++ b/sync/internal_api/public/base/invalidation_test_util.h @@ -11,8 +11,12 @@ namespace syncer { +class AckHandle; struct Invalidation; +void PrintTo(const AckHandle& ack_handle, ::std::ostream* os); +::testing::Matcher<const AckHandle&> Eq(const AckHandle& expected); + void PrintTo(const Invalidation& invalidation, ::std::ostream* os); ::testing::Matcher<const Invalidation&> Eq(const Invalidation& expected); diff --git a/sync/notifier/fake_invalidation_state_tracker.cc b/sync/notifier/fake_invalidation_state_tracker.cc index 9073e45b..2af5db5 100644 --- a/sync/notifier/fake_invalidation_state_tracker.cc +++ b/sync/notifier/fake_invalidation_state_tracker.cc @@ -4,6 +4,10 @@ #include "sync/notifier/fake_invalidation_state_tracker.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/task_runner.h" #include "testing/gtest/include/gtest/gtest.h" namespace syncer { @@ -25,8 +29,10 @@ FakeInvalidationStateTracker::GetAllInvalidationStates() const { return state_map_; } -void FakeInvalidationStateTracker::SetMaxVersion( - const invalidation::ObjectId& id, int64 max_version) { +void FakeInvalidationStateTracker::SetMaxVersionAndPayload( + const invalidation::ObjectId& id, + int64 max_version, + const std::string& payload) { InvalidationStateMap::const_iterator it = state_map_.find(id); if ((it != state_map_.end()) && (max_version <= it->second.version)) { ADD_FAILURE(); @@ -50,4 +56,25 @@ std::string FakeInvalidationStateTracker::GetBootstrapData() const { return bootstrap_data_; } +void FakeInvalidationStateTracker::GenerateAckHandles( + const ObjectIdSet& ids, + const scoped_refptr<base::TaskRunner>& task_runner, + base::Callback<void(const AckHandleMap&)> callback) { + AckHandleMap ack_handles; + for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { + state_map_[*it].expected = AckHandle::CreateUnique(); + ack_handles.insert(std::make_pair(*it, state_map_[*it].expected)); + } + if (!task_runner->PostTask(FROM_HERE, base::Bind(callback, ack_handles))) + ADD_FAILURE(); +} + +void FakeInvalidationStateTracker::Acknowledge(const invalidation::ObjectId& id, + const AckHandle& ack_handle) { + InvalidationStateMap::iterator it = state_map_.find(id); + if (it == state_map_.end()) + ADD_FAILURE(); + it->second.current = ack_handle; +} + } // namespace syncer diff --git a/sync/notifier/fake_invalidation_state_tracker.h b/sync/notifier/fake_invalidation_state_tracker.h index bd9003b..a3ea0bf 100644 --- a/sync/notifier/fake_invalidation_state_tracker.h +++ b/sync/notifier/fake_invalidation_state_tracker.h @@ -23,11 +23,18 @@ class FakeInvalidationStateTracker // InvalidationStateTracker implementation. virtual InvalidationStateMap GetAllInvalidationStates() const OVERRIDE; - virtual void SetMaxVersion(const invalidation::ObjectId& id, - int64 max_version) OVERRIDE; + virtual void SetMaxVersionAndPayload(const invalidation::ObjectId& id, + int64 max_version, + const std::string& payload) OVERRIDE; virtual void Forget(const ObjectIdSet& ids) OVERRIDE; virtual void SetBootstrapData(const std::string& data) OVERRIDE; virtual std::string GetBootstrapData() const OVERRIDE; + virtual void GenerateAckHandles( + const ObjectIdSet& ids, + const scoped_refptr<base::TaskRunner>& task_runner, + base::Callback<void(const AckHandleMap&)> callback) OVERRIDE; + virtual void Acknowledge(const invalidation::ObjectId& id, + const AckHandle& ack_handle) OVERRIDE; static const int64 kMinVersion; diff --git a/sync/notifier/invalidation_state_tracker.cc b/sync/notifier/invalidation_state_tracker.cc index 9d21807..335f3b2 100644 --- a/sync/notifier/invalidation_state_tracker.cc +++ b/sync/notifier/invalidation_state_tracker.cc @@ -6,8 +6,19 @@ namespace syncer { +InvalidationState::InvalidationState() + : version(kint64min), + expected(AckHandle::InvalidAckHandle()), + current(AckHandle::InvalidAckHandle()) { +} + +InvalidationState::~InvalidationState() { +} + bool operator==(const InvalidationState& lhs, const InvalidationState& rhs) { - return lhs.version == rhs.version; + return lhs.version == rhs.version && + lhs.expected.Equals(rhs.expected) && + lhs.current.Equals(rhs.current); } } // namespace syncer diff --git a/sync/notifier/invalidation_state_tracker.h b/sync/notifier/invalidation_state_tracker.h index 259ac83..2f26895 100644 --- a/sync/notifier/invalidation_state_tracker.h +++ b/sync/notifier/invalidation_state_tracker.h @@ -2,22 +2,40 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// An InvalidationVersionTracker is an interface that handles getting -// and setting (persisting) max invalidation versions. +// An InvalidationStateTracker is an interface that handles persisting state +// needed for invalidations. Currently, it is responsible for managing the +// following information: +// - Max version seen from the invalidation server to help dedupe invalidations. +// - Bootstrap data for the invalidation client. +// - Payloads and locally generated ack handles, to support local acking. #ifndef SYNC_NOTIFIER_INVALIDATION_STATE_TRACKER_H_ #define SYNC_NOTIFIER_INVALIDATION_STATE_TRACKER_H_ #include <map> +#include <string> #include "base/basictypes.h" +#include "base/callback_forward.h" +#include "base/memory/ref_counted.h" #include "google/cacheinvalidation/include/types.h" +#include "sync/internal_api/public/base/invalidation.h" #include "sync/notifier/invalidation_util.h" +namespace base { +class TaskRunner; +} // namespace base + namespace syncer { struct InvalidationState { + InvalidationState(); + ~InvalidationState(); + int64 version; + std::string payload; + AckHandle expected; + AckHandle current; }; // TODO(dcheng): Remove this in favor of adding an Equals() method. @@ -25,6 +43,8 @@ bool operator==(const InvalidationState& lhs, const InvalidationState& rhs); typedef std::map<invalidation::ObjectId, InvalidationState, ObjectIdLessThan> InvalidationStateMap; +typedef std::map<invalidation::ObjectId, AckHandle, ObjectIdLessThan> + AckHandleMap; class InvalidationStateTracker { public: @@ -34,8 +54,9 @@ class InvalidationStateTracker { // |max_version| should be strictly greater than any existing max // version for |model_type|. - virtual void SetMaxVersion(const invalidation::ObjectId& id, - int64 max_version) = 0; + virtual void SetMaxVersionAndPayload(const invalidation::ObjectId& id, + int64 max_version, + const std::string& payload) = 0; // Removes all state tracked for |ids|. virtual void Forget(const ObjectIdSet& ids) = 0; @@ -46,6 +67,21 @@ class InvalidationStateTracker { virtual void SetBootstrapData(const std::string& data) = 0; virtual std::string GetBootstrapData() const = 0; + // Used for generating our own local ack handles. Generates a new ack handle + // for each object id in |ids|. The result is returned via |callback| posted + // to |task_runner|. + virtual void GenerateAckHandles( + const ObjectIdSet& ids, + const scoped_refptr<base::TaskRunner>& task_runner, + base::Callback<void(const AckHandleMap&)> callback) = 0; + + // Records an acknowledgement for |id|. Note that no attempt at ordering is + // made. Acknowledge() only records the last ack_handle it received, even if + // the last ack_handle it received was generated before the value currently + // recorded. + virtual void Acknowledge(const invalidation::ObjectId& id, + const AckHandle& ack_handle) = 0; + protected: virtual ~InvalidationStateTracker() {} }; diff --git a/sync/notifier/p2p_invalidator_unittest.cc b/sync/notifier/p2p_invalidator_unittest.cc index 6be2c21..e8a1b86 100644 --- a/sync/notifier/p2p_invalidator_unittest.cc +++ b/sync/notifier/p2p_invalidator_unittest.cc @@ -194,9 +194,11 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) { EXPECT_EQ( "{\"idInvalidationMap\":[" "{\"objectId\":{\"name\":\"BOOKMARK\",\"source\":1004}," - "\"state\":{\"ackHandle\":{},\"payload\":\"\"}}," + "\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"}," + "\"payload\":\"\"}}," "{\"objectId\":{\"name\":\"THEME\",\"source\":1004}," - "\"state\":{\"ackHandle\":{},\"payload\":\"\"}}" + "\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"}," + "\"payload\":\"\"}}" "],\"notificationType\":\"notifyAll\"," "\"senderId\":\"sender\",\"source\":1}", notification_data_str); diff --git a/sync/notifier/sync_invalidation_listener.cc b/sync/notifier/sync_invalidation_listener.cc index 1b23501..e84bc38 100644 --- a/sync/notifier/sync_invalidation_listener.cc +++ b/sync/notifier/sync_invalidation_listener.cc @@ -148,19 +148,20 @@ void SyncInvalidationListener::Invalidate( client->Acknowledge(ack_handle); return; } - DVLOG(2) << "Setting max invalidation version for " << ObjectIdToString(id) - << " to " << invalidation.version(); - invalidation_state_map_[id].version = invalidation.version(); - invalidation_state_tracker_.Call( - FROM_HERE, - &InvalidationStateTracker::SetMaxVersion, - id, invalidation.version()); std::string payload; // payload() CHECK()'s has_payload(), so we must check it ourselves first. if (invalidation.has_payload()) payload = invalidation.payload(); + DVLOG(2) << "Setting max invalidation version for " << ObjectIdToString(id) + << " to " << invalidation.version(); + invalidation_state_map_[id].version = invalidation.version(); + invalidation_state_tracker_.Call( + FROM_HERE, + &InvalidationStateTracker::SetMaxVersionAndPayload, + id, invalidation.version(), payload); + ObjectIdInvalidationMap invalidation_map; invalidation_map[id].payload = payload; EmitInvalidation(invalidation_map); diff --git a/sync/sync.gyp b/sync/sync.gyp index 6a2bf58..af859d1 100644 --- a/sync/sync.gyp +++ b/sync/sync.gyp @@ -921,6 +921,25 @@ 'conditions': [ ['OS != "ios"', { 'targets': [ + { + 'target_name': 'sync_tools_helper', + 'type': 'static_library', + 'include_dirs': [ + '..', + ], + 'dependencies': [ + '../base/base.gyp:base', + 'sync_notifier', + ], + 'export_dependent_settings': [ + '../base/base.gyp:base', + 'sync_notifier', + ], + 'sources': [ + 'tools/null_invalidation_state_tracker.cc', + 'tools/null_invalidation_state_tracker.h', + ], + }, # A tool to listen to sync notifications and print them out. { 'target_name': 'sync_listen_notifications', @@ -931,6 +950,7 @@ '../net/net.gyp:net', '../net/net.gyp:net_test_support', 'sync', + 'sync_tools_helper', ], 'sources': [ 'tools/sync_listen_notifications.cc', @@ -950,6 +970,7 @@ '../net/net.gyp:net', '../net/net.gyp:net_test_support', 'sync', + 'sync_tools_helper', ], 'sources': [ 'tools/sync_client.cc', diff --git a/sync/tools/null_invalidation_state_tracker.cc b/sync/tools/null_invalidation_state_tracker.cc new file mode 100644 index 0000000..5eb5f78 --- /dev/null +++ b/sync/tools/null_invalidation_state_tracker.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sync/tools/null_invalidation_state_tracker.h" + +#include "base/base64.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/task_runner.h" +#include "sync/notifier/invalidation_util.h" + +namespace syncer { + +NullInvalidationStateTracker::NullInvalidationStateTracker() {} +NullInvalidationStateTracker::~NullInvalidationStateTracker() {} + +InvalidationStateMap +NullInvalidationStateTracker::GetAllInvalidationStates() const { + return InvalidationStateMap(); +} + +void NullInvalidationStateTracker::SetMaxVersionAndPayload( + const invalidation::ObjectId& id, + int64 max_invalidation_version, + const std::string& payload) { + LOG(INFO) << "Setting max invalidation version for " + << ObjectIdToString(id) << " to " << max_invalidation_version + << " with payload " << payload; +} + +void NullInvalidationStateTracker::Forget(const ObjectIdSet& ids) { + for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { + LOG(INFO) << "Forgetting invalidation state for " << ObjectIdToString(*it); + } +} + +std::string NullInvalidationStateTracker::GetBootstrapData() const { + return std::string(); +} + +void NullInvalidationStateTracker::SetBootstrapData(const std::string& data) { + std::string base64_data; + CHECK(base::Base64Encode(data, &base64_data)); + LOG(INFO) << "Setting bootstrap data to: " << base64_data; +} + +void NullInvalidationStateTracker::GenerateAckHandles( + const ObjectIdSet& ids, + const scoped_refptr<base::TaskRunner>& task_runner, + base::Callback<void(const AckHandleMap&)> callback) { + AckHandleMap ack_handles; + for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { + ack_handles.insert(std::make_pair(*it, AckHandle::InvalidAckHandle())); + } + CHECK(task_runner->PostTask(FROM_HERE, base::Bind(callback, ack_handles))); +} + +void NullInvalidationStateTracker::Acknowledge(const invalidation::ObjectId& id, + const AckHandle& ack_handle) { + LOG(INFO) << "Received ack for " << ObjectIdToString(id); +} + +} // namespace syncer diff --git a/sync/tools/null_invalidation_state_tracker.h b/sync/tools/null_invalidation_state_tracker.h new file mode 100644 index 0000000..13e55c7 --- /dev/null +++ b/sync/tools/null_invalidation_state_tracker.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SYNC_TOOLS_NULL_INVALIDATION_STATE_TRACKER_H_ +#define SYNC_TOOLS_NULL_INVALIDATION_STATE_TRACKER_H_ + +#include "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "sync/notifier/invalidation_state_tracker.h" + +namespace syncer { + +class NullInvalidationStateTracker + : public base::SupportsWeakPtr<NullInvalidationStateTracker>, + public InvalidationStateTracker { + public: + NullInvalidationStateTracker(); + virtual ~NullInvalidationStateTracker(); + + virtual InvalidationStateMap GetAllInvalidationStates() const OVERRIDE; + virtual void SetMaxVersionAndPayload(const invalidation::ObjectId& id, + int64 max_invalidation_version, + const std::string& payload) OVERRIDE; + virtual void Forget(const ObjectIdSet& ids) OVERRIDE; + + virtual std::string GetBootstrapData() const OVERRIDE; + virtual void SetBootstrapData(const std::string& data) OVERRIDE; + + virtual void GenerateAckHandles( + const ObjectIdSet& ids, + const scoped_refptr<base::TaskRunner>& task_runner, + base::Callback<void(const AckHandleMap&)> callback) OVERRIDE; + virtual void Acknowledge(const invalidation::ObjectId& id, + const AckHandle& ack_handle) OVERRIDE; +}; + +} // namespace syncer + +#endif // SYNC_TOOLS_NULL_INVALIDATION_STATE_TRACKER_H_ diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc index c2dc657..d973093 100644 --- a/sync/tools/sync_client.cc +++ b/sync/tools/sync_client.cc @@ -7,7 +7,6 @@ #include <string> #include "base/at_exit.h" -#include "base/base64.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/debug/stack_trace.h" @@ -44,6 +43,7 @@ #include "sync/notifier/invalidator.h" #include "sync/notifier/invalidator_factory.h" #include "sync/test/fake_encryptor.h" +#include "sync/tools/null_invalidation_state_tracker.h" #if defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" @@ -65,41 +65,6 @@ const char kXmppAllowInsecureConnectionSwitch[] = "xmpp-allow-insecure-connection"; const char kNotificationMethodSwitch[] = "notification-method"; -class NullInvalidationStateTracker - : public base::SupportsWeakPtr<NullInvalidationStateTracker>, - public InvalidationStateTracker { - public: - NullInvalidationStateTracker() {} - virtual ~NullInvalidationStateTracker() {} - - virtual InvalidationStateMap GetAllInvalidationStates() const OVERRIDE { - return InvalidationStateMap(); - } - - virtual void SetMaxVersion( - const invalidation::ObjectId& id, - int64 max_invalidation_version) OVERRIDE { - VLOG(1) << "Setting max invalidation version for " - << ObjectIdToString(id) << " to " << max_invalidation_version; - } - - virtual void Forget(const ObjectIdSet& ids) OVERRIDE { - for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { - VLOG(1) << "Forgetting invalidation state for " << ObjectIdToString(*it); - } - } - - virtual std::string GetBootstrapData() const OVERRIDE { - return std::string(); - } - - virtual void SetBootstrapData(const std::string& data) OVERRIDE { - std::string base64_data; - CHECK(base::Base64Encode(data, &base64_data)); - VLOG(1) << "Setting bootstrap data to: " << base64_data; - } -}; - // Needed to use a real host resolver. class MyTestURLRequestContext : public net::TestURLRequestContext { public: diff --git a/sync/tools/sync_listen_notifications.cc b/sync/tools/sync_listen_notifications.cc index bc90088..ce901a4 100644 --- a/sync/tools/sync_listen_notifications.cc +++ b/sync/tools/sync_listen_notifications.cc @@ -7,13 +7,11 @@ #include <string> #include "base/at_exit.h" -#include "base/base64.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/threading/thread.h" #include "jingle/notifier/base/notification_method.h" @@ -30,6 +28,7 @@ #include "sync/notifier/invalidation_util.h" #include "sync/notifier/invalidator_factory.h" #include "sync/notifier/invalidator.h" +#include "sync/tools/null_invalidation_state_tracker.h" #if defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" @@ -78,41 +77,6 @@ class NotificationPrinter : public InvalidationHandler { DISALLOW_COPY_AND_ASSIGN(NotificationPrinter); }; -class NullInvalidationStateTracker - : public base::SupportsWeakPtr<NullInvalidationStateTracker>, - public InvalidationStateTracker { - public: - NullInvalidationStateTracker() {} - virtual ~NullInvalidationStateTracker() {} - - virtual InvalidationStateMap GetAllInvalidationStates() const OVERRIDE { - return InvalidationStateMap(); - } - - virtual void SetMaxVersion( - const invalidation::ObjectId& id, - int64 max_invalidation_version) OVERRIDE { - LOG(INFO) << "Setting max invalidation version for " - << ObjectIdToString(id) << " to " << max_invalidation_version; - } - - virtual void Forget(const ObjectIdSet& ids) OVERRIDE { - for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { - LOG(INFO) << "Forgetting saved state for " << ObjectIdToString(*it); - } - } - - virtual std::string GetBootstrapData() const OVERRIDE { - return std::string(); - } - - virtual void SetBootstrapData(const std::string& data) OVERRIDE { - std::string base64_data; - CHECK(base::Base64Encode(data, &base64_data)); - LOG(INFO) << "Setting bootstrap data to: " << base64_data; - } -}; - // Needed to use a real host resolver. class MyTestURLRequestContext : public net::TestURLRequestContext { public: |