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

Side by Side Diff: components/reading_list/reading_list_store.cc

Issue 2511723002: Enable RL sync by default on iOS (Closed)
Patch Set: rebase Created 4 years 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
OLDNEW
(Empty)
1 // Copyright 2016 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 "components/reading_list/reading_list_store.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/ptr_util.h"
10 #include "components/reading_list/proto/reading_list.pb.h"
11 #include "components/reading_list/reading_list_model_impl.h"
12 #include "components/sync/model/entity_change.h"
13 #include "components/sync/model/metadata_batch.h"
14 #include "components/sync/model/metadata_change_list.h"
15 #include "components/sync/model/model_type_change_processor.h"
16 #include "components/sync/model/mutable_data_batch.h"
17 #include "components/sync/model_impl/accumulating_metadata_change_list.h"
18 #include "components/sync/protocol/model_type_state.pb.h"
19
20 ReadingListStore::ReadingListStore(
21 StoreFactoryFunction create_store_callback,
22 const ChangeProcessorFactory& change_processor_factory)
23 : ModelTypeSyncBridge(change_processor_factory, syncer::READING_LIST),
24 create_store_callback_(create_store_callback),
25 pending_transaction_count_(0) {}
26
27 ReadingListStore::~ReadingListStore() {
28 DCHECK(pending_transaction_count_ == 0);
29 }
30
31 void ReadingListStore::SetReadingListModel(ReadingListModel* model,
32 ReadingListStoreDelegate* delegate) {
33 DCHECK(CalledOnValidThread());
34 model_ = model;
35 delegate_ = delegate;
36 create_store_callback_.Run(
37 base::Bind(&ReadingListStore::OnStoreCreated, base::AsWeakPtr(this)));
38 }
39
40 std::unique_ptr<ReadingListModelStorage::ScopedBatchUpdate>
41 ReadingListStore::EnsureBatchCreated() {
42 return base::WrapUnique<ReadingListModelStorage::ScopedBatchUpdate>(
43 new ScopedBatchUpdate(this));
44 }
45
46 ReadingListStore::ScopedBatchUpdate::ScopedBatchUpdate(ReadingListStore* store)
47 : store_(store) {
48 store_->BeginTransaction();
49 }
50
51 ReadingListStore::ScopedBatchUpdate::~ScopedBatchUpdate() {
52 store_->CommitTransaction();
53 }
54
55 void ReadingListStore::BeginTransaction() {
56 DCHECK(CalledOnValidThread());
57 pending_transaction_count_++;
58 if (pending_transaction_count_ == 1) {
59 batch_ = store_->CreateWriteBatch();
60 }
61 }
62
63 void ReadingListStore::CommitTransaction() {
64 DCHECK(CalledOnValidThread());
65 pending_transaction_count_--;
66 if (pending_transaction_count_ == 0) {
67 store_->CommitWriteBatch(
68 std::move(batch_),
69 base::Bind(&ReadingListStore::OnDatabaseSave, base::AsWeakPtr(this)));
70 batch_.reset();
71 }
72 }
73
74 void ReadingListStore::SaveEntry(const ReadingListEntry& entry, bool read) {
75 DCHECK(CalledOnValidThread());
76 auto token = EnsureBatchCreated();
77
78 std::unique_ptr<reading_list::ReadingListLocal> pb_entry =
79 entry.AsReadingListLocal(read);
80
81 batch_->WriteData(entry.URL().spec(), pb_entry->SerializeAsString());
82
83 if (!change_processor()->IsTrackingMetadata()) {
84 return;
85 }
86 std::unique_ptr<sync_pb::ReadingListSpecifics> pb_entry_sync =
87 entry.AsReadingListSpecifics(read);
88
89 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
90 CreateMetadataChangeList();
91
92 std::unique_ptr<syncer::EntityData> entity_data(new syncer::EntityData());
93 *entity_data->specifics.mutable_reading_list() = *pb_entry_sync;
94 entity_data->non_unique_name = pb_entry_sync->entry_id();
95
96 change_processor()->Put(entry.URL().spec(), std::move(entity_data),
97 metadata_change_list.get());
98 batch_->TransferMetadataChanges(std::move(metadata_change_list));
99 }
100
101 void ReadingListStore::RemoveEntry(const ReadingListEntry& entry) {
102 DCHECK(CalledOnValidThread());
103 auto token = EnsureBatchCreated();
104
105 batch_->DeleteData(entry.URL().spec());
106 if (!change_processor()->IsTrackingMetadata()) {
107 return;
108 }
109 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
110 CreateMetadataChangeList();
111
112 change_processor()->Delete(entry.URL().spec(), metadata_change_list.get());
113 batch_->TransferMetadataChanges(std::move(metadata_change_list));
114 }
115
116 void ReadingListStore::OnDatabaseLoad(
117 syncer::ModelTypeStore::Result result,
118 std::unique_ptr<syncer::ModelTypeStore::RecordList> entries) {
119 DCHECK(CalledOnValidThread());
120 if (result != syncer::ModelTypeStore::Result::SUCCESS) {
121 change_processor()->OnMetadataLoaded(
122 change_processor()->CreateAndUploadError(
123 FROM_HERE, "Cannot load Reading List Database."),
124 nullptr);
125 return;
126 }
127 auto read = base::MakeUnique<ReadingListEntries>();
128 auto unread = base::MakeUnique<ReadingListEntries>();
129
130 for (const syncer::ModelTypeStore::Record& r : *entries.get()) {
131 // for (const reading_list::ReadingListLocal& pb_entry : *entries) {
132 reading_list::ReadingListLocal proto;
133 if (!proto.ParseFromString(r.value)) {
134 continue;
135 // TODO(skym, crbug.com/582460): Handle unrecoverable initialization
136 // failure.
137 }
138
139 std::unique_ptr<ReadingListEntry> entry(
140 ReadingListEntry::FromReadingListLocal(proto));
141 if (!entry) {
142 continue;
143 }
144 if (proto.status() == reading_list::ReadingListLocal::READ) {
145 read->push_back(std::move(*entry));
146 } else {
147 unread->push_back(std::move(*entry));
148 }
149 }
150
151 delegate_->StoreLoaded(std::move(unread), std::move(read));
152
153 store_->ReadAllMetadata(
154 base::Bind(&ReadingListStore::OnReadAllMetadata, base::AsWeakPtr(this)));
155 }
156
157 void ReadingListStore::OnReadAllMetadata(
158 syncer::SyncError sync_error,
159 std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
160 DCHECK(CalledOnValidThread());
161 change_processor()->OnMetadataLoaded(sync_error, std::move(metadata_batch));
162 }
163
164 void ReadingListStore::OnDatabaseSave(syncer::ModelTypeStore::Result result) {
165 return;
166 }
167
168 void ReadingListStore::OnStoreCreated(
169 syncer::ModelTypeStore::Result result,
170 std::unique_ptr<syncer::ModelTypeStore> store) {
171 DCHECK(CalledOnValidThread());
172 if (result != syncer::ModelTypeStore::Result::SUCCESS) {
173 // TODO(crbug.com/664926): handle store creation error.
174 return;
175 }
176 store_ = std::move(store);
177 store_->ReadAllData(
178 base::Bind(&ReadingListStore::OnDatabaseLoad, base::AsWeakPtr(this)));
179 return;
180 }
181
182 syncer::ModelTypeSyncBridge* ReadingListStore::GetModelTypeSyncBridge() {
183 return this;
184 }
185
186 // Creates an object used to communicate changes in the sync metadata to the
187 // model type store.
188 std::unique_ptr<syncer::MetadataChangeList>
189 ReadingListStore::CreateMetadataChangeList() {
190 return syncer::ModelTypeStore::WriteBatch::CreateMetadataChangeList();
191 }
192
193 // Perform the initial merge between local and sync data. This should only be
194 // called when a data type is first enabled to start syncing, and there is no
195 // sync metadata. Best effort should be made to match local and sync data. The
196 // keys in the |entity_data_map| will have been created via GetClientTag(...),
197 // and if a local and sync data should match/merge but disagree on tags, the
198 // service should use the sync data's tag. Any local pieces of data that are
199 // not present in sync should immediately be Put(...) to the processor before
200 // returning. The same MetadataChangeList that was passed into this function
201 // can be passed to Put(...) calls. Delete(...) can also be called but should
202 // not be needed for most model types. Durable storage writes, if not able to
203 // combine all change atomically, should save the metadata after the data
204 // changes, so that this merge will be re-driven by sync if is not completely
205 // saved during the current run.
206 syncer::SyncError ReadingListStore::MergeSyncData(
207 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
208 syncer::EntityDataMap entity_data_map) {
209 DCHECK(CalledOnValidThread());
210 auto token = EnsureBatchCreated();
211 // Keep track of the last update of each item.
212 std::set<std::string> synced_entries;
213 std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate>
214 model_batch_updates = model_->BeginBatchUpdates();
215
216 // Merge sync to local data.
217 for (const auto& kv : entity_data_map) {
218 synced_entries.insert(kv.first);
219 const sync_pb::ReadingListSpecifics& specifics =
220 kv.second.value().specifics.reading_list();
221 // Deserialize entry.
222 bool read = specifics.status() == sync_pb::ReadingListSpecifics::READ;
223 std::unique_ptr<ReadingListEntry> entry(
224 ReadingListEntry::FromReadingListSpecifics(specifics));
225
226 bool was_read;
227 const ReadingListEntry* existing_entry =
228 model_->GetEntryFromURL(entry->URL(), &was_read);
229
230 if (!existing_entry) {
231 // This entry is new. Add it to the store and model.
232 // Convert to local store format and write to store.
233 std::unique_ptr<reading_list::ReadingListLocal> entry_pb =
234 entry->AsReadingListLocal(read);
235 batch_->WriteData(entry->URL().spec(), entry_pb->SerializeAsString());
236
237 // Notify model about updated entry.
238 delegate_->SyncAddEntry(std::move(entry), read);
239 } else if (existing_entry->UpdateTime() < entry->UpdateTime()) {
240 // The entry from sync is more recent.
241 // Merge the local data to it and store it.
242 ReadingListEntry* merged_entry =
243 delegate_->SyncMergeEntry(std::move(entry), read);
244
245 // Write to the store.
246 std::unique_ptr<reading_list::ReadingListLocal> entry_local_pb =
247 merged_entry->AsReadingListLocal(read);
248 batch_->WriteData(entry->URL().spec(),
249 entry_local_pb->SerializeAsString());
250
251 // Send to sync
252 std::unique_ptr<sync_pb::ReadingListSpecifics> entry_sync_pb =
253 merged_entry->AsReadingListSpecifics(read);
254 auto entity_data = base::MakeUnique<syncer::EntityData>();
255 *(entity_data->specifics.mutable_reading_list()) = *entry_sync_pb;
256 entity_data->non_unique_name = entry_sync_pb->entry_id();
257
258 // TODO(crbug.com/666232): Investigate if there is a risk of sync
259 // ping-pong.
260 change_processor()->Put(entry_sync_pb->entry_id(), std::move(entity_data),
261 metadata_change_list.get());
262
263 } else {
264 // The entry from sync is out of date.
265 // Send back the local more recent entry.
266 // No need to update
267 std::unique_ptr<sync_pb::ReadingListSpecifics> entry_pb =
268 existing_entry->AsReadingListSpecifics(was_read);
269 auto entity_data = base::MakeUnique<syncer::EntityData>();
270 *(entity_data->specifics.mutable_reading_list()) = *entry_pb;
271 entity_data->non_unique_name = entry_pb->entry_id();
272
273 change_processor()->Put(entry_pb->entry_id(), std::move(entity_data),
274 metadata_change_list.get());
275 }
276 }
277
278 // Commit local only entries to server.
279 int unread_count = model_->unread_size();
280 int read_count = model_->read_size();
281 for (int index = 0; index < unread_count + read_count; index++) {
282 bool read = index >= unread_count;
283 const ReadingListEntry& entry =
284 read ? model_->GetReadEntryAtIndex(index - unread_count)
285 : model_->GetUnreadEntryAtIndex(index);
286 if (synced_entries.count(entry.URL().spec())) {
287 // Entry already exists and has been merged above.
288 continue;
289 }
290
291 // Local entry has later timestamp. It should be committed to server.
292 std::unique_ptr<sync_pb::ReadingListSpecifics> entry_pb =
293 entry.AsReadingListSpecifics(read);
294
295 auto entity_data = base::MakeUnique<syncer::EntityData>();
296 *(entity_data->specifics.mutable_reading_list()) = *entry_pb;
297 entity_data->non_unique_name = entry_pb->entry_id();
298
299 change_processor()->Put(entry_pb->entry_id(), std::move(entity_data),
300 metadata_change_list.get());
301 }
302 batch_->TransferMetadataChanges(std::move(metadata_change_list));
303
304 return syncer::SyncError();
305 }
306
307 // Apply changes from the sync server locally.
308 // Please note that |entity_changes| might have fewer entries than
309 // |metadata_change_list| in case when some of the data changes are filtered
310 // out, or even be empty in case when a commit confirmation is processed and
311 // only the metadata needs to persisted.
312 syncer::SyncError ReadingListStore::ApplySyncChanges(
313 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
314 syncer::EntityChangeList entity_changes) {
315 DCHECK(CalledOnValidThread());
316 std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate> batch =
317 model_->BeginBatchUpdates();
318 auto token = EnsureBatchCreated();
319
320 for (syncer::EntityChange& change : entity_changes) {
321 if (change.type() == syncer::EntityChange::ACTION_DELETE) {
322 batch_->DeleteData(change.storage_key());
323 // Need to notify model that entry is deleted.
324 delegate_->SyncRemoveEntry(GURL(change.storage_key()));
325 } else {
326 // Deserialize entry.
327 const sync_pb::ReadingListSpecifics& specifics =
328 change.data().specifics.reading_list();
329 bool read = specifics.status() == sync_pb::ReadingListSpecifics::READ;
330 std::unique_ptr<ReadingListEntry> entry(
331 ReadingListEntry::FromReadingListSpecifics(specifics));
332
333 bool was_read;
334 const ReadingListEntry* existing_entry =
335 model_->GetEntryFromURL(entry->URL(), &was_read);
336
337 if (!existing_entry) {
338 // This entry is new. Add it to the store and model.
339 // Convert to local store format and write to store.
340 std::unique_ptr<reading_list::ReadingListLocal> entry_pb =
341 entry->AsReadingListLocal(read);
342 batch_->WriteData(entry->URL().spec(), entry_pb->SerializeAsString());
343
344 // Notify model about updated entry.
345 delegate_->SyncAddEntry(std::move(entry), read);
346 } else if (existing_entry->UpdateTime() < entry->UpdateTime()) {
347 // The entry from sync is more recent.
348 // Merge the local data to it and store it.
349 ReadingListEntry* merged_entry =
350 delegate_->SyncMergeEntry(std::move(entry), read);
351
352 // Write to the store.
353 std::unique_ptr<reading_list::ReadingListLocal> entry_local_pb =
354 merged_entry->AsReadingListLocal(read);
355 batch_->WriteData(merged_entry->URL().spec(),
356 entry_local_pb->SerializeAsString());
357
358 // Send to sync
359 std::unique_ptr<sync_pb::ReadingListSpecifics> entry_sync_pb =
360 merged_entry->AsReadingListSpecifics(read);
361 auto entity_data = base::MakeUnique<syncer::EntityData>();
362 *(entity_data->specifics.mutable_reading_list()) = *entry_sync_pb;
363 entity_data->non_unique_name = entry_sync_pb->entry_id();
364
365 // TODO(crbug.com/666232): Investigate if there is a risk of sync
366 // ping-pong.
367 change_processor()->Put(entry_sync_pb->entry_id(),
368 std::move(entity_data),
369 metadata_change_list.get());
370
371 } else {
372 // The entry from sync is out of date.
373 // Send back the local more recent entry.
374 // No need to update
375 std::unique_ptr<sync_pb::ReadingListSpecifics> entry_pb =
376 existing_entry->AsReadingListSpecifics(was_read);
377 auto entity_data = base::MakeUnique<syncer::EntityData>();
378 *(entity_data->specifics.mutable_reading_list()) = *entry_pb;
379 entity_data->non_unique_name = entry_pb->entry_id();
380
381 change_processor()->Put(entry_pb->entry_id(), std::move(entity_data),
382 metadata_change_list.get());
383 }
384 }
385 }
386
387 batch_->TransferMetadataChanges(std::move(metadata_change_list));
388 return syncer::SyncError();
389 }
390
391 void ReadingListStore::GetData(StorageKeyList storage_keys,
392 DataCallback callback) {
393 DCHECK(CalledOnValidThread());
394 auto batch = base::MakeUnique<syncer::MutableDataBatch>();
395 for (std::string url_string : storage_keys) {
396 bool read;
397 const ReadingListEntry* entry =
398 model_->GetEntryFromURL(GURL(url_string), &read);
399 if (entry) {
400 AddEntryToBatch(batch.get(), *entry, read);
401 }
402 }
403
404 callback.Run(syncer::SyncError(), std::move(batch));
405 }
406
407 void ReadingListStore::GetAllData(DataCallback callback) {
408 DCHECK(CalledOnValidThread());
409 auto batch = base::MakeUnique<syncer::MutableDataBatch>();
410 int unread_count = model_->unread_size();
411 int read_count = model_->read_size();
412 for (int index = 0; index < unread_count + read_count; index++) {
413 bool read = index >= unread_count;
414 const ReadingListEntry& entry =
415 read ? model_->GetReadEntryAtIndex(index - unread_count)
416 : model_->GetUnreadEntryAtIndex(index);
417 AddEntryToBatch(batch.get(), entry, read);
418 }
419
420 callback.Run(syncer::SyncError(), std::move(batch));
421 }
422
423 void ReadingListStore::AddEntryToBatch(syncer::MutableDataBatch* batch,
424 const ReadingListEntry& entry,
425 bool read) {
426 DCHECK(CalledOnValidThread());
427 std::unique_ptr<sync_pb::ReadingListSpecifics> entry_pb =
428 entry.AsReadingListSpecifics(read);
429
430 std::unique_ptr<syncer::EntityData> entity_data(new syncer::EntityData());
431 *(entity_data->specifics.mutable_reading_list()) = *entry_pb;
432 entity_data->non_unique_name = entry_pb->entry_id();
433
434 batch->Put(entry_pb->entry_id(), std::move(entity_data));
435 }
436
437 // Get or generate a client tag for |entity_data|. This must be the same tag
438 // that was/would have been generated in the SyncableService/Directory world
439 // for backward compatibility with pre-USS clients. The only time this
440 // theoretically needs to be called is on the creation of local data, however
441 // it is also used to verify the hash of remote data. If a data type was never
442 // launched pre-USS, then method does not need to be different from
443 // GetStorageKey().
444 std::string ReadingListStore::GetClientTag(
445 const syncer::EntityData& entity_data) {
446 DCHECK(CalledOnValidThread());
447 return GetStorageKey(entity_data);
448 }
449
450 // Get or generate a storage key for |entity_data|. This will only ever be
451 // called once when first encountering a remote entity. Local changes will
452 // provide their storage keys directly to Put instead of using this method.
453 // Theoretically this function doesn't need to be stable across multiple calls
454 // on the same or different clients, but to keep things simple, it probably
455 // should be.
456 std::string ReadingListStore::GetStorageKey(
457 const syncer::EntityData& entity_data) {
458 DCHECK(CalledOnValidThread());
459 return entity_data.specifics.reading_list().entry_id();
460 }
OLDNEW
« no previous file with comments | « components/reading_list/reading_list_store.h ('k') | components/reading_list/reading_list_store_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698