Merge "Drop support for device configurable "compatibility WAL"."

This commit is contained in:
Narayan Kamath
2019-02-27 11:03:29 +00:00
committed by Android (Google) Code Review
12 changed files with 109 additions and 82 deletions

View File

@@ -684,7 +684,6 @@ package android.database.sqlite {
method public static int getWALAutoCheckpoint();
method public static int getWALConnectionPoolSize();
method public static String getWALSyncMode();
method public static boolean isCompatibilityWalSupported();
method public static int releaseMemory();
}

View File

@@ -40,8 +40,7 @@ public class SQLiteCompatibilityWalFlags {
private static final String TAG = "SQLiteCompatibilityWalFlags";
private static volatile boolean sInitialized;
private static volatile boolean sFlagsSet;
private static volatile boolean sCompatibilityWalSupported;
private static volatile boolean sLegacyCompatibilityWalEnabled;
private static volatile String sWALSyncMode;
private static volatile long sTruncateSize = -1;
// This flag is used to avoid recursive initialization due to circular dependency on Settings
@@ -54,18 +53,9 @@ public class SQLiteCompatibilityWalFlags {
* @hide
*/
@VisibleForTesting
public static boolean areFlagsSet() {
public static boolean isLegacyCompatibilityWalEnabled() {
initIfNeeded();
return sFlagsSet;
}
/**
* @hide
*/
@VisibleForTesting
public static boolean isCompatibilityWalSupported() {
initIfNeeded();
return sCompatibilityWalSupported;
return sLegacyCompatibilityWalEnabled;
}
/**
@@ -74,6 +64,14 @@ public class SQLiteCompatibilityWalFlags {
@VisibleForTesting
public static String getWALSyncMode() {
initIfNeeded();
// The configurable WAL sync mode should only ever be used if the legacy compatibility
// WAL is enabled. It should *not* have any effect if app developers explicitly turn on
// WAL for their database using setWriteAheadLoggingEnabled. Throwing an exception here
// adds an extra layer of checking that we never use it in the wrong place.
if (!sLegacyCompatibilityWalEnabled) {
throw new IllegalStateException("isLegacyCompatibilityWalEnabled() == false");
}
return sWALSyncMode;
}
@@ -131,13 +129,12 @@ public class SQLiteCompatibilityWalFlags {
sInitialized = true;
return;
}
sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported",
SQLiteGlobal.isCompatibilityWalSupported());
sLegacyCompatibilityWalEnabled = parser.getBoolean(
"legacy_compatibility_wal_enabled", false);
sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode());
sTruncateSize = parser.getInt("truncate_size", -1);
Log.i(TAG, "Read compatibility WAL flags: compatibility_wal_supported="
+ sCompatibilityWalSupported + ", wal_syncmode=" + sWALSyncMode);
sFlagsSet = true;
Log.i(TAG, "Read compatibility WAL flags: legacy_compatibility_wal_enabled="
+ sLegacyCompatibilityWalEnabled + ", wal_syncmode=" + sWALSyncMode);
sInitialized = true;
}
@@ -148,8 +145,7 @@ public class SQLiteCompatibilityWalFlags {
@TestApi
public static void reset() {
sInitialized = false;
sFlagsSet = false;
sCompatibilityWalSupported = false;
sLegacyCompatibilityWalEnabled = false;
sWALSyncMode = null;
}
}

View File

@@ -300,12 +300,13 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
(mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
// Use compatibility WAL unless an app explicitly set journal/synchronous mode
// or DISABLE_COMPATIBILITY_WAL flag is set
final boolean useCompatibilityWal = mConfiguration.useCompatibilityWal();
if (walEnabled || useCompatibilityWal) {
final boolean isCompatibilityWalEnabled =
mConfiguration.isLegacyCompatibilityWalEnabled();
if (walEnabled || isCompatibilityWalEnabled) {
setJournalMode("WAL");
if (mConfiguration.syncMode != null) {
setSyncMode(mConfiguration.syncMode);
} else if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
} else if (isCompatibilityWalEnabled) {
setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
} else {
setSyncMode(SQLiteGlobal.getWALSyncMode());
@@ -504,7 +505,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
!= mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
& (SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING
| SQLiteDatabase.DISABLE_COMPATIBILITY_WAL)) != 0;
| SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL)) != 0;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
// Update configuration parameters.

View File

@@ -321,7 +321,7 @@ public final class SQLiteConnectionPool implements Closeable {
// We should do in-place switching when transitioning from compatibility WAL
// to rollback journal. Otherwise transient connection state will be lost
boolean onlyCompatWalChanged = (mConfiguration.openFlags ^ configuration.openFlags)
== SQLiteDatabase.DISABLE_COMPATIBILITY_WAL;
== SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL;
if (!onlyCompatWalChanged && mConfiguration.openFlags != configuration.openFlags) {
// If we are changing open flags and WAL mode at the same time, then
@@ -1113,19 +1113,18 @@ public final class SQLiteConnectionPool implements Closeable {
if (directories != null) {
directories.add(new File(mConfiguration.path).getParent());
}
boolean isCompatibilityWalEnabled = mConfiguration.isLegacyCompatibilityWalEnabled();
printer.println("Connection pool for " + mConfiguration.path + ":");
printer.println(" Open: " + mIsOpen);
printer.println(" Max connections: " + mMaxConnectionPoolSize);
printer.println(" Total execution time: " + mTotalExecutionTimeCounter);
printer.println(" Configuration: openFlags=" + mConfiguration.openFlags
+ ", useCompatibilityWal=" + mConfiguration.useCompatibilityWal()
+ ", isLegacyCompatibilityWalEnabled=" + isCompatibilityWalEnabled
+ ", journalMode=" + TextUtils.emptyIfNull(mConfiguration.journalMode)
+ ", syncMode=" + TextUtils.emptyIfNull(mConfiguration.syncMode));
if (SQLiteCompatibilityWalFlags.areFlagsSet()) {
printer.println(" Compatibility WAL settings: compatibility_wal_supported="
+ SQLiteCompatibilityWalFlags
.isCompatibilityWalSupported() + ", wal_syncmode="
if (isCompatibilityWalEnabled) {
printer.println(" Compatibility WAL enabled: wal_syncmode="
+ SQLiteCompatibilityWalFlags.getWALSyncMode());
}
if (mConfiguration.isLookasideConfigSet()) {

View File

@@ -266,12 +266,17 @@ public final class SQLiteDatabase extends SQLiteClosable {
*/
public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
// Note: The below value was only used on Android Pie.
// public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
/**
* Open flag: Flag for {@link #openDatabase} to disable Compatibility WAL when opening database.
* Open flag: Flag for {@link #openDatabase} to enable the legacy Compatibility WAL when opening
* database.
*
* @hide
*/
public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
public static final int ENABLE_LEGACY_COMPATIBILITY_WAL = 0x80000000;
/**
* Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
@@ -309,10 +314,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
mConfigurationLocked.journalMode = journalMode;
mConfigurationLocked.syncMode = syncMode;
if (!SQLiteGlobal.isCompatibilityWalSupported() || (
SQLiteCompatibilityWalFlags.areFlagsSet() && !SQLiteCompatibilityWalFlags
.isCompatibilityWalSupported())) {
mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
if (SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled()) {
mConfigurationLocked.openFlags |= ENABLE_LEGACY_COMPATIBILITY_WAL;
}
}
@@ -2123,15 +2126,18 @@ public final class SQLiteDatabase extends SQLiteClosable {
throwIfNotOpenLocked();
final int oldFlags = mConfigurationLocked.openFlags;
final boolean walDisabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0;
final boolean compatibilityWalDisabled = (oldFlags & DISABLE_COMPATIBILITY_WAL) != 0;
if (walDisabled && compatibilityWalDisabled) {
final boolean walEnabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
final boolean compatibilityWalEnabled =
(oldFlags & ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
// WAL was never enabled for this database, so there's nothing left to do.
if (!walEnabled && !compatibilityWalEnabled) {
return;
}
// If an app explicitly disables WAL, it takes priority over any directive
// to use the legacy "compatibility WAL" mode.
mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
// If an app explicitly disables WAL, compatibility mode should be disabled too
mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
mConfigurationLocked.openFlags &= ~ENABLE_LEGACY_COMPATIBILITY_WAL;
try {
mConnectionPoolLocked.reconfigure(mConfigurationLocked);

View File

@@ -17,6 +17,7 @@
package android.database.sqlite;
import android.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Pattern;
@@ -197,9 +198,9 @@ public final class SQLiteDatabaseConfiguration {
return path.equalsIgnoreCase(MEMORY_DB_PATH);
}
boolean useCompatibilityWal() {
boolean isLegacyCompatibilityWalEnabled() {
return journalMode == null && syncMode == null
&& (openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0;
&& (openFlags & SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
}
private static String stripPathForLogs(String path) {

View File

@@ -90,16 +90,6 @@ public final class SQLiteGlobal {
com.android.internal.R.string.db_default_journal_mode));
}
/**
* Returns true if compatibility WAL mode is supported. In this mode, only
* database journal mode is changed. Connection pool will use at most one connection.
*/
public static boolean isCompatibilityWalSupported() {
return SystemProperties.getBoolean("debug.sqlite.compatibility_wal_supported",
Resources.getSystem().getBoolean(
com.android.internal.R.bool.db_compatibility_wal_supported));
}
/**
* Gets the journal size limit in bytes.
*/

View File

@@ -202,8 +202,9 @@ public abstract class SQLiteOpenHelper implements AutoCloseable {
}
mOpenParamsBuilder.setWriteAheadLoggingEnabled(enabled);
}
// Compatibility WAL is disabled if an app disables or enables WAL
mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.DISABLE_COMPATIBILITY_WAL);
mOpenParamsBuilder.removeOpenFlags(SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL);
}
}

View File

@@ -14200,10 +14200,24 @@ public final class Settings {
* Configuration flags for SQLite Compatibility WAL. Encoded as a key-value list, separated
* by commas. E.g.: compatibility_wal_supported=true, wal_syncmode=OFF
*
* Supported keys:
* compatibility_wal_supported (boolean)
* wal_syncmode (String)
* truncate_size (int)
* Supported keys:<br/>
* <li>
* <ul> {@code legacy_compatibility_wal_enabled} : A {code boolean} flag that determines
* whether or not "compatibility WAL" mode is enabled by default. This is a legacy flag
* and is honoured on Android Q and higher. This flag will be removed in a future release.
* </ul>
* <ul> {@code wal_syncmode} : A {@code String} representing the synchronization mode to use
* when WAL is enabled, either via {@code legacy_compatibility_wal_enabled} or using the
* obsolete {@code compatibility_wal_supported} flag.
* </ul>
* <ul> {@code truncate_size} : A {@code int} flag that specifies the truncate size of the
* WAL journal.
* </ul>
* <ul> {@code compatibility_wal_supported} : A {code boolean} flag that specifies whether
* the legacy "compatibility WAL" mode is enabled by default. This flag is obsolete and is
* only supported on Android Pie.
* </ul>
* </li>
*
* @hide
*/

View File

@@ -2008,11 +2008,6 @@
a transaction, so it interacts poorly with SECURE_DELETE. -->
<string name="db_default_journal_mode" translatable="false">TRUNCATE</string>
<!-- Enables compatibility WAL mode.
In this mode, only database journal mode will be changed, connection pool
size will still be limited to a single connection. -->
<bool name="db_compatibility_wal_supported">true</bool>
<!-- Maximum size of the persistent journal file in bytes.
If the journal file grows to be larger than this amount then SQLite will
truncate it after committing the transaction. -->

View File

@@ -752,7 +752,6 @@
<java-symbol type="string" name="date_time" />
<java-symbol type="string" name="date_time_set" />
<java-symbol type="string" name="date_time_done" />
<java-symbol type="bool" name="db_compatibility_wal_supported" />
<java-symbol type="string" name="db_default_journal_mode" />
<java-symbol type="string" name="db_default_sync_mode" />
<java-symbol type="string" name="db_wal_sync_mode" />

View File

@@ -19,6 +19,7 @@ package android.database.sqlite;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
import android.database.DatabaseUtils;
@@ -54,44 +55,52 @@ public class SQLiteCompatibilityWalFlagsTest {
@Test
public void testParseConfig() {
SQLiteCompatibilityWalFlags.init("");
assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
SQLiteCompatibilityWalFlags.init(null);
assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=false,wal_syncmode=OFF");
assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
assertFalse(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
assertEquals("OFF", SQLiteCompatibilityWalFlags.getWALSyncMode());
// Ensure that legacy compatibility wal isn't turned on by the old flag.
SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true,wal_syncmode=OFF");
assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
try {
SQLiteCompatibilityWalFlags.getWALSyncMode();
fail();
} catch (IllegalStateException expected) {
}
assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.init("wal_syncmode=VALUE");
assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
assertEquals(SQLiteGlobal.isCompatibilityWalSupported(),
SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode());
assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
try {
SQLiteCompatibilityWalFlags.getWALSyncMode();
fail();
} catch (IllegalStateException expected) {
}
SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true");
assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
SQLiteCompatibilityWalFlags.init("legacy_compatibility_wal_enabled=true");
assertTrue(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
assertEquals(SQLiteGlobal.getWALSyncMode(),
SQLiteCompatibilityWalFlags.getWALSyncMode());
assertTrue(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.init(
"legacy_compatibility_wal_enabled=true,wal_syncmode=VALUE");
assertTrue(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode());
SQLiteCompatibilityWalFlags.init("truncate_size=1024");
assertEquals(1024, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.reset();
SQLiteCompatibilityWalFlags.init("Invalid value");
assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
}
@Test
public void testApplyFlags() {
Context ctx = InstrumentationRegistry.getContext();
SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true,wal_syncmode=NORMAL");
SQLiteCompatibilityWalFlags.init(
"legacy_compatibility_wal_enabled=true,wal_syncmode=NORMAL");
mDatabase = SQLiteDatabase
.openOrCreateDatabase(ctx.getDatabasePath("SQLiteCompatibilityWalFlagsTest"), null);
String journalMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA journal_mode", null);
@@ -100,5 +109,22 @@ public class SQLiteCompatibilityWalFlagsTest {
assertEquals("Normal mode (1) is expected", "1", syncMode);
}
@Test
public void testApplyFlags_thenDisableWriteAheadLogging() {
Context ctx = InstrumentationRegistry.getContext();
SQLiteCompatibilityWalFlags.init(
"legacy_compatibility_wal_enabled=true,wal_syncmode=FULL");
mDatabase = SQLiteDatabase
.openOrCreateDatabase(ctx.getDatabasePath("SQLiteCompatibilityWalFlagsTest"), null);
mDatabase.disableWriteAheadLogging();
String journalMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA journal_mode", null);
assertEquals(SQLiteGlobal.getDefaultJournalMode(), journalMode.toUpperCase());
String syncMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA synchronous", null);
// TODO: This is the old behaviour and seems incorrect. The specified wal_syncmode was only
// intended to be used if the database is in WAL mode, and we should revert to the global
// default sync mode if WAL is disabled.
assertEquals("Normal mode (2) is expected", "2", syncMode);
}
}