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

Side by Side Diff: sql/connection.cc

Issue 17752002: [sql] Additional Raze() unit tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Trim page_size rather than constant size. 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
« no previous file with comments | « no previous file | sql/connection_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 (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 "sql/connection.h" 5 #include "sql/connection.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 sqlite3_exec(db_, "PRAGMA writable_schema=1", NULL, NULL, NULL); 57 sqlite3_exec(db_, "PRAGMA writable_schema=1", NULL, NULL, NULL);
58 } 58 }
59 ~ScopedWritableSchema() { 59 ~ScopedWritableSchema() {
60 sqlite3_exec(db_, "PRAGMA writable_schema=0", NULL, NULL, NULL); 60 sqlite3_exec(db_, "PRAGMA writable_schema=0", NULL, NULL, NULL);
61 } 61 }
62 62
63 private: 63 private:
64 sqlite3* db_; 64 sqlite3* db_;
65 }; 65 };
66 66
67 // Helper to wrap the sqlite3_backup_*() step of Raze(). Return
68 // SQLite error code from running the backup step.
69 int BackupDatabase(sqlite3* src, sqlite3* dst, const char* db_name) {
70 DCHECK_NE(src, dst);
71 sqlite3_backup* backup = sqlite3_backup_init(dst, db_name, src, db_name);
72 if (!backup) {
73 // Since this call only sets things up, this indicates a gross
74 // error in SQLite.
75 DLOG(FATAL) << "Unable to start sqlite3_backup(): " << sqlite3_errmsg(dst);
76 return sqlite3_errcode(dst);
77 }
78
79 // -1 backs up the entire database.
80 int rc = sqlite3_backup_step(backup, -1);
81 int pages = sqlite3_backup_pagecount(backup);
82 sqlite3_backup_finish(backup);
83
84 // If successful, exactly one page should have been backed up. If
85 // this breaks, check this function to make sure assumptions aren't
86 // being broken.
87 if (rc == SQLITE_DONE)
88 DCHECK_EQ(pages, 1);
89
90 return rc;
91 }
92
67 } // namespace 93 } // namespace
68 94
69 namespace sql { 95 namespace sql {
70 96
71 // static 97 // static
72 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL; 98 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL;
73 99
74 // static 100 // static
75 bool Connection::ShouldIgnore(int error) { 101 bool Connection::ShouldIgnore(int error) {
76 if (!current_ignorer_cb_) 102 if (!current_ignorer_cb_)
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 // page, and if it does not match the total retrieved from a 332 // page, and if it does not match the total retrieved from a
307 // filesystem call, treats the database as corrupt. This situation 333 // filesystem call, treats the database as corrupt. This situation
308 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be 334 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be
309 // used to hint to SQLite to soldier on in that case, specifically 335 // used to hint to SQLite to soldier on in that case, specifically
310 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in 336 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in
311 // sqlite3.c lockBtree().] 337 // sqlite3.c lockBtree().]
312 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA 338 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA
313 // page_size" can be used to query such a database. 339 // page_size" can be used to query such a database.
314 ScopedWritableSchema writable_schema(db_); 340 ScopedWritableSchema writable_schema(db_);
315 341
316 sqlite3_backup* backup = sqlite3_backup_init(db_, "main", 342 const char* kMain = "main";
317 null_db.db_, "main"); 343 int rc = BackupDatabase(null_db.db_, db_, kMain);
318 if (!backup) { 344 UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase",rc);
319 DLOG(FATAL) << "Unable to start sqlite3_backup().";
320 return false;
321 }
322
323 // -1 backs up the entire database.
324 int rc = sqlite3_backup_step(backup, -1);
325 int pages = sqlite3_backup_pagecount(backup);
326 sqlite3_backup_finish(backup);
327 345
328 // The destination database was locked. 346 // The destination database was locked.
329 if (rc == SQLITE_BUSY) { 347 if (rc == SQLITE_BUSY) {
330 return false; 348 return false;
331 } 349 }
332 350
351 // SQLITE_NOTADB can happen if page 1 of db_ exists, but is not
352 // formatted correctly. SQLITE_IOERR_SHORT_READ can happen if db_
353 // isn't even big enough for one page. Either way, reach in and
354 // truncate it before trying again.
355 // TODO(shess): Maybe it would be worthwhile to just truncate from
356 // the get-go?
357 if (rc == SQLITE_NOTADB || rc == SQLITE_IOERR_SHORT_READ) {
358 sqlite3_file* file = NULL;
359 rc = sqlite3_file_control(db_, "main", SQLITE_FCNTL_FILE_POINTER, &file);
360 if (rc != SQLITE_OK) {
361 DLOG(FATAL) << "Failure getting file handle.";
362 return false;
363 } else if (!file) {
364 DLOG(FATAL) << "File handle is empty.";
365 return false;
366 }
367
368 rc = file->pMethods->xTruncate(file, 0);
369 if (rc != SQLITE_OK) {
370 UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabaseTruncate",rc);
371 DLOG(FATAL) << "Failed to truncate file.";
372 return false;
373 }
374
375 rc = BackupDatabase(null_db.db_, db_, kMain);
376 UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase2",rc);
377
378 if (rc != SQLITE_DONE) {
379 DLOG(FATAL) << "Failed retrying Raze().";
380 }
381 }
382
333 // The entire database should have been backed up. 383 // The entire database should have been backed up.
334 if (rc != SQLITE_DONE) { 384 if (rc != SQLITE_DONE) {
385 // TODO(shess): Figure out which other cases can happen.
335 DLOG(FATAL) << "Unable to copy entire null database."; 386 DLOG(FATAL) << "Unable to copy entire null database.";
336 return false; 387 return false;
337 } 388 }
338 389
339 // Exactly one page should have been backed up. If this breaks,
340 // check this function to make sure assumptions aren't being broken.
341 DCHECK_EQ(pages, 1);
342
343 return true; 390 return true;
344 } 391 }
345 392
346 bool Connection::RazeWithTimout(base::TimeDelta timeout) { 393 bool Connection::RazeWithTimout(base::TimeDelta timeout) {
347 if (!db_) { 394 if (!db_) {
348 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; 395 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db";
349 return false; 396 return false;
350 } 397 }
351 398
352 ScopedBusyTimeout busy_timeout(db_); 399 ScopedBusyTimeout busy_timeout(db_);
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 return false; 703 return false;
657 } 704 }
658 705
659 // If |poisoned_| is set, it means an error handler called 706 // If |poisoned_| is set, it means an error handler called
660 // RazeAndClose(). Until regular Close() is called, the caller 707 // RazeAndClose(). Until regular Close() is called, the caller
661 // should be treating the database as open, but is_open() currently 708 // should be treating the database as open, but is_open() currently
662 // only considers the sqlite3 handle's state. 709 // only considers the sqlite3 handle's state.
663 // TODO(shess): Revise is_open() to consider poisoned_, and review 710 // TODO(shess): Revise is_open() to consider poisoned_, and review
664 // to see if any non-testing code even depends on it. 711 // to see if any non-testing code even depends on it.
665 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open."; 712 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open.";
713 poisoned_ = false;
666 714
667 int err = sqlite3_open(file_name.c_str(), &db_); 715 int err = sqlite3_open(file_name.c_str(), &db_);
668 if (err != SQLITE_OK) { 716 if (err != SQLITE_OK) {
669 // Histogram failures specific to initial open for debugging 717 // Histogram failures specific to initial open for debugging
670 // purposes. 718 // purposes.
671 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); 719 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50);
672 720
673 OnSqliteError(err, NULL); 721 OnSqliteError(err, NULL);
674 Close(); 722 Close();
675 db_ = NULL; 723 db_ = NULL;
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 } 888 }
841 889
842 // Best effort to put things back as they were before. 890 // Best effort to put things back as they were before.
843 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; 891 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF";
844 ignore_result(Execute(kNoWritableSchema)); 892 ignore_result(Execute(kNoWritableSchema));
845 893
846 return ret; 894 return ret;
847 } 895 }
848 896
849 } // namespace sql 897 } // namespace sql
OLDNEW
« no previous file with comments | « no previous file | sql/connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698