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 |