| Index: sync/engine/process_commit_response_command.cc
|
| diff --git a/sync/engine/process_commit_response_command.cc b/sync/engine/process_commit_response_command.cc
|
| index b82ff6d5246dac3c908b4060444a7c390d9d3dcf..3ed1a6c03de3ef22679dc135cc6b776b4c0e6d68 100644
|
| --- a/sync/engine/process_commit_response_command.cc
|
| +++ b/sync/engine/process_commit_response_command.cc
|
| @@ -48,7 +48,15 @@ using sessions::StatusController;
|
| using sessions::SyncSession;
|
| using sessions::ConflictProgress;
|
|
|
| -ProcessCommitResponseCommand::ProcessCommitResponseCommand() {}
|
| +ProcessCommitResponseCommand::ProcessCommitResponseCommand(
|
| + const sessions::OrderedCommitSet& commit_set,
|
| + const ClientToServerMessage& commit_message,
|
| + const ClientToServerResponse& commit_response)
|
| + : commit_set_(commit_set),
|
| + commit_message_(commit_message),
|
| + commit_response_(commit_response) {
|
| +}
|
| +
|
| ProcessCommitResponseCommand::~ProcessCommitResponseCommand() {}
|
|
|
| std::set<ModelSafeGroup> ProcessCommitResponseCommand::GetGroupsToChange(
|
| @@ -57,10 +65,9 @@ std::set<ModelSafeGroup> ProcessCommitResponseCommand::GetGroupsToChange(
|
|
|
| syncable::Directory* dir = session.context()->directory();
|
| syncable::ReadTransaction trans(FROM_HERE, dir);
|
| - const StatusController& status = session.status_controller();
|
| - for (size_t i = 0; i < status.commit_ids().size(); ++i) {
|
| + for (size_t i = 0; i < commit_set_.Size(); ++i) {
|
| groups_with_commits.insert(
|
| - GetGroupForModelType(status.GetUnrestrictedCommitModelTypeAt(i),
|
| + GetGroupForModelType(commit_set_.GetModelTypeAt(i),
|
| session.routing_info()));
|
| }
|
|
|
| @@ -68,19 +75,18 @@ std::set<ModelSafeGroup> ProcessCommitResponseCommand::GetGroupsToChange(
|
| }
|
|
|
| SyncerError ProcessCommitResponseCommand::ModelNeutralExecuteImpl(
|
| - sessions::SyncSession* session) {
|
| - const StatusController& status = session->status_controller();
|
| - const ClientToServerResponse& response(status.commit_response());
|
| - const vector<syncable::Id>& commit_ids(status.commit_ids());
|
| + SyncSession* session) {
|
| + syncable::Directory* dir = session->context()->directory();
|
| + const vector<syncable::Id>& commit_ids = commit_set_.GetAllCommitIds();
|
|
|
| - if (!response.has_commit()) {
|
| - // TODO(sync): What if we didn't try to commit anything?
|
| + if (!commit_response_.has_commit()) {
|
| LOG(WARNING) << "Commit response has no commit body!";
|
| + ClearSyncingBits(dir, commit_ids);
|
| return SERVER_RESPONSE_VALIDATION_FAILED;
|
| }
|
|
|
| - const CommitResponse& cr = response.commit();
|
| - int commit_count = commit_ids.size();
|
| + const CommitResponse& cr = commit_response_.commit();
|
| + int commit_count = commit_set_.Size();
|
| if (cr.entryresponse_size() != commit_count) {
|
| LOG(ERROR) << "Commit response has wrong number of entries! Expected:" <<
|
| commit_count << " Got:" << cr.entryresponse_size();
|
| @@ -90,6 +96,7 @@ SyncerError ProcessCommitResponseCommand::ModelNeutralExecuteImpl(
|
| if (cr.entryresponse(i).has_error_message())
|
| LOG(ERROR) << " " << cr.entryresponse(i).error_message();
|
| }
|
| + ClearSyncingBits(dir, commit_ids);
|
| return SERVER_RESPONSE_VALIDATION_FAILED;
|
| }
|
| return SYNCER_OK;
|
| @@ -99,60 +106,61 @@ SyncerError ProcessCommitResponseCommand::ModelChangingExecuteImpl(
|
| SyncSession* session) {
|
| SyncerError result = ProcessCommitResponse(session);
|
| ExtensionsActivityMonitor* monitor = session->context()->extensions_monitor();
|
| - if (session->status_controller().HasBookmarkCommitActivity() &&
|
| - session->status_controller().syncer_status()
|
| +
|
| + // This is to be run on one model only: the bookmark model.
|
| + if (session->status_controller()
|
| + .ActiveGroupRestrictionIncludesModel(syncable::BOOKMARKS)) {
|
| + // If the commit failed, return the data to the ExtensionsActivityMonitor.
|
| + if (session->status_controller().syncer_status()
|
| .num_successful_bookmark_commits == 0) {
|
| - monitor->PutRecords(session->extensions_activity());
|
| + monitor->PutRecords(session->extensions_activity());
|
| + }
|
| + // Clear our cached data in either case.
|
| session->mutable_extensions_activity()->clear();
|
| }
|
| +
|
| return result;
|
| }
|
|
|
| SyncerError ProcessCommitResponseCommand::ProcessCommitResponse(
|
| SyncSession* session) {
|
| syncable::Directory* dir = session->context()->directory();
|
| -
|
| StatusController* status = session->mutable_status_controller();
|
| - const ClientToServerResponse& response(status->commit_response());
|
| - const CommitResponse& cr = response.commit();
|
| - const sync_pb::CommitMessage& commit_message =
|
| - status->commit_message().commit();
|
| -
|
| - // If we try to commit a parent and child together and the parent conflicts
|
| - // the child will have a bad parent causing an error. As this is not a
|
| - // critical error, we trap it and don't LOG(ERROR). To enable this we keep
|
| - // a map of conflicting new folders.
|
| + const CommitResponse& cr = commit_response_.commit();
|
| + const sync_pb::CommitMessage& commit_message = commit_message_.commit();
|
| +
|
| int transient_error_commits = 0;
|
| int conflicting_commits = 0;
|
| int error_commits = 0;
|
| int successes = 0;
|
| - set<syncable::Id> conflicting_new_folder_ids;
|
| +
|
| set<syncable::Id> deleted_folders;
|
| ConflictProgress* conflict_progress = status->mutable_conflict_progress();
|
| - OrderedCommitSet::Projection proj = status->commit_id_projection();
|
| + OrderedCommitSet::Projection proj = status->commit_id_projection(
|
| + commit_set_);
|
| +
|
| if (!proj.empty()) { // Scope for WriteTransaction.
|
| WriteTransaction trans(FROM_HERE, SYNCER, dir);
|
| for (size_t i = 0; i < proj.size(); i++) {
|
| - CommitResponse::ResponseType response_type =
|
| - ProcessSingleCommitResponse(&trans, cr.entryresponse(proj[i]),
|
| - commit_message.entries(proj[i]),
|
| - status->GetCommitIdAt(proj[i]),
|
| - &conflicting_new_folder_ids,
|
| - &deleted_folders);
|
| + CommitResponse::ResponseType response_type = ProcessSingleCommitResponse(
|
| + &trans,
|
| + cr.entryresponse(proj[i]),
|
| + commit_message.entries(proj[i]),
|
| + commit_set_.GetCommitIdAt(proj[i]),
|
| + &deleted_folders);
|
| switch (response_type) {
|
| case CommitResponse::INVALID_MESSAGE:
|
| ++error_commits;
|
| break;
|
| case CommitResponse::CONFLICT:
|
| ++conflicting_commits;
|
| - // Only server CONFLICT responses will activate conflict resolution.
|
| conflict_progress->AddServerConflictingItemById(
|
| - status->GetCommitIdAt(proj[i]));
|
| + commit_set_.GetCommitIdAt(proj[i]));
|
| break;
|
| case CommitResponse::SUCCESS:
|
| // TODO(sync): worry about sync_rate_ rate calc?
|
| ++successes;
|
| - if (status->GetCommitModelTypeAt(proj[i]) == syncable::BOOKMARKS)
|
| + if (commit_set_.GetModelTypeAt(proj[i]) == syncable::BOOKMARKS)
|
| status->increment_num_successful_bookmark_commits();
|
| status->increment_num_successful_commits();
|
| break;
|
| @@ -171,16 +179,25 @@ SyncerError ProcessCommitResponseCommand::ProcessCommitResponse(
|
| SyncerUtil::MarkDeletedChildrenSynced(dir, &deleted_folders);
|
|
|
| int commit_count = static_cast<int>(proj.size());
|
| - if (commit_count == (successes + conflicting_commits)) {
|
| - // We consider conflicting commits as a success because things will work out
|
| - // on their own when we receive them. Flags will be set so that
|
| - // HasMoreToSync() will cause SyncScheduler to enter another sync cycle to
|
| - // handle this condition.
|
| + if (commit_count == successes) {
|
| return SYNCER_OK;
|
| } else if (error_commits > 0) {
|
| return SERVER_RETURN_UNKNOWN_ERROR;
|
| } else if (transient_error_commits > 0) {
|
| return SERVER_RETURN_TRANSIENT_ERROR;
|
| + } else if (conflicting_commits > 0) {
|
| + // This means that the server already has an item with this version, but
|
| + // we haven't seen that update yet. The correct response is to go back
|
| + // to the download upates phase and try to fetch the conflicting update
|
| + // so we can resolve it.
|
| + //
|
| + // The easiest and safest way to handle this is to treat it as a transient
|
| + // error. This will cause us to abort this sync cycle, wait a little while,
|
| + // then try again starting with a GetUpdate.
|
| + //
|
| + // TODO: Remove this option when the CONFLICT return value is fully
|
| + // deprecated.
|
| + return SERVER_RETURN_TRANSIENT_ERROR;
|
| } else {
|
| LOG(FATAL) << "Inconsistent counts when processing commit response";
|
| return SYNCER_OK;
|
| @@ -200,7 +217,6 @@ ProcessCommitResponseCommand::ProcessSingleCommitResponse(
|
| const sync_pb::CommitResponse_EntryResponse& pb_server_entry,
|
| const sync_pb::SyncEntity& commit_request_entry,
|
| const syncable::Id& pre_commit_id,
|
| - std::set<syncable::Id>* conflicting_new_folder_ids,
|
| set<syncable::Id>* deleted_folders) {
|
|
|
| const CommitResponse_EntryResponse& server_entry =
|
| @@ -229,10 +245,6 @@ ProcessCommitResponseCommand::ProcessSingleCommitResponse(
|
| }
|
| if (CommitResponse::CONFLICT == response) {
|
| DVLOG(1) << "Conflict Committing: " << local_entry;
|
| - // TODO(nick): conflicting_new_folder_ids is a purposeless anachronism.
|
| - if (!pre_commit_id.ServerKnows() && local_entry.Get(IS_DIR)) {
|
| - conflicting_new_folder_ids->insert(pre_commit_id);
|
| - }
|
| return response;
|
| }
|
| if (CommitResponse::RETRY == response) {
|
| @@ -479,4 +491,22 @@ void ProcessCommitResponseCommand::ProcessSuccessfulCommitResponse(
|
| }
|
| }
|
|
|
| +void ProcessCommitResponseCommand::ClearSyncingBits(
|
| + syncable::Directory *dir,
|
| + const vector<syncable::Id>& commit_ids) {
|
| + // This is part of the cleanup in the case of a failed commit. Normally we
|
| + // would unset the SYNCING bit when processing the commit response. In the
|
| + // failure case we don't process the response, so we need to clear those bits
|
| + // here.
|
| + syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
|
| + for (size_t i = 0; i < commit_ids.size(); i++) {
|
| + syncable::MutableEntry entry(&trans, syncable::GET_BY_ID, commit_ids[i]);
|
| + if (entry.good()) {
|
| + entry.Put(syncable::SYNCING, false);
|
| + } else {
|
| + LOG(WARNING) << "Id: " << commit_ids[i] << " disappeared";
|
| + }
|
| + }
|
| +}
|
| +
|
| } // namespace browser_sync
|
|
|