Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: sync/engine/commit.cc

Issue 25638003: sync: Implement per-type commit interface (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix compile warning Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/engine/commit.h" 5 #include "sync/engine/commit.h"
6 6
7 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
8 #include "sync/engine/build_commit_command.h" 8 #include "sync/engine/build_commit_command.h"
9 #include "sync/engine/get_commit_ids.h"
10 #include "sync/engine/process_commit_response_command.h" 9 #include "sync/engine/process_commit_response_command.h"
10 #include "sync/engine/sync_directory_commit_contribution.h"
11 #include "sync/engine/syncer.h" 11 #include "sync/engine/syncer.h"
12 #include "sync/engine/syncer_proto_util.h" 12 #include "sync/engine/syncer_proto_util.h"
13 #include "sync/sessions/sync_session.h" 13 #include "sync/sessions/sync_session.h"
14 #include "sync/syncable/mutable_entry.h" 14 #include "sync/syncable/directory.h"
15 #include "sync/syncable/syncable_model_neutral_write_transaction.h"
16 15
17 namespace syncer { 16 namespace syncer {
18 17
19 using sessions::SyncSession; 18 SyncerError BuildAndPostCommits(ModelTypeSet requested_types,
20 using sessions::StatusController; 19 Syncer* syncer,
21 using syncable::SYNCER; 20 sessions::SyncSession* session) {
22 using syncable::ModelNeutralWriteTransaction;
23
24 namespace {
25
26 // Sets the SYNCING bits of all items in the commit set to value_to_set.
27 void SetAllSyncingBitsToValue(ModelNeutralWriteTransaction* trans,
28 const sessions::OrderedCommitSet& commit_set,
29 bool value_to_set) {
30 const std::vector<int64>& commit_handles = commit_set.GetAllCommitHandles();
31 for (std::vector<int64>::const_iterator it = commit_handles.begin();
32 it != commit_handles.end(); ++it) {
33 syncable::ModelNeutralMutableEntry entry(
34 trans, syncable::GET_BY_HANDLE, *it);
35 if (entry.good()) {
36 entry.PutSyncing(value_to_set);
37 }
38 }
39 }
40
41 // Sets the SYNCING bits for all items in the OrderedCommitSet.
42 void SetSyncingBits(ModelNeutralWriteTransaction* trans,
43 const sessions::OrderedCommitSet& commit_set) {
44 SetAllSyncingBitsToValue(trans, commit_set, true);
45 }
46
47 // Clears the SYNCING bits for all items in the OrderedCommitSet.
48 void ClearSyncingBits(syncable::Directory* dir,
49 const sessions::OrderedCommitSet& commit_set) {
50 ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir);
51 SetAllSyncingBitsToValue(&trans, commit_set, false);
52 }
53
54 // Helper function that finds sync items that are ready to be committed to the
55 // server and serializes them into a commit message protobuf. It will return
56 // false iff there are no entries ready to be committed at this time.
57 //
58 // The OrderedCommitSet parameter is an output parameter which will contain
59 // the set of all items which are to be committed. The number of items in
60 // the set shall not exceed the maximum batch size. (The default batch size
61 // is currently 25, though it can be overwritten by the server.)
62 //
63 // The ClientToServerMessage parameter is an output parameter which will contain
64 // the commit message which should be sent to the server. It is valid iff the
65 // return value of this function is true.
66 bool PrepareCommitMessage(
67 sessions::SyncSession* session,
68 ModelTypeSet requested_types,
69 sessions::OrderedCommitSet* commit_set,
70 sync_pb::ClientToServerMessage* commit_message,
71 ExtensionsActivity::Records* extensions_activity_buffer) {
72 TRACE_EVENT0("sync", "PrepareCommitMessage");
73
74 commit_set->Clear();
75 commit_message->Clear();
76
77 ModelNeutralWriteTransaction trans(
78 FROM_HERE, SYNCER, session->context()->directory());
79
80 // Fetch the items to commit.
81 const size_t batch_size = session->context()->max_commit_batch_size();
82 GetCommitIds(&trans, requested_types, batch_size, commit_set);
83
84 DVLOG(1) << "Commit message will contain " << commit_set->Size() << " items.";
85 if (commit_set->Empty()) {
86 return false;
87 }
88
89 // Serialize the message.
90 BuildCommitCommand build_commit_command(&trans,
91 *commit_set,
92 commit_message,
93 extensions_activity_buffer);
94 build_commit_command.Execute(session);
95
96 SetSyncingBits(&trans, *commit_set);
97 return true;
98 }
99
100 SyncerError BuildAndPostCommitsImpl(ModelTypeSet requested_types,
101 Syncer* syncer,
102 sessions::SyncSession* session,
103 sessions::OrderedCommitSet* commit_set) {
104 ModelTypeSet commit_request_types;
105 while (!syncer->ExitRequested()) { 21 while (!syncer->ExitRequested()) {
106 sync_pb::ClientToServerMessage commit_message; 22 scoped_ptr<Commit> commit(
107 ExtensionsActivity::Records extensions_activity_buffer; 23 Commit::Init(
108 24 requested_types,
109 if (!PrepareCommitMessage(session, 25 session->context()->commit_contributor_map(),
110 requested_types, 26 session->context()->max_commit_batch_size(),
111 commit_set, 27 session->context()->account_name(),
112 &commit_message, 28 session->context()->directory()->cache_guid(),
113 &extensions_activity_buffer)) { 29 session->context()->extensions_activity()));
30 if (!commit) {
114 break; 31 break;
115 } 32 }
116 33
117 commit_request_types.PutAll(commit_set->Types()); 34 SyncerError error = commit->PostAndProcessResponse(
118 session->mutable_status_controller()->set_commit_request_types( 35 session,
119 commit_request_types); 36 session->mutable_status_controller(),
120 37 session->context()->extensions_activity());
121 sync_pb::ClientToServerResponse commit_response; 38 if (error != SYNCER_OK) {
122 39 return error;
123 DVLOG(1) << "Sending commit message.";
124 TRACE_EVENT_BEGIN0("sync", "PostCommit");
125 const SyncerError post_result = SyncerProtoUtil::PostClientToServerMessage(
126 &commit_message, &commit_response, session);
127 TRACE_EVENT_END0("sync", "PostCommit");
128
129 // TODO(rlarocque): Put all the post-commit logic in one place.
130 // See crbug.com/196338.
131
132 if (post_result != SYNCER_OK) {
133 LOG(WARNING) << "Post commit failed";
134 return post_result;
135 } 40 }
136
137 if (!commit_response.has_commit()) {
138 LOG(WARNING) << "Commit response has no commit body!";
139 return SERVER_RESPONSE_VALIDATION_FAILED;
140 }
141
142 const size_t num_responses = commit_response.commit().entryresponse_size();
143 if (num_responses != commit_set->Size()) {
144 LOG(ERROR)
145 << "Commit response has wrong number of entries! "
146 << "Expected: " << commit_set->Size() << ", "
147 << "Got: " << num_responses;
148 return SERVER_RESPONSE_VALIDATION_FAILED;
149 }
150
151 TRACE_EVENT_BEGIN0("sync", "ProcessCommitResponse");
152 ProcessCommitResponseCommand process_response_command(
153 *commit_set, commit_message, commit_response);
154 const SyncerError processing_result =
155 process_response_command.Execute(session);
156 TRACE_EVENT_END0("sync", "ProcessCommitResponse");
157
158 // If the commit failed, return the data to the ExtensionsActivityMonitor.
159 if (session->status_controller().
160 model_neutral_state().num_successful_bookmark_commits == 0) {
161 ExtensionsActivity* extensions_activity =
162 session->context()->extensions_activity();
163 extensions_activity->PutRecords(extensions_activity_buffer);
164 }
165
166 if (processing_result != SYNCER_OK) {
167 return processing_result;
168 }
169 session->SendEventNotification(SyncEngineEvent::STATUS_CHANGED);
170 } 41 }
171 42
172 return SYNCER_OK; 43 return SYNCER_OK;
173 } 44 }
174 45
175 } // namespace 46 Commit* Commit::Init(
47 ModelTypeSet requested_types,
48 CommitContributorMap* contributor_map,
49 size_t max_entries,
50 const std::string& account_name,
51 const std::string& cache_guid,
52 ExtensionsActivity* extensions_activity) {
53 // Gather per-type contributions.
54 ContributionMap contributions;
55 size_t num_entries = 0;
56 for (ModelTypeSet::Iterator it = requested_types.First();
57 it.Good(); it.Inc()) {
58 CommitContributorMap::iterator cm_it = contributor_map->find(it.Get());
59 if (cm_it == contributor_map->end()) {
60 NOTREACHED()
61 << "Could not find requested type " << ModelTypeToString(it.Get())
62 << " in contributor map.";
63 continue;
64 }
65 size_t spaces_remaining = max_entries - num_entries;
66 SyncDirectoryCommitContribution* contribution =
67 cm_it->second->GetContribution(spaces_remaining);
68 if (contribution) {
69 num_entries += contribution->GetNumEntries();
70 contributions.insert(std::make_pair(it.Get(), contribution));
71 }
72 }
176 73
74 // Give up if no one had anything to commit.
75 if (contributions.empty())
76 return NULL;
177 77
178 SyncerError BuildAndPostCommits(ModelTypeSet requested_types, 78 sync_pb::ClientToServerMessage message;
179 Syncer* syncer, 79 message.set_message_contents(sync_pb::ClientToServerMessage::COMMIT);
180 sessions::SyncSession* session) { 80 message.set_share(account_name);
181 sessions::OrderedCommitSet commit_set; 81
182 SyncerError result = 82 sync_pb::CommitMessage* commit_message = message.mutable_commit();
183 BuildAndPostCommitsImpl(requested_types, syncer, session, &commit_set); 83 commit_message->set_cache_guid(cache_guid);
184 if (result != SYNCER_OK) { 84
185 ClearSyncingBits(session->context()->directory(), commit_set); 85 // Set extensions activity if bookmark commits are present.
86 ExtensionsActivity::Records extensions_activity_buffer;
87 ContributionMap::iterator it = contributions.find(syncer::BOOKMARKS);
88 if (it != contributions.end() && it->second->GetNumEntries() != 0) {
89 BuildCommitCommand::AddExtensionsActivityToMessage(
90 extensions_activity,
91 &extensions_activity_buffer,
92 commit_message);
186 } 93 }
187 return result; 94
95 // Set the client config params.
96 ModelTypeSet enabled_types;
97 for (CommitContributorMap::iterator it = contributor_map->begin();
98 it != contributor_map->end(); ++it) {
99 enabled_types.Put(it->first);
100 }
101 BuildCommitCommand::AddClientConfigParamsToMessage(enabled_types,
102 commit_message);
103
104 // Finally, serialize all our contributions.
105 for (std::map<ModelType, SyncDirectoryCommitContribution*>::iterator it =
106 contributions.begin(); it != contributions.end(); ++it) {
107 it->second->AddToCommitMessage(&message);
108 }
109
110 // If we made it this far, then we've successfully prepared a commit message.
111 return new Commit(contributions, message, extensions_activity_buffer);
112 }
113
114 Commit::Commit(std::map<ModelType,
115 SyncDirectoryCommitContribution*> contributions,
116 sync_pb::ClientToServerMessage message,
117 ExtensionsActivity::Records extensions_activity_buffer)
118 : contributions_(contributions),
119 deleter_(&contributions_),
120 message_(message),
121 extensions_activity_buffer_(extensions_activity_buffer) {
122 }
123
124 Commit::~Commit() {
125 }
126
127 SyncerError Commit::PostAndProcessResponse(
128 sessions::SyncSession* session,
129 sessions::StatusController* status,
130 ExtensionsActivity* extensions_activity) {
131 ModelTypeSet request_types;
132 for (ContributionMap::const_iterator it = contributions_.begin();
133 it != contributions_.end(); ++it) {
134 request_types.Put(it->first);
135 }
136 session->mutable_status_controller()->set_commit_request_types(request_types);
137
138 DVLOG(1) << "Sending commit message.";
139 TRACE_EVENT_BEGIN0("sync", "PostCommit");
140 const SyncerError post_result = SyncerProtoUtil::PostClientToServerMessage(
141 &message_, &response_, session);
142 TRACE_EVENT_END0("sync", "PostCommit");
143
144 if (post_result != SYNCER_OK) {
145 LOG(WARNING) << "Post commit failed";
146 return post_result;
147 }
148
149 if (!response_.has_commit()) {
150 LOG(WARNING) << "Commit response has no commit body!";
151 return SERVER_RESPONSE_VALIDATION_FAILED;
152 }
153
154 size_t message_entries = message_.commit().entries_size();
155 size_t response_entries = response_.commit().entryresponse_size();
156 if (message_entries != response_entries) {
157 LOG(ERROR)
158 << "Commit response has wrong number of entries! "
159 << "Expected: " << message_entries << ", "
160 << "Got: " << response_entries;
161 return SERVER_RESPONSE_VALIDATION_FAILED;
162 }
163
164 // Let the contributors process the responses to each of their requests.
165 SyncerError processing_result = SYNCER_OK;
166 for (std::map<ModelType, SyncDirectoryCommitContribution*>::iterator it =
167 contributions_.begin(); it != contributions_.end(); ++it) {
168 TRACE_EVENT1("sync", "ProcessCommitResponse",
169 "type", ModelTypeToString(it->first));
170 SyncerError type_result =
171 it->second->ProcessCommitResponse(response_, status);
172 if (processing_result == SYNCER_OK && type_result != SYNCER_OK) {
173 processing_result = type_result;
174 }
175 }
176
177 // Handle bookmarks' special extensions activity stats.
178 if (session->status_controller().
179 model_neutral_state().num_successful_bookmark_commits == 0) {
180 extensions_activity->PutRecords(extensions_activity_buffer_);
181 }
182
183 return processing_result;
188 } 184 }
189 185
190 } // namespace syncer 186 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698