Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / bookmarks / bookmark_storage.cc
1 // Copyright (c) 2012 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 "chrome/browser/bookmarks/bookmark_storage.h"
6
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/json/json_file_value_serializer.h"
12 #include "base/json/json_string_value_serializer.h"
13 #include "base/metrics/histogram.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/bookmarks/bookmark_codec.h"
16 #include "chrome/browser/bookmarks/bookmark_index.h"
17 #include "chrome/browser/bookmarks/bookmark_model.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "components/startup_metric_utils/startup_metric_utils.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22
23 using base::TimeTicks;
24 using content::BrowserThread;
25
26 namespace {
27
28 // Extension used for backup files (copy of main file created during startup).
29 const base::FilePath::CharType kBackupExtension[] = FILE_PATH_LITERAL("bak");
30
31 // How often we save.
32 const int kSaveDelayMS = 2500;
33
34 void BackupCallback(const base::FilePath& path) {
35   base::FilePath backup_path = path.ReplaceExtension(kBackupExtension);
36   base::CopyFile(path, backup_path);
37 }
38
39 // Adds node to the model's index, recursing through all children as well.
40 void AddBookmarksToIndex(BookmarkLoadDetails* details,
41                          BookmarkNode* node) {
42   if (node->is_url()) {
43     if (node->url().is_valid())
44       details->index()->Add(node);
45   } else {
46     for (int i = 0; i < node->child_count(); ++i)
47       AddBookmarksToIndex(details, node->GetChild(i));
48   }
49 }
50
51 void LoadCallback(const base::FilePath& path,
52                   BookmarkStorage* storage,
53                   BookmarkLoadDetails* details) {
54   startup_metric_utils::ScopedSlowStartupUMA
55       scoped_timer("Startup.SlowStartupBookmarksLoad");
56   bool bookmark_file_exists = base::PathExists(path);
57   if (bookmark_file_exists) {
58     JSONFileValueSerializer serializer(path);
59     scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL));
60
61     if (root.get()) {
62       // Building the index can take a while, so we do it on the background
63       // thread.
64       int64 max_node_id = 0;
65       BookmarkCodec codec;
66       TimeTicks start_time = TimeTicks::Now();
67       codec.Decode(details->bb_node(), details->other_folder_node(),
68                    details->mobile_folder_node(), &max_node_id, *root.get());
69       details->set_max_id(std::max(max_node_id, details->max_id()));
70       details->set_computed_checksum(codec.computed_checksum());
71       details->set_stored_checksum(codec.stored_checksum());
72       details->set_ids_reassigned(codec.ids_reassigned());
73       details->set_model_meta_info_map(codec.model_meta_info_map());
74       details->set_model_sync_transaction_version(
75           codec.model_sync_transaction_version());
76       UMA_HISTOGRAM_TIMES("Bookmarks.DecodeTime",
77                           TimeTicks::Now() - start_time);
78
79       start_time = TimeTicks::Now();
80       AddBookmarksToIndex(details, details->bb_node());
81       AddBookmarksToIndex(details, details->other_folder_node());
82       AddBookmarksToIndex(details, details->mobile_folder_node());
83       UMA_HISTOGRAM_TIMES("Bookmarks.CreateBookmarkIndexTime",
84                           TimeTicks::Now() - start_time);
85     }
86   }
87
88   BrowserThread::PostTask(
89       BrowserThread::UI, FROM_HERE,
90       base::Bind(&BookmarkStorage::OnLoadFinished, storage));
91 }
92
93 }  // namespace
94
95 // BookmarkLoadDetails ---------------------------------------------------------
96
97 BookmarkLoadDetails::BookmarkLoadDetails(
98     BookmarkPermanentNode* bb_node,
99     BookmarkPermanentNode* other_folder_node,
100     BookmarkPermanentNode* mobile_folder_node,
101     BookmarkIndex* index,
102     int64 max_id)
103     : bb_node_(bb_node),
104       other_folder_node_(other_folder_node),
105       mobile_folder_node_(mobile_folder_node),
106       index_(index),
107       model_sync_transaction_version_(
108           BookmarkNode::kInvalidSyncTransactionVersion),
109       max_id_(max_id),
110       ids_reassigned_(false) {
111 }
112
113 BookmarkLoadDetails::~BookmarkLoadDetails() {
114 }
115
116 // BookmarkStorage -------------------------------------------------------------
117
118 BookmarkStorage::BookmarkStorage(
119     content::BrowserContext* context,
120     BookmarkModel* model,
121     base::SequencedTaskRunner* sequenced_task_runner)
122     : model_(model),
123       writer_(context->GetPath().Append(chrome::kBookmarksFileName),
124               sequenced_task_runner) {
125   sequenced_task_runner_ = sequenced_task_runner;
126   writer_.set_commit_interval(base::TimeDelta::FromMilliseconds(kSaveDelayMS));
127   sequenced_task_runner_->PostTask(FROM_HERE,
128                                    base::Bind(&BackupCallback, writer_.path()));
129 }
130
131 BookmarkStorage::~BookmarkStorage() {
132   if (writer_.HasPendingWrite())
133     writer_.DoScheduledWrite();
134 }
135
136 void BookmarkStorage::LoadBookmarks(BookmarkLoadDetails* details) {
137   DCHECK(!details_.get());
138   DCHECK(details);
139   details_.reset(details);
140   sequenced_task_runner_->PostTask(
141       FROM_HERE,
142       base::Bind(&LoadCallback, writer_.path(), make_scoped_refptr(this),
143                  details_.get()));
144 }
145
146 void BookmarkStorage::ScheduleSave() {
147   writer_.ScheduleWrite(this);
148 }
149
150 void BookmarkStorage::BookmarkModelDeleted() {
151   // We need to save now as otherwise by the time SaveNow is invoked
152   // the model is gone.
153   if (writer_.HasPendingWrite())
154     SaveNow();
155   model_ = NULL;
156 }
157
158 bool BookmarkStorage::SerializeData(std::string* output) {
159   BookmarkCodec codec;
160   scoped_ptr<base::Value> value(codec.Encode(model_));
161   JSONStringValueSerializer serializer(output);
162   serializer.set_pretty_print(true);
163   return serializer.Serialize(*(value.get()));
164 }
165
166 void BookmarkStorage::OnLoadFinished() {
167   if (!model_)
168     return;
169
170   model_->DoneLoading(details_.release());
171 }
172
173 bool BookmarkStorage::SaveNow() {
174   if (!model_ || !model_->loaded()) {
175     // We should only get here if we have a valid model and it's finished
176     // loading.
177     NOTREACHED();
178     return false;
179   }
180
181   std::string data;
182   if (!SerializeData(&data))
183     return false;
184   writer_.WriteNow(data);
185   return true;
186 }