nigori_model_type_processor.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // Copyright 2019 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. #include "components/sync/nigori/nigori_model_type_processor.h"
  5. #include "base/logging.h"
  6. #include "base/threading/sequenced_task_runner_handle.h"
  7. #include "components/sync/base/client_tag_hash.h"
  8. #include "components/sync/base/data_type_histogram.h"
  9. #include "components/sync/base/time.h"
  10. #include "components/sync/engine/commit_queue.h"
  11. #include "components/sync/engine/data_type_activation_response.h"
  12. #include "components/sync/engine/forwarding_model_type_processor.h"
  13. #include "components/sync/engine/model_type_processor_metrics.h"
  14. #include "components/sync/model/processor_entity.h"
  15. #include "components/sync/model/type_entities_count.h"
  16. #include "components/sync/nigori/nigori_sync_bridge.h"
  17. #include "components/sync/protocol/entity_metadata.pb.h"
  18. #include "components/sync/protocol/entity_specifics.pb.h"
  19. #include "components/sync/protocol/proto_memory_estimations.h"
  20. #include "components/sync/protocol/proto_value_conversions.h"
  21. namespace syncer {
  22. namespace {
  23. // TODO(mamir): remove those and adjust the code accordingly. Similarly in
  24. // tests.
  25. const char kNigoriStorageKey[] = "NigoriStorageKey";
  26. const char kRawNigoriClientTagHash[] = "NigoriClientTagHash";
  27. } // namespace
  28. NigoriModelTypeProcessor::NigoriModelTypeProcessor() : bridge_(nullptr) {}
  29. NigoriModelTypeProcessor::~NigoriModelTypeProcessor() {
  30. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  31. }
  32. void NigoriModelTypeProcessor::ConnectSync(
  33. std::unique_ptr<CommitQueue> worker) {
  34. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  35. DVLOG(1) << "Successfully connected Encryption Keys";
  36. worker_ = std::move(worker);
  37. NudgeForCommitIfNeeded();
  38. }
  39. void NigoriModelTypeProcessor::DisconnectSync() {
  40. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  41. DCHECK(IsConnected());
  42. DVLOG(1) << "Disconnecting sync for Encryption Keys";
  43. worker_.reset();
  44. if (entity_) {
  45. entity_->ClearTransientSyncState();
  46. }
  47. }
  48. void NigoriModelTypeProcessor::GetLocalChanges(
  49. size_t max_entries,
  50. GetLocalChangesCallback callback) {
  51. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  52. DCHECK_GT(max_entries, 0U);
  53. // If there is a model error, it must have been reported already but hasn't
  54. // reached the sync engine yet. In this case return directly to avoid
  55. // interactions with the bridge.
  56. if (model_error_) {
  57. std::move(callback).Run(CommitRequestDataList());
  58. return;
  59. }
  60. DCHECK(entity_);
  61. // No local changes to commit.
  62. if (!entity_->RequiresCommitRequest()) {
  63. std::move(callback).Run(CommitRequestDataList());
  64. return;
  65. }
  66. if (entity_->RequiresCommitData()) {
  67. // SetCommitData will update EntityData's fields with values from
  68. // metadata.
  69. entity_->SetCommitData(bridge_->GetData());
  70. }
  71. auto commit_request_data = std::make_unique<CommitRequestData>();
  72. entity_->InitializeCommitRequestData(commit_request_data.get());
  73. CommitRequestDataList commit_request_data_list;
  74. commit_request_data_list.push_back(std::move(commit_request_data));
  75. std::move(callback).Run(std::move(commit_request_data_list));
  76. }
  77. void NigoriModelTypeProcessor::OnCommitCompleted(
  78. const sync_pb::ModelTypeState& type_state,
  79. const CommitResponseDataList& committed_response_list,
  80. const FailedCommitResponseDataList& error_response_list) {
  81. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  82. DCHECK(entity_);
  83. model_type_state_ = type_state;
  84. if (!committed_response_list.empty()) {
  85. entity_->ReceiveCommitResponse(committed_response_list[0],
  86. /*commit_only=*/false);
  87. } else {
  88. // If the entity hasn't been mentioned in response_list, then it's not
  89. // committed and we should reset its commit_requested_sequence_number so
  90. // they are committed again on next sync cycle.
  91. entity_->ClearTransientSyncState();
  92. }
  93. // Ask the bridge to persist the new metadata.
  94. bridge_->ApplySyncChanges(/*data=*/absl::nullopt);
  95. }
  96. void NigoriModelTypeProcessor::OnUpdateReceived(
  97. const sync_pb::ModelTypeState& type_state,
  98. UpdateResponseDataList updates) {
  99. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  100. DCHECK(model_ready_to_sync_);
  101. // If there is a model error, it must have been reported already but hasn't
  102. // reached the sync engine yet. In this case return directly to avoid
  103. // interactions with the bridge.
  104. if (model_error_) {
  105. return;
  106. }
  107. absl::optional<ModelError> error;
  108. const bool is_initial_sync = !model_type_state_.initial_sync_done();
  109. LogUpdatesReceivedByProcessorHistogram(NIGORI, is_initial_sync,
  110. updates.size());
  111. model_type_state_ = type_state;
  112. if (is_initial_sync) {
  113. DCHECK(!entity_);
  114. if (updates.empty()) {
  115. error = bridge_->MergeSyncData(absl::nullopt);
  116. } else {
  117. DCHECK(!updates[0].entity.is_deleted());
  118. entity_ = ProcessorEntity::CreateNew(
  119. kNigoriStorageKey, ClientTagHash::FromHashed(kRawNigoriClientTagHash),
  120. updates[0].entity.id, updates[0].entity.creation_time);
  121. entity_->RecordAcceptedRemoteUpdate(updates[0], /*trimmed_specifics=*/{});
  122. error = bridge_->MergeSyncData(std::move(updates[0].entity));
  123. }
  124. if (error) {
  125. ReportError(*error);
  126. }
  127. return;
  128. }
  129. if (updates.empty()) {
  130. bridge_->ApplySyncChanges(/*data=*/absl::nullopt);
  131. return;
  132. }
  133. DCHECK(entity_);
  134. // We assume the bridge will issue errors in case of deletions. Therefore, we
  135. // are adding the following DCHECK to simplify the code.
  136. DCHECK(!updates[0].entity.is_deleted());
  137. if (entity_->IsVersionAlreadyKnown(updates[0].response_version)) {
  138. // Seen this update before; just ignore it.
  139. bridge_->ApplySyncChanges(/*data=*/absl::nullopt);
  140. return;
  141. }
  142. if (entity_->IsUnsynced()) {
  143. // Remote update always win in case of conflict, because bridge takes care
  144. // of reapplying pending local changes after processing the remote update.
  145. entity_->RecordForcedRemoteUpdate(updates[0], /*trimmed_specifics=*/{});
  146. error = bridge_->ApplySyncChanges(std::move(updates[0].entity));
  147. } else if (!entity_->MatchesData(updates[0].entity)) {
  148. // Inform the bridge of the new or updated data.
  149. entity_->RecordAcceptedRemoteUpdate(updates[0], /*trimmed_specifics=*/{});
  150. error = bridge_->ApplySyncChanges(std::move(updates[0].entity));
  151. }
  152. if (error) {
  153. ReportError(*error);
  154. return;
  155. }
  156. // There may be new reasons to commit by the time this function is done.
  157. NudgeForCommitIfNeeded();
  158. }
  159. void NigoriModelTypeProcessor::OnSyncStarting(
  160. const DataTypeActivationRequest& request,
  161. StartCallback callback) {
  162. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  163. DVLOG(1) << "Sync is starting for Encryption Keys";
  164. DCHECK(request.error_handler) << "Encryption Keys";
  165. DCHECK(callback) << "Encryption Keys";
  166. DCHECK(!start_callback_) << "Encryption Keys";
  167. DCHECK(!IsConnected()) << "Encryption Keys";
  168. start_callback_ = std::move(callback);
  169. activation_request_ = request;
  170. ConnectIfReady();
  171. }
  172. void NigoriModelTypeProcessor::OnSyncStopping(
  173. SyncStopMetadataFate metadata_fate) {
  174. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  175. // Disabling sync for a type shouldn't happen before the model is loaded
  176. // because OnSyncStopping() is not allowed to be called before
  177. // OnSyncStarting() has completed.
  178. DCHECK(!start_callback_);
  179. worker_.reset();
  180. switch (metadata_fate) {
  181. case syncer::KEEP_METADATA: {
  182. break;
  183. }
  184. case syncer::CLEAR_METADATA: {
  185. ClearMetadataAndReset();
  186. model_ready_to_sync_ = false;
  187. // The model is still ready to sync (with the same |bridge_|) and same
  188. // sync metadata.
  189. ModelReadyToSync(bridge_, NigoriMetadataBatch());
  190. break;
  191. }
  192. }
  193. }
  194. void NigoriModelTypeProcessor::GetAllNodesForDebugging(
  195. AllNodesCallback callback) {
  196. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  197. std::unique_ptr<EntityData> entity_data = bridge_->GetData();
  198. if (!entity_data) {
  199. std::move(callback).Run(syncer::NIGORI, base::Value::List());
  200. return;
  201. }
  202. if (entity_) {
  203. const sync_pb::EntityMetadata& metadata = entity_->metadata();
  204. // Set id value as the legacy Directory implementation, "s" means server.
  205. entity_data->id = "s" + metadata.server_id();
  206. entity_data->creation_time = ProtoTimeToTime(metadata.creation_time());
  207. entity_data->modification_time =
  208. ProtoTimeToTime(metadata.modification_time());
  209. }
  210. base::Value::Dict root_node = entity_data->ToDictionaryValue();
  211. if (entity_) {
  212. root_node.Set("metadata", base::Value::FromUniquePtrValue(
  213. EntityMetadataToValue(entity_->metadata())));
  214. }
  215. // Function isTypeRootNode in sync_node_browser.js use PARENT_ID and
  216. // UNIQUE_SERVER_TAG to check if the node is root node. isChildOf in
  217. // sync_node_browser.js uses modelType to check if root node is parent of real
  218. // data node.
  219. root_node.Set("PARENT_ID", "r");
  220. root_node.Set("UNIQUE_SERVER_TAG", "Nigori");
  221. root_node.Set("modelType", ModelTypeToDebugString(NIGORI));
  222. base::Value::List all_nodes;
  223. all_nodes.Append(std::move(root_node));
  224. std::move(callback).Run(syncer::NIGORI, std::move(all_nodes));
  225. }
  226. void NigoriModelTypeProcessor::GetTypeEntitiesCountForDebugging(
  227. base::OnceCallback<void(const TypeEntitiesCount&)> callback) const {
  228. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  229. TypeEntitiesCount count(syncer::NIGORI);
  230. count.non_tombstone_entities = entity_ ? 1 : 0;
  231. count.entities = count.non_tombstone_entities;
  232. std::move(callback).Run(count);
  233. }
  234. void NigoriModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
  235. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  236. size_t memory_usage = 0;
  237. memory_usage += EstimateMemoryUsage(model_type_state_);
  238. memory_usage += entity_ ? entity_->EstimateMemoryUsage() : 0;
  239. SyncRecordModelTypeMemoryHistogram(ModelType::NIGORI, memory_usage);
  240. SyncRecordModelTypeCountHistogram(ModelType::NIGORI, entity_ ? 1 : 0);
  241. }
  242. void NigoriModelTypeProcessor::ModelReadyToSync(
  243. NigoriSyncBridge* bridge,
  244. NigoriMetadataBatch nigori_metadata) {
  245. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  246. DCHECK(bridge);
  247. DCHECK(!model_ready_to_sync_);
  248. bridge_ = bridge;
  249. model_ready_to_sync_ = true;
  250. // Abort if the model already experienced an error.
  251. if (model_error_) {
  252. return;
  253. }
  254. if (nigori_metadata.model_type_state.initial_sync_done() &&
  255. nigori_metadata.entity_metadata) {
  256. model_type_state_ = std::move(nigori_metadata.model_type_state);
  257. sync_pb::EntityMetadata metadata =
  258. std::move(*nigori_metadata.entity_metadata);
  259. metadata.set_client_tag_hash(kRawNigoriClientTagHash);
  260. entity_ = ProcessorEntity::CreateFromMetadata(kNigoriStorageKey,
  261. std::move(metadata));
  262. } else {
  263. // First time syncing or persisted data are corrupted; initialize metadata.
  264. model_type_state_.mutable_progress_marker()->set_data_type_id(
  265. sync_pb::EntitySpecifics::kNigoriFieldNumber);
  266. }
  267. ConnectIfReady();
  268. }
  269. void NigoriModelTypeProcessor::Put(std::unique_ptr<EntityData> entity_data) {
  270. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  271. DCHECK(entity_data);
  272. DCHECK(!entity_data->is_deleted());
  273. DCHECK(!entity_data->name.empty());
  274. DCHECK(!entity_data->specifics.has_encrypted());
  275. DCHECK_EQ(NIGORI, GetModelTypeFromSpecifics(entity_data->specifics));
  276. DCHECK(entity_);
  277. if (!model_type_state_.initial_sync_done()) {
  278. // Ignore changes before the initial sync is done.
  279. return;
  280. }
  281. if (entity_->MatchesData(*entity_data)) {
  282. // Ignore changes that don't actually change anything.
  283. return;
  284. }
  285. entity_->RecordLocalUpdate(std::move(entity_data), /*trimmed_specifics=*/{});
  286. NudgeForCommitIfNeeded();
  287. }
  288. bool NigoriModelTypeProcessor::IsEntityUnsynced() {
  289. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  290. if (entity_ == nullptr) {
  291. return false;
  292. }
  293. return entity_->IsUnsynced();
  294. }
  295. NigoriMetadataBatch NigoriModelTypeProcessor::GetMetadata() {
  296. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  297. DCHECK(IsTrackingMetadata());
  298. DCHECK(entity_);
  299. NigoriMetadataBatch nigori_metadata_batch;
  300. nigori_metadata_batch.model_type_state = model_type_state_;
  301. nigori_metadata_batch.entity_metadata = entity_->metadata();
  302. return nigori_metadata_batch;
  303. }
  304. void NigoriModelTypeProcessor::ReportError(const ModelError& error) {
  305. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  306. // Ignore all errors after the first.
  307. if (model_error_) {
  308. return;
  309. }
  310. model_error_ = error;
  311. if (IsConnected()) {
  312. DisconnectSync();
  313. }
  314. // Shouldn't connect anymore.
  315. start_callback_.Reset();
  316. if (activation_request_.error_handler) {
  317. // Tell sync about the error.
  318. activation_request_.error_handler.Run(error);
  319. }
  320. }
  321. base::WeakPtr<ModelTypeControllerDelegate>
  322. NigoriModelTypeProcessor::GetControllerDelegate() {
  323. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  324. return weak_ptr_factory_for_controller_.GetWeakPtr();
  325. }
  326. bool NigoriModelTypeProcessor::IsConnectedForTest() const {
  327. return IsConnected();
  328. }
  329. const sync_pb::ModelTypeState&
  330. NigoriModelTypeProcessor::GetModelTypeStateForTest() {
  331. return model_type_state_;
  332. }
  333. bool NigoriModelTypeProcessor::IsTrackingMetadata() {
  334. return model_type_state_.initial_sync_done();
  335. }
  336. bool NigoriModelTypeProcessor::IsConnected() const {
  337. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  338. return worker_ != nullptr;
  339. }
  340. void NigoriModelTypeProcessor::ConnectIfReady() {
  341. if (!start_callback_) {
  342. return;
  343. }
  344. if (model_error_) {
  345. activation_request_.error_handler.Run(model_error_.value());
  346. start_callback_.Reset();
  347. return;
  348. }
  349. if (!model_ready_to_sync_) {
  350. return;
  351. }
  352. if (model_type_state_.initial_sync_done() &&
  353. model_type_state_.cache_guid() != activation_request_.cache_guid) {
  354. ClearMetadataAndReset();
  355. DCHECK(model_ready_to_sync_);
  356. }
  357. model_type_state_.set_cache_guid(activation_request_.cache_guid);
  358. // Cache GUID verification earlier above guarantees the user is the same.
  359. model_type_state_.set_authenticated_account_id(
  360. activation_request_.authenticated_account_id.ToString());
  361. auto activation_response = std::make_unique<DataTypeActivationResponse>();
  362. activation_response->model_type_state = model_type_state_;
  363. activation_response->type_processor =
  364. std::make_unique<ForwardingModelTypeProcessor>(this);
  365. std::move(start_callback_).Run(std::move(activation_response));
  366. }
  367. void NigoriModelTypeProcessor::NudgeForCommitIfNeeded() const {
  368. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  369. // Don't bother sending anything if there's no one to send to.
  370. if (!IsConnected()) {
  371. return;
  372. }
  373. // Don't send anything if the type is not ready to handle commits.
  374. if (!model_type_state_.initial_sync_done()) {
  375. return;
  376. }
  377. // Nudge worker if there are any entities with local changes.
  378. if (entity_->RequiresCommitRequest()) {
  379. worker_->NudgeForCommit();
  380. }
  381. }
  382. void NigoriModelTypeProcessor::ClearMetadataAndReset() {
  383. // The bridge is responsible for deleting all data and metadata upon
  384. // disabling sync.
  385. bridge_->ApplyDisableSyncChanges();
  386. entity_.reset();
  387. model_type_state_ = sync_pb::ModelTypeState();
  388. model_type_state_.mutable_progress_marker()->set_data_type_id(
  389. sync_pb::EntitySpecifics::kNigoriFieldNumber);
  390. }
  391. } // namespace syncer