diff options
| author | 2012-03-22 15:07:48 -0700 | |
|---|---|---|
| committer | 2012-03-22 15:07:48 -0700 | |
| commit | df78cd5ee959f57c35dd9d6ad0f6871c72438f3c (patch) | |
| tree | f526ba77b8c60e04f912492bad5d37d35944a7a1 | |
| parent | 4355b001cb736d4aa312231ce129506a3c7f6808 (diff) | |
| parent | d67c8c67899481682657d41a61f3846b8d77d165 (diff) | |
Merge "Work around problems changing the database journal mode."
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 e2c222bbaa4e..bf10bcb999ed 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 00d3309b03dc..27c9ee544f30 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 24a780015bcf..0ecce4d1f689 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 efbcaca0034f..e06a5eebe2b3 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);      } |