Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df78cd5e authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Work around problems changing the database journal mode."

parents 4355b001 d67c8c67
Loading
Loading
Loading
Loading
+61 −29
Original line number Diff line number Diff line
@@ -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;
            if (mConfiguration.walEnabled) {
                setJournalMode("WAL");
                setSyncMode(SQLiteGlobal.getWALSyncMode());
            } else {
                setJournalMode(SQLiteGlobal.getDefaultJournalMode());
                setSyncMode(SQLiteGlobal.getDefaultSyncMode());
            }
        }
    }

    private void setSyncMode(String newValue) {
        String value = executeForString("PRAGMA synchronous", null, null);
            if (!value.equalsIgnoreCase(newValue)) {
        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 setJournalModeFromConfiguration() {
        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
            final String newValue = mConfiguration.journalMode;
    private void setJournalMode(String newValue) {
        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);
                }
            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.
+1 −2
Original line number Diff line number Diff line
@@ -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()) {
+6 −22
Original line number Diff line number Diff line
@@ -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;
        }
    }

+4 −14
Original line number Diff line number Diff line
@@ -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);
    }