| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "sync/engine/build_commit_command.h" | |
| 6 | |
| 7 #include <limits> | |
| 8 #include <set> | |
| 9 #include <string> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/strings/string_util.h" | |
| 13 #include "sync/engine/syncer_proto_util.h" | |
| 14 #include "sync/internal_api/public/base/unique_position.h" | |
| 15 #include "sync/protocol/bookmark_specifics.pb.h" | |
| 16 #include "sync/protocol/sync.pb.h" | |
| 17 #include "sync/sessions/ordered_commit_set.h" | |
| 18 #include "sync/sessions/sync_session.h" | |
| 19 #include "sync/syncable/directory.h" | |
| 20 #include "sync/syncable/entry.h" | |
| 21 #include "sync/syncable/syncable_base_transaction.h" | |
| 22 #include "sync/syncable/syncable_changes_version.h" | |
| 23 #include "sync/syncable/syncable_proto_util.h" | |
| 24 #include "sync/util/time.h" | |
| 25 | |
| 26 using std::set; | |
| 27 using std::string; | |
| 28 using std::vector; | |
| 29 | |
| 30 namespace syncer { | |
| 31 | |
| 32 using sessions::SyncSession; | |
| 33 using syncable::Entry; | |
| 34 using syncable::IS_DEL; | |
| 35 using syncable::IS_UNAPPLIED_UPDATE; | |
| 36 using syncable::IS_UNSYNCED; | |
| 37 using syncable::Id; | |
| 38 using syncable::SPECIFICS; | |
| 39 using syncable::UNIQUE_POSITION; | |
| 40 | |
| 41 BuildCommitCommand::BuildCommitCommand( | |
| 42 syncable::BaseTransaction* trans, | |
| 43 const sessions::OrderedCommitSet& batch_commit_set, | |
| 44 sync_pb::ClientToServerMessage* commit_message, | |
| 45 ExtensionsActivity::Records* extensions_activity_buffer) | |
| 46 : trans_(trans), | |
| 47 batch_commit_set_(batch_commit_set), | |
| 48 commit_message_(commit_message), | |
| 49 extensions_activity_buffer_(extensions_activity_buffer) { | |
| 50 } | |
| 51 | |
| 52 BuildCommitCommand::~BuildCommitCommand() {} | |
| 53 | |
| 54 void BuildCommitCommand::AddExtensionsActivityToMessage( | |
| 55 SyncSession* session, sync_pb::CommitMessage* message) { | |
| 56 // We only send ExtensionsActivity to the server if bookmarks are being | |
| 57 // committed. | |
| 58 ExtensionsActivity* activity = session->context()->extensions_activity(); | |
| 59 if (batch_commit_set_.HasBookmarkCommitId()) { | |
| 60 // This isn't perfect, since the set of extensions activity may not | |
| 61 // correlate exactly with the items being committed. That's OK as | |
| 62 // long as we're looking for a rough estimate of extensions activity, | |
| 63 // not an precise mapping of which commits were triggered by which | |
| 64 // extension. | |
| 65 // | |
| 66 // We will push this list of extensions activity back into the | |
| 67 // ExtensionsActivityMonitor if this commit fails. That's why we must keep | |
| 68 // a copy of these records in the session. | |
| 69 activity->GetAndClearRecords(extensions_activity_buffer_); | |
| 70 | |
| 71 const ExtensionsActivity::Records& records = | |
| 72 *extensions_activity_buffer_; | |
| 73 for (ExtensionsActivity::Records::const_iterator it = | |
| 74 records.begin(); | |
| 75 it != records.end(); ++it) { | |
| 76 sync_pb::ChromiumExtensionsActivity* activity_message = | |
| 77 message->add_extensions_activity(); | |
| 78 activity_message->set_extension_id(it->second.extension_id); | |
| 79 activity_message->set_bookmark_writes_since_last_commit( | |
| 80 it->second.bookmark_write_count); | |
| 81 } | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 void BuildCommitCommand::AddClientConfigParamsToMessage( | |
| 86 SyncSession* session, sync_pb::CommitMessage* message) { | |
| 87 const ModelSafeRoutingInfo& routing_info = session->context()->routing_info(); | |
| 88 sync_pb::ClientConfigParams* config_params = message->mutable_config_params(); | |
| 89 for (std::map<ModelType, ModelSafeGroup>::const_iterator iter = | |
| 90 routing_info.begin(); iter != routing_info.end(); ++iter) { | |
| 91 if (ProxyTypes().Has(iter->first)) | |
| 92 continue; | |
| 93 int field_number = GetSpecificsFieldNumberFromModelType(iter->first); | |
| 94 config_params->mutable_enabled_type_ids()->Add(field_number); | |
| 95 } | |
| 96 config_params->set_tabs_datatype_enabled( | |
| 97 routing_info.count(syncer::PROXY_TABS) > 0); | |
| 98 } | |
| 99 | |
| 100 namespace { | |
| 101 void SetEntrySpecifics(const Entry& meta_entry, | |
| 102 sync_pb::SyncEntity* sync_entry) { | |
| 103 // Add the new style extension and the folder bit. | |
| 104 sync_entry->mutable_specifics()->CopyFrom(meta_entry.GetSpecifics()); | |
| 105 sync_entry->set_folder(meta_entry.GetIsDir()); | |
| 106 | |
| 107 CHECK(!sync_entry->specifics().password().has_client_only_encrypted_data()); | |
| 108 DCHECK_EQ(meta_entry.GetModelType(), GetModelType(*sync_entry)); | |
| 109 } | |
| 110 } // namespace | |
| 111 | |
| 112 SyncerError BuildCommitCommand::ExecuteImpl(SyncSession* session) { | |
| 113 commit_message_->set_share(session->context()->account_name()); | |
| 114 commit_message_->set_message_contents(sync_pb::ClientToServerMessage::COMMIT); | |
| 115 | |
| 116 sync_pb::CommitMessage* commit_message = commit_message_->mutable_commit(); | |
| 117 commit_message->set_cache_guid(trans_->directory()->cache_guid()); | |
| 118 AddExtensionsActivityToMessage(session, commit_message); | |
| 119 AddClientConfigParamsToMessage(session, commit_message); | |
| 120 | |
| 121 for (size_t i = 0; i < batch_commit_set_.Size(); i++) { | |
| 122 int64 handle = batch_commit_set_.GetCommitHandleAt(i); | |
| 123 sync_pb::SyncEntity* sync_entry = commit_message->add_entries(); | |
| 124 | |
| 125 Entry meta_entry(trans_, syncable::GET_BY_HANDLE, handle); | |
| 126 CHECK(meta_entry.good()); | |
| 127 | |
| 128 DCHECK_NE(0UL, | |
| 129 session->context()->routing_info().count( | |
| 130 meta_entry.GetModelType())) | |
| 131 << "Committing change to datatype that's not actively enabled."; | |
| 132 | |
| 133 BuildCommitItem(meta_entry, sync_entry); | |
| 134 } | |
| 135 | |
| 136 | |
| 137 return SYNCER_OK; | |
| 138 } | |
| 139 | |
| 140 // static. | |
| 141 void BuildCommitCommand::BuildCommitItem( | |
| 142 const syncable::Entry& meta_entry, | |
| 143 sync_pb::SyncEntity* sync_entry) { | |
| 144 syncable::Id id = meta_entry.GetId(); | |
| 145 sync_entry->set_id_string(SyncableIdToProto(id)); | |
| 146 | |
| 147 string name = meta_entry.GetNonUniqueName(); | |
| 148 CHECK(!name.empty()); // Make sure this isn't an update. | |
| 149 // Note: Truncation is also performed in WriteNode::SetTitle(..). But this | |
| 150 // call is still necessary to handle any title changes that might originate | |
| 151 // elsewhere, or already be persisted in the directory. | |
| 152 TruncateUTF8ToByteSize(name, 255, &name); | |
| 153 sync_entry->set_name(name); | |
| 154 | |
| 155 // Set the non_unique_name. If we do, the server ignores | |
| 156 // the |name| value (using |non_unique_name| instead), and will return | |
| 157 // in the CommitResponse a unique name if one is generated. | |
| 158 // We send both because it may aid in logging. | |
| 159 sync_entry->set_non_unique_name(name); | |
| 160 | |
| 161 if (!meta_entry.GetUniqueClientTag().empty()) { | |
| 162 sync_entry->set_client_defined_unique_tag( | |
| 163 meta_entry.GetUniqueClientTag()); | |
| 164 } | |
| 165 | |
| 166 // Deleted items with server-unknown parent ids can be a problem so we set | |
| 167 // the parent to 0. (TODO(sync): Still true in protocol?). | |
| 168 Id new_parent_id; | |
| 169 if (meta_entry.GetIsDel() && | |
| 170 !meta_entry.GetParentId().ServerKnows()) { | |
| 171 new_parent_id = syncable::BaseTransaction::root_id(); | |
| 172 } else { | |
| 173 new_parent_id = meta_entry.GetParentId(); | |
| 174 } | |
| 175 sync_entry->set_parent_id_string(SyncableIdToProto(new_parent_id)); | |
| 176 | |
| 177 // If our parent has changed, send up the old one so the server | |
| 178 // can correctly deal with multiple parents. | |
| 179 // TODO(nick): With the server keeping track of the primary sync parent, | |
| 180 // it should not be necessary to provide the old_parent_id: the version | |
| 181 // number should suffice. | |
| 182 if (new_parent_id != meta_entry.GetServerParentId() && | |
| 183 0 != meta_entry.GetBaseVersion() && | |
| 184 syncable::CHANGES_VERSION != meta_entry.GetBaseVersion()) { | |
| 185 sync_entry->set_old_parent_id( | |
| 186 SyncableIdToProto(meta_entry.GetServerParentId())); | |
| 187 } | |
| 188 | |
| 189 int64 version = meta_entry.GetBaseVersion(); | |
| 190 if (syncable::CHANGES_VERSION == version || 0 == version) { | |
| 191 // Undeletions are only supported for items that have a client tag. | |
| 192 DCHECK(!id.ServerKnows() || | |
| 193 !meta_entry.GetUniqueClientTag().empty()) | |
| 194 << meta_entry; | |
| 195 | |
| 196 // Version 0 means to create or undelete an object. | |
| 197 sync_entry->set_version(0); | |
| 198 } else { | |
| 199 DCHECK(id.ServerKnows()) << meta_entry; | |
| 200 sync_entry->set_version(meta_entry.GetBaseVersion()); | |
| 201 } | |
| 202 sync_entry->set_ctime(TimeToProtoTime(meta_entry.GetCtime())); | |
| 203 sync_entry->set_mtime(TimeToProtoTime(meta_entry.GetMtime())); | |
| 204 | |
| 205 // Deletion is final on the server, let's move things and then delete them. | |
| 206 if (meta_entry.GetIsDel()) { | |
| 207 sync_entry->set_deleted(true); | |
| 208 } else { | |
| 209 if (meta_entry.GetSpecifics().has_bookmark()) { | |
| 210 // Both insert_after_item_id and position_in_parent fields are set only | |
| 211 // for legacy reasons. See comments in sync.proto for more information. | |
| 212 const Id& prev_id = meta_entry.GetPredecessorId(); | |
| 213 string prev_id_string = | |
| 214 prev_id.IsRoot() ? string() : prev_id.GetServerId(); | |
| 215 sync_entry->set_insert_after_item_id(prev_id_string); | |
| 216 sync_entry->set_position_in_parent( | |
| 217 meta_entry.GetUniquePosition().ToInt64()); | |
| 218 meta_entry.GetUniquePosition().ToProto( | |
| 219 sync_entry->mutable_unique_position()); | |
| 220 } | |
| 221 SetEntrySpecifics(meta_entry, sync_entry); | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 } // namespace syncer | |
| OLD | NEW |