OLD | NEW |
---|---|
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" |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
101 | 101 |
102 // Failed to recover an individual table. | 102 // Failed to recover an individual table. |
103 RECOVERY_FAILED_AUTORECOVERDB_TABLE, | 103 RECOVERY_FAILED_AUTORECOVERDB_TABLE, |
104 | 104 |
105 // Failed to recover [sqlite_sequence] table. | 105 // Failed to recover [sqlite_sequence] table. |
106 RECOVERY_FAILED_AUTORECOVERDB_SEQUENCE, | 106 RECOVERY_FAILED_AUTORECOVERDB_SEQUENCE, |
107 | 107 |
108 // Failed to recover triggers or views or virtual tables. | 108 // Failed to recover triggers or views or virtual tables. |
109 RECOVERY_FAILED_AUTORECOVERDB_AUX, | 109 RECOVERY_FAILED_AUTORECOVERDB_AUX, |
110 | 110 |
111 // After SQLITE_NOTADB failure setting up for recovery, Delete() failed. | |
112 RECOVERY_FAILED_AUTORECOVERDB_NOTADB_DELETE, | |
113 | |
114 // After SQLITE_NOTADB failure setting up for recovery, Delete() succeeded | |
115 // then Open() failed. | |
116 RECOVERY_FAILED_AUTORECOVERDB_NOTADB_REOPEN, | |
117 | |
118 // After SQLITE_NOTADB failure setting up for recovery, Delete() and Open() | |
119 // succeeded, then querying the database failed. | |
120 RECOVERY_FAILED_AUTORECOVERDB_NOTADB_QUERY, | |
121 | |
122 // After SQLITE_NOTADB failure setting up for recovery, the database was | |
123 // successfully deleted. | |
124 RECOVERY_SUCCESS_AUTORECOVERDB_NOTADB_DELETE, | |
125 | |
111 // Always keep this at the end. | 126 // Always keep this at the end. |
112 RECOVERY_EVENT_MAX, | 127 RECOVERY_EVENT_MAX, |
113 }; | 128 }; |
114 | 129 |
115 void RecordRecoveryEvent(RecoveryEventType recovery_event) { | 130 void RecordRecoveryEvent(RecoveryEventType recovery_event) { |
116 UMA_HISTOGRAM_ENUMERATION("Sqlite.RecoveryEvents", | 131 UMA_HISTOGRAM_ENUMERATION("Sqlite.RecoveryEvents", |
117 recovery_event, RECOVERY_EVENT_MAX); | 132 recovery_event, RECOVERY_EVENT_MAX); |
118 } | 133 } |
119 | 134 |
120 } // namespace | 135 } // namespace |
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
581 // TODO(shess): This conservatively uses Rollback() rather than Unrecoverable(). | 596 // TODO(shess): This conservatively uses Rollback() rather than Unrecoverable(). |
582 // With Rollback(), it is expected that the database will continue to generate | 597 // With Rollback(), it is expected that the database will continue to generate |
583 // errors. Change the failure cases to Unrecoverable() if/when histogram | 598 // errors. Change the failure cases to Unrecoverable() if/when histogram |
584 // results indicate that everything is working reasonably. | 599 // results indicate that everything is working reasonably. |
585 // | 600 // |
586 // static | 601 // static |
587 void Recovery::RecoverDatabase(Connection* db, | 602 void Recovery::RecoverDatabase(Connection* db, |
588 const base::FilePath& db_path) { | 603 const base::FilePath& db_path) { |
589 std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path); | 604 std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path); |
590 if (!recovery) { | 605 if (!recovery) { |
591 // TODO(shess): If recovery can't even get started, Raze() or Delete(). | 606 // Close the underlying sqlite* handle. Windows does not allow deleting |
592 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_BEGIN); | 607 // open files, and all platforms block opening a second sqlite3* handle |
608 // against a database when exclusive locking is set. | |
593 db->Poison(); | 609 db->Poison(); |
610 | |
611 // Histograms from Recovery::Begin() show all current failures are in | |
pwnall
2017/02/27 23:54:51
This is a really helpful comment! Thank you!
| |
612 // attaching the corrupt database, with 2/3 being SQLITE_NOTADB. Don't | |
613 // delete the database except for that specific failure case. | |
614 { | |
615 Connection probe_db; | |
616 if (!probe_db.OpenInMemory() || | |
617 probe_db.AttachDatabase(db_path, "corrupt") || | |
618 probe_db.GetErrorCode() != SQLITE_NOTADB) { | |
619 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_BEGIN); | |
620 return; | |
621 } | |
622 } | |
623 | |
624 // The database has invalid data in the SQLite header, so it is almost | |
625 // certainly not recoverable without manual intervention (and likely not | |
626 // recoverable _with_ manual intervention). Clear away the broken database. | |
627 if (!sql::Connection::Delete(db_path)) { | |
628 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_DELETE); | |
629 return; | |
630 } | |
631 | |
632 // Query to verify that the database no longer throws SQLITE_NOTADB. | |
633 { | |
634 Connection probe_db; | |
635 if (!probe_db.Open(db_path)) { | |
636 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_REOPEN); | |
637 return; | |
638 } | |
639 if (!probe_db.Execute("PRAGMA auto_vacuum")) { | |
640 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_QUERY); | |
641 return; | |
642 } | |
643 } | |
644 | |
645 // The rest of the recovery code could be run on the re-opened database, but | |
646 // the database is empty, so there would be no point. | |
647 RecordRecoveryEvent(RECOVERY_SUCCESS_AUTORECOVERDB_NOTADB_DELETE); | |
594 return; | 648 return; |
595 } | 649 } |
596 | 650 |
597 #if DCHECK_IS_ON() | 651 #if DCHECK_IS_ON() |
598 // This code silently fails to recover fts3 virtual tables. At this time no | 652 // 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 | 653 // browser database contain fts3 tables. Just to be safe, complain loudly if |
600 // the database contains virtual tables. | 654 // the database contains virtual tables. |
601 // | 655 // |
602 // fts3 has an [x_segdir] table containing a column [end_block INTEGER]. But | 656 // 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 | 657 // 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 Loading... | |
706 // - SQLITE_READONLY - permissions could be fixed. | 760 // - SQLITE_READONLY - permissions could be fixed. |
707 // - SQLITE_IOERR - rewrite using new blocks. | 761 // - SQLITE_IOERR - rewrite using new blocks. |
708 // - SQLITE_FULL - recover in memory and rewrite subset of data. | 762 // - SQLITE_FULL - recover in memory and rewrite subset of data. |
709 | 763 |
710 default: | 764 default: |
711 return false; | 765 return false; |
712 } | 766 } |
713 } | 767 } |
714 | 768 |
715 } // namespace sql | 769 } // namespace sql |
OLD | NEW |