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

Side by Side Diff: content/browser/dom_storage/dom_storage_database.cc

Issue 22297005: Move webkit/{browser,common}/dom_storage into content/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 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
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 "webkit/browser/dom_storage/dom_storage_database.h" 5 #include "content/browser/dom_storage/dom_storage_database.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "sql/statement.h" 10 #include "sql/statement.h"
11 #include "sql/transaction.h" 11 #include "sql/transaction.h"
12 #include "third_party/sqlite/sqlite3.h" 12 #include "third_party/sqlite/sqlite3.h"
13 13
14 namespace { 14 namespace {
15 15
16 const base::FilePath::CharType kJournal[] = FILE_PATH_LITERAL("-journal"); 16 const base::FilePath::CharType kJournal[] = FILE_PATH_LITERAL("-journal");
17 17
18 } // anon namespace 18 } // anon namespace
19 19
20 namespace dom_storage { 20 namespace content {
21 21
22 // static 22 // static
23 base::FilePath DomStorageDatabase::GetJournalFilePath( 23 base::FilePath DOMStorageDatabase::GetJournalFilePath(
24 const base::FilePath& database_path) { 24 const base::FilePath& database_path) {
25 base::FilePath::StringType journal_file_name = 25 base::FilePath::StringType journal_file_name =
26 database_path.BaseName().value() + kJournal; 26 database_path.BaseName().value() + kJournal;
27 return database_path.DirName().Append(journal_file_name); 27 return database_path.DirName().Append(journal_file_name);
28 } 28 }
29 29
30 DomStorageDatabase::DomStorageDatabase(const base::FilePath& file_path) 30 DOMStorageDatabase::DOMStorageDatabase(const base::FilePath& file_path)
31 : file_path_(file_path) { 31 : file_path_(file_path) {
32 // Note: in normal use we should never get an empty backing path here. 32 // Note: in normal use we should never get an empty backing path here.
33 // However, the unit test for this class can contruct an instance 33 // However, the unit test for this class can contruct an instance
34 // with an empty path. 34 // with an empty path.
35 Init(); 35 Init();
36 } 36 }
37 37
38 DomStorageDatabase::DomStorageDatabase() { 38 DOMStorageDatabase::DOMStorageDatabase() {
39 Init(); 39 Init();
40 } 40 }
41 41
42 void DomStorageDatabase::Init() { 42 void DOMStorageDatabase::Init() {
43 failed_to_open_ = false; 43 failed_to_open_ = false;
44 tried_to_recreate_ = false; 44 tried_to_recreate_ = false;
45 known_to_be_empty_ = false; 45 known_to_be_empty_ = false;
46 } 46 }
47 47
48 DomStorageDatabase::~DomStorageDatabase() { 48 DOMStorageDatabase::~DOMStorageDatabase() {
49 if (known_to_be_empty_ && !file_path_.empty()) { 49 if (known_to_be_empty_ && !file_path_.empty()) {
50 // Delete the db and any lingering journal file from disk. 50 // Delete the db and any lingering journal file from disk.
51 Close(); 51 Close();
52 sql::Connection::Delete(file_path_); 52 sql::Connection::Delete(file_path_);
53 } 53 }
54 } 54 }
55 55
56 void DomStorageDatabase::ReadAllValues(ValuesMap* result) { 56 void DOMStorageDatabase::ReadAllValues(DOMStorageValuesMap* result) {
57 if (!LazyOpen(false)) 57 if (!LazyOpen(false))
58 return; 58 return;
59 59
60 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, 60 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
61 "SELECT * from ItemTable")); 61 "SELECT * from ItemTable"));
62 DCHECK(statement.is_valid()); 62 DCHECK(statement.is_valid());
63 63
64 while (statement.Step()) { 64 while (statement.Step()) {
65 base::string16 key = statement.ColumnString16(0); 65 base::string16 key = statement.ColumnString16(0);
66 base::string16 value; 66 base::string16 value;
67 statement.ColumnBlobAsString16(1, &value); 67 statement.ColumnBlobAsString16(1, &value);
68 (*result)[key] = base::NullableString16(value, false); 68 (*result)[key] = base::NullableString16(value, false);
69 } 69 }
70 known_to_be_empty_ = result->empty(); 70 known_to_be_empty_ = result->empty();
71 } 71 }
72 72
73 bool DomStorageDatabase::CommitChanges(bool clear_all_first, 73 bool DOMStorageDatabase::CommitChanges(bool clear_all_first,
74 const ValuesMap& changes) { 74 const DOMStorageValuesMap& changes) {
75 if (!LazyOpen(!changes.empty())) { 75 if (!LazyOpen(!changes.empty())) {
76 // If we're being asked to commit changes that will result in an 76 // If we're being asked to commit changes that will result in an
77 // empty database, we return true if the database file doesn't exist. 77 // empty database, we return true if the database file doesn't exist.
78 return clear_all_first && changes.empty() && 78 return clear_all_first && changes.empty() &&
79 !base::PathExists(file_path_); 79 !base::PathExists(file_path_);
80 } 80 }
81 81
82 bool old_known_to_be_empty = known_to_be_empty_; 82 bool old_known_to_be_empty = known_to_be_empty_;
83 sql::Transaction transaction(db_.get()); 83 sql::Transaction transaction(db_.get());
84 if (!transaction.Begin()) 84 if (!transaction.Begin())
85 return false; 85 return false;
86 86
87 if (clear_all_first) { 87 if (clear_all_first) {
88 if (!db_->Execute("DELETE FROM ItemTable")) 88 if (!db_->Execute("DELETE FROM ItemTable"))
89 return false; 89 return false;
90 known_to_be_empty_ = true; 90 known_to_be_empty_ = true;
91 } 91 }
92 92
93 bool did_delete = false; 93 bool did_delete = false;
94 bool did_insert = false; 94 bool did_insert = false;
95 ValuesMap::const_iterator it = changes.begin(); 95 DOMStorageValuesMap::const_iterator it = changes.begin();
96 for(; it != changes.end(); ++it) { 96 for(; it != changes.end(); ++it) {
97 sql::Statement statement; 97 sql::Statement statement;
98 base::string16 key = it->first; 98 base::string16 key = it->first;
99 base::NullableString16 value = it->second; 99 base::NullableString16 value = it->second;
100 if (value.is_null()) { 100 if (value.is_null()) {
101 statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE, 101 statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE,
102 "DELETE FROM ItemTable WHERE key=?")); 102 "DELETE FROM ItemTable WHERE key=?"));
103 statement.BindString16(0, key); 103 statement.BindString16(0, key);
104 did_delete = true; 104 did_delete = true;
105 } else { 105 } else {
(...skipping 15 matching lines...) Expand all
121 if (statement.Step()) 121 if (statement.Step())
122 known_to_be_empty_ = statement.ColumnInt(0) == 0; 122 known_to_be_empty_ = statement.ColumnInt(0) == 0;
123 } 123 }
124 124
125 bool success = transaction.Commit(); 125 bool success = transaction.Commit();
126 if (!success) 126 if (!success)
127 known_to_be_empty_ = old_known_to_be_empty; 127 known_to_be_empty_ = old_known_to_be_empty;
128 return success; 128 return success;
129 } 129 }
130 130
131 bool DomStorageDatabase::LazyOpen(bool create_if_needed) { 131 bool DOMStorageDatabase::LazyOpen(bool create_if_needed) {
132 if (failed_to_open_) { 132 if (failed_to_open_) {
133 // Don't try to open a database that we know has failed 133 // Don't try to open a database that we know has failed
134 // already. 134 // already.
135 return false; 135 return false;
136 } 136 }
137 137
138 if (IsOpen()) 138 if (IsOpen())
139 return true; 139 return true;
140 140
141 bool database_exists = base::PathExists(file_path_); 141 bool database_exists = base::PathExists(file_path_);
142 142
143 if (!database_exists && !create_if_needed) { 143 if (!database_exists && !create_if_needed) {
144 // If the file doesn't exist already and we haven't been asked to create 144 // If the file doesn't exist already and we haven't been asked to create
145 // a file on disk, then we don't bother opening the database. This means 145 // a file on disk, then we don't bother opening the database. This means
146 // we wait until we absolutely need to put something onto disk before we 146 // we wait until we absolutely need to put something onto disk before we
147 // do so. 147 // do so.
148 return false; 148 return false;
149 } 149 }
150 150
151 db_.reset(new sql::Connection()); 151 db_.reset(new sql::Connection());
152 db_->set_histogram_tag("DomStorageDatabase"); 152 db_->set_histogram_tag("DOMStorageDatabase");
153 153
154 if (file_path_.empty()) { 154 if (file_path_.empty()) {
155 // This code path should only be triggered by unit tests. 155 // This code path should only be triggered by unit tests.
156 if (!db_->OpenInMemory()) { 156 if (!db_->OpenInMemory()) {
157 NOTREACHED() << "Unable to open DOM storage database in memory."; 157 NOTREACHED() << "Unable to open DOM storage database in memory.";
158 failed_to_open_ = true; 158 failed_to_open_ = true;
159 return false; 159 return false;
160 } 160 }
161 } else { 161 } else {
162 if (!db_->Open(file_path_)) { 162 if (!db_->Open(file_path_)) {
(...skipping 27 matching lines...) Expand all
190 return true; 190 return true;
191 } 191 }
192 } 192 }
193 193
194 // This is the exceptional case - to try and recover we'll attempt 194 // This is the exceptional case - to try and recover we'll attempt
195 // to delete the file and start again. 195 // to delete the file and start again.
196 Close(); 196 Close();
197 return DeleteFileAndRecreate(); 197 return DeleteFileAndRecreate();
198 } 198 }
199 199
200 DomStorageDatabase::SchemaVersion DomStorageDatabase::DetectSchemaVersion() { 200 DOMStorageDatabase::SchemaVersion DOMStorageDatabase::DetectSchemaVersion() {
201 DCHECK(IsOpen()); 201 DCHECK(IsOpen());
202 202
203 // Connection::Open() may succeed even if the file we try and open is not a 203 // Connection::Open() may succeed even if the file we try and open is not a
204 // database, however in the case that the database is corrupted to the point 204 // database, however in the case that the database is corrupted to the point
205 // that SQLite doesn't actually think it's a database, 205 // that SQLite doesn't actually think it's a database,
206 // sql::Connection::GetCachedStatement will DCHECK when we later try and 206 // sql::Connection::GetCachedStatement will DCHECK when we later try and
207 // run statements. So we run a query here that will not DCHECK but fail 207 // run statements. So we run a query here that will not DCHECK but fail
208 // on an invalid database to verify that what we've opened is usable. 208 // on an invalid database to verify that what we've opened is usable.
209 if (db_->ExecuteAndReturnErrorCode("PRAGMA auto_vacuum") != SQLITE_OK) 209 if (db_->ExecuteAndReturnErrorCode("PRAGMA auto_vacuum") != SQLITE_OK)
210 return INVALID; 210 return INVALID;
(...skipping 15 matching lines...) Expand all
226 return V2; 226 return V2;
227 case sql::COLUMN_TYPE_TEXT: 227 case sql::COLUMN_TYPE_TEXT:
228 return V1; 228 return V1;
229 default: 229 default:
230 return INVALID; 230 return INVALID;
231 } 231 }
232 NOTREACHED(); 232 NOTREACHED();
233 return INVALID; 233 return INVALID;
234 } 234 }
235 235
236 bool DomStorageDatabase::CreateTableV2() { 236 bool DOMStorageDatabase::CreateTableV2() {
237 DCHECK(IsOpen()); 237 DCHECK(IsOpen());
238 238
239 return db_->Execute( 239 return db_->Execute(
240 "CREATE TABLE ItemTable (" 240 "CREATE TABLE ItemTable ("
241 "key TEXT UNIQUE ON CONFLICT REPLACE, " 241 "key TEXT UNIQUE ON CONFLICT REPLACE, "
242 "value BLOB NOT NULL ON CONFLICT FAIL)"); 242 "value BLOB NOT NULL ON CONFLICT FAIL)");
243 } 243 }
244 244
245 bool DomStorageDatabase::DeleteFileAndRecreate() { 245 bool DOMStorageDatabase::DeleteFileAndRecreate() {
246 DCHECK(!IsOpen()); 246 DCHECK(!IsOpen());
247 DCHECK(base::PathExists(file_path_)); 247 DCHECK(base::PathExists(file_path_));
248 248
249 // We should only try and do this once. 249 // We should only try and do this once.
250 if (tried_to_recreate_) 250 if (tried_to_recreate_)
251 return false; 251 return false;
252 252
253 tried_to_recreate_ = true; 253 tried_to_recreate_ = true;
254 254
255 // If it's not a directory and we can delete the file, try and open it again. 255 // If it's not a directory and we can delete the file, try and open it again.
256 if (!base::DirectoryExists(file_path_) && 256 if (!base::DirectoryExists(file_path_) &&
257 sql::Connection::Delete(file_path_)) { 257 sql::Connection::Delete(file_path_)) {
258 return LazyOpen(true); 258 return LazyOpen(true);
259 } 259 }
260 260
261 failed_to_open_ = true; 261 failed_to_open_ = true;
262 return false; 262 return false;
263 } 263 }
264 264
265 bool DomStorageDatabase::UpgradeVersion1To2() { 265 bool DOMStorageDatabase::UpgradeVersion1To2() {
266 DCHECK(IsOpen()); 266 DCHECK(IsOpen());
267 DCHECK(DetectSchemaVersion() == V1); 267 DCHECK(DetectSchemaVersion() == V1);
268 268
269 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, 269 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
270 "SELECT * FROM ItemTable")); 270 "SELECT * FROM ItemTable"));
271 DCHECK(statement.is_valid()); 271 DCHECK(statement.is_valid());
272 272
273 // Need to migrate from TEXT value column to BLOB. 273 // Need to migrate from TEXT value column to BLOB.
274 // Store the current database content so we can re-insert 274 // Store the current database content so we can re-insert
275 // the data into the new V2 table. 275 // the data into the new V2 table.
276 ValuesMap values; 276 DOMStorageValuesMap values;
277 while (statement.Step()) { 277 while (statement.Step()) {
278 base::string16 key = statement.ColumnString16(0); 278 base::string16 key = statement.ColumnString16(0);
279 base::NullableString16 value(statement.ColumnString16(1), false); 279 base::NullableString16 value(statement.ColumnString16(1), false);
280 values[key] = value; 280 values[key] = value;
281 } 281 }
282 282
283 sql::Transaction migration(db_.get()); 283 sql::Transaction migration(db_.get());
284 return migration.Begin() && 284 return migration.Begin() &&
285 db_->Execute("DROP TABLE ItemTable") && 285 db_->Execute("DROP TABLE ItemTable") &&
286 CreateTableV2() && 286 CreateTableV2() &&
287 CommitChanges(false, values) && 287 CommitChanges(false, values) &&
288 migration.Commit(); 288 migration.Commit();
289 } 289 }
290 290
291 void DomStorageDatabase::Close() { 291 void DOMStorageDatabase::Close() {
292 db_.reset(NULL); 292 db_.reset(NULL);
293 } 293 }
294 294
295 } // namespace dom_storage 295 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/dom_storage/dom_storage_database.h ('k') | content/browser/dom_storage/dom_storage_database_adapter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698