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