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

Side by Side Diff: sql/recovery.cc

Issue 18180013: Scoped recovery module for sql/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Oops, add recover_unittest.cc Created 7 years, 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 "sql/recovery.h"
6
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "sql/connection.h"
10 #include "third_party/sqlite/sqlite3.h"
11
12 namespace sql {
13
14 Recovery::Recovery(Connection* connection)
15 : db_(connection),
16 recover_db_(),
17 attach_(&recover_db_) {
18 // TODO(shess): Consider only applying this for small databases.
19
20 // Result should keep the page size specified earlier.
21 if (db_->page_size_)
22 recover_db_.set_page_size(db_->page_size_);
23 }
24
25 Recovery::~Recovery() {
26 if (db_)
27 Unrecoverable();
28 }
29
30 bool Recovery::Open(const base::FilePath& db_path) {
31 // Prevent re-entrancy if some call to db_ happens to fail.
32 // TODO(shess): Should this be scoped? Should the caller manage it?
33 db_->reset_error_callback();
34
35 if (!recover_db_.OpenTemporary())
36 return false;
37
38 // Turn on |SQLITE_RecoveryMode|, which allows reading certain
39 // broken databases.
40 // TODO(shess): Double-check that this works for attached dbs.
41 if (!recover_db_.Execute("PRAGMA writable_schema=1")) {
42 recover_db_.Close();
43 return false;
44 }
45
46 // Break any outstanding transactions on original database to
47 // prevent deadlocks reading through the attached version.
48 // TODO(shess): A client may legitimately wish to recover from
49 // within the transaction context, because it would potentially
50 // preserve the in-process changes. Unfortunately, any attach-based
51 // system could not handle that. A system which manually queried
52 // one database and stored to the other could.
53 db_->RollbackAllTransactions();
54
55 if (!attach_.Attach(db_path, "corrupt")) {
56 recover_db_.Close();
57 return false;
58 }
59
60 return true;
61 }
62
63 void Recovery::Unrecoverable() {
64 CHECK(db_);
65 attach_.Detach();
66 recover_db_.Close();
67 db_->RazeAndClose();
68 db_ = NULL;
69 }
70
71 bool Recovery::Recovered() {
72 CHECK(db_);
73 CHECK(recover_db_.is_open());
74
75 sqlite3_backup* backup = sqlite3_backup_init(db_->db_, "main",
76 recover_db_.db_, "main");
77 if (!backup) {
78 LOG(ERROR) << "Failed to make backup?";
79 return false;
80 }
81
82 // -1 backs up the entire database.
83 int rc = sqlite3_backup_step(backup, -1);
84 int pages = sqlite3_backup_pagecount(backup);
85 sqlite3_backup_finish(backup);
86 DCHECK_GT(pages, 0);
87
88 // The destination database was locked.
89 if (rc == SQLITE_BUSY) {
90 // TODO(shess): Ignore it? What if it's ALWAYS locked? If it's
91 // locked, it probably can't be deleted, either, and Raze() will
92 // fail the same way.
93 attach_.Detach();
94 recover_db_.Close();
95 db_->CloseAndPoison();
96 db_ = NULL;
97 return false;
98 }
99
100 // It is unclear what errors are possible at this point, and how to
101 // handle them. Some could perhaps be resolved with a future retry,
102 // but it is unclear how that could possibly work.
103 // TODO(shess): I wonder about try/sleep/try :-).
104 if (rc != SQLITE_DONE) {
105 attach_.Detach();
106 recover_db_.Close();
107 db_->RazeAndClose();
108 db_ = NULL;
109 return false;
110 }
111
112 // Clean up the recovery db, and terminate the main database
113 // connection.
114 attach_.Detach();
115 recover_db_.Close();
116 db_->CloseAndPoison();
117 db_ = NULL;
118 return true;
119 }
120
121 } // namespace sql
OLDNEW
« sql/recovery.h ('K') | « sql/recovery.h ('k') | sql/scoped_attach.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698