1 // Copyright 2014 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.
5 #ifndef COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_
6 #define COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/strings/string_util.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "base/threading/thread_checker.h"
19 #include "base/strings/string_split.h"
20 #include "components/leveldb_proto/leveldb_database.h"
21 #include "components/leveldb_proto/proto_database.h"
23 namespace leveldb_proto
{
25 using KeyValueVector
= base::StringPairs
;
26 using KeyVector
= std::vector
<std::string
>;
28 // When the ProtoDatabaseImpl instance is deleted, in-progress asynchronous
29 // operations will be completed and the corresponding callbacks will be called.
30 // Construction/calls/destruction should all happen on the same thread.
32 class ProtoDatabaseImpl
: public ProtoDatabase
<T
> {
34 // All blocking calls/disk access will happen on the provided |task_runner|.
35 explicit ProtoDatabaseImpl(
36 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
);
38 ~ProtoDatabaseImpl() override
;
40 // ProtoDatabase implementation.
41 // TODO(cjhopman): Perhaps Init() shouldn't be exposed to users and not just
42 // part of the constructor
43 void Init(const base::FilePath
& database_dir
,
44 const typename ProtoDatabase
<T
>::InitCallback
& callback
) override
;
46 scoped_ptr
<typename ProtoDatabase
<T
>::KeyEntryVector
> entries_to_save
,
47 scoped_ptr
<KeyVector
> keys_to_remove
,
48 const typename ProtoDatabase
<T
>::UpdateCallback
& callback
) override
;
50 const typename ProtoDatabase
<T
>::LoadCallback
& callback
) override
;
52 // Allow callers to provide their own Database implementation.
53 void InitWithDatabase(
54 scoped_ptr
<LevelDB
> database
,
55 const base::FilePath
& database_dir
,
56 const typename ProtoDatabase
<T
>::InitCallback
& callback
);
59 base::ThreadChecker thread_checker_
;
61 // Used to run blocking tasks in-order.
62 scoped_refptr
<base::SequencedTaskRunner
> task_runner_
;
64 scoped_ptr
<LevelDB
> db_
;
66 DISALLOW_COPY_AND_ASSIGN(ProtoDatabaseImpl
);
72 void RunInitCallback(const typename ProtoDatabase
<T
>::InitCallback
& callback
,
73 const bool* success
) {
74 callback
.Run(*success
);
78 void RunUpdateCallback(
79 const typename ProtoDatabase
<T
>::UpdateCallback
& callback
,
80 const bool* success
) {
81 callback
.Run(*success
);
85 void RunLoadCallback(const typename ProtoDatabase
<T
>::LoadCallback
& callback
,
87 scoped_ptr
<std::vector
<T
>> entries
) {
88 callback
.Run(*success
, entries
.Pass());
91 void InitFromTaskRunner(LevelDB
* database
, const base::FilePath
& database_dir
,
95 // TODO(cjhopman): Histogram for database size.
96 *success
= database
->Init(database_dir
);
100 void UpdateEntriesFromTaskRunner(
102 scoped_ptr
<typename ProtoDatabase
<T
>::KeyEntryVector
> entries_to_save
,
103 scoped_ptr
<KeyVector
> keys_to_remove
,
107 // Serialize the values from Proto to string before passing on to database.
108 KeyValueVector pairs_to_save
;
109 for (const auto& pair
: *entries_to_save
) {
110 pairs_to_save
.push_back(
111 std::make_pair(pair
.first
, pair
.second
.SerializeAsString()));
114 *success
= database
->Save(pairs_to_save
, *keys_to_remove
);
117 template <typename T
>
118 void LoadEntriesFromTaskRunner(LevelDB
* database
,
119 std::vector
<T
>* entries
,
126 std::vector
<std::string
> loaded_entries
;
127 *success
= database
->Load(&loaded_entries
);
129 for (const auto& serialized_entry
: loaded_entries
) {
131 if (!entry
.ParseFromString(serialized_entry
)) {
132 DLOG(WARNING
) << "Unable to parse leveldb_proto entry";
133 // TODO(cjhopman): Decide what to do about un-parseable entries.
136 entries
->push_back(entry
);
142 template <typename T
>
143 ProtoDatabaseImpl
<T
>::ProtoDatabaseImpl(
144 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
)
145 : task_runner_(task_runner
) {}
147 template <typename T
>
148 ProtoDatabaseImpl
<T
>::~ProtoDatabaseImpl() {
149 DCHECK(thread_checker_
.CalledOnValidThread());
150 if (!task_runner_
->DeleteSoon(FROM_HERE
, db_
.release()))
151 DLOG(WARNING
) << "Proto database will not be deleted.";
154 template <typename T
>
155 void ProtoDatabaseImpl
<T
>::Init(
156 const base::FilePath
& database_dir
,
157 const typename ProtoDatabase
<T
>::InitCallback
& callback
) {
158 DCHECK(thread_checker_
.CalledOnValidThread());
159 InitWithDatabase(make_scoped_ptr(new LevelDB()), database_dir
, callback
);
162 template <typename T
>
163 void ProtoDatabaseImpl
<T
>::InitWithDatabase(
164 scoped_ptr
<LevelDB
> database
,
165 const base::FilePath
& database_dir
,
166 const typename ProtoDatabase
<T
>::InitCallback
& callback
) {
167 DCHECK(thread_checker_
.CalledOnValidThread());
170 db_
.reset(database
.release());
171 bool* success
= new bool(false);
172 task_runner_
->PostTaskAndReply(
173 FROM_HERE
, base::Bind(InitFromTaskRunner
, base::Unretained(db_
.get()),
174 database_dir
, success
),
175 base::Bind(RunInitCallback
<T
>, callback
, base::Owned(success
)));
178 template <typename T
>
179 void ProtoDatabaseImpl
<T
>::UpdateEntries(
180 scoped_ptr
<typename ProtoDatabase
<T
>::KeyEntryVector
> entries_to_save
,
181 scoped_ptr
<KeyVector
> keys_to_remove
,
182 const typename ProtoDatabase
<T
>::UpdateCallback
& callback
) {
183 DCHECK(thread_checker_
.CalledOnValidThread());
184 bool* success
= new bool(false);
185 task_runner_
->PostTaskAndReply(
187 base::Bind(UpdateEntriesFromTaskRunner
<T
>, base::Unretained(db_
.get()),
188 base::Passed(&entries_to_save
), base::Passed(&keys_to_remove
),
190 base::Bind(RunUpdateCallback
<T
>, callback
, base::Owned(success
)));
193 template <typename T
>
194 void ProtoDatabaseImpl
<T
>::LoadEntries(
195 const typename ProtoDatabase
<T
>::LoadCallback
& callback
) {
196 DCHECK(thread_checker_
.CalledOnValidThread());
197 bool* success
= new bool(false);
199 scoped_ptr
<std::vector
<T
> > entries(new std::vector
<T
>());
200 // Get this pointer before entries is base::Passed() so we can use it below.
201 std::vector
<T
>* entries_ptr
= entries
.get();
203 task_runner_
->PostTaskAndReply(
204 FROM_HERE
, base::Bind(LoadEntriesFromTaskRunner
<T
>,
205 base::Unretained(db_
.get()), entries_ptr
, success
),
206 base::Bind(RunLoadCallback
<T
>, callback
, base::Owned(success
),
207 base::Passed(&entries
)));
210 } // namespace leveldb_proto
212 #endif // COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_