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

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

Issue 1834563002: initial add of SQL based storage (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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 2016 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_sql.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/location.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/sequenced_task_runner.h"
13 #include "components/offline_pages/offline_page_item.h"
14 #include "sql/connection.h"
15 #include "sql/error_delegate_util.h"
16 #include "sql/meta_table.h"
17 #include "sql/statement.h"
18 #include "sql/transaction.h"
19
20 namespace offline_pages {
21
22 namespace {
23
24 const int kCurrentVersion = 1;
25 const int kCompatibleVersion = 1;
26
27 const char kTableName[] = "offlinepages";
fgorski 2016/03/24 16:27:54 kOfflinePagesTable(Name)
bburns 2016/03/25 23:07:37 Done.
28 const char kColumns[] =
fgorski 2016/03/24 16:27:55 kOfflinePagesTableColumns
bburns 2016/03/25 23:07:38 Done.
29 "(offline_id INTEGER PRIMARY_KEY,"
30 " client_namespace VARCHAR(256),"
31 " client_id VARCHAR(256),"
32 " online_url VARCHAR(2048),"
33 " offline_url VARCHAR(2048),"
34 " version INTEGER,"
35 " creation_time INTEGER,"
36 " file_path VARCHAR(1024),"
37 " file_size INTEGER,"
38 " last_access_time INTEGER,"
39 " access_count INTEGER,"
40 " status INTEGER,"
41 " user_initiated BOOLEAN)";
42
43 #define OFFLINE_ID 0
fgorski 2016/03/24 16:27:55 Add table prefix, e.g. OP_ It will come in handy
Dmitry Titov 2016/03/24 23:22:20 I believe we this form is preferable lately in Chr
bburns 2016/03/25 23:07:37 Done.
bburns 2016/03/25 23:07:38 Done.
44 #define CLIENT_NAMESPACE 1
45 #define CLIENT_ID 2
46 #define ONLINE_URL 3
47 #define OFFLINE_URL 4
48 #define VERSION 5
49 #define CREATION_TIME 6
50 #define FILE_PATH 7
51 #define FILE_SIZE 8
52 #define LAST_ACCESS 9
53 #define ACCESS_COUNT 10
54 #define STATUS 11
55 #define USER_INITIATED 12
56
57 bool CreateTable(sql::Connection* db,
58 const char* table_name,
59 const char* columns) {
60 std::string sql("CREATE TABLE ");
61 sql += table_name;
62 sql += columns;
63 return db->Execute(sql.c_str());
64 }
65
66 bool CreateSchema(sql::MetaTable* meta_table, sql::Connection* db) {
67 sql::Transaction transaction(db);
68 if (!transaction.Begin())
69 return false;
70
71 if (!meta_table->Init(db, kCurrentVersion, kCompatibleVersion))
72 return false;
73
74 if (!CreateTable(db, kTableName, kColumns))
75 return false;
76
77 // TODO: indexes here
Dmitry Titov 2016/03/24 23:22:20 // TODO(bburns): ....
bburns 2016/03/25 23:07:37 Done.
78 return transaction.Commit();
79 }
80
81 bool DropTable(sql::Connection* db, const char* table_name) {
82 std::string sql("DROP TABLE ");
83 sql += table_name;
84 return db->Execute(sql.c_str());
85 }
86
87 bool DeleteOfflineId(sql::Connection* db, int64_t offline_id) {
fgorski 2016/03/24 16:27:55 DeleteByOfflineId
bburns 2016/03/25 23:07:37 Done.
88 std::string sql("DELETE FROM ");
fgorski 2016/03/24 16:27:54 this whole statement should be a const with " offl
bburns 2016/03/25 23:07:38 Done.
89 sql += kTableName;
90 sql += " WHERE offline_id=";
91 sql += offline_id;
92 return db->Execute(sql.c_str());
93 }
94
95 OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) {
96 int64_t id = statement->ColumnInt64(OFFLINE_ID);
97 GURL url(statement->ColumnString(ONLINE_URL));
98 ClientId client_id(statement->ColumnString(CLIENT_NAMESPACE),
99 statement->ColumnString(CLIENT_ID));
100 base::FilePath path(statement->ColumnString(FILE_PATH));
101 int64_t file_size = statement->ColumnInt64(FILE_SIZE);
102 base::Time creation =
Dmitry Titov 2016/03/24 23:22:20 creationTime
bburns 2016/03/25 23:07:37 Done.
103 base::Time::FromDoubleT(statement->ColumnInt64(CREATION_TIME));
fgorski 2016/03/24 16:27:54 base::Time::FromInternalValue(statement->ColumnInt
bburns 2016/03/25 23:07:37 Done.
104
105 return OfflinePageItem(url, id, client_id, path, file_size, creation);
106 }
107
108 bool InsertOrReplace(sql::Connection* db, const OfflinePageItem& item) {
109 std::string sql = "INSERT OR REPLACE INTO ";
fgorski 2016/03/24 16:27:55 extract as constant the whole sql statement.
bburns 2016/03/25 23:07:37 Done.
110 sql += kTableName;
111 sql +=
112 " (offline_id, online_url, client_namespace, client_id, file_path, "
113 "file_size, creation_time)"
fgorski 2016/03/24 16:27:55 what about other fields?
bburns 2016/03/25 23:07:38 added a couple more. The database is actually a s
114 " VALUES "
115 " (?, ?, ?, ?, ?, ?, ?)";
116
117 sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
118 statement.BindInt64(OFFLINE_ID, item.offline_id);
119 statement.BindString(ONLINE_URL, item.url.spec());
120 statement.BindString(CLIENT_NAMESPACE, item.client_id.name_space);
121 statement.BindString(CLIENT_ID, item.client_id.id);
122 statement.BindString(FILE_PATH, item.file_path.value());
123 statement.BindInt64(FILE_SIZE, item.file_size);
124 statement.BindInt64(CREATION_TIME, (int64_t)item.creation_time.ToDoubleT());
fgorski 2016/03/24 16:27:55 item.creation_time.ToInternalValue();
bburns 2016/03/25 23:07:37 Done.
125
126 return statement.Run();
127 }
128
129 } // anonymous namespace
130
131 OfflinePageMetadataStoreSQL::OfflinePageMetadataStoreSQL(
132 scoped_refptr<base::SequencedTaskRunner> background_task_runner,
133 const base::FilePath& path)
134 : background_task_runner_(background_task_runner),
135 db_file_path_(path),
136 weak_ptr_factory_(this) {}
137
138 OfflinePageMetadataStoreSQL::~OfflinePageMetadataStoreSQL() {}
139
140 void OfflinePageMetadataStoreSQL::LoadSync(const LoadCallback& callback) {
141 // TODO: should this be async?
fgorski 2016/03/24 16:27:54 nit: TODO(bburns): ;)
bburns 2016/03/25 23:07:37 Removed.
142 bool opened = false;
143 db_.reset(new sql::Connection);
144 meta_table_.reset(new sql::MetaTable);
145
146 if (use_in_memory_) {
147 opened = db_->OpenInMemory();
148 } else if (!base::CreateDirectory(db_file_path_.DirName())) {
149 LOG(ERROR) << "Failed to create appcache directory.";
fgorski 2016/03/24 16:27:54 I admire your Copy-Paste Fu ;) also, I actually l
bburns 2016/03/25 23:07:38 Done.
150 } else {
151 opened = db_->Open(db_file_path_);
152 if (opened)
153 db_->Preload();
154 }
155 if (!opened) {
156 NotifyLoadResult(callback, STORE_INIT_FAILED,
157 std::vector<OfflinePageItem>());
158 }
159
160 if (!sql::MetaTable::DoesTableExist(db_.get())) {
161 if (!CreateSchema(meta_table_.get(), db_.get())) {
162 NotifyLoadResult(callback, STORE_INIT_FAILED,
163 std::vector<OfflinePageItem>());
164 }
165 }
166
167 if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion))
168 NotifyLoadResult(callback, STORE_INIT_FAILED,
fgorski 2016/03/24 16:27:54 seems like we will not be able to distinguish thes
bburns 2016/03/25 23:07:37 This is still TBD, but will add before final revie
fgorski 2016/03/29 06:50:18 At least put a visible TODO for now, please
169 std::vector<OfflinePageItem>());
170
171 if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) {
172 LOG(WARNING) << "Offline database is too new.";
173 NotifyLoadResult(callback, STORE_INIT_FAILED,
174 std::vector<OfflinePageItem>());
175 }
176
177 std::string sql("SELECT * FROM ");
fgorski 2016/03/24 16:27:54 extract const char []
bburns 2016/03/25 23:07:37 Done.
178 sql += kTableName;
179
180 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, sql.c_str()));
181
182 std::vector<OfflinePageItem> result;
183 while (statement.Step()) {
184 result.push_back(MakeOfflinePageItem(&statement));
185 }
186
187 if (!statement.Succeeded()) {
188 NotifyLoadResult(callback, STORE_INIT_FAILED,
fgorski 2016/03/24 16:27:55 STORE_LOAD_FAILED?
bburns 2016/03/25 23:07:37 Done.
189 std::vector<OfflinePageItem>());
190 }
fgorski 2016/03/24 16:27:55 When do we notify of LOAD_SUCCEEDED?
bburns 2016/03/25 23:07:37 Done.
191 }
192
193 void OfflinePageMetadataStoreSQL::AddOrUpdateOfflinePageSync(
194 const OfflinePageItem& offline_page,
195 const UpdateCallback& callback) {
196 bool ok = InsertOrReplace(db_.get(), offline_page);
197 callback.Run(ok);
fgorski 2016/03/24 16:27:54 you are on the background_task_runner_ here I don'
bburns 2016/03/25 23:07:38 Done.
198 }
199
200 void OfflinePageMetadataStoreSQL::RemoveOfflinePagesSync(
201 const std::vector<int64_t>& offline_ids,
202 const UpdateCallback& callback) {
203 sql::Transaction transaction(db_.get());
204
205 for (auto offline_id : offline_ids) {
206 if (!DeleteOfflineId(db_.get(), offline_id)) {
fgorski 2016/03/24 16:27:54 will this cancel the whole transaction if nothing
bburns 2016/03/25 23:07:37 Fixed with an early exit.
207 callback.Run(false);
208 return;
209 }
210 }
211
212 if (!transaction.Commit()) {
213 callback.Run(false);
214 }
215 callback.Run(true);
216 }
217
218 void OfflinePageMetadataStoreSQL::Reset(const ResetCallback& callback) {
219 bool success = DropTable(db_.get(), kTableName);
220 callback.Run(success);
221 }
222
223 void OfflinePageMetadataStoreSQL::NotifyLoadResult(
224 const LoadCallback& callback,
225 LoadStatus status,
226 const std::vector<OfflinePageItem>& result) {
fgorski 2016/03/24 16:27:55 probably worth adding UMA histogram for load time.
bburns 2016/03/25 23:07:37 As above working on getting UMA together.
227 UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus", status,
228 OfflinePageMetadataStore::LOAD_STATUS_COUNT);
229 if (status == LOAD_SUCCEEDED) {
230 UMA_HISTOGRAM_COUNTS("OfflinePages.SavedPageCount", result.size());
231 } else {
232 DVLOG(1) << "Offline pages database loading failed: " << status;
233 db_.reset();
234 }
235 callback.Run(status, result);
236 }
237
238 void OfflinePageMetadataStoreSQL::Load(const LoadCallback& callback) {
239 background_task_runner_->PostTask(
240 FROM_HERE, base::Bind(&OfflinePageMetadataStoreSQL::LoadSync,
241 weak_ptr_factory_.GetWeakPtr(), callback));
fgorski 2016/03/24 16:27:54 applies to next 3 calls: which thread is callback
bburns 2016/03/25 23:07:37 Done.
242 }
243
244 void OfflinePageMetadataStoreSQL::AddOrUpdateOfflinePage(
245 const OfflinePageItem& offline_page,
246 const UpdateCallback& callback) {
247 background_task_runner_->PostTask(
248 FROM_HERE,
249 base::Bind(&OfflinePageMetadataStoreSQL::AddOrUpdateOfflinePageSync,
250 weak_ptr_factory_.GetWeakPtr(), offline_page, callback));
251 }
252
253 void OfflinePageMetadataStoreSQL::RemoveOfflinePages(
254 const std::vector<int64_t>& offline_ids,
255 const UpdateCallback& callback) {
256 background_task_runner_->PostTask(
257 FROM_HERE,
258 base::Bind(&OfflinePageMetadataStoreSQL::RemoveOfflinePagesSync,
259 weak_ptr_factory_.GetWeakPtr(), offline_ids, callback));
260 }
261
262 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698