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

Side by Side Diff: sql/recovery.cc

Issue 2710823005: [sql] RecoverDatabase() deletes SQLITE_NOTADB databases. (Closed)
Patch Set: Comment on enum required to match histogram enumeration. Created 3 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
« no previous file with comments | « sql/recovery.h ('k') | sql/recovery_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "sql/recovery.h" 5 #include "sql/recovery.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/format_macros.h" 10 #include "base/format_macros.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
13 #include "base/metrics/sparse_histogram.h" 13 #include "base/metrics/sparse_histogram.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
16 #include "sql/connection.h" 16 #include "sql/connection.h"
17 #include "sql/statement.h" 17 #include "sql/statement.h"
18 #include "third_party/sqlite/sqlite3.h" 18 #include "third_party/sqlite/sqlite3.h"
19 #include "third_party/sqlite/src/src/recover.h" 19 #include "third_party/sqlite/src/src/recover.h"
20 20
21 namespace sql { 21 namespace sql {
22 22
23 namespace { 23 namespace {
24 24
25 // This enum must match the numbering for Sqlite.RecoveryEvents in
26 // histograms.xml. Do not reorder or remove items, only add new items before
27 // RECOVERY_EVENT_MAX.
25 enum RecoveryEventType { 28 enum RecoveryEventType {
26 // Init() completed successfully. 29 // Init() completed successfully.
27 RECOVERY_SUCCESS_INIT = 0, 30 RECOVERY_SUCCESS_INIT = 0,
28 31
29 // Failed to open temporary database to recover into. 32 // Failed to open temporary database to recover into.
30 RECOVERY_FAILED_OPEN_TEMPORARY, 33 RECOVERY_FAILED_OPEN_TEMPORARY,
31 34
32 // Failed to initialize recover vtable system. 35 // Failed to initialize recover vtable system.
33 RECOVERY_FAILED_VIRTUAL_TABLE_INIT, 36 RECOVERY_FAILED_VIRTUAL_TABLE_INIT,
34 37
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 104
102 // Failed to recover an individual table. 105 // Failed to recover an individual table.
103 RECOVERY_FAILED_AUTORECOVERDB_TABLE, 106 RECOVERY_FAILED_AUTORECOVERDB_TABLE,
104 107
105 // Failed to recover [sqlite_sequence] table. 108 // Failed to recover [sqlite_sequence] table.
106 RECOVERY_FAILED_AUTORECOVERDB_SEQUENCE, 109 RECOVERY_FAILED_AUTORECOVERDB_SEQUENCE,
107 110
108 // Failed to recover triggers or views or virtual tables. 111 // Failed to recover triggers or views or virtual tables.
109 RECOVERY_FAILED_AUTORECOVERDB_AUX, 112 RECOVERY_FAILED_AUTORECOVERDB_AUX,
110 113
111 // Always keep this at the end. 114 // After SQLITE_NOTADB failure setting up for recovery, Delete() failed.
115 RECOVERY_FAILED_AUTORECOVERDB_NOTADB_DELETE,
116
117 // After SQLITE_NOTADB failure setting up for recovery, Delete() succeeded
118 // then Open() failed.
119 RECOVERY_FAILED_AUTORECOVERDB_NOTADB_REOPEN,
120
121 // After SQLITE_NOTADB failure setting up for recovery, Delete() and Open()
122 // succeeded, then querying the database failed.
123 RECOVERY_FAILED_AUTORECOVERDB_NOTADB_QUERY,
124
125 // After SQLITE_NOTADB failure setting up for recovery, the database was
126 // successfully deleted.
127 RECOVERY_SUCCESS_AUTORECOVERDB_NOTADB_DELETE,
128
129 // Add new items before this one, always keep this one at the end.
112 RECOVERY_EVENT_MAX, 130 RECOVERY_EVENT_MAX,
113 }; 131 };
114 132
115 void RecordRecoveryEvent(RecoveryEventType recovery_event) { 133 void RecordRecoveryEvent(RecoveryEventType recovery_event) {
116 UMA_HISTOGRAM_ENUMERATION("Sqlite.RecoveryEvents", 134 UMA_HISTOGRAM_ENUMERATION("Sqlite.RecoveryEvents",
117 recovery_event, RECOVERY_EVENT_MAX); 135 recovery_event, RECOVERY_EVENT_MAX);
118 } 136 }
119 137
120 } // namespace 138 } // namespace
121 139
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 // TODO(shess): This conservatively uses Rollback() rather than Unrecoverable(). 599 // TODO(shess): This conservatively uses Rollback() rather than Unrecoverable().
582 // With Rollback(), it is expected that the database will continue to generate 600 // With Rollback(), it is expected that the database will continue to generate
583 // errors. Change the failure cases to Unrecoverable() if/when histogram 601 // errors. Change the failure cases to Unrecoverable() if/when histogram
584 // results indicate that everything is working reasonably. 602 // results indicate that everything is working reasonably.
585 // 603 //
586 // static 604 // static
587 void Recovery::RecoverDatabase(Connection* db, 605 void Recovery::RecoverDatabase(Connection* db,
588 const base::FilePath& db_path) { 606 const base::FilePath& db_path) {
589 std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path); 607 std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
590 if (!recovery) { 608 if (!recovery) {
591 // TODO(shess): If recovery can't even get started, Raze() or Delete(). 609 // Close the underlying sqlite* handle. Windows does not allow deleting
592 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_BEGIN); 610 // open files, and all platforms block opening a second sqlite3* handle
611 // against a database when exclusive locking is set.
593 db->Poison(); 612 db->Poison();
613
614 // Histograms from Recovery::Begin() show all current failures are in
615 // attaching the corrupt database, with 2/3 being SQLITE_NOTADB. Don't
616 // delete the database except for that specific failure case.
617 {
618 Connection probe_db;
619 if (!probe_db.OpenInMemory() ||
620 probe_db.AttachDatabase(db_path, "corrupt") ||
621 probe_db.GetErrorCode() != SQLITE_NOTADB) {
622 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_BEGIN);
623 return;
624 }
625 }
626
627 // The database has invalid data in the SQLite header, so it is almost
628 // certainly not recoverable without manual intervention (and likely not
629 // recoverable _with_ manual intervention). Clear away the broken database.
630 if (!sql::Connection::Delete(db_path)) {
631 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_DELETE);
632 return;
633 }
634
635 // Windows deletion is complicated by file scanners and malware - sometimes
636 // Delete() appears to succeed, even though the file remains. The following
637 // attempts to track if this happens often enough to cause concern.
638 {
639 Connection probe_db;
640 if (!probe_db.Open(db_path)) {
641 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_REOPEN);
642 return;
643 }
644 if (!probe_db.Execute("PRAGMA auto_vacuum")) {
645 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_QUERY);
646 return;
647 }
648 }
649
650 // The rest of the recovery code could be run on the re-opened database, but
651 // the database is empty, so there would be no point.
652 RecordRecoveryEvent(RECOVERY_SUCCESS_AUTORECOVERDB_NOTADB_DELETE);
594 return; 653 return;
595 } 654 }
596 655
597 #if DCHECK_IS_ON() 656 #if DCHECK_IS_ON()
598 // This code silently fails to recover fts3 virtual tables. At this time no 657 // This code silently fails to recover fts3 virtual tables. At this time no
599 // browser database contain fts3 tables. Just to be safe, complain loudly if 658 // browser database contain fts3 tables. Just to be safe, complain loudly if
600 // the database contains virtual tables. 659 // the database contains virtual tables.
601 // 660 //
602 // fts3 has an [x_segdir] table containing a column [end_block INTEGER]. But 661 // fts3 has an [x_segdir] table containing a column [end_block INTEGER]. But
603 // it actually stores either an integer or a text containing a pair of 662 // it actually stores either an integer or a text containing a pair of
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
706 // - SQLITE_READONLY - permissions could be fixed. 765 // - SQLITE_READONLY - permissions could be fixed.
707 // - SQLITE_IOERR - rewrite using new blocks. 766 // - SQLITE_IOERR - rewrite using new blocks.
708 // - SQLITE_FULL - recover in memory and rewrite subset of data. 767 // - SQLITE_FULL - recover in memory and rewrite subset of data.
709 768
710 default: 769 default:
711 return false; 770 return false;
712 } 771 }
713 } 772 }
714 773
715 } // namespace sql 774 } // namespace sql
OLDNEW
« no previous file with comments | « sql/recovery.h ('k') | sql/recovery_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698