diff options
author | Jeff Brown <jeffbrown@google.com> | 2012-03-22 15:07:48 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-03-22 15:07:48 -0700 |
commit | df78cd5ee959f57c35dd9d6ad0f6871c72438f3c (patch) | |
tree | f526ba77b8c60e04f912492bad5d37d35944a7a1 /core/java/android/database | |
parent | 4355b001cb736d4aa312231ce129506a3c7f6808 (diff) | |
parent | d67c8c67899481682657d41a61f3846b8d77d165 (diff) | |
download | frameworks_base-df78cd5ee959f57c35dd9d6ad0f6871c72438f3c.zip frameworks_base-df78cd5ee959f57c35dd9d6ad0f6871c72438f3c.tar.gz frameworks_base-df78cd5ee959f57c35dd9d6ad0f6871c72438f3c.tar.bz2 |
Merge "Work around problems changing the database journal mode."
Diffstat (limited to 'core/java/android/database')
4 files changed, 72 insertions, 67 deletions
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index e2c222b..bf10bcb 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -211,8 +211,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME); setPageSize(); - setSyncModeFromConfiguration(); - setJournalModeFromConfiguration(); + setWalModeFromConfiguration(); setJournalSizeLimit(); setAutoCheckpointInterval(); setLocaleFromConfiguration(); @@ -268,28 +267,69 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } } - private void setSyncModeFromConfiguration() { + private void setWalModeFromConfiguration() { if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { - final String newValue = mConfiguration.syncMode; - String value = executeForString("PRAGMA synchronous", null, null); - if (!value.equalsIgnoreCase(newValue)) { - execute("PRAGMA synchronous=" + newValue, null, null); + if (mConfiguration.walEnabled) { + setJournalMode("WAL"); + setSyncMode(SQLiteGlobal.getWALSyncMode()); + } else { + setJournalMode(SQLiteGlobal.getDefaultJournalMode()); + setSyncMode(SQLiteGlobal.getDefaultSyncMode()); } } } - private void setJournalModeFromConfiguration() { - if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { - final String newValue = mConfiguration.journalMode; - String value = executeForString("PRAGMA journal_mode", null, null); - if (!value.equalsIgnoreCase(newValue)) { - value = executeForString("PRAGMA journal_mode=" + newValue, null, null); - if (!value.equalsIgnoreCase(newValue)) { - Log.e(TAG, "setting journal_mode to " + newValue - + " failed for db: " + mConfiguration.label - + " (on pragma set journal_mode, sqlite returned:" + value); + private void setSyncMode(String newValue) { + String value = executeForString("PRAGMA synchronous", null, null); + if (!canonicalizeSyncMode(value).equalsIgnoreCase( + canonicalizeSyncMode(newValue))) { + execute("PRAGMA synchronous=" + newValue, null, null); + } + } + + private static String canonicalizeSyncMode(String value) { + if (value.equals("0")) { + return "OFF"; + } else if (value.equals("1")) { + return "NORMAL"; + } else if (value.equals("2")) { + return "FULL"; + } + return value; + } + + private void setJournalMode(String newValue) { + String value = executeForString("PRAGMA journal_mode", null, null); + if (!value.equalsIgnoreCase(newValue)) { + try { + String result = executeForString("PRAGMA journal_mode=" + newValue, null, null); + if (result.equalsIgnoreCase(newValue)) { + return; } + // PRAGMA journal_mode silently fails and returns the original journal + // mode in some cases if the journal mode could not be changed. + } catch (SQLiteDatabaseLockedException ex) { + // This error (SQLITE_BUSY) occurs if one connection has the database + // open in WAL mode and another tries to change it to non-WAL. } + // Because we always disable WAL mode when a database is first opened + // (even if we intend to re-enable it), we can encounter problems if + // there is another open connection to the database somewhere. + // This can happen for a variety of reasons such as an application opening + // the same database in multiple processes at the same time or if there is a + // crashing content provider service that the ActivityManager has + // removed from its registry but whose process hasn't quite died yet + // by the time it is restarted in a new process. + // + // If we don't change the journal mode, nothing really bad happens. + // In the worst case, an application that enables WAL might not actually + // get it, although it can still use connection pooling. + Log.w(TAG, "Could not change the database journal mode of '" + + mConfiguration.label + "' from '" + value + "' to '" + newValue + + "' because the database is locked. This usually means that " + + "there are other open connections to the database which prevents " + + "the database from enabling or disabling write-ahead logging mode. " + + "Proceeding without changing the journal mode."); } } @@ -349,10 +389,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } // Remember what changed. - boolean syncModeChanged = !configuration.syncMode.equalsIgnoreCase( - mConfiguration.syncMode); - boolean journalModeChanged = !configuration.journalMode.equalsIgnoreCase( - mConfiguration.journalMode); + boolean walModeChanged = configuration.walEnabled != mConfiguration.walEnabled; boolean localeChanged = !configuration.locale.equals(mConfiguration.locale); // Update configuration parameters. @@ -361,14 +398,9 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen // Update prepared statement cache size. mPreparedStatementCache.resize(configuration.maxSqlCacheSize); - // Update sync mode. - if (syncModeChanged) { - setSyncModeFromConfiguration(); - } - - // Update journal mode. - if (journalModeChanged) { - setJournalModeFromConfiguration(); + // Update WAL. + if (walModeChanged) { + setWalModeFromConfiguration(); } // Update locale. diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java index 00d3309..27c9ee5 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -258,8 +258,7 @@ public final class SQLiteConnectionPool implements Closeable { throwIfClosedLocked(); boolean restrictToOneConnection = false; - if (mConfiguration.journalMode.equalsIgnoreCase("WAL") - != configuration.journalMode.equalsIgnoreCase("WAL")) { + if (mConfiguration.walEnabled != configuration.walEnabled) { // WAL mode can only be changed if there are no acquired connections // because we need to close all but the primary connection first. if (!mAcquiredConnections.isEmpty()) { diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 24a7800..0ecce4d 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -127,10 +127,6 @@ public final class SQLiteDatabase extends SQLiteClosable { // INVARIANT: Guarded by mLock. private boolean mHasAttachedDbsLocked; - // True if the database is in WAL mode. - // INVARIANT: Guarded by mLock. - private boolean mIsWALEnabledLocked; - /** * When a constraint violation occurs, an immediate ROLLBACK occurs, * thus ending the current transaction, and the command aborts with a @@ -1834,7 +1830,7 @@ public final class SQLiteDatabase extends SQLiteClosable { synchronized (mLock) { throwIfNotOpenLocked(); - if (mIsWALEnabledLocked) { + if (mConfigurationLocked.walEnabled) { return true; } @@ -1860,21 +1856,15 @@ public final class SQLiteDatabase extends SQLiteClosable { } final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize; - final String oldSyncMode = mConfigurationLocked.syncMode; - final String oldJournalMode = mConfigurationLocked.journalMode; mConfigurationLocked.maxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize(); - mConfigurationLocked.syncMode = SQLiteGlobal.getWALSyncMode(); - mConfigurationLocked.journalMode = "WAL"; + mConfigurationLocked.walEnabled = true; try { mConnectionPoolLocked.reconfigure(mConfigurationLocked); } catch (RuntimeException ex) { mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize; - mConfigurationLocked.syncMode = oldSyncMode; - mConfigurationLocked.journalMode = oldJournalMode; + mConfigurationLocked.walEnabled = false; throw ex; } - - mIsWALEnabledLocked = true; } return true; } @@ -1890,26 +1880,20 @@ public final class SQLiteDatabase extends SQLiteClosable { synchronized (mLock) { throwIfNotOpenLocked(); - if (!mIsWALEnabledLocked) { + if (!mConfigurationLocked.walEnabled) { return; } final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize; - final String oldSyncMode = mConfigurationLocked.syncMode; - final String oldJournalMode = mConfigurationLocked.journalMode; mConfigurationLocked.maxConnectionPoolSize = 1; - mConfigurationLocked.syncMode = SQLiteGlobal.getDefaultSyncMode(); - mConfigurationLocked.journalMode = SQLiteGlobal.getDefaultJournalMode(); + mConfigurationLocked.walEnabled = false; try { mConnectionPoolLocked.reconfigure(mConfigurationLocked); } catch (RuntimeException ex) { mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize; - mConfigurationLocked.syncMode = oldSyncMode; - mConfigurationLocked.journalMode = oldJournalMode; + mConfigurationLocked.walEnabled = true; throw ex; } - - mIsWALEnabledLocked = false; } } diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index efbcaca..e06a5ee 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -85,18 +85,11 @@ public final class SQLiteDatabaseConfiguration { public Locale locale; /** - * The database synchronization mode. + * True if WAL mode is enabled. * - * Default is {@link SQLiteGlobal#getDefaultSyncMode()}. + * Default is false. */ - public String syncMode; - - /** - * The database journal mode. - * - * Default is {@link SQLiteGlobal#getDefaultJournalMode()}. - */ - public String journalMode; + public boolean walEnabled; /** * The custom functions to register. @@ -124,8 +117,6 @@ public final class SQLiteDatabaseConfiguration { maxConnectionPoolSize = 1; maxSqlCacheSize = 25; locale = Locale.getDefault(); - syncMode = SQLiteGlobal.getDefaultSyncMode(); - journalMode = SQLiteGlobal.getDefaultJournalMode(); } /** @@ -162,8 +153,7 @@ public final class SQLiteDatabaseConfiguration { maxConnectionPoolSize = other.maxConnectionPoolSize; maxSqlCacheSize = other.maxSqlCacheSize; locale = other.locale; - syncMode = other.syncMode; - journalMode = other.journalMode; + walEnabled = other.walEnabled; customFunctions.clear(); customFunctions.addAll(other.customFunctions); } |