[AndroidWebViewShell] Replace rebaseline script with a new version using test_runner.py
[chromium-blink-merge.git] / components / bookmarks / browser / bookmark_storage.cc
blobbc3fbfb24cc91827f118a4abfb6e9daab8bad259
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 #include "components/bookmarks/browser/bookmark_storage.h"
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/files/file_util.h"
10 #include "base/json/json_file_value_serializer.h"
11 #include "base/json/json_string_value_serializer.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/time/time.h"
15 #include "components/bookmarks/browser/bookmark_codec.h"
16 #include "components/bookmarks/browser/bookmark_index.h"
17 #include "components/bookmarks/browser/bookmark_model.h"
18 #include "components/bookmarks/common/bookmark_constants.h"
20 using base::TimeTicks;
22 namespace bookmarks {
24 namespace {
26 // Extension used for backup files (copy of main file created during startup).
27 const base::FilePath::CharType kBackupExtension[] = FILE_PATH_LITERAL("bak");
29 // How often we save.
30 const int kSaveDelayMS = 2500;
32 void BackupCallback(const base::FilePath& path) {
33 base::FilePath backup_path = path.ReplaceExtension(kBackupExtension);
34 base::CopyFile(path, backup_path);
37 // Adds node to the model's index, recursing through all children as well.
38 void AddBookmarksToIndex(BookmarkLoadDetails* details,
39 BookmarkNode* node) {
40 if (node->is_url()) {
41 if (node->url().is_valid())
42 details->index()->Add(node);
43 } else {
44 for (int i = 0; i < node->child_count(); ++i)
45 AddBookmarksToIndex(details, node->GetChild(i));
49 void LoadCallback(const base::FilePath& path,
50 const base::WeakPtr<BookmarkStorage>& storage,
51 scoped_ptr<BookmarkLoadDetails> details,
52 base::SequencedTaskRunner* task_runner) {
53 bool load_index = false;
54 bool bookmark_file_exists = base::PathExists(path);
55 if (bookmark_file_exists) {
56 JSONFileValueDeserializer deserializer(path);
57 scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL));
59 if (root.get()) {
60 // Building the index can take a while, so we do it on the background
61 // thread.
62 int64 max_node_id = 0;
63 BookmarkCodec codec;
64 TimeTicks start_time = TimeTicks::Now();
65 codec.Decode(details->bb_node(), details->other_folder_node(),
66 details->mobile_folder_node(), &max_node_id, *root.get());
67 details->set_max_id(std::max(max_node_id, details->max_id()));
68 details->set_computed_checksum(codec.computed_checksum());
69 details->set_stored_checksum(codec.stored_checksum());
70 details->set_ids_reassigned(codec.ids_reassigned());
71 details->set_model_meta_info_map(codec.model_meta_info_map());
72 details->set_model_sync_transaction_version(
73 codec.model_sync_transaction_version());
74 UMA_HISTOGRAM_TIMES("Bookmarks.DecodeTime",
75 TimeTicks::Now() - start_time);
77 load_index = true;
81 // Load any extra root nodes now, after the IDs have been potentially
82 // reassigned.
83 details->LoadExtraNodes();
85 // Load the index if there are any bookmarks in the extra nodes.
86 const BookmarkPermanentNodeList& extra_nodes = details->extra_nodes();
87 for (size_t i = 0; i < extra_nodes.size(); ++i) {
88 if (!extra_nodes[i]->empty()) {
89 load_index = true;
90 break;
94 if (load_index) {
95 TimeTicks start_time = TimeTicks::Now();
96 AddBookmarksToIndex(details.get(), details->bb_node());
97 AddBookmarksToIndex(details.get(), details->other_folder_node());
98 AddBookmarksToIndex(details.get(), details->mobile_folder_node());
99 for (size_t i = 0; i < extra_nodes.size(); ++i)
100 AddBookmarksToIndex(details.get(), extra_nodes[i]);
101 UMA_HISTOGRAM_TIMES("Bookmarks.CreateBookmarkIndexTime",
102 TimeTicks::Now() - start_time);
105 task_runner->PostTask(FROM_HERE,
106 base::Bind(&BookmarkStorage::OnLoadFinished, storage,
107 base::Passed(&details)));
110 } // namespace
112 // BookmarkLoadDetails ---------------------------------------------------------
114 BookmarkLoadDetails::BookmarkLoadDetails(
115 BookmarkPermanentNode* bb_node,
116 BookmarkPermanentNode* other_folder_node,
117 BookmarkPermanentNode* mobile_folder_node,
118 const LoadExtraCallback& load_extra_callback,
119 BookmarkIndex* index,
120 int64 max_id)
121 : bb_node_(bb_node),
122 other_folder_node_(other_folder_node),
123 mobile_folder_node_(mobile_folder_node),
124 load_extra_callback_(load_extra_callback),
125 index_(index),
126 model_sync_transaction_version_(
127 BookmarkNode::kInvalidSyncTransactionVersion),
128 max_id_(max_id),
129 ids_reassigned_(false) {
132 BookmarkLoadDetails::~BookmarkLoadDetails() {
135 void BookmarkLoadDetails::LoadExtraNodes() {
136 extra_nodes_ = load_extra_callback_.Run(&max_id_);
139 // BookmarkStorage -------------------------------------------------------------
141 BookmarkStorage::BookmarkStorage(
142 BookmarkModel* model,
143 const base::FilePath& profile_path,
144 base::SequencedTaskRunner* sequenced_task_runner)
145 : model_(model),
146 writer_(profile_path.Append(kBookmarksFileName), sequenced_task_runner),
147 weak_factory_(this) {
148 sequenced_task_runner_ = sequenced_task_runner;
149 writer_.set_commit_interval(base::TimeDelta::FromMilliseconds(kSaveDelayMS));
150 sequenced_task_runner_->PostTask(FROM_HERE,
151 base::Bind(&BackupCallback, writer_.path()));
154 BookmarkStorage::~BookmarkStorage() {
155 if (writer_.HasPendingWrite())
156 writer_.DoScheduledWrite();
159 void BookmarkStorage::LoadBookmarks(
160 scoped_ptr<BookmarkLoadDetails> details,
161 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
162 sequenced_task_runner_->PostTask(FROM_HERE,
163 base::Bind(&LoadCallback,
164 writer_.path(),
165 weak_factory_.GetWeakPtr(),
166 base::Passed(&details),
167 task_runner));
170 void BookmarkStorage::ScheduleSave() {
171 writer_.ScheduleWrite(this);
174 void BookmarkStorage::BookmarkModelDeleted() {
175 // We need to save now as otherwise by the time SaveNow is invoked
176 // the model is gone.
177 if (writer_.HasPendingWrite())
178 SaveNow();
179 model_ = NULL;
182 bool BookmarkStorage::SerializeData(std::string* output) {
183 BookmarkCodec codec;
184 scoped_ptr<base::Value> value(codec.Encode(model_));
185 JSONStringValueSerializer serializer(output);
186 serializer.set_pretty_print(true);
187 return serializer.Serialize(*(value.get()));
190 void BookmarkStorage::OnLoadFinished(scoped_ptr<BookmarkLoadDetails> details) {
191 if (!model_)
192 return;
194 model_->DoneLoading(details.Pass());
197 bool BookmarkStorage::SaveNow() {
198 if (!model_ || !model_->loaded()) {
199 // We should only get here if we have a valid model and it's finished
200 // loading.
201 NOTREACHED();
202 return false;
205 scoped_ptr<std::string> data(new std::string);
206 if (!SerializeData(data.get()))
207 return false;
208 writer_.WriteNow(data.Pass());
209 return true;
212 } // namespace bookmarks