Commit f12d8791 authored by Mikel Astiz's avatar Mikel Astiz Committed by Commit Bot

Adopt Entity pointer as handle in SyncedBookmarkTracker

This patch refactors the SyncedBookmarkTracker API to make it less
sync-ID-centric (aka server IDs). Instead, entity pointers are proposed
(const SyncedBookmarkTracker::Entity*) as handles, following the design
principle in BookmarkModel and const BookmarkNode*.

This spares a few lookups but otherwise introduces no behavioral
changes.

Change-Id: Idfcaff7dfc268a29ca3f52e68b54ae11a51c6c71
Bug: 1032052
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2094982Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarMohamed Amir Yosef <mamir@chromium.org>
Commit-Queue: Mikel Astiz <mastiz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748675}
parent c31f0a8f
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
namespace sync_bookmarks { namespace sync_bookmarks {
BookmarkLocalChangesBuilder::BookmarkLocalChangesBuilder( BookmarkLocalChangesBuilder::BookmarkLocalChangesBuilder(
const SyncedBookmarkTracker* const bookmark_tracker, SyncedBookmarkTracker* const bookmark_tracker,
bookmarks::BookmarkModel* bookmark_model) bookmarks::BookmarkModel* bookmark_model)
: bookmark_tracker_(bookmark_tracker), bookmark_model_(bookmark_model) { : bookmark_tracker_(bookmark_tracker), bookmark_model_(bookmark_model) {
DCHECK(bookmark_tracker); DCHECK(bookmark_tracker);
...@@ -71,6 +71,7 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests( ...@@ -71,6 +71,7 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests(
entity->final_guid_matches(node->guid())); entity->final_guid_matches(node->guid()));
data->name = data->specifics.bookmark().title(); data->name = data->specifics.bookmark().title();
} }
auto request = std::make_unique<syncer::CommitRequestData>(); auto request = std::make_unique<syncer::CommitRequestData>();
request->entity = std::move(data); request->entity = std::move(data);
request->sequence_number = metadata->sequence_number(); request->sequence_number = metadata->sequence_number();
...@@ -79,6 +80,8 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests( ...@@ -79,6 +80,8 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests(
// added/updated. // added/updated.
request->specifics_hash = metadata->specifics_hash(); request->specifics_hash = metadata->specifics_hash();
bookmark_tracker_->MarkCommitMayHaveStarted(entity);
commit_requests.push_back(std::move(request)); commit_requests.push_back(std::move(request));
} }
return commit_requests; return commit_requests;
......
...@@ -21,13 +21,13 @@ class BookmarkLocalChangesBuilder { ...@@ -21,13 +21,13 @@ class BookmarkLocalChangesBuilder {
public: public:
// |bookmark_tracker| and |bookmark_model| must not be null and must outlive // |bookmark_tracker| and |bookmark_model| must not be null and must outlive
// this object. // this object.
BookmarkLocalChangesBuilder(const SyncedBookmarkTracker* bookmark_tracker, BookmarkLocalChangesBuilder(SyncedBookmarkTracker* bookmark_tracker,
bookmarks::BookmarkModel* bookmark_model); bookmarks::BookmarkModel* bookmark_model);
// Builds the commit requests list. // Builds the commit requests list.
syncer::CommitRequestDataList BuildCommitRequests(size_t max_entries) const; syncer::CommitRequestDataList BuildCommitRequests(size_t max_entries) const;
private: private:
const SyncedBookmarkTracker* const bookmark_tracker_; SyncedBookmarkTracker* const bookmark_tracker_;
bookmarks::BookmarkModel* const bookmark_model_; bookmarks::BookmarkModel* const bookmark_model_;
DISALLOW_COPY_AND_ASSIGN(BookmarkLocalChangesBuilder); DISALLOW_COPY_AND_ASSIGN(BookmarkLocalChangesBuilder);
......
...@@ -425,7 +425,7 @@ void BookmarkModelMerger::MergeSubtree( ...@@ -425,7 +425,7 @@ void BookmarkModelMerger::MergeSubtree(
const RemoteTreeNode& remote_node) { const RemoteTreeNode& remote_node) {
const EntityData& remote_update_entity = remote_node.entity(); const EntityData& remote_update_entity = remote_node.entity();
bookmark_tracker_->Add( bookmark_tracker_->Add(
remote_update_entity.id, local_subtree_root, local_subtree_root, remote_update_entity.id,
remote_node.response_version(), remote_update_entity.creation_time, remote_node.response_version(), remote_update_entity.creation_time,
remote_update_entity.unique_position, remote_update_entity.specifics); remote_update_entity.unique_position, remote_update_entity.specifics);
...@@ -570,7 +570,7 @@ void BookmarkModelMerger::ProcessRemoteCreation( ...@@ -570,7 +570,7 @@ void BookmarkModelMerger::ProcessRemoteCreation(
remote_update_entity.is_folder, remote_update_entity.is_folder,
bookmark_model_, favicon_service_); bookmark_model_, favicon_service_);
DCHECK(bookmark_node); DCHECK(bookmark_node);
bookmark_tracker_->Add(remote_update_entity.id, bookmark_node, bookmark_tracker_->Add(bookmark_node, remote_update_entity.id,
remote_node.response_version(), remote_node.response_version(),
remote_update_entity.creation_time, remote_update_entity.creation_time,
remote_update_entity.unique_position, specifics); remote_update_entity.unique_position, specifics);
...@@ -640,10 +640,10 @@ void BookmarkModelMerger::ProcessLocalCreation( ...@@ -640,10 +640,10 @@ void BookmarkModelMerger::ProcessLocalCreation(
const sync_pb::EntitySpecifics specifics = CreateSpecificsFromBookmarkNode( const sync_pb::EntitySpecifics specifics = CreateSpecificsFromBookmarkNode(
node, bookmark_model_, /*force_favicon_load=*/true, node, bookmark_model_, /*force_favicon_load=*/true,
/*include_guid=*/true); /*include_guid=*/true);
bookmark_tracker_->Add(sync_id, node, server_version, creation_time, const SyncedBookmarkTracker::Entity* entity = bookmark_tracker_->Add(
pos.ToProto(), specifics); node, sync_id, server_version, creation_time, pos.ToProto(), specifics);
// Mark the entity that it needs to be committed. // Mark the entity that it needs to be committed.
bookmark_tracker_->IncrementSequenceNumber(sync_id); bookmark_tracker_->IncrementSequenceNumber(entity);
for (size_t i = 0; i < node->children().size(); ++i) { for (size_t i = 0; i < node->children().size(); ++i) {
// If a local node hasn't matched with any remote entity, its descendants // If a local node hasn't matched with any remote entity, its descendants
// will neither, unless they have been or will be matched by GUID, in which // will neither, unless they have been or will be matched by GUID, in which
......
...@@ -62,17 +62,16 @@ void BookmarkModelObserverImpl::BookmarkNodeMoved( ...@@ -62,17 +62,16 @@ void BookmarkModelObserverImpl::BookmarkNodeMoved(
const std::string& sync_id = entity->metadata()->server_id(); const std::string& sync_id = entity->metadata()->server_id();
const base::Time modification_time = base::Time::Now(); const base::Time modification_time = base::Time::Now();
const sync_pb::UniquePosition unique_position = const sync_pb::UniquePosition unique_position =
ComputePosition(*new_parent, new_index, sync_id).ToProto(); ComputePosition(*new_parent, new_index, sync_id).ToProto();
sync_pb::EntitySpecifics specifics = CreateSpecificsFromBookmarkNode( sync_pb::EntitySpecifics specifics = CreateSpecificsFromBookmarkNode(
node, model, /*force_favicon_load=*/true, entity->has_final_guid()); node, model, /*force_favicon_load=*/true, entity->has_final_guid());
bookmark_tracker_->Update(sync_id, entity->metadata()->server_version(), bookmark_tracker_->Update(entity, entity->metadata()->server_version(),
modification_time, unique_position, specifics); modification_time, unique_position, specifics);
// Mark the entity that it needs to be committed. // Mark the entity that it needs to be committed.
bookmark_tracker_->IncrementSequenceNumber(sync_id); bookmark_tracker_->IncrementSequenceNumber(entity);
nudge_for_commit_closure_.Run(); nudge_for_commit_closure_.Run();
} }
...@@ -108,10 +107,10 @@ void BookmarkModelObserverImpl::BookmarkNodeAdded( ...@@ -108,10 +107,10 @@ void BookmarkModelObserverImpl::BookmarkNodeAdded(
sync_pb::EntitySpecifics specifics = sync_pb::EntitySpecifics specifics =
CreateSpecificsFromBookmarkNode(node, model, /*force_favicon_load=*/true, CreateSpecificsFromBookmarkNode(node, model, /*force_favicon_load=*/true,
/*include_guid=*/true); /*include_guid=*/true);
bookmark_tracker_->Add(sync_id, node, server_version, creation_time, const SyncedBookmarkTracker::Entity* entity = bookmark_tracker_->Add(
unique_position, specifics); node, sync_id, server_version, creation_time, unique_position, specifics);
// Mark the entity that it needs to be committed. // Mark the entity that it needs to be committed.
bookmark_tracker_->IncrementSequenceNumber(sync_id); bookmark_tracker_->IncrementSequenceNumber(entity);
nudge_for_commit_closure_.Run(); nudge_for_commit_closure_.Run();
} }
...@@ -198,12 +197,11 @@ void BookmarkModelObserverImpl::BookmarkNodeChanged( ...@@ -198,12 +197,11 @@ void BookmarkModelObserverImpl::BookmarkNodeChanged(
// (e.g.upon a favicon load). // (e.g.upon a favicon load).
return; return;
} }
const std::string& sync_id = entity->metadata()->server_id(); bookmark_tracker_->Update(entity, entity->metadata()->server_version(),
bookmark_tracker_->Update(sync_id, entity->metadata()->server_version(),
modification_time, modification_time,
entity->metadata()->unique_position(), specifics); entity->metadata()->unique_position(), specifics);
// Mark the entity that it needs to be committed. // Mark the entity that it needs to be committed.
bookmark_tracker_->IncrementSequenceNumber(sync_id); bookmark_tracker_->IncrementSequenceNumber(entity);
nudge_for_commit_closure_.Run(); nudge_for_commit_closure_.Run();
} }
...@@ -271,10 +269,10 @@ void BookmarkModelObserverImpl::BookmarkNodeChildrenReordered( ...@@ -271,10 +269,10 @@ void BookmarkModelObserverImpl::BookmarkNodeChildrenReordered(
child.get(), model, /*force_favicon_load=*/true, child.get(), model, /*force_favicon_load=*/true,
entity->has_final_guid()); entity->has_final_guid());
bookmark_tracker_->Update(sync_id, entity->metadata()->server_version(), bookmark_tracker_->Update(entity, entity->metadata()->server_version(),
modification_time, position.ToProto(), specifics); modification_time, position.ToProto(), specifics);
// Mark the entity that it needs to be committed. // Mark the entity that it needs to be committed.
bookmark_tracker_->IncrementSequenceNumber(sync_id); bookmark_tracker_->IncrementSequenceNumber(entity);
} }
nudge_for_commit_closure_.Run(); nudge_for_commit_closure_.Run();
} }
...@@ -352,17 +350,16 @@ void BookmarkModelObserverImpl::ProcessDelete( ...@@ -352,17 +350,16 @@ void BookmarkModelObserverImpl::ProcessDelete(
bookmark_tracker_->GetEntityForBookmarkNode(node); bookmark_tracker_->GetEntityForBookmarkNode(node);
// Shouldn't try to delete untracked entities. // Shouldn't try to delete untracked entities.
DCHECK(entity); DCHECK(entity);
const std::string& sync_id = entity->metadata()->server_id();
// If the entity hasn't been committed and doesn't have an inflight commit // If the entity hasn't been committed and doesn't have an inflight commit
// request, simply remove it from the tracker. // request, simply remove it from the tracker.
if (entity->metadata()->server_version() == syncer::kUncommittedVersion && if (entity->metadata()->server_version() == syncer::kUncommittedVersion &&
!entity->commit_may_have_started()) { !entity->commit_may_have_started()) {
bookmark_tracker_->Remove(sync_id); bookmark_tracker_->Remove(entity);
return; return;
} }
bookmark_tracker_->MarkDeleted(sync_id); bookmark_tracker_->MarkDeleted(entity);
// Mark the entity that it needs to be committed. // Mark the entity that it needs to be committed.
bookmark_tracker_->IncrementSequenceNumber(sync_id); bookmark_tracker_->IncrementSequenceNumber(entity);
} }
} // namespace sync_bookmarks } // namespace sync_bookmarks
...@@ -51,8 +51,8 @@ class BookmarkModelObserverImplTest : public testing::Test { ...@@ -51,8 +51,8 @@ class BookmarkModelObserverImplTest : public testing::Test {
sync_pb::EntitySpecifics specifics; sync_pb::EntitySpecifics specifics;
specifics.mutable_bookmark()->set_title(kBookmarkBarTag); specifics.mutable_bookmark()->set_title(kBookmarkBarTag);
bookmark_tracker_->Add( bookmark_tracker_->Add(
/*sync_id=*/kBookmarkBarId,
/*bookmark_node=*/bookmark_model()->bookmark_bar_node(), /*bookmark_node=*/bookmark_model()->bookmark_bar_node(),
/*sync_id=*/kBookmarkBarId,
/*server_version=*/0, /*creation_time=*/base::Time::Now(), /*server_version=*/0, /*creation_time=*/base::Time::Now(),
syncer::UniquePosition::InitialPosition( syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()) syncer::UniquePosition::RandomSuffix())
...@@ -60,8 +60,8 @@ class BookmarkModelObserverImplTest : public testing::Test { ...@@ -60,8 +60,8 @@ class BookmarkModelObserverImplTest : public testing::Test {
specifics); specifics);
specifics.mutable_bookmark()->set_title(kOtherBookmarksTag); specifics.mutable_bookmark()->set_title(kOtherBookmarksTag);
bookmark_tracker_->Add( bookmark_tracker_->Add(
/*sync_id=*/kOtherBookmarksId,
/*bookmark_node=*/bookmark_model()->other_node(), /*bookmark_node=*/bookmark_model()->other_node(),
/*sync_id=*/kOtherBookmarksId,
/*server_version=*/0, /*creation_time=*/base::Time::Now(), /*server_version=*/0, /*creation_time=*/base::Time::Now(),
syncer::UniquePosition::InitialPosition( syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()) syncer::UniquePosition::RandomSuffix())
...@@ -69,8 +69,8 @@ class BookmarkModelObserverImplTest : public testing::Test { ...@@ -69,8 +69,8 @@ class BookmarkModelObserverImplTest : public testing::Test {
specifics); specifics);
specifics.mutable_bookmark()->set_title(kMobileBookmarksTag); specifics.mutable_bookmark()->set_title(kMobileBookmarksTag);
bookmark_tracker_->Add( bookmark_tracker_->Add(
/*sync_id=*/kMobileBookmarksId,
/*bookmark_node=*/bookmark_model()->mobile_node(), /*bookmark_node=*/bookmark_model()->mobile_node(),
/*sync_id=*/kMobileBookmarksId,
/*server_version=*/0, /*creation_time=*/base::Time::Now(), /*server_version=*/0, /*creation_time=*/base::Time::Now(),
syncer::UniquePosition::InitialPosition( syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()) syncer::UniquePosition::RandomSuffix())
...@@ -87,9 +87,9 @@ class BookmarkModelObserverImplTest : public testing::Test { ...@@ -87,9 +87,9 @@ class BookmarkModelObserverImplTest : public testing::Test {
bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries)) { bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries)) {
const std::string id = entity->metadata()->server_id(); const std::string id = entity->metadata()->server_id();
// Don't simulate change in id for simplicity. // Don't simulate change in id for simplicity.
bookmark_tracker()->UpdateUponCommitResponse(id, id, bookmark_tracker()->UpdateUponCommitResponse(entity, id,
/*acked_sequence_number=*/1, /*server_version=*/1,
/*server_version=*/1); /*acked_sequence_number=*/1);
} }
} }
...@@ -401,23 +401,22 @@ TEST_F(BookmarkModelObserverImplTest, ...@@ -401,23 +401,22 @@ TEST_F(BookmarkModelObserverImplTest,
// Node should be tracked now. // Node should be tracked now.
ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U); ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
const std::string id = bookmark_tracker() const SyncedBookmarkTracker::Entity* entity =
->GetEntityForBookmarkNode(folder_node) bookmark_tracker()->GetEntityForBookmarkNode(folder_node);
->metadata() const std::string id = entity->metadata()->server_id();
->server_id();
ASSERT_THAT( ASSERT_THAT(
bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 1U); bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 1U);
bookmark_tracker()->MarkCommitMayHaveStarted(id); bookmark_tracker()->MarkCommitMayHaveStarted(entity);
// Remove the folder. // Remove the folder.
bookmark_model()->Remove(folder_node); bookmark_model()->Remove(folder_node);
// Simulate a commit response for the first commit request (the creation). // Simulate a commit response for the first commit request (the creation).
// Don't simulate change in id for simplicity. // Don't simulate change in id for simplicity.
bookmark_tracker()->UpdateUponCommitResponse(id, id, bookmark_tracker()->UpdateUponCommitResponse(entity, id,
/*acked_sequence_number=*/1, /*server_version=*/1,
/*server_version=*/1); /*acked_sequence_number=*/1);
// There should still be one local change (the deletion). // There should still be one local change (the deletion).
EXPECT_THAT( EXPECT_THAT(
...@@ -427,9 +426,9 @@ TEST_F(BookmarkModelObserverImplTest, ...@@ -427,9 +426,9 @@ TEST_F(BookmarkModelObserverImplTest,
EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U); EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
// Commit the deletion. // Commit the deletion.
bookmark_tracker()->UpdateUponCommitResponse(id, id, bookmark_tracker()->UpdateUponCommitResponse(entity, id,
/*acked_sequence_number=*/2, /*server_version=*/2,
/*server_version=*/2); /*acked_sequence_number=*/2);
// Entity should have been dropped. // Entity should have been dropped.
EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 3U); EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 3U);
} }
...@@ -515,8 +514,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) { ...@@ -515,8 +514,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) {
sync_pb::EntitySpecifics specifics; sync_pb::EntitySpecifics specifics;
specifics.mutable_bookmark()->set_title(kBookmarkBarTag); specifics.mutable_bookmark()->set_title(kBookmarkBarTag);
bookmark_tracker->Add( bookmark_tracker->Add(
/*sync_id=*/kBookmarkBarId,
/*bookmark_node=*/model->bookmark_bar_node(), /*bookmark_node=*/model->bookmark_bar_node(),
/*sync_id=*/kBookmarkBarId,
/*server_version=*/0, /*creation_time=*/base::Time::Now(), /*server_version=*/0, /*creation_time=*/base::Time::Now(),
syncer::UniquePosition::InitialPosition( syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()) syncer::UniquePosition::RandomSuffix())
...@@ -524,8 +523,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) { ...@@ -524,8 +523,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) {
specifics); specifics);
specifics.mutable_bookmark()->set_title(kOtherBookmarksTag); specifics.mutable_bookmark()->set_title(kOtherBookmarksTag);
bookmark_tracker->Add( bookmark_tracker->Add(
/*sync_id=*/kOtherBookmarksId,
/*bookmark_node=*/model->other_node(), /*bookmark_node=*/model->other_node(),
/*sync_id=*/kOtherBookmarksId,
/*server_version=*/0, /*creation_time=*/base::Time::Now(), /*server_version=*/0, /*creation_time=*/base::Time::Now(),
syncer::UniquePosition::InitialPosition( syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()) syncer::UniquePosition::RandomSuffix())
...@@ -533,8 +532,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) { ...@@ -533,8 +532,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotSyncUnsyncableBookmarks) {
specifics); specifics);
specifics.mutable_bookmark()->set_title(kMobileBookmarksTag); specifics.mutable_bookmark()->set_title(kMobileBookmarksTag);
bookmark_tracker->Add( bookmark_tracker->Add(
/*sync_id=*/kMobileBookmarksId,
/*bookmark_node=*/model->mobile_node(), /*bookmark_node=*/model->mobile_node(),
/*sync_id=*/kMobileBookmarksId,
/*server_version=*/0, /*creation_time=*/base::Time::Now(), /*server_version=*/0, /*creation_time=*/base::Time::Now(),
syncer::UniquePosition::InitialPosition( syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()) syncer::UniquePosition::RandomSuffix())
...@@ -586,8 +585,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldAddChildrenInArbitraryOrder) { ...@@ -586,8 +585,8 @@ TEST_F(BookmarkModelObserverImplTest, ShouldAddChildrenInArbitraryOrder) {
sync_pb::EntitySpecifics specifics; sync_pb::EntitySpecifics specifics;
specifics.mutable_bookmark()->set_title(kBookmarkBarTag); specifics.mutable_bookmark()->set_title(kBookmarkBarTag);
bookmark_tracker->Add( bookmark_tracker->Add(
/*sync_id=*/kBookmarkBarId,
/*bookmark_node=*/bookmark_model()->bookmark_bar_node(), /*bookmark_node=*/bookmark_model()->bookmark_bar_node(),
/*sync_id=*/kBookmarkBarId,
/*server_version=*/0, /*creation_time=*/base::Time::Now(), /*server_version=*/0, /*creation_time=*/base::Time::Now(),
syncer::UniquePosition::InitialPosition( syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()) syncer::UniquePosition::RandomSuffix())
......
...@@ -185,13 +185,7 @@ void BookmarkModelTypeProcessor::GetLocalChanges( ...@@ -185,13 +185,7 @@ void BookmarkModelTypeProcessor::GetLocalChanges(
GetLocalChangesCallback callback) { GetLocalChangesCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
BookmarkLocalChangesBuilder builder(bookmark_tracker_.get(), bookmark_model_); BookmarkLocalChangesBuilder builder(bookmark_tracker_.get(), bookmark_model_);
syncer::CommitRequestDataList local_changes = std::move(callback).Run(builder.BuildCommitRequests(max_entries));
builder.BuildCommitRequests(max_entries);
for (const std::unique_ptr<syncer::CommitRequestData>& local_change :
local_changes) {
bookmark_tracker_->MarkCommitMayHaveStarted(local_change->entity->id);
}
std::move(callback).Run(std::move(local_changes));
} }
void BookmarkModelTypeProcessor::OnCommitCompleted( void BookmarkModelTypeProcessor::OnCommitCompleted(
...@@ -209,10 +203,19 @@ void BookmarkModelTypeProcessor::OnCommitCompleted( ...@@ -209,10 +203,19 @@ void BookmarkModelTypeProcessor::OnCommitCompleted(
// during the commit, and |response.id| carries both the old and new ids. // during the commit, and |response.id| carries both the old and new ids.
const std::string& old_sync_id = const std::string& old_sync_id =
response.id_in_request.empty() ? response.id : response.id_in_request; response.id_in_request.empty() ? response.id : response.id_in_request;
bookmark_tracker_->UpdateUponCommitResponse(old_sync_id, response.id, const SyncedBookmarkTracker::Entity* entity =
response.sequence_number, bookmark_tracker_->GetEntityForSyncId(old_sync_id);
response.response_version); if (!entity) {
DLOG(WARNING) << "Received a commit response for an unknown entity: "
<< old_sync_id;
continue;
}
bookmark_tracker_->UpdateUponCommitResponse(entity, response.id,
response.response_version,
response.sequence_number);
} }
bookmark_tracker_->set_model_type_state(type_state); bookmark_tracker_->set_model_type_state(type_state);
schedule_save_closure_.Run(); schedule_save_closure_.Run();
} }
......
...@@ -63,9 +63,10 @@ class BookmarkRemoteUpdatesHandler { ...@@ -63,9 +63,10 @@ class BookmarkRemoteUpdatesHandler {
// ignored. // ignored.
// 3. Otherwise, a new node is created in the local bookmark model and // 3. Otherwise, a new node is created in the local bookmark model and
// registered in |bookmark_tracker_|. // registered in |bookmark_tracker_|.
// Returns true if a new bookmark has been registered in the //
// |bookmark_tracker_|, false otherwise. // Returns the newly tracked entity or null if the creation failed.
bool ProcessCreate(const syncer::UpdateResponseData& update); const SyncedBookmarkTracker::Entity* ProcessCreate(
const syncer::UpdateResponseData& update);
// Processes a remote update of a bookmark node. |update| must not be a // Processes a remote update of a bookmark node. |update| must not be a
// deletion, and the server_id must be already tracked, otherwise, it is a // deletion, and the server_id must be already tracked, otherwise, it is a
......
...@@ -148,45 +148,48 @@ class SyncedBookmarkTracker { ...@@ -148,45 +148,48 @@ class SyncedBookmarkTracker {
const SyncedBookmarkTracker::Entity* GetEntityForBookmarkNode( const SyncedBookmarkTracker::Entity* GetEntityForBookmarkNode(
const bookmarks::BookmarkNode* node) const; const bookmarks::BookmarkNode* node) const;
// Adds an entry for the |sync_id| and the corresponding local bookmark node // Starts tracking local bookmark |bookmark_node|, which must not be tracked
// and metadata in |sync_id_to_entities_map_|. // beforehand. The rest of the arguments represent the initial metadata.
void Add(const std::string& sync_id, // Returns the tracked entity.
const bookmarks::BookmarkNode* bookmark_node, const Entity* Add(const bookmarks::BookmarkNode* bookmark_node,
int64_t server_version, const std::string& sync_id,
base::Time creation_time, int64_t server_version,
const sync_pb::UniquePosition& unique_position, base::Time creation_time,
const sync_pb::EntitySpecifics& specifics); const sync_pb::UniquePosition& unique_position,
const sync_pb::EntitySpecifics& specifics);
// Updates an existing entry for the |sync_id| and the corresponding metadata
// in |sync_id_to_entities_map_|. // Updates the sync metadata for a tracked entity. |entity| must be owned by
void Update(const std::string& sync_id, // this tracker.
void Update(const Entity* entity,
int64_t server_version, int64_t server_version,
base::Time modification_time, base::Time modification_time,
const sync_pb::UniquePosition& unique_position, const sync_pb::UniquePosition& unique_position,
const sync_pb::EntitySpecifics& specifics); const sync_pb::EntitySpecifics& specifics);
// Updates the server version of an existing entry for the |sync_id|. // Updates the server version of an existing entity. |entity| must be owned by
void UpdateServerVersion(const std::string& sync_id, int64_t server_version); // this tracker.
void UpdateServerVersion(const Entity* entity, int64_t server_version);
// Populates a bookmark's final GUID. // Populates a bookmark's final GUID. |entity| must be owned by this tracker.
void PopulateFinalGuid(const std::string& sync_id, const std::string& guid); void PopulateFinalGuid(const Entity* entity, const std::string& guid);
// Marks an existing entry for |sync_id| that a commit request might have been // Marks an existing entry that a commit request might have been sent to the
// sent to the server. // server. |entity| must be owned by this tracker.
void MarkCommitMayHaveStarted(const std::string& sync_id); void MarkCommitMayHaveStarted(const Entity* entity);
// This class maintains the order of calls to this method and the same order // This class maintains the order of calls to this method and the same order
// is guaranteed when returning local changes in // is guaranteed when returning local changes in
// GetEntitiesWithLocalChanges() as well as in BuildBookmarkModelMetadata(). // GetEntitiesWithLocalChanges() as well as in BuildBookmarkModelMetadata().
void MarkDeleted(const std::string& sync_id); // |entity| must be owned by this tracker.
void MarkDeleted(const Entity* entity);
// Removes the entry coressponding to the |sync_id| from // Untracks an entity, which also invalidates the pointer. |entity| must be
// |sync_id_to_entities_map_|. // owned by this tracker.
void Remove(const std::string& sync_id); void Remove(const Entity* entity);
// Increment sequence number in the metadata for the entity with |sync_id|. // Increment sequence number in the metadata for |entity|. |entity| must be
// Tracker must contain a non-tombstone entity with server id = |sync_id|. // owned by this tracker.
void IncrementSequenceNumber(const std::string& sync_id); void IncrementSequenceNumber(const Entity* entity);
sync_pb::BookmarkModelMetadata BuildBookmarkModelMetadata() const; sync_pb::BookmarkModelMetadata BuildBookmarkModelMetadata() const;
...@@ -206,30 +209,30 @@ class SyncedBookmarkTracker { ...@@ -206,30 +209,30 @@ class SyncedBookmarkTracker {
std::vector<const Entity*> GetEntitiesWithLocalChanges( std::vector<const Entity*> GetEntitiesWithLocalChanges(
size_t max_entries) const; size_t max_entries) const;
// Updates the tracker after receiving the commit response. |old_id| should be // Updates the tracker after receiving the commit response. |sync_id| should
// equal to |new_id| for all updates except the initial commit, where the // match the already tracked sync ID for |entity|, with the exception of the
// temporary client-generated ID will be overriden by the server-provided // initial commit, where the temporary client-generated ID will be overridden
// final ID. In which case |sync_id_to_entities_map_| will be updated // by the server-provided final ID. |entity| must be owned by this tracker.
// accordingly. void UpdateUponCommitResponse(const Entity* entity,
void UpdateUponCommitResponse(const std::string& old_id, const std::string& sync_id,
const std::string& new_id, int64_t server_version,
int64_t acked_sequence_number, int64_t acked_sequence_number);
int64_t server_version);
// Informs the tracker that the sync ID for |entity| has changed. It updates
// Informs the tracker that the sync id for an entity has changed. It updates // the internal state of the tracker accordingly. |entity| must be owned by
// the internal state of the tracker accordingly. // this tracker.
void UpdateSyncForLocalCreationIfNeeded(const std::string& old_id, void UpdateSyncIdForLocalCreationIfNeeded(const Entity* entity,
const std::string& new_id); const std::string& sync_id);
// Informs the tracker that a BookmarkNode has been replaced. It updates // Informs the tracker that a BookmarkNode has been replaced. It updates
// the internal state of the tracker accordingly. // the internal state of the tracker accordingly.
void UpdateBookmarkNodePointer(const bookmarks::BookmarkNode* old_node, void UpdateBookmarkNodePointer(const bookmarks::BookmarkNode* old_node,
const bookmarks::BookmarkNode* new_node); const bookmarks::BookmarkNode* new_node);
// Set the value of |EntityMetadata.acked_sequence_number| in the entity with // Set the value of |EntityMetadata.acked_sequence_number| for |entity| to be
// |sync_id| to be equal to |EntityMetadata.sequence_number| such that it is // equal to |EntityMetadata.sequence_number| such that it is not returned in
// not returned in GetEntitiesWithLocalChanges(). // GetEntitiesWithLocalChanges(). |entity| must be owned by this tracker.
void AckSequenceNumber(const std::string& sync_id); void AckSequenceNumber(const Entity* entity);
// Whether the tracker is empty or not. // Whether the tracker is empty or not.
bool IsEmpty() const; bool IsEmpty() const;
...@@ -281,8 +284,10 @@ class SyncedBookmarkTracker { ...@@ -281,8 +284,10 @@ class SyncedBookmarkTracker {
const bookmarks::BookmarkModel* model, const bookmarks::BookmarkModel* model,
sync_pb::BookmarkModelMetadata model_metadata); sync_pb::BookmarkModelMetadata model_metadata);
// Returns null if no entity is found. // Conceptually, find a tracked entity that matches |entity| and returns a
Entity* GetMutableEntityForSyncId(const std::string& sync_id); // non-const pointer of it. The actual implementation is a const_cast.
// |entity| must be owned by this tracker.
Entity* AsMutableEntity(const Entity* entity);
// Reorders |entities| that represents local non-deletions such that parent // Reorders |entities| that represents local non-deletions such that parent
// creation/update is before child creation/update. Returns the ordered list. // creation/update is before child creation/update. Returns the ordered list.
......
...@@ -110,10 +110,9 @@ TEST(SyncedBookmarkTrackerTest, ShouldGetAssociatedNodes) { ...@@ -110,10 +110,9 @@ TEST(SyncedBookmarkTrackerTest, ShouldGetAssociatedNodes) {
GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
bookmarks::BookmarkNode node(kId, base::GenerateGUID(), kUrl); bookmarks::BookmarkNode node(kId, base::GenerateGUID(), kUrl);
tracker->Add(kSyncId, &node, kServerVersion, kCreationTime,
unique_position.ToProto(), specifics);
const SyncedBookmarkTracker::Entity* entity = const SyncedBookmarkTracker::Entity* entity =
tracker->GetEntityForSyncId(kSyncId); tracker->Add(&node, kSyncId, kServerVersion, kCreationTime,
unique_position.ToProto(), specifics);
ASSERT_THAT(entity, NotNull()); ASSERT_THAT(entity, NotNull());
EXPECT_THAT(entity->bookmark_node(), Eq(&node)); EXPECT_THAT(entity->bookmark_node(), Eq(&node));
EXPECT_THAT(entity->metadata()->server_id(), Eq(kSyncId)); EXPECT_THAT(entity->metadata()->server_id(), Eq(kSyncId));
...@@ -144,10 +143,12 @@ TEST(SyncedBookmarkTrackerTest, ShouldReturnNullForDisassociatedNodes) { ...@@ -144,10 +143,12 @@ TEST(SyncedBookmarkTrackerTest, ShouldReturnNullForDisassociatedNodes) {
const sync_pb::EntitySpecifics specifics = const sync_pb::EntitySpecifics specifics =
GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL()); bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL());
tracker->Add(kSyncId, &node, kServerVersion, kModificationTime, const SyncedBookmarkTracker::Entity* entity =
unique_position, specifics); tracker->Add(&node, kSyncId, kServerVersion, kModificationTime,
ASSERT_THAT(tracker->GetEntityForSyncId(kSyncId), NotNull()); unique_position, specifics);
tracker->Remove(kSyncId); ASSERT_THAT(entity, NotNull());
ASSERT_THAT(tracker->GetEntityForSyncId(kSyncId), Eq(entity));
tracker->Remove(entity);
EXPECT_THAT(tracker->GetEntityForSyncId(kSyncId), IsNull()); EXPECT_THAT(tracker->GetEntityForSyncId(kSyncId), IsNull());
} }
...@@ -169,7 +170,7 @@ TEST(SyncedBookmarkTrackerTest, ShouldBuildBookmarkModelMetadata) { ...@@ -169,7 +170,7 @@ TEST(SyncedBookmarkTrackerTest, ShouldBuildBookmarkModelMetadata) {
GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
bookmarks::BookmarkNode node(kId, base::GenerateGUID(), kUrl); bookmarks::BookmarkNode node(kId, base::GenerateGUID(), kUrl);
tracker->Add(kSyncId, &node, kServerVersion, kCreationTime, tracker->Add(&node, kSyncId, kServerVersion, kCreationTime,
unique_position.ToProto(), specifics); unique_position.ToProto(), specifics);
sync_pb::BookmarkModelMetadata bookmark_model_metadata = sync_pb::BookmarkModelMetadata bookmark_model_metadata =
...@@ -195,11 +196,12 @@ TEST(SyncedBookmarkTrackerTest, ...@@ -195,11 +196,12 @@ TEST(SyncedBookmarkTrackerTest,
const sync_pb::EntitySpecifics specifics = const sync_pb::EntitySpecifics specifics =
GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL()); bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL());
tracker->Add(kSyncId, &node, kServerVersion, kModificationTime, const SyncedBookmarkTracker::Entity* entity =
unique_position, specifics); tracker->Add(&node, kSyncId, kServerVersion, kModificationTime,
unique_position, specifics);
EXPECT_THAT(tracker->HasLocalChanges(), Eq(false)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(false));
tracker->IncrementSequenceNumber(kSyncId); tracker->IncrementSequenceNumber(entity);
EXPECT_THAT(tracker->HasLocalChanges(), Eq(true)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(true));
// TODO(crbug.com/516866): Test HasLocalChanges after submitting commit // TODO(crbug.com/516866): Test HasLocalChanges after submitting commit
// request in a separate test probably. // request in a separate test probably.
...@@ -218,23 +220,24 @@ TEST(SyncedBookmarkTrackerTest, ShouldAckSequenceNumber) { ...@@ -218,23 +220,24 @@ TEST(SyncedBookmarkTrackerTest, ShouldAckSequenceNumber) {
const sync_pb::EntitySpecifics specifics = const sync_pb::EntitySpecifics specifics =
GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL()); bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL());
tracker->Add(kSyncId, &node, kServerVersion, kModificationTime, const SyncedBookmarkTracker::Entity* entity =
unique_position, specifics); tracker->Add(&node, kSyncId, kServerVersion, kModificationTime,
unique_position, specifics);
// Test simple scenario of ack'ing an incrememented sequence number. // Test simple scenario of ack'ing an incrememented sequence number.
EXPECT_THAT(tracker->HasLocalChanges(), Eq(false)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(false));
tracker->IncrementSequenceNumber(kSyncId); tracker->IncrementSequenceNumber(entity);
EXPECT_THAT(tracker->HasLocalChanges(), Eq(true)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(true));
tracker->AckSequenceNumber(kSyncId); tracker->AckSequenceNumber(entity);
EXPECT_THAT(tracker->HasLocalChanges(), Eq(false)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(false));
// Test ack'ing of a multiple times incremented sequence number. // Test ack'ing of a multiple times incremented sequence number.
tracker->IncrementSequenceNumber(kSyncId); tracker->IncrementSequenceNumber(entity);
EXPECT_THAT(tracker->HasLocalChanges(), Eq(true)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(true));
tracker->IncrementSequenceNumber(kSyncId); tracker->IncrementSequenceNumber(entity);
tracker->IncrementSequenceNumber(kSyncId); tracker->IncrementSequenceNumber(entity);
EXPECT_THAT(tracker->HasLocalChanges(), Eq(true)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(true));
tracker->AckSequenceNumber(kSyncId); tracker->AckSequenceNumber(entity);
EXPECT_THAT(tracker->HasLocalChanges(), Eq(false)); EXPECT_THAT(tracker->HasLocalChanges(), Eq(false));
} }
...@@ -253,18 +256,23 @@ TEST(SyncedBookmarkTrackerTest, ShouldUpdateUponCommitResponseWithNewId) { ...@@ -253,18 +256,23 @@ TEST(SyncedBookmarkTrackerTest, ShouldUpdateUponCommitResponseWithNewId) {
const sync_pb::EntitySpecifics specifics = const sync_pb::EntitySpecifics specifics =
GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL()); bookmarks::BookmarkNode node(kId, base::GenerateGUID(), GURL());
tracker->Add(kSyncId, &node, kServerVersion, kModificationTime, const SyncedBookmarkTracker::Entity* entity =
unique_position, specifics); tracker->Add(&node, kSyncId, kServerVersion, kModificationTime,
ASSERT_THAT(tracker->GetEntityForSyncId(kSyncId), NotNull()); unique_position, specifics);
ASSERT_THAT(entity, NotNull());
// Initially only the old ID should be tracked.
ASSERT_THAT(tracker->GetEntityForSyncId(kSyncId), Eq(entity));
ASSERT_THAT(tracker->GetEntityForSyncId(kNewSyncId), IsNull());
// Receive a commit response with a changed id. // Receive a commit response with a changed id.
tracker->UpdateUponCommitResponse( tracker->UpdateUponCommitResponse(entity, kNewSyncId, kNewServerVersion,
kSyncId, kNewSyncId, /*acked_sequence_number=*/1, kNewServerVersion); /*acked_sequence_number=*/1);
// Old id shouldn't be there.
// Old id shouldn't be there, but the new one should.
EXPECT_THAT(tracker->GetEntityForSyncId(kSyncId), IsNull()); EXPECT_THAT(tracker->GetEntityForSyncId(kSyncId), IsNull());
EXPECT_THAT(tracker->GetEntityForSyncId(kNewSyncId), Eq(entity));
const SyncedBookmarkTracker::Entity* entity =
tracker->GetEntityForSyncId(kNewSyncId);
ASSERT_THAT(entity, NotNull());
EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId)); EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId));
EXPECT_THAT(entity->bookmark_node(), Eq(&node)); EXPECT_THAT(entity->bookmark_node(), Eq(&node));
EXPECT_THAT(entity->metadata()->server_version(), Eq(kNewServerVersion)); EXPECT_THAT(entity->metadata()->server_version(), Eq(kNewServerVersion));
...@@ -284,18 +292,18 @@ TEST(SyncedBookmarkTrackerTest, ShouldUpdateId) { ...@@ -284,18 +292,18 @@ TEST(SyncedBookmarkTrackerTest, ShouldUpdateId) {
GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string()); GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
bookmarks::BookmarkNode node(/*id=*/1, base::GenerateGUID(), GURL()); bookmarks::BookmarkNode node(/*id=*/1, base::GenerateGUID(), GURL());
// Track a sync entity. // Track a sync entity.
tracker->Add(kSyncId, &node, kServerVersion, kModificationTime, const SyncedBookmarkTracker::Entity* entity =
unique_position, specifics); tracker->Add(&node, kSyncId, kServerVersion, kModificationTime,
unique_position, specifics);
ASSERT_THAT(tracker->GetEntityForSyncId(kSyncId), NotNull()); ASSERT_THAT(entity, NotNull());
// Update the sync id. // Update the sync id.
tracker->UpdateSyncForLocalCreationIfNeeded(kSyncId, kNewSyncId); tracker->UpdateSyncIdForLocalCreationIfNeeded(entity, kNewSyncId);
// Old id shouldn't be there.
// Old id shouldn't be there, but the new one should.
EXPECT_THAT(tracker->GetEntityForSyncId(kSyncId), IsNull()); EXPECT_THAT(tracker->GetEntityForSyncId(kSyncId), IsNull());
EXPECT_THAT(tracker->GetEntityForSyncId(kNewSyncId), Eq(entity));
const SyncedBookmarkTracker::Entity* entity =
tracker->GetEntityForSyncId(kNewSyncId);
ASSERT_THAT(entity, NotNull());
EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId)); EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId));
EXPECT_THAT(entity->bookmark_node(), Eq(&node)); EXPECT_THAT(entity->bookmark_node(), Eq(&node));
EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion)); EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion));
...@@ -406,9 +414,9 @@ TEST(SyncedBookmarkTrackerTest, ...@@ -406,9 +414,9 @@ TEST(SyncedBookmarkTrackerTest,
ASSERT_THAT(tracker, NotNull()); ASSERT_THAT(tracker, NotNull());
// Mark entities deleted in that order kId2, kId4, kId1 // Mark entities deleted in that order kId2, kId4, kId1
tracker->MarkDeleted(kId2); tracker->MarkDeleted(tracker->GetEntityForSyncId(kId2));
tracker->MarkDeleted(kId4); tracker->MarkDeleted(tracker->GetEntityForSyncId(kId4));
tracker->MarkDeleted(kId1); tracker->MarkDeleted(tracker->GetEntityForSyncId(kId1));
const sync_pb::BookmarkModelMetadata output_model_metadata = const sync_pb::BookmarkModelMetadata output_model_metadata =
tracker->BuildBookmarkModelMetadata(); tracker->BuildBookmarkModelMetadata();
...@@ -480,10 +488,10 @@ TEST(SyncedBookmarkTrackerTest, ...@@ -480,10 +488,10 @@ TEST(SyncedBookmarkTrackerTest,
// Mark the entities that they have local changes. (in shuffled order just to // Mark the entities that they have local changes. (in shuffled order just to
// verify the tracker doesn't simply maintain the order of updates similar to // verify the tracker doesn't simply maintain the order of updates similar to
// with deletions). // with deletions).
tracker->IncrementSequenceNumber(kId3); tracker->IncrementSequenceNumber(tracker->GetEntityForSyncId(kId3));
tracker->IncrementSequenceNumber(kId1); tracker->IncrementSequenceNumber(tracker->GetEntityForSyncId(kId1));
tracker->IncrementSequenceNumber(kId2); tracker->IncrementSequenceNumber(tracker->GetEntityForSyncId(kId2));
tracker->IncrementSequenceNumber(kId0); tracker->IncrementSequenceNumber(tracker->GetEntityForSyncId(kId0));
std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_change = std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_change =
tracker->GetEntitiesWithLocalChanges(kMaxEntries); tracker->GetEntitiesWithLocalChanges(kMaxEntries);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment