OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/omnibox/browser/shortcuts_database.h" | 5 #include "components/omnibox/browser/shortcuts_database.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | |
9 #include "base/guid.h" | 10 #include "base/guid.h" |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
12 #include "base/time/time.h" | 13 #include "base/time/time.h" |
13 #include "components/omnibox/browser/autocomplete_match_type.h" | 14 #include "components/omnibox/browser/autocomplete_match_type.h" |
14 #include "sql/meta_table.h" | 15 #include "sql/meta_table.h" |
16 #include "sql/recovery.h" | |
15 #include "sql/statement.h" | 17 #include "sql/statement.h" |
16 #include "sql/transaction.h" | 18 #include "sql/transaction.h" |
17 #include "ui/base/page_transition_types.h" | 19 #include "ui/base/page_transition_types.h" |
18 | 20 |
19 | 21 |
20 // Helpers -------------------------------------------------------------------- | 22 // Helpers -------------------------------------------------------------------- |
21 | 23 |
22 namespace { | 24 namespace { |
23 | 25 |
24 // Current version number. We write databases at the "current" version number, | 26 // Current version number. We write databases at the "current" version number, |
(...skipping 23 matching lines...) Expand all Loading... | |
48 bool DeleteShortcut(const char* field_name, | 50 bool DeleteShortcut(const char* field_name, |
49 const std::string& id, | 51 const std::string& id, |
50 sql::Connection& db) { | 52 sql::Connection& db) { |
51 sql::Statement s(db.GetUniqueStatement( | 53 sql::Statement s(db.GetUniqueStatement( |
52 base::StringPrintf("DELETE FROM omni_box_shortcuts WHERE %s = ?", | 54 base::StringPrintf("DELETE FROM omni_box_shortcuts WHERE %s = ?", |
53 field_name).c_str())); | 55 field_name).c_str())); |
54 s.BindString(0, id); | 56 s.BindString(0, id); |
55 return s.Run(); | 57 return s.Run(); |
56 } | 58 } |
57 | 59 |
60 void DatabaseErrorCallback(sql::Connection* db, | |
61 const base::FilePath& db_path, | |
62 int extended_error, | |
63 sql::Statement* stmt) { | |
64 // Attempt to fix corrupt databases. SQLITE_CANTOPEN and SQLITE_NOTADB | |
65 // generally mean that the file doesn't even look like a SQLite database, for | |
66 // instance if the header is broken, but there are a few cases that can be | |
67 // recovered. SQLITE_CORRUPT generally means that data within the database | |
68 // contradicts itself, but SQLite is able to read it. | |
Mark P
2016/04/07 23:09:43
Do you want this explanation here rather than than
Scott Hess - ex-Googler
2016/04/15 00:38:14
Acknowledged.
| |
69 // TODO(shess): At least some of the SQLITE_IOERR cases might be cleared by | |
70 // this, too. Probable loss of data, but the disk block is unlikely to fix | |
71 // itself. | |
Mark P
2016/04/07 23:09:43
ditto about this TODO
Scott Hess - ex-Googler
2016/04/15 00:38:14
Leftover from when the code checked directly again
| |
72 if (sql::Recovery::ShouldRecoverOrRaze(extended_error)) { | |
73 // Prevent reentrant calls. | |
74 db->reset_error_callback(); | |
75 | |
76 // Attempt to recover the database by creating a new database with the | |
77 // schema from the current database, and copying over as much of the data as | |
78 // possible. Then restore the new database over the original. If the | |
79 // database is unreadable, the new database will be empty. | |
80 // | |
81 // After this call, the |db| handle is poisoned so that future calls will | |
82 // return errors until the handle is re-opened. | |
Mark P
2016/04/07 23:09:43
This comment duplicates much of the comment by the
Scott Hess - ex-Googler
2016/04/15 00:38:14
OK. Leaving the last line, because IMHO it's pert
| |
83 sql::Recovery::RecoverDatabaseOrRaze(db, db_path); | |
84 } | |
85 | |
86 // The default handling is to assert on debug and to ignore on release. | |
87 if (!sql::Connection::ShouldIgnoreSqliteError(extended_error)) | |
Mark P
2016/04/07 23:09:43
Do you still want to run this code / possibly disp
Scott Hess - ex-Googler
2016/04/15 00:38:14
I'll have to think about this. Corruption general
| |
88 DLOG(FATAL) << db->GetErrorMessage(); | |
89 } | |
90 | |
58 } // namespace | 91 } // namespace |
59 | 92 |
60 // ShortcutsDatabase::Shortcut::MatchCore ------------------------------------- | 93 // ShortcutsDatabase::Shortcut::MatchCore ------------------------------------- |
61 | 94 |
62 ShortcutsDatabase::Shortcut::MatchCore::MatchCore( | 95 ShortcutsDatabase::Shortcut::MatchCore::MatchCore( |
63 const base::string16& fill_into_edit, | 96 const base::string16& fill_into_edit, |
64 const GURL& destination_url, | 97 const GURL& destination_url, |
65 const base::string16& contents, | 98 const base::string16& contents, |
66 const std::string& contents_class, | 99 const std::string& contents_class, |
67 const base::string16& description, | 100 const base::string16& description, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
116 | 149 |
117 // ShortcutsDatabase ---------------------------------------------------------- | 150 // ShortcutsDatabase ---------------------------------------------------------- |
118 | 151 |
119 ShortcutsDatabase::ShortcutsDatabase(const base::FilePath& database_path) | 152 ShortcutsDatabase::ShortcutsDatabase(const base::FilePath& database_path) |
120 : database_path_(database_path) { | 153 : database_path_(database_path) { |
121 } | 154 } |
122 | 155 |
123 bool ShortcutsDatabase::Init() { | 156 bool ShortcutsDatabase::Init() { |
124 db_.set_histogram_tag("Shortcuts"); | 157 db_.set_histogram_tag("Shortcuts"); |
125 | 158 |
159 // To recover from corruption. | |
160 db_.set_error_callback( | |
161 base::Bind(&DatabaseErrorCallback, &db_, database_path_)); | |
162 | |
126 // Set the database page size to something a little larger to give us | 163 // Set the database page size to something a little larger to give us |
127 // better performance (we're typically seek rather than bandwidth limited). | 164 // better performance (we're typically seek rather than bandwidth limited). |
128 // This only has an effect before any tables have been created, otherwise | 165 // This only has an effect before any tables have been created, otherwise |
129 // this is a NOP. Must be a power of 2 and a max of 8192. | 166 // this is a NOP. Must be a power of 2 and a max of 8192. |
130 db_.set_page_size(4096); | 167 db_.set_page_size(4096); |
131 | 168 |
132 // Run the database in exclusive mode. Nobody else should be accessing the | 169 // Run the database in exclusive mode. Nobody else should be accessing the |
133 // database while we're running, and this will give somewhat improved perf. | 170 // database while we're running, and this will give somewhat improved perf. |
134 db_.set_exclusive_locking(); | 171 db_.set_exclusive_locking(); |
135 | 172 |
136 // Attach the database to our index file. | 173 // Attach the database to our index file. |
174 // TODO(shess): The return value is never checked, so failures will never be | |
175 // addressed. Someone needs to handle invalid schema. | |
Mark P
2016/04/07 23:09:43
This shouldn't be a comment. File a bug against p
Scott Hess - ex-Googler
2016/04/15 00:38:14
OK. Adding http://crbug.com/603304 about this. I
| |
137 return db_.Open(database_path_) && EnsureTable(); | 176 return db_.Open(database_path_) && EnsureTable(); |
138 } | 177 } |
139 | 178 |
140 bool ShortcutsDatabase::AddShortcut(const Shortcut& shortcut) { | 179 bool ShortcutsDatabase::AddShortcut(const Shortcut& shortcut) { |
141 sql::Statement s(db_.GetCachedStatement( | 180 sql::Statement s(db_.GetCachedStatement( |
142 SQL_FROM_HERE, | 181 SQL_FROM_HERE, |
143 "INSERT INTO omni_box_shortcuts (id, text, fill_into_edit, url, " | 182 "INSERT INTO omni_box_shortcuts (id, text, fill_into_edit, url, " |
144 "contents, contents_class, description, description_class, " | 183 "contents, contents_class, description, description_class, " |
145 "transition, type, keyword, last_access_time, number_of_hits) " | 184 "transition, type, keyword, last_access_time, number_of_hits) " |
146 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)")); | 185 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)")); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 "UPDATE omni_box_shortcuts SET type = %d", | 289 "UPDATE omni_box_shortcuts SET type = %d", |
251 static_cast<int>(AutocompleteMatchType::HISTORY_TITLE)).c_str()) && | 290 static_cast<int>(AutocompleteMatchType::HISTORY_TITLE)).c_str()) && |
252 db_.Execute("ALTER TABLE omni_box_shortcuts " | 291 db_.Execute("ALTER TABLE omni_box_shortcuts " |
253 "ADD COLUMN keyword VARCHAR") && | 292 "ADD COLUMN keyword VARCHAR") && |
254 transaction.Commit())) { | 293 transaction.Commit())) { |
255 return false; | 294 return false; |
256 } | 295 } |
257 } | 296 } |
258 | 297 |
259 if (!sql::MetaTable::DoesTableExist(&db_)) { | 298 if (!sql::MetaTable::DoesTableExist(&db_)) { |
260 meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber); | |
261 sql::Transaction transaction(&db_); | 299 sql::Transaction transaction(&db_); |
262 if (!(transaction.Begin() && | 300 if (!(transaction.Begin() && |
263 // Migrate old SEARCH_OTHER_ENGINE values to the new type value. | 301 meta_table_.Init( |
264 db_.Execute(base::StringPrintf("UPDATE omni_box_shortcuts " | 302 &db_, kCurrentVersionNumber, kCompatibleVersionNumber) && |
265 "SET type = 13 WHERE type = 9").c_str()) && | 303 // Migrate old SEARCH_OTHER_ENGINE values to the new type value. |
266 // Migrate old EXTENSION_APP values to the new type value. | 304 db_.Execute( |
267 db_.Execute(base::StringPrintf("UPDATE omni_box_shortcuts " | 305 "UPDATE omni_box_shortcuts SET type = 13 WHERE type = 9") && |
268 "SET type = 14 WHERE type = 10").c_str()) && | 306 // Migrate old EXTENSION_APP values to the new type value. |
269 // Migrate old CONTACT values to the new type value. | 307 db_.Execute( |
270 db_.Execute(base::StringPrintf("UPDATE omni_box_shortcuts " | 308 "UPDATE omni_box_shortcuts SET type = 14 WHERE type = 10") && |
271 "SET type = 15 WHERE type = 11").c_str()) && | 309 // Migrate old CONTACT values to the new type value. |
272 // Migrate old BOOKMARK_TITLE values to the new type value. | 310 db_.Execute( |
273 db_.Execute(base::StringPrintf("UPDATE omni_box_shortcuts " | 311 "UPDATE omni_box_shortcuts SET type = 15 WHERE type = 11") && |
274 "SET type = 16 WHERE type = 12").c_str()) && | 312 // Migrate old BOOKMARK_TITLE values to the new type value. |
275 transaction.Commit())) { | 313 db_.Execute( |
314 "UPDATE omni_box_shortcuts SET type = 16 WHERE type = 12") && | |
315 transaction.Commit())) { | |
276 return false; | 316 return false; |
277 } | 317 } |
278 } | 318 } |
279 return true; | 319 return true; |
280 } | 320 } |
OLD | NEW |