Make sure webrtc::VideoSource is released when WebRtcVideoTrackAdapter is destroyed.
[chromium-blink-merge.git] / components / dom_distiller / core / dom_distiller_database.cc
bloba799a622823cd3e049f777a155d6943a5efe1b7c
1 // Copyright 2013 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 #include "components/dom_distiller/core/dom_distiller_database.h"
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/strings/string_util.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "components/dom_distiller/core/article_entry.h"
14 #include "third_party/leveldatabase/src/include/leveldb/db.h"
15 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
16 #include "third_party/leveldatabase/src/include/leveldb/options.h"
17 #include "third_party/leveldatabase/src/include/leveldb/slice.h"
18 #include "third_party/leveldatabase/src/include/leveldb/status.h"
19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
21 using base::MessageLoop;
22 using base::SequencedTaskRunner;
24 namespace dom_distiller {
26 DomDistillerDatabase::LevelDB::LevelDB() {}
28 DomDistillerDatabase::LevelDB::~LevelDB() {
29 DFAKE_SCOPED_LOCK(thread_checker_);
32 bool DomDistillerDatabase::LevelDB::Init(const base::FilePath& database_dir) {
33 DFAKE_SCOPED_LOCK(thread_checker_);
35 leveldb::Options options;
36 options.create_if_missing = true;
37 options.max_open_files = 0; // Use minimum.
39 std::string path = database_dir.AsUTF8Unsafe();
41 leveldb::DB* db = NULL;
42 leveldb::Status status = leveldb::DB::Open(options, path, &db);
43 if (status.IsCorruption()) {
44 base::DeleteFile(database_dir, true);
45 status = leveldb::DB::Open(options, path, &db);
48 if (status.ok()) {
49 CHECK(db);
50 db_.reset(db);
51 return true;
54 LOG(WARNING) << "Unable to open " << database_dir.value() << ": "
55 << status.ToString();
56 return false;
59 bool DomDistillerDatabase::LevelDB::Save(const EntryVector& entries_to_save,
60 const EntryVector& entries_to_remove) {
61 DFAKE_SCOPED_LOCK(thread_checker_);
63 leveldb::WriteBatch updates;
64 for (EntryVector::const_iterator it = entries_to_save.begin();
65 it != entries_to_save.end();
66 ++it) {
67 updates.Put(leveldb::Slice(it->entry_id()),
68 leveldb::Slice(it->SerializeAsString()));
70 for (EntryVector::const_iterator it = entries_to_remove.begin();
71 it != entries_to_remove.end();
72 ++it) {
73 updates.Delete(leveldb::Slice(it->entry_id()));
76 leveldb::WriteOptions options;
77 options.sync = true;
78 leveldb::Status status = db_->Write(options, &updates);
79 if (status.ok())
80 return true;
82 DLOG(WARNING) << "Failed writing dom_distiller entries: "
83 << status.ToString();
84 return false;
87 bool DomDistillerDatabase::LevelDB::Load(EntryVector* entries) {
88 DFAKE_SCOPED_LOCK(thread_checker_);
90 leveldb::ReadOptions options;
91 scoped_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
92 for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) {
93 leveldb::Slice value_slice = db_iterator->value();
95 ArticleEntry entry;
96 if (!entry.ParseFromArray(value_slice.data(), value_slice.size())) {
97 DLOG(WARNING) << "Unable to parse dom_distiller entry "
98 << db_iterator->key().ToString();
99 // TODO(cjhopman): Decide what to do about un-parseable entries.
101 entries->push_back(entry);
103 return true;
106 namespace {
108 void RunInitCallback(DomDistillerDatabaseInterface::InitCallback callback,
109 const bool* success) {
110 callback.Run(*success);
113 void RunUpdateCallback(DomDistillerDatabaseInterface::UpdateCallback callback,
114 const bool* success) {
115 callback.Run(*success);
118 void RunLoadCallback(DomDistillerDatabaseInterface::LoadCallback callback,
119 const bool* success,
120 scoped_ptr<EntryVector> entries) {
121 callback.Run(*success, entries.Pass());
124 void InitFromTaskRunner(DomDistillerDatabase::Database* database,
125 const base::FilePath& database_dir,
126 bool* success) {
127 DCHECK(success);
129 // TODO(cjhopman): Histogram for database size.
130 *success = database->Init(database_dir);
133 void UpdateEntriesFromTaskRunner(DomDistillerDatabase::Database* database,
134 scoped_ptr<EntryVector> entries_to_save,
135 scoped_ptr<EntryVector> entries_to_remove,
136 bool* success) {
137 DCHECK(success);
138 *success = database->Save(*entries_to_save, *entries_to_remove);
141 void LoadEntriesFromTaskRunner(DomDistillerDatabase::Database* database,
142 EntryVector* entries,
143 bool* success) {
144 DCHECK(success);
145 DCHECK(entries);
147 entries->clear();
148 *success = database->Load(entries);
151 } // namespace
153 DomDistillerDatabase::DomDistillerDatabase(
154 scoped_refptr<base::SequencedTaskRunner> task_runner)
155 : task_runner_(task_runner) {
158 void DomDistillerDatabase::Init(const base::FilePath& database_dir,
159 InitCallback callback) {
160 DCHECK(thread_checker_.CalledOnValidThread());
161 InitWithDatabase(scoped_ptr<Database>(new LevelDB()), database_dir, callback);
164 void DomDistillerDatabase::InitWithDatabase(scoped_ptr<Database> database,
165 const base::FilePath& database_dir,
166 InitCallback callback) {
167 DCHECK(thread_checker_.CalledOnValidThread());
168 DCHECK(!db_);
169 DCHECK(database);
170 db_.reset(database.release());
171 bool* success = new bool(false);
172 task_runner_->PostTaskAndReply(
173 FROM_HERE,
174 base::Bind(InitFromTaskRunner,
175 base::Unretained(db_.get()),
176 database_dir,
177 success),
178 base::Bind(RunInitCallback, callback, base::Owned(success)));
181 void DomDistillerDatabase::UpdateEntries(
182 scoped_ptr<EntryVector> entries_to_save,
183 scoped_ptr<EntryVector> entries_to_remove,
184 UpdateCallback callback) {
185 DCHECK(thread_checker_.CalledOnValidThread());
186 bool* success = new bool(false);
187 task_runner_->PostTaskAndReply(
188 FROM_HERE,
189 base::Bind(UpdateEntriesFromTaskRunner,
190 base::Unretained(db_.get()),
191 base::Passed(&entries_to_save),
192 base::Passed(&entries_to_remove),
193 success),
194 base::Bind(RunUpdateCallback, callback, base::Owned(success)));
197 void DomDistillerDatabase::LoadEntries(LoadCallback callback) {
198 DCHECK(thread_checker_.CalledOnValidThread());
199 bool* success = new bool(false);
201 scoped_ptr<EntryVector> entries(new EntryVector());
202 // Get this pointer before entries is base::Passed() so we can use it below.
203 EntryVector* entries_ptr = entries.get();
205 task_runner_->PostTaskAndReply(
206 FROM_HERE,
207 base::Bind(LoadEntriesFromTaskRunner,
208 base::Unretained(db_.get()),
209 entries_ptr,
210 success),
211 base::Bind(RunLoadCallback,
212 callback,
213 base::Owned(success),
214 base::Passed(&entries)));
217 DomDistillerDatabase::~DomDistillerDatabase() {
218 DCHECK(thread_checker_.CalledOnValidThread());
219 if (!task_runner_->DeleteSoon(FROM_HERE, db_.release())) {
220 DLOG(WARNING) << "DOM distiller database will not be deleted.";
224 } // namespace dom_distiller