Chromium Code Reviews| 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 |