| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 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 "chrome/browser/sync/engine/process_updates_command.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/basictypes.h" | |
| 10 #include "base/location.h" | |
| 11 #include "chrome/browser/sync/engine/syncer.h" | |
| 12 #include "chrome/browser/sync/engine/syncer_proto_util.h" | |
| 13 #include "chrome/browser/sync/engine/syncer_util.h" | |
| 14 #include "chrome/browser/sync/engine/syncproto.h" | |
| 15 #include "chrome/browser/sync/sessions/sync_session.h" | |
| 16 #include "chrome/browser/sync/syncable/syncable.h" | |
| 17 #include "chrome/browser/sync/util/cryptographer.h" | |
| 18 | |
| 19 using std::vector; | |
| 20 | |
| 21 namespace browser_sync { | |
| 22 | |
| 23 using sessions::SyncSession; | |
| 24 using sessions::StatusController; | |
| 25 using sessions::UpdateProgress; | |
| 26 | |
| 27 ProcessUpdatesCommand::ProcessUpdatesCommand() {} | |
| 28 ProcessUpdatesCommand::~ProcessUpdatesCommand() {} | |
| 29 | |
| 30 std::set<ModelSafeGroup> ProcessUpdatesCommand::GetGroupsToChange( | |
| 31 const sessions::SyncSession& session) const { | |
| 32 return session.GetEnabledGroupsWithVerifiedUpdates(); | |
| 33 } | |
| 34 | |
| 35 SyncerError ProcessUpdatesCommand::ModelChangingExecuteImpl( | |
| 36 SyncSession* session) { | |
| 37 syncable::Directory* dir = session->context()->directory(); | |
| 38 | |
| 39 const sessions::UpdateProgress* progress = | |
| 40 session->status_controller().update_progress(); | |
| 41 if (!progress) | |
| 42 return SYNCER_OK; // Nothing to do. | |
| 43 | |
| 44 syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir); | |
| 45 vector<sessions::VerifiedUpdate>::const_iterator it; | |
| 46 for (it = progress->VerifiedUpdatesBegin(); | |
| 47 it != progress->VerifiedUpdatesEnd(); | |
| 48 ++it) { | |
| 49 const sync_pb::SyncEntity& update = it->second; | |
| 50 | |
| 51 if (it->first != VERIFY_SUCCESS && it->first != VERIFY_UNDELETE) | |
| 52 continue; | |
| 53 switch (ProcessUpdate(update, | |
| 54 dir->GetCryptographer(&trans), | |
| 55 &trans)) { | |
| 56 case SUCCESS_PROCESSED: | |
| 57 case SUCCESS_STORED: | |
| 58 break; | |
| 59 default: | |
| 60 NOTREACHED(); | |
| 61 break; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 StatusController* status = session->mutable_status_controller(); | |
| 66 status->mutable_update_progress()->ClearVerifiedUpdates(); | |
| 67 return SYNCER_OK; | |
| 68 } | |
| 69 | |
| 70 namespace { | |
| 71 // Returns true if the entry is still ok to process. | |
| 72 bool ReverifyEntry(syncable::WriteTransaction* trans, const SyncEntity& entry, | |
| 73 syncable::MutableEntry* same_id) { | |
| 74 | |
| 75 const bool deleted = entry.has_deleted() && entry.deleted(); | |
| 76 const bool is_directory = entry.IsFolder(); | |
| 77 const syncable::ModelType model_type = entry.GetModelType(); | |
| 78 | |
| 79 return VERIFY_SUCCESS == SyncerUtil::VerifyUpdateConsistency(trans, | |
| 80 entry, | |
| 81 same_id, | |
| 82 deleted, | |
| 83 is_directory, | |
| 84 model_type); | |
| 85 } | |
| 86 } // namespace | |
| 87 | |
| 88 // Process a single update. Will avoid touching global state. | |
| 89 ServerUpdateProcessingResult ProcessUpdatesCommand::ProcessUpdate( | |
| 90 const sync_pb::SyncEntity& proto_update, | |
| 91 const Cryptographer* cryptographer, | |
| 92 syncable::WriteTransaction* const trans) { | |
| 93 | |
| 94 const SyncEntity& update = *static_cast<const SyncEntity*>(&proto_update); | |
| 95 syncable::Id server_id = update.id(); | |
| 96 const std::string name = SyncerProtoUtil::NameFromSyncEntity(update); | |
| 97 | |
| 98 // Look to see if there's a local item that should recieve this update, | |
| 99 // maybe due to a duplicate client tag or a lost commit response. | |
| 100 syncable::Id local_id = SyncerUtil::FindLocalIdToUpdate(trans, update); | |
| 101 | |
| 102 // FindLocalEntryToUpdate has veto power. | |
| 103 if (local_id.IsNull()) { | |
| 104 return SUCCESS_PROCESSED; // The entry has become irrelevant. | |
| 105 } | |
| 106 | |
| 107 SyncerUtil::CreateNewEntry(trans, local_id); | |
| 108 | |
| 109 // We take a two step approach. First we store the entries data in the | |
| 110 // server fields of a local entry and then move the data to the local fields | |
| 111 syncable::MutableEntry target_entry(trans, syncable::GET_BY_ID, local_id); | |
| 112 | |
| 113 // We need to run the Verify checks again; the world could have changed | |
| 114 // since VerifyUpdatesCommand. | |
| 115 if (!ReverifyEntry(trans, update, &target_entry)) { | |
| 116 return SUCCESS_PROCESSED; // The entry has become irrelevant. | |
| 117 } | |
| 118 | |
| 119 // If we're repurposing an existing local entry with a new server ID, | |
| 120 // change the ID now, after we're sure that the update can succeed. | |
| 121 if (local_id != server_id) { | |
| 122 DCHECK(!update.deleted()); | |
| 123 SyncerUtil::ChangeEntryIDAndUpdateChildren(trans, &target_entry, | |
| 124 server_id); | |
| 125 // When IDs change, versions become irrelevant. Forcing BASE_VERSION | |
| 126 // to zero would ensure that this update gets applied, but would indicate | |
| 127 // creation or undeletion if it were committed that way. Instead, prefer | |
| 128 // forcing BASE_VERSION to entry.version() while also forcing | |
| 129 // IS_UNAPPLIED_UPDATE to true. If the item is UNSYNCED, it's committable | |
| 130 // from the new state; it may commit before the conflict resolver gets | |
| 131 // a crack at it. | |
| 132 if (target_entry.Get(syncable::IS_UNSYNCED) || | |
| 133 target_entry.Get(syncable::BASE_VERSION) > 0) { | |
| 134 // If either of these conditions are met, then we can expect valid client | |
| 135 // fields for this entry. When BASE_VERSION is positive, consistency is | |
| 136 // enforced on the client fields at update-application time. Otherwise, | |
| 137 // we leave the BASE_VERSION field alone; it'll get updated the first time | |
| 138 // we successfully apply this update. | |
| 139 target_entry.Put(syncable::BASE_VERSION, update.version()); | |
| 140 } | |
| 141 // Force application of this update, no matter what. | |
| 142 target_entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); | |
| 143 } | |
| 144 | |
| 145 // If this is a newly received undecryptable update, and the only thing that | |
| 146 // has changed are the specifics, store the original decryptable specifics, | |
| 147 // (on which any current or future local changes are based) before we | |
| 148 // overwrite SERVER_SPECIFICS. | |
| 149 // MTIME, CTIME, and NON_UNIQUE_NAME are not enforced. | |
| 150 if (!update.deleted() && !target_entry.Get(syncable::SERVER_IS_DEL) && | |
| 151 (update.parent_id() == target_entry.Get(syncable::SERVER_PARENT_ID)) && | |
| 152 (update.position_in_parent() == | |
| 153 target_entry.Get(syncable::SERVER_POSITION_IN_PARENT)) && | |
| 154 update.has_specifics() && update.specifics().has_encrypted() && | |
| 155 !cryptographer->CanDecrypt(update.specifics().encrypted())) { | |
| 156 sync_pb::EntitySpecifics prev_specifics = | |
| 157 target_entry.Get(syncable::SERVER_SPECIFICS); | |
| 158 // We only store the old specifics if they were decryptable and applied and | |
| 159 // there is no BASE_SERVER_SPECIFICS already. Else do nothing. | |
| 160 if (!target_entry.Get(syncable::IS_UNAPPLIED_UPDATE) && | |
| 161 !syncable::IsRealDataType(syncable::GetModelTypeFromSpecifics( | |
| 162 target_entry.Get(syncable::BASE_SERVER_SPECIFICS))) && | |
| 163 (!prev_specifics.has_encrypted() || | |
| 164 cryptographer->CanDecrypt(prev_specifics.encrypted()))) { | |
| 165 DVLOG(2) << "Storing previous server specifcs: " | |
| 166 << prev_specifics.SerializeAsString(); | |
| 167 target_entry.Put(syncable::BASE_SERVER_SPECIFICS, prev_specifics); | |
| 168 } | |
| 169 } else if (syncable::IsRealDataType(syncable::GetModelTypeFromSpecifics( | |
| 170 target_entry.Get(syncable::BASE_SERVER_SPECIFICS)))) { | |
| 171 // We have a BASE_SERVER_SPECIFICS, but a subsequent non-specifics-only | |
| 172 // change arrived. As a result, we can't use the specifics alone to detect | |
| 173 // changes, so we clear BASE_SERVER_SPECIFICS. | |
| 174 target_entry.Put(syncable::BASE_SERVER_SPECIFICS, | |
| 175 sync_pb::EntitySpecifics()); | |
| 176 } | |
| 177 | |
| 178 SyncerUtil::UpdateServerFieldsFromUpdate(&target_entry, update, name); | |
| 179 | |
| 180 return SUCCESS_PROCESSED; | |
| 181 } | |
| 182 | |
| 183 } // namespace browser_sync | |
| OLD | NEW |