Merge "Drop support for device configurable "compatibility WAL"."
This commit is contained in:
committed by
Android (Google) Code Review
commit
01794b570b
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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. -->
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user