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

Side by Side Diff: ios/chrome/browser/reading_list/reading_list_store.cc

Issue 2398233003: with sync (Closed)
Patch Set: done Created 4 years, 2 months 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ios/chrome/browser/reading_list/reading_list_store.h" 5 #include "ios/chrome/browser/reading_list/reading_list_store.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/files/file_path.h" 8 #include "base/files/file_path.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
11 #include "components/sync/api/entity_change.h"
12 #include "components/sync/api/metadata_change_list.h"
13 #include "components/sync/api/metadata_batch.h"
14 #include "components/sync/core/simple_metadata_change_list.h"
15 #include "components/sync/core/shared_model_type_processor.h"
16 #include "components/sync/protocol/model_type_state.pb.h"
11 #include "ios/chrome/browser/reading_list/proto/reading_list.pb.h" 17 #include "ios/chrome/browser/reading_list/proto/reading_list.pb.h"
12 #include "ios/chrome/browser/reading_list/reading_list_model_impl.h" 18 #include "ios/chrome/browser/reading_list/reading_list_model_impl.h"
13 #include "ios/web/public/web_thread.h" 19 #include "ios/web/public/web_thread.h"
14 20
15 ReadingListStore::ReadingListStore(std::unique_ptr<ReadingListDB> database, 21 ReadingListStore::ReadingListStore(std::unique_ptr<ReadingListDB> database,
16 const base::FilePath& database_dir) 22 const base::FilePath& database_dir,
17 : database_(std::move(database)), 23 StoreFactoryFunction create_store_callback)
24 : ModelTypeService(
25 base::Bind(
26 &syncer::SharedModelTypeProcessor::CreateAsChangeProcessor),
27 syncer::READING_LIST),
18 database_loaded_(false), 28 database_loaded_(false),
19 pending_transaction_(0), 29 create_store_callback_(create_store_callback),
20 weak_ptr_factory_(this) { 30 pending_transaction_(0) {}
21 database_->Init("ReadingList", database_dir,
22 base::Bind(&ReadingListStore::OnDatabaseInit,
23 weak_ptr_factory_.GetWeakPtr()));
24 }
25 31
26 ReadingListStore::~ReadingListStore() { 32 ReadingListStore::~ReadingListStore() {
27 DCHECK(pending_transaction_ == 0); 33 DCHECK(pending_transaction_ == 0);
28 } 34 }
29 35
30 void ReadingListStore::OnDatabaseInit(bool success) {
31 DCHECK_CURRENTLY_ON(web::WebThread::UI);
32 if (!success) {
33 database_.reset();
34 }
35 }
36
37 void ReadingListStore::SetReadingListModel(ReadingListModelImpl* model) { 36 void ReadingListStore::SetReadingListModel(ReadingListModelImpl* model) {
38 DCHECK_CURRENTLY_ON(web::WebThread::UI); 37 DCHECK_CURRENTLY_ON(web::WebThread::UI);
39 model_ = model; 38 model_ = model;
39 create_store_callback_.Run(
40 base::Bind(&ReadingListStore::OnStoreCreated, base::AsWeakPtr(this)));
40 } 41 }
41 42
42 void ReadingListStore::LoadPersistentLists() { 43 void ReadingListStore::LoadPersistentLists() {
43 DCHECK_CURRENTLY_ON(web::WebThread::UI); 44 DCHECK_CURRENTLY_ON(web::WebThread::UI);
44 DCHECK(model_); 45 DCHECK(model_);
45 database_->LoadEntries(base::Bind(&ReadingListStore::OnDatabaseLoad, 46 // database_->LoadEntries(
46 weak_ptr_factory_.GetWeakPtr())); 47 // base::Bind(&ReadingListStore::OnDatabaseLoad, base::AsWeakPtr(this)));
47 } 48 }
48 49
49 void ReadingListStore::BeginTransaction() { 50 void ReadingListStore::BeginTransaction() {
50 DCHECK_CURRENTLY_ON(web::WebThread::UI); 51 DCHECK_CURRENTLY_ON(web::WebThread::UI);
51 pending_transaction_++; 52 pending_transaction_++;
52 if (pending_transaction_ == 1) { 53 if (pending_transaction_ == 1) {
53 pending_keys_to_save_ = base::MakeUnique<ReadingListDB::KeyEntryVector>(); 54 pending_keys_to_save_ = base::MakeUnique<ReadingListDB::KeyEntryVector>();
54 pending_keys_to_remove_ = base::MakeUnique<std::vector<std::string>>(); 55 pending_keys_to_remove_ = base::MakeUnique<std::vector<std::string>>();
55 } 56 }
56 } 57 }
57 58
58 void ReadingListStore::CommitTransaction() { 59 void ReadingListStore::CommitTransaction() {
59 DCHECK_CURRENTLY_ON(web::WebThread::UI); 60 DCHECK_CURRENTLY_ON(web::WebThread::UI);
60 pending_transaction_--; 61 pending_transaction_--;
61 if (pending_transaction_ == 0) { 62 if (pending_transaction_ == 0) {
62 database_->UpdateEntries(std::move(pending_keys_to_save_), 63 // database_->UpdateEntries(
63 std::move(pending_keys_to_remove_), 64 // std::move(pending_keys_to_save_),
64 base::Bind(&ReadingListStore::OnDatabaseSave, 65 // std::move(pending_keys_to_remove_),
65 weak_ptr_factory_.GetWeakPtr())); 66 // base::Bind(&ReadingListStore::OnDatabaseSave,
67 // base::AsWeakPtr(this)));
66 pending_keys_to_save_ = nullptr; 68 pending_keys_to_save_ = nullptr;
67 pending_keys_to_remove_ = nullptr; 69 pending_keys_to_remove_ = nullptr;
68 } 70 }
69 } 71 }
70 72
71 void ReadingListStore::SaveEntry(const ReadingListEntry& entry, bool read) { 73 void ReadingListStore::SaveEntry(const ReadingListEntry& entry, bool read) {
72 DCHECK_CURRENTLY_ON(web::WebThread::UI); 74 DCHECK_CURRENTLY_ON(web::WebThread::UI);
73 BeginTransaction(); 75 // BeginTransaction();
74 76 //
75 std::unique_ptr<reading_list::ReadingListLocal> pb_entry = 77 std::unique_ptr<reading_list::ReadingListLocal> pb_entry =
76 entry.AsReadingListLocal(read); 78 entry.AsReadingListLocal(read);
77 // Unref the URL before making asynchronous call. 79 // Unref the URL before making asynchronous call.
78 std::string local_key = entry.URL().spec(); 80 std::string local_key = entry.URL().spec();
79 pending_keys_to_save_->push_back(std::make_pair(local_key, *pb_entry));
80 81
81 CommitTransaction(); 82 std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch =
83 store_->CreateWriteBatch();
84 store_->WriteData(batch.get(), local_key, pb_entry->SerializeAsString());
85
86 if (!change_processor()) {
87 store_->CommitWriteBatch(
88 std::move(batch),
89 base::Bind(&ReadingListStore::OnDatabaseSave, base::AsWeakPtr(this)));
90 return;
91 }
92
93 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
94 CreateMetadataChangeList();
95
96 std::unique_ptr<syncer::EntityData> entity_data(new syncer::EntityData());
97 *entity_data->specifics.mutable_reading_list() = pb_entry->entry();
98 entity_data->non_unique_name = pb_entry->entry().url();
99
100 if (read) {
101 change_processor()->Delete(pb_entry->entry().url(),
102 metadata_change_list.get());
103 } else {
104 change_processor()->Put(pb_entry->entry().url(), std::move(entity_data),
105 metadata_change_list.get());
106 }
107
108 static_cast<syncer::SimpleMetadataChangeList*>(metadata_change_list.get())
109 ->TransferChanges(store_.get(), batch.get());
110 store_->CommitWriteBatch(
111 std::move(batch),
112 base::Bind(&ReadingListStore::OnDatabaseSave, base::AsWeakPtr(this)));
82 } 113 }
83 114
84 void ReadingListStore::RemoveEntry(const ReadingListEntry& entry) { 115 void ReadingListStore::RemoveEntry(const ReadingListEntry& entry) {
85 DCHECK_CURRENTLY_ON(web::WebThread::UI); 116 DCHECK_CURRENTLY_ON(web::WebThread::UI);
86 BeginTransaction(); 117 std::string local_key = entry.URL().spec();
87 pending_keys_to_remove_->push_back(entry.URL().spec()); 118 std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch =
88 CommitTransaction(); 119 store_->CreateWriteBatch();
120 store_->DeleteData(batch.get(), local_key);
121 store_->CommitWriteBatch(
122 std::move(batch),
123 base::Bind(&ReadingListStore::OnDatabaseSave, base::AsWeakPtr(this)));
89 } 124 }
90 125
91 void ReadingListStore::OnDatabaseLoad(bool success, 126 void ReadingListStore::OnDatabaseLoad(
92 std::unique_ptr<EntryVector> entries) { 127 syncer::ModelTypeStore::Result result,
128 std::unique_ptr<syncer::ModelTypeStore::RecordList> entries) {
93 DCHECK_CURRENTLY_ON(web::WebThread::UI); 129 DCHECK_CURRENTLY_ON(web::WebThread::UI);
94 if (!success) { 130 if (result != syncer::ModelTypeStore::Result::SUCCESS) {
95 database_.reset();
96 return; 131 return;
97 } 132 }
98 database_loaded_ = true; 133 database_loaded_ = true;
99 auto read = base::MakeUnique<ReadingListEntries>(); 134 auto read = base::MakeUnique<ReadingListEntries>();
100 auto unread = base::MakeUnique<ReadingListEntries>(); 135 auto unread = base::MakeUnique<ReadingListEntries>();
101 136
102 for (const reading_list::ReadingListLocal& pb_entry : *entries) { 137 for (const syncer::ModelTypeStore::Record& r : *entries.get()) {
138 // for (const reading_list::ReadingListLocal& pb_entry : *entries) {
139 std::unique_ptr<reading_list::ReadingListLocal> proto =
140 base::MakeUnique<reading_list::ReadingListLocal>();
141 if (!proto->ParseFromString(r.value)) {
142 continue;
143 // TODO(skym, crbug.com/582460): Handle unrecoverable initialization
144 // failure.
145 }
146
103 std::unique_ptr<ReadingListEntry> entry( 147 std::unique_ptr<ReadingListEntry> entry(
104 ReadingListEntry::FromReadingListLocal(pb_entry)); 148 ReadingListEntry::FromReadingListLocal(*proto));
105 if (!entry) { 149 if (!entry) {
106 continue; 150 continue;
107 } 151 }
108 if (pb_entry.entry().status() == sync_pb::ReadingListSpecifics::READ) { 152 if (proto->entry().status() == sync_pb::ReadingListSpecifics::READ) {
109 read->push_back(std::move(*entry)); 153 read->push_back(std::move(*entry));
110 } else { 154 } else {
111 unread->push_back(std::move(*entry)); 155 unread->push_back(std::move(*entry));
112 } 156 }
113 } 157 }
114 std::sort(read->begin(), read->end(), 158 std::sort(read->begin(), read->end(),
115 ReadingListEntry::CompareEntryUpdateTime); 159 ReadingListEntry::CompareEntryUpdateTime);
116 std::sort(unread->begin(), unread->end(), 160 std::sort(unread->begin(), unread->end(),
117 ReadingListEntry::CompareEntryUpdateTime); 161 ReadingListEntry::CompareEntryUpdateTime);
118 162
119 model_->ModelLoaded(std::move(unread), std::move(read)); 163 model_->ModelLoaded(std::move(unread), std::move(read));
120 } 164
121 165 store_->ReadAllMetadata(
122 void ReadingListStore::OnDatabaseSave(bool success) { 166 base::Bind(&ReadingListStore::OnReadAllMetadata, base::AsWeakPtr(this)));
123 DCHECK_CURRENTLY_ON(web::WebThread::UI); 167 }
124 if (!success) { 168
125 database_.reset(); 169 void ReadingListStore::OnReadAllMetadata(
126 database_loaded_ = false; 170 syncer::ModelTypeStore::Result result,
127 } 171 std::unique_ptr<syncer::ModelTypeStore::RecordList> metadata_records,
128 } 172 const std::string& global_metadata) {
173 if (result != syncer::ModelTypeStore::Result::SUCCESS) {
174 // Store has encountered some serious error. We should still be able to
175 // continue as a read only service, since if we got this far we must have
176 // loaded all data out succesfully.
177 return;
178 }
179
180 // If we have no metadata then we don't want to create a processor. The idea
181 // is that by not having a processor, the services will suffer less of a
182 // performance hit. This isn't terribly applicable for this model type, but
183 // we want this class to be as similar to other services as possible so follow
184 // the convention.
185 if (metadata_records->size() > 0 || !global_metadata.empty()) {
186 CreateChangeProcessor();
187 }
188
189 // Set this after OnChangeProcessorSet so that we can correctly avoid giving
190 // the processor empty metadata. We always want to set |has_metadata_loaded_|
191 // at this point so that we'll know to give a processor empty metadata if it
192 // is created later.
193 has_metadata_loaded_ = true;
194
195 if (!change_processor()) {
196 // This means we haven't been told to start syncing and we don't have any
197 // local metadata.
198 return;
199 }
200
201 std::unique_ptr<syncer::MetadataBatch> batch(new syncer::MetadataBatch());
202 sync_pb::ModelTypeState state;
203 if (state.ParseFromString(global_metadata)) {
204 batch->SetModelTypeState(state);
205 } else {
206 // TODO(skym): How bad is this scenario? We may be able to just give an
207 // empty batch to the processor and we'll treat corrupted data type state
208 // as no data type state at all. The question is do we want to add any of
209 // the entity metadata to the batch or completely skip that step? We're
210 // going to have to perform a merge shortly. Does this decision/logic even
211 // belong in this service?
212 change_processor()->OnMetadataLoaded(
213 change_processor()->CreateAndUploadError(
214 FROM_HERE, "Failed to deserialize global metadata."),
215 nullptr);
216 }
217 for (const syncer::ModelTypeStore::Record& r : *metadata_records.get()) {
218 sync_pb::EntityMetadata entity_metadata;
219 if (entity_metadata.ParseFromString(r.value)) {
220 batch->AddMetadata(r.id, entity_metadata);
221 } else {
222 // TODO(skym): This really isn't too bad. We just want to regenerate
223 // metadata for this particular entity. Unfortunately there isn't a
224 // convenient way to tell the processor to do this.
225 LOG(WARNING) << "Failed to deserialize entity metadata.";
226 }
227 }
228 change_processor()->OnMetadataLoaded(syncer::SyncError(), std::move(batch));
229 }
230
231 void ReadingListStore::OnDatabaseSave(syncer::ModelTypeStore::Result result) {
232 return;
233 }
234
235 void ReadingListStore::OnStoreCreated(
236 syncer::ModelTypeStore::Result result,
237 std::unique_ptr<syncer::ModelTypeStore> store) {
238 store_ = std::move(store);
239 store_->ReadAllData(
240 base::Bind(&ReadingListStore::OnDatabaseLoad, base::AsWeakPtr(this)));
241 return;
242 }
243
244 syncer::ModelTypeService* ReadingListStore::GetModelTypeService() {
245 return this;
246 }
247
248 // Creates an object used to communicate changes in the sync metadata to the
249 // model type store.
250 std::unique_ptr<syncer::MetadataChangeList>
251 ReadingListStore::CreateMetadataChangeList() {
252 return base::MakeUnique<syncer::SimpleMetadataChangeList>();
253 }
254
255 // Perform the initial merge between local and sync data. This should only be
256 // called when a data type is first enabled to start syncing, and there is no
257 // sync metadata. Best effort should be made to match local and sync data. The
258 // keys in the |entity_data_map| will have been created via GetClientTag(...),
259 // and if a local and sync data should match/merge but disagree on tags, the
260 // service should use the sync data's tag. Any local pieces of data that are
261 // not present in sync should immediately be Put(...) to the processor before
262 // returning. The same MetadataChangeList that was passed into this function
263 // can be passed to Put(...) calls. Delete(...) can also be called but should
264 // not be needed for most model types. Durable storage writes, if not able to
265 // combine all change atomically, should save the metadata after the data
266 // changes, so that this merge will be re-driven by sync if is not completely
267 // saved during the current run.
268 syncer::SyncError ReadingListStore::MergeSyncData(
269 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
270 syncer::EntityDataMap entity_data_map) {
271 // std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch =
272 // store_->CreateWriteBatch();
273 for (const auto& kv : entity_data_map) {
274 const sync_pb::ReadingListSpecifics& specifics =
275 kv.second.value().specifics.reading_list();
276
277 if (!model_->CallbackEntryURL(
278 GURL(specifics.url()),
279 base::Bind(&ReadingListStore::NoopEntry, base::AsWeakPtr(this)))) {
280 model_->AddEntry(GURL(specifics.url()), specifics.title());
281 }
282
283 // std::unique_ptr<reading_list::ReadingListLocal> proto =
284 // base::MakeUnique<reading_list::ReadingListLocal>();
285 //
286 // proto->set_allocated_entry(new
287 // sync_pb::ReadingListSpecifics(specifics));
288 //
289 // // Unref the URL before making asynchronous call.
290 // std::string local_key = specifics.url();
291 //
292 //
293 // store_->WriteData(batch.get(), local_key, proto->SerializeAsString());
294 }
295
296 // store_->CommitWriteBatch(
297 // std::move(batch),
298 // base::Bind(&ReadingListStore::OnDatabaseSave,
299 // base::AsWeakPtr(this)));
300 return syncer::SyncError();
301 }
302
303 // Apply changes from the sync server locally.
304 // Please note that |entity_changes| might have fewer entries than
305 // |metadata_change_list| in case when some of the data changes are filtered
306 // out, or even be empty in case when a commit confirmation is processed and
307 // only the metadata needs to persisted.
308 syncer::SyncError ReadingListStore::ApplySyncChanges(
309 std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
310 syncer::EntityChangeList entity_changes) {
311 // std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch =
312 // store_->CreateWriteBatch();
313 for (syncer::EntityChange& change : entity_changes) {
314 if (change.type() == syncer::EntityChange::ACTION_DELETE) {
315 // if (model_->CallbackEntryURL(GURL(change.storage_key()),
316 // base::Bind(&ReadingListStore::NoopEnt ry,
317 // base::AsWeakPtr(this)))) {
318 // model_->RemoveEntryByUrl(GURL(specifics.url()));
319 // }
320 continue;
321 } else {
322 const sync_pb::ReadingListSpecifics& specifics =
323 change.data().specifics.reading_list();
324
325 if (!model_->CallbackEntryURL(GURL(specifics.url()),
326 base::Bind(&ReadingListStore::NoopEntry,
327 base::AsWeakPtr(this)))) {
328 model_->AddEntry(GURL(specifics.url()), specifics.title());
329 }
330
331 // proto->set_allocated_entry(new
332 // sync_pb::ReadingListSpecifics(specifics));
333 //
334 // // Unref the URL before making asynchronous call.
335 // std::string local_key = specifics.url();
336 //
337 //
338 // store_->WriteData(batch.get(), local_key,
339 // proto->SerializeAsString());
340 }
341 }
342 // store_->CommitWriteBatch(
343 // std::move(batch),
344 // base::Bind(&ReadingListStore::OnDatabaseSave,
345 // base::AsWeakPtr(this)));
346
347 return syncer::SyncError();
348 }
349
350 void ReadingListStore::NoopEntry(const ReadingListEntry&) {}
351
352 // Asynchronously retrieve the corresponding sync data for |storage_keys|.
353 void ReadingListStore::GetData(StorageKeyList storage_keys,
354 DataCallback callback) {
355 return;
356 }
357
358 // Asynchronously retrieve all of the local sync data.
359 void ReadingListStore::GetAllData(DataCallback callback) {}
360
361 // Get or generate a client tag for |entity_data|. This must be the same tag
362 // that was/would have been generated in the SyncableService/Directory world
363 // for backward compatibility with pre-USS clients. The only time this
364 // theoretically needs to be called is on the creation of local data, however
365 // it is also used to verify the hash of remote data. If a data type was never
366 // launched pre-USS, then method does not need to be different from
367 // GetStorageKey().
368 std::string ReadingListStore::GetClientTag(
369 const syncer::EntityData& entity_data) {
370 return entity_data.specifics.reading_list().url();
371 }
372
373 // Get or generate a storage key for |entity_data|. This will only ever be
374 // called once when first encountering a remote entity. Local changes will
375 // provide their storage keys directly to Put instead of using this method.
376 // Theoretically this function doesn't need to be stable across multiple calls
377 // on the same or different clients, but to keep things simple, it probably
378 // should be.
379 std::string ReadingListStore::GetStorageKey(
380 const syncer::EntityData& entity_data) {
381 return entity_data.specifics.reading_list().url();
382 }
383
384 // Overridable notification for when the processor is set. This is typically
385 // when the service should start loading metadata and then subsequently giving
386 // it to the processor.
387 void ReadingListStore::OnChangeProcessorSet() {
388 if (has_metadata_loaded_) {
389 change_processor()->OnMetadataLoaded(
390 syncer::SyncError(), base::MakeUnique<syncer::MetadataBatch>());
391 }
392 }
OLDNEW
« no previous file with comments | « ios/chrome/browser/reading_list/reading_list_store.h ('k') | ios/chrome/browser/sync/ios_chrome_sync_client.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698