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

Side by Side Diff: components/offline_pages/offline_page_metadata_store_impl.cc

Issue 1999443003: delete the levelDB storage implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: remove proto headers Created 4 years, 7 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
(Empty)
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/offline_pages/offline_page_metadata_store_impl.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/location.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "build/build_config.h"
20 #include "components/leveldb_proto/proto_database_impl.h"
21 #include "components/offline_pages/offline_page_item.h"
22 #include "components/offline_pages/offline_page_model.h"
23 #include "components/offline_pages/proto/offline_pages.pb.h"
24 #include "third_party/leveldatabase/env_chromium.h"
25 #include "third_party/leveldatabase/src/include/leveldb/db.h"
26 #include "url/gurl.h"
27
28 using leveldb_proto::ProtoDatabase;
29
30 namespace {
31 // Statistics are logged to UMA with this string as part of histogram name. They
32 // can all be found under LevelDB.*.OfflinePageMetadataStore. Changing this
33 // needs to synchronize with histograms.xml, AND will also become incompatible
34 // with older browsers still reporting the previous values.
35 const char kDatabaseUMAClientName[] = "OfflinePageMetadataStore";
36 }
37
38 namespace offline_pages {
39 namespace {
40
41 void OfflinePageItemToEntry(const OfflinePageItem& item,
42 offline_pages::OfflinePageEntry* item_proto) {
43 DCHECK(item_proto);
44 item_proto->set_url(item.url.spec());
45 item_proto->set_offline_id(item.offline_id);
46 item_proto->set_version(item.version);
47 std::string path_string;
48 #if defined(OS_POSIX)
49 path_string = item.file_path.value();
50 #elif defined(OS_WIN)
51 path_string = base::WideToUTF8(item.file_path.value());
52 #endif
53 item_proto->set_file_path(path_string);
54 item_proto->set_file_size(item.file_size);
55 item_proto->set_creation_time(item.creation_time.ToInternalValue());
56 item_proto->set_last_access_time(item.last_access_time.ToInternalValue());
57 item_proto->set_access_count(item.access_count);
58 item_proto->set_flags(
59 static_cast<::offline_pages::OfflinePageEntry_Flags>(item.flags));
60 item_proto->set_client_id_name_space(item.client_id.name_space);
61 item_proto->set_client_id(item.client_id.id);
62 }
63
64 bool OfflinePageItemFromEntry(const offline_pages::OfflinePageEntry& item_proto,
65 OfflinePageItem* item) {
66 DCHECK(item);
67 bool has_offline_id =
68 item_proto.has_offline_id() || item_proto.has_deprecated_bookmark_id();
69 if (!item_proto.has_url() || !has_offline_id || !item_proto.has_version() ||
70 !item_proto.has_file_path()) {
71 return false;
72 }
73 item->url = GURL(item_proto.url());
74 item->offline_id = item_proto.offline_id();
75 item->version = item_proto.version();
76 #if defined(OS_POSIX)
77 item->file_path = base::FilePath(item_proto.file_path());
78 #elif defined(OS_WIN)
79 item->file_path = base::FilePath(base::UTF8ToWide(item_proto.file_path()));
80 #endif
81 if (item_proto.has_file_size()) {
82 item->file_size = item_proto.file_size();
83 }
84 if (item_proto.has_creation_time()) {
85 item->creation_time =
86 base::Time::FromInternalValue(item_proto.creation_time());
87 }
88 if (item_proto.has_last_access_time()) {
89 item->last_access_time =
90 base::Time::FromInternalValue(item_proto.last_access_time());
91 }
92 if (item_proto.has_access_count()) {
93 item->access_count = item_proto.access_count();
94 }
95 if (item_proto.has_flags()) {
96 item->flags = static_cast<OfflinePageItem::Flags>(item_proto.flags());
97 }
98 item->client_id.name_space = item_proto.client_id_name_space();
99 item->client_id.id = item_proto.client_id();
100
101 return true;
102 }
103
104 } // namespace
105
106 OfflinePageMetadataStoreImpl::OfflinePageMetadataStoreImpl(
107 scoped_refptr<base::SequencedTaskRunner> background_task_runner,
108 const base::FilePath& database_dir)
109 : background_task_runner_(background_task_runner),
110 database_dir_(database_dir),
111 weak_ptr_factory_(this) {
112 }
113
114 OfflinePageMetadataStoreImpl::~OfflinePageMetadataStoreImpl() {
115 }
116
117 void OfflinePageMetadataStoreImpl::Load(const LoadCallback& callback) {
118 // First initialize the database.
119 database_.reset(new leveldb_proto::ProtoDatabaseImpl<OfflinePageEntry>(
120 background_task_runner_));
121 database_->Init(kDatabaseUMAClientName, database_dir_,
122 base::Bind(&OfflinePageMetadataStoreImpl::LoadContinuation,
123 weak_ptr_factory_.GetWeakPtr(),
124 callback));
125 }
126
127 void OfflinePageMetadataStoreImpl::LoadContinuation(
128 const LoadCallback& callback,
129 bool success) {
130 if (!success) {
131 NotifyLoadResult(callback,
132 STORE_INIT_FAILED,
133 std::vector<OfflinePageItem>());
134 return;
135 }
136
137 // After initialization, start to load the data.
138 database_->LoadEntries(
139 base::Bind(&OfflinePageMetadataStoreImpl::LoadDone,
140 weak_ptr_factory_.GetWeakPtr(),
141 callback));
142 }
143
144 void OfflinePageMetadataStoreImpl::LoadDone(
145 const LoadCallback& callback,
146 bool success,
147 std::unique_ptr<std::vector<OfflinePageEntry>> entries) {
148 DCHECK(entries);
149
150 std::vector<OfflinePageItem> result;
151 std::unique_ptr<ProtoDatabase<OfflinePageEntry>::KeyEntryVector>
152 entries_to_update(new ProtoDatabase<OfflinePageEntry>::KeyEntryVector());
153 std::unique_ptr<std::vector<std::string>> keys_to_remove(
154 new std::vector<std::string>());
155
156 LoadStatus status = LOAD_SUCCEEDED;
157
158 if (success) {
159 for (auto& entry : *entries) {
160 OfflinePageItem item;
161 // We don't want to fail the entire database if one item is corrupt,
162 // so log error and keep going.
163 if (!OfflinePageItemFromEntry(entry, &item)) {
164 LOG(ERROR) << "failed to parse entry: " << entry.url() << " skipping.";
165 continue;
166 }
167 // Legacy storage. We upgrade them to the new offline_id keyed storage.
168 // TODO(bburns): Remove this eventually when we are sure everyone is
169 // upgraded.
170 if (!entry.has_offline_id()) {
171 item.offline_id = OfflinePageModel::GenerateOfflineId();
172
173 if (!entry.has_deprecated_bookmark_id()) {
174 LOG(ERROR) << "unexpected entry missing bookmark id";
175 continue;
176 }
177 item.client_id.name_space = offline_pages::kBookmarkNamespace;
178 item.client_id.id = base::Int64ToString(entry.deprecated_bookmark_id());
179
180 OfflinePageEntry upgraded_entry;
181 OfflinePageItemToEntry(item, &upgraded_entry);
182 entries_to_update->push_back(
183 std::make_pair(base::Int64ToString(upgraded_entry.offline_id()),
184 upgraded_entry));
185 // Remove the old entry that is indexed with deprecated id.
186 keys_to_remove->push_back(item.client_id.id);
187 }
188 result.push_back(item);
189 }
190 } else {
191 status = STORE_LOAD_FAILED;
192 }
193
194 // If we couldn't load _anything_ report a parse failure.
195 if (entries->size() > 0 && result.size() == 0) {
196 status = DATA_PARSING_FAILED;
197 }
198
199 if (status == LOAD_SUCCEEDED && entries_to_update->size() > 0) {
200 UpdateEntries(std::move(entries_to_update), std::move(keys_to_remove),
201 base::Bind(&OfflinePageMetadataStoreImpl::DatabaseUpdateDone,
202 weak_ptr_factory_.GetWeakPtr(), callback, status,
203 std::move(result)));
204 } else {
205 NotifyLoadResult(callback, status, result);
206 }
207 }
208
209 void OfflinePageMetadataStoreImpl::NotifyLoadResult(
210 const LoadCallback& callback,
211 LoadStatus status,
212 const std::vector<OfflinePageItem>& result) {
213 UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus",
214 status,
215 OfflinePageMetadataStore::LOAD_STATUS_COUNT);
216 if (status == LOAD_SUCCEEDED) {
217 UMA_HISTOGRAM_COUNTS("OfflinePages.SavedPageCount", result.size());
218 } else {
219 DVLOG(1) << "Offline pages database loading failed: " << status;
220 database_.reset();
221 }
222 callback.Run(status, result);
223 }
224
225 void OfflinePageMetadataStoreImpl::AddOrUpdateOfflinePage(
226 const OfflinePageItem& offline_page_item,
227 const UpdateCallback& callback) {
228 std::unique_ptr<ProtoDatabase<OfflinePageEntry>::KeyEntryVector>
229 entries_to_save(new ProtoDatabase<OfflinePageEntry>::KeyEntryVector());
230 std::unique_ptr<std::vector<std::string>> keys_to_remove(
231 new std::vector<std::string>());
232
233 OfflinePageEntry offline_page_proto;
234 OfflinePageItemToEntry(offline_page_item, &offline_page_proto);
235
236 entries_to_save->push_back(std::make_pair(
237 base::Int64ToString(offline_page_item.offline_id), offline_page_proto));
238
239 UpdateEntries(std::move(entries_to_save), std::move(keys_to_remove),
240 callback);
241 }
242
243 void OfflinePageMetadataStoreImpl::RemoveOfflinePages(
244 const std::vector<int64_t>& offline_ids,
245 const UpdateCallback& callback) {
246 std::unique_ptr<ProtoDatabase<OfflinePageEntry>::KeyEntryVector>
247 entries_to_save(new ProtoDatabase<OfflinePageEntry>::KeyEntryVector());
248 std::unique_ptr<std::vector<std::string>> keys_to_remove(
249 new std::vector<std::string>());
250
251 for (int64_t id : offline_ids)
252 keys_to_remove->push_back(base::Int64ToString(id));
253
254 UpdateEntries(std::move(entries_to_save), std::move(keys_to_remove),
255 callback);
256 }
257
258 void OfflinePageMetadataStoreImpl::UpdateEntries(
259 std::unique_ptr<ProtoDatabase<OfflinePageEntry>::KeyEntryVector>
260 entries_to_save,
261 std::unique_ptr<std::vector<std::string>> keys_to_remove,
262 const UpdateCallback& callback) {
263 if (!database_.get()) {
264 // Failing fast here, because DB is not initialized, and there is nothing
265 // that can be done about it.
266 // Callback is invoked through message loop to avoid improper retry and
267 // simplify testing.
268 DVLOG(1) << "Offline pages database not available in UpdateEntries.";
269 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
270 base::Bind(callback, false));
271 return;
272 }
273
274 database_->UpdateEntries(
275 std::move(entries_to_save), std::move(keys_to_remove),
276 base::Bind(&OfflinePageMetadataStoreImpl::UpdateDone,
277 weak_ptr_factory_.GetWeakPtr(), callback));
278 }
279
280 void OfflinePageMetadataStoreImpl::UpdateDone(
281 const OfflinePageMetadataStore::UpdateCallback& callback,
282 bool success) {
283 if (!success) {
284 // TODO(fgorski): Add UMA for this case. Consider rebuilding the store.
285 DVLOG(1) << "Offline pages database update failed.";
286 }
287
288 callback.Run(success);
289 }
290
291 void OfflinePageMetadataStoreImpl::Reset(const ResetCallback& callback) {
292 database_->Destroy(
293 base::Bind(&OfflinePageMetadataStoreImpl::ResetDone,
294 weak_ptr_factory_.GetWeakPtr(),
295 callback));
296 }
297
298 void OfflinePageMetadataStoreImpl::ResetDone(
299 const ResetCallback& callback,
300 bool success) {
301 database_.reset();
302 weak_ptr_factory_.InvalidateWeakPtrs();
303 callback.Run(success);
304 }
305
306 void OfflinePageMetadataStoreImpl::DatabaseUpdateDone(
307 const OfflinePageMetadataStore::LoadCallback& cb,
308 LoadStatus status,
309 const std::vector<OfflinePageItem>& result,
310 bool success) {
311 // If the update failed, log and keep going. We'll try to
312 // update next time.
313 if (!success) {
314 LOG(ERROR) << "Failed to update database";
315 }
316 NotifyLoadResult(cb, status, result);
317 }
318
319 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698