diff options
author | shess@chromium.org <shess@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-06 19:36:49 +0000 |
---|---|---|
committer | shess@chromium.org <shess@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-06 19:36:49 +0000 |
commit | 8e0c0128f4860cc1393eb458f9b389fce5e46a93 (patch) | |
tree | 3fecb5a2b13c74d9ec8540ae2de73b9de2ad57b4 /sql/connection.cc | |
parent | 2781409defa7484f927ffe302c70cebbf7967134 (diff) | |
download | chromium_src-8e0c0128f4860cc1393eb458f9b389fce5e46a93.zip chromium_src-8e0c0128f4860cc1393eb458f9b389fce5e46a93.tar.gz chromium_src-8e0c0128f4860cc1393eb458f9b389fce5e46a93.tar.bz2 |
Implement sql::Connection::Raze() in terms of sqlite3_backup API.
Wraps up the notion of reseting a database in a way which respects
SQLite locking constraints and doesn't require closing the database.
A similar outcome could be managed using filesystem operations, which
requires coordination between clients of the database to make sure
that no corruption occurs due to incorrect handling of -journal files.
Also, Windows pins files until the last handle closes, making that
approach challenging in some cases.
BUG=none
TEST=none
Review URL: https://chromiumcodereview.appspot.com/9768006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131167 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sql/connection.cc')
-rw-r--r-- | sql/connection.cc | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/sql/connection.cc b/sql/connection.cc index 58bfb11..b2274f1 100644 --- a/sql/connection.cc +++ b/sql/connection.cc @@ -168,6 +168,85 @@ void Connection::Preload() { #endif } +// Create an in-memory database with the existing database's page +// size, then backup that database over the existing database. +bool Connection::Raze() { + if (!db_) { + DLOG(FATAL) << "Cannot raze null db"; + return false; + } + + if (transaction_nesting_ > 0) { + DLOG(FATAL) << "Cannot raze within a transaction"; + return false; + } + + sql::Connection null_db; + if (!null_db.OpenInMemory()) { + DLOG(FATAL) << "Unable to open in-memory database."; + return false; + } + + // Get the page size from the current connection, then propagate it + // to the null database. + Statement s(GetUniqueStatement("PRAGMA page_size")); + if (!s.Step()) + return false; + const std::string sql = StringPrintf("PRAGMA page_size=%d", s.ColumnInt(0)); + if (!null_db.Execute(sql.c_str())) + return false; + + // The page size doesn't take effect until a database has pages, and + // at this point the null database has none. Changing the schema + // version will create the first page. This will not affect the + // schema version in the resulting database, as SQLite's backup + // implementation propagates the schema version from the original + // connection to the new version of the database, incremented by one + // so that other readers see the schema change and act accordingly. + if (!null_db.Execute("PRAGMA schema_version = 1")) + return false; + + sqlite3_backup* backup = sqlite3_backup_init(db_, "main", + null_db.db_, "main"); + if (!backup) { + DLOG(FATAL) << "Unable to start sqlite3_backup()."; + return false; + } + + // -1 backs up the entire database. + int rc = sqlite3_backup_step(backup, -1); + int pages = sqlite3_backup_pagecount(backup); + sqlite3_backup_finish(backup); + + // The destination database was locked. + if (rc == SQLITE_BUSY) { + return false; + } + + // The entire database should have been backed up. + if (rc != SQLITE_DONE) { + DLOG(FATAL) << "Unable to copy entire null database."; + return false; + } + + // Exactly one page should have been backed up. If this breaks, + // check this function to make sure assumptions aren't being broken. + DCHECK_EQ(pages, 1); + + return true; +} + +bool Connection::RazeWithTimout(base::TimeDelta timeout) { + if (!db_) { + DLOG(FATAL) << "Cannot raze null db"; + return false; + } + + ScopedBusyTimeout busy_timeout(db_); + busy_timeout.SetTimeout(timeout); + return Raze(); +} + bool Connection::BeginTransaction() { if (needs_rollback_) { DCHECK_GT(transaction_nesting_, 0); |