1 // Copyright 2015 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/sync/model_impl/model_type_store_impl.h"
6 
7 #include <map>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/check_op.h"
13 #include "base/location.h"
14 #include "base/optional.h"
15 #include "base/task_runner_util.h"
16 #include "components/sync/model/model_error.h"
17 #include "components/sync/model_impl/blocking_model_type_store_impl.h"
18 
19 namespace syncer {
20 
21 namespace {
22 
ReadAllDataAndPreprocessOnBackendSequence(BlockingModelTypeStoreImpl * blocking_store,ModelTypeStore::PreprocessCallback preprocess_on_backend_sequence_callback)23 base::Optional<ModelError> ReadAllDataAndPreprocessOnBackendSequence(
24     BlockingModelTypeStoreImpl* blocking_store,
25     ModelTypeStore::PreprocessCallback
26         preprocess_on_backend_sequence_callback) {
27   DCHECK(blocking_store);
28 
29   auto record_list = std::make_unique<ModelTypeStoreBase::RecordList>();
30   base::Optional<ModelError> error =
31       blocking_store->ReadAllData(record_list.get());
32   if (error) {
33     return error;
34   }
35 
36   return std::move(preprocess_on_backend_sequence_callback)
37       .Run(std::move(record_list));
38 }
39 
40 }  // namespace
41 
ModelTypeStoreImpl(ModelType type,std::unique_ptr<BlockingModelTypeStoreImpl,base::OnTaskRunnerDeleter> backend_store,scoped_refptr<base::SequencedTaskRunner> backend_task_runner)42 ModelTypeStoreImpl::ModelTypeStoreImpl(
43     ModelType type,
44     std::unique_ptr<BlockingModelTypeStoreImpl, base::OnTaskRunnerDeleter>
45         backend_store,
46     scoped_refptr<base::SequencedTaskRunner> backend_task_runner)
47     : type_(type),
48       backend_task_runner_(std::move(backend_task_runner)),
49       backend_store_(std::move(backend_store)) {
50   DCHECK(backend_store_);
51   DCHECK(backend_task_runner_);
52 }
53 
~ModelTypeStoreImpl()54 ModelTypeStoreImpl::~ModelTypeStoreImpl() {
55   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
56 }
57 
58 // Note on pattern for communicating with backend:
59 //  - API function (e.g. ReadData) allocates lists for output.
60 //  - API function prepares two callbacks: task that will be posted on backend
61 //    thread and reply which will be posted on model type thread once task
62 //    finishes.
63 //  - Task for backend thread takes raw pointers to output lists while reply
64 //    takes ownership of those lists. This allows backend interface to be simple
65 //    while ensuring proper objects' lifetime.
66 //  - Function bound by reply calls consumer's callback and passes ownership of
67 //    output lists to it.
68 
ReadData(const IdList & id_list,ReadDataCallback callback)69 void ModelTypeStoreImpl::ReadData(const IdList& id_list,
70                                   ReadDataCallback callback) {
71   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
72   DCHECK(!callback.is_null());
73   std::unique_ptr<RecordList> record_list(new RecordList());
74   std::unique_ptr<IdList> missing_id_list(new IdList());
75 
76   auto task = base::BindOnce(&BlockingModelTypeStore::ReadData,
77                              base::Unretained(backend_store_.get()), id_list,
78                              base::Unretained(record_list.get()),
79                              base::Unretained(missing_id_list.get()));
80   auto reply = base::BindOnce(
81       &ModelTypeStoreImpl::ReadDataDone, weak_ptr_factory_.GetWeakPtr(),
82       std::move(callback), std::move(record_list), std::move(missing_id_list));
83   base::PostTaskAndReplyWithResult(backend_task_runner_.get(), FROM_HERE,
84                                    std::move(task), std::move(reply));
85 }
86 
ReadDataDone(ReadDataCallback callback,std::unique_ptr<RecordList> record_list,std::unique_ptr<IdList> missing_id_list,const base::Optional<ModelError> & error)87 void ModelTypeStoreImpl::ReadDataDone(ReadDataCallback callback,
88                                       std::unique_ptr<RecordList> record_list,
89                                       std::unique_ptr<IdList> missing_id_list,
90                                       const base::Optional<ModelError>& error) {
91   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
92   std::move(callback).Run(error, std::move(record_list),
93                           std::move(missing_id_list));
94 }
95 
ReadAllData(ReadAllDataCallback callback)96 void ModelTypeStoreImpl::ReadAllData(ReadAllDataCallback callback) {
97   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
98   DCHECK(!callback.is_null());
99   std::unique_ptr<RecordList> record_list(new RecordList());
100   auto task = base::BindOnce(&BlockingModelTypeStore::ReadAllData,
101                              base::Unretained(backend_store_.get()),
102                              base::Unretained(record_list.get()));
103   auto reply = base::BindOnce(&ModelTypeStoreImpl::ReadAllDataDone,
104                               weak_ptr_factory_.GetWeakPtr(),
105                               std::move(callback), std::move(record_list));
106   base::PostTaskAndReplyWithResult(backend_task_runner_.get(), FROM_HERE,
107                                    std::move(task), std::move(reply));
108 }
109 
ReadAllDataDone(ReadAllDataCallback callback,std::unique_ptr<RecordList> record_list,const base::Optional<ModelError> & error)110 void ModelTypeStoreImpl::ReadAllDataDone(
111     ReadAllDataCallback callback,
112     std::unique_ptr<RecordList> record_list,
113     const base::Optional<ModelError>& error) {
114   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
115   std::move(callback).Run(error, std::move(record_list));
116 }
117 
ReadAllMetadata(ReadMetadataCallback callback)118 void ModelTypeStoreImpl::ReadAllMetadata(ReadMetadataCallback callback) {
119   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
120   DCHECK(!callback.is_null());
121 
122   auto metadata_batch = std::make_unique<MetadataBatch>();
123   auto task = base::BindOnce(&BlockingModelTypeStore::ReadAllMetadata,
124                              base::Unretained(backend_store_.get()),
125                              base::Unretained(metadata_batch.get()));
126   auto reply = base::BindOnce(&ModelTypeStoreImpl::ReadAllMetadataDone,
127                               weak_ptr_factory_.GetWeakPtr(),
128                               std::move(callback), std::move(metadata_batch));
129   base::PostTaskAndReplyWithResult(backend_task_runner_.get(), FROM_HERE,
130                                    std::move(task), std::move(reply));
131 }
132 
ReadAllMetadataDone(ReadMetadataCallback callback,std::unique_ptr<MetadataBatch> metadata_batch,const base::Optional<ModelError> & error)133 void ModelTypeStoreImpl::ReadAllMetadataDone(
134     ReadMetadataCallback callback,
135     std::unique_ptr<MetadataBatch> metadata_batch,
136     const base::Optional<ModelError>& error) {
137   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
138 
139   if (error) {
140     std::move(callback).Run(*error, std::make_unique<MetadataBatch>());
141     return;
142   }
143 
144   std::move(callback).Run({}, std::move(metadata_batch));
145 }
146 
ReadAllDataAndPreprocess(PreprocessCallback preprocess_on_backend_sequence_callback,CallbackWithResult completion_on_frontend_sequence_callback)147 void ModelTypeStoreImpl::ReadAllDataAndPreprocess(
148     PreprocessCallback preprocess_on_backend_sequence_callback,
149     CallbackWithResult completion_on_frontend_sequence_callback) {
150   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
151   DCHECK(!preprocess_on_backend_sequence_callback.is_null());
152   DCHECK(!completion_on_frontend_sequence_callback.is_null());
153   auto task =
154       base::BindOnce(&ReadAllDataAndPreprocessOnBackendSequence,
155                      base::Unretained(backend_store_.get()),
156                      std::move(preprocess_on_backend_sequence_callback));
157   // ReadAllDataAndPreprocessDone() is only needed to guarantee that callbacks
158   // get cancelled if |this| gets destroyed.
159   auto reply =
160       base::BindOnce(&ModelTypeStoreImpl::ReadAllDataAndPreprocessDone,
161                      weak_ptr_factory_.GetWeakPtr(),
162                      std::move(completion_on_frontend_sequence_callback));
163   base::PostTaskAndReplyWithResult(backend_task_runner_.get(), FROM_HERE,
164                                    std::move(task), std::move(reply));
165 }
166 
ReadAllDataAndPreprocessDone(CallbackWithResult callback,const base::Optional<ModelError> & error)167 void ModelTypeStoreImpl::ReadAllDataAndPreprocessDone(
168     CallbackWithResult callback,
169     const base::Optional<ModelError>& error) {
170   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
171   std::move(callback).Run(error);
172 }
173 
DeleteAllDataAndMetadata(CallbackWithResult callback)174 void ModelTypeStoreImpl::DeleteAllDataAndMetadata(CallbackWithResult callback) {
175   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
176   DCHECK(!callback.is_null());
177   auto task = base::BindOnce(&BlockingModelTypeStore::DeleteAllDataAndMetadata,
178                              base::Unretained(backend_store_.get()));
179   auto reply =
180       base::BindOnce(&ModelTypeStoreImpl::WriteModificationsDone,
181                      weak_ptr_factory_.GetWeakPtr(), std::move(callback));
182   base::PostTaskAndReplyWithResult(backend_task_runner_.get(), FROM_HERE,
183                                    std::move(task), std::move(reply));
184 }
185 
186 std::unique_ptr<ModelTypeStore::WriteBatch>
CreateWriteBatch()187 ModelTypeStoreImpl::CreateWriteBatch() {
188   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
189   return BlockingModelTypeStoreImpl::CreateWriteBatchForType(type_);
190 }
191 
CommitWriteBatch(std::unique_ptr<WriteBatch> write_batch,CallbackWithResult callback)192 void ModelTypeStoreImpl::CommitWriteBatch(
193     std::unique_ptr<WriteBatch> write_batch,
194     CallbackWithResult callback) {
195   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
196   DCHECK(!callback.is_null());
197   auto task = base::BindOnce(&BlockingModelTypeStore::CommitWriteBatch,
198                              base::Unretained(backend_store_.get()),
199                              std::move(write_batch));
200   auto reply =
201       base::BindOnce(&ModelTypeStoreImpl::WriteModificationsDone,
202                      weak_ptr_factory_.GetWeakPtr(), std::move(callback));
203   base::PostTaskAndReplyWithResult(backend_task_runner_.get(), FROM_HERE,
204                                    std::move(task), std::move(reply));
205 }
206 
WriteModificationsDone(CallbackWithResult callback,const base::Optional<ModelError> & error)207 void ModelTypeStoreImpl::WriteModificationsDone(
208     CallbackWithResult callback,
209     const base::Optional<ModelError>& error) {
210   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
211   std::move(callback).Run(error);
212 }
213 
214 }  // namespace syncer
215