diff options
| author | 2017-12-15 01:40:17 +0000 | |
|---|---|---|
| committer | 2017-12-15 01:40:17 +0000 | |
| commit | a629e4c393e5ac52c07598a5d3b4ed120115c97d (patch) | |
| tree | 78b5235da78d52716af5129b16657c058aa37154 | |
| parent | ba025ee20a33c4b8b041827ae3602f21a1ede187 (diff) | |
| parent | ee90c03fe787ccc52c9605212eddf80cf50a7824 (diff) | |
Merge "Added compatibility WAL flags for Global.Settings"
7 files changed, 260 insertions, 1 deletions
diff --git a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java new file mode 100644 index 000000000000..e02e68dced95 --- /dev/null +++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.database.sqlite; + +import android.app.ActivityThread; +import android.app.Application; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.KeyValueListParser; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Helper class for accessing + * {@link Settings.Global#SQLITE_COMPATIBILITY_WAL_FLAGS global compatibility WAL settings}. + * + * <p>The value of {@link Settings.Global#SQLITE_COMPATIBILITY_WAL_FLAGS} is cached on first access + * for consistent behavior across all connections opened in the process. + * @hide + */ +public class SQLiteCompatibilityWalFlags { + + private static final String TAG = "SQLiteCompatibilityWalFlags"; + + private static volatile boolean sInitialized = true; // Temporarily disable flags + private static volatile boolean sFlagsSet; + private static volatile boolean sCompatibilityWalSupported; + private static volatile String sWALSyncMode; + // This flag is used to avoid recursive initialization due to circular dependency on Settings + private static volatile boolean sCallingGlobalSettings; + + /** + * @hide + */ + @VisibleForTesting + public static boolean areFlagsSet() { + initIfNeeded(); + return sFlagsSet; + } + + /** + * @hide + */ + @VisibleForTesting + public static boolean isCompatibilityWalSupported() { + initIfNeeded(); + return sCompatibilityWalSupported; + } + + /** + * @hide + */ + @VisibleForTesting + public static String getWALSyncMode() { + initIfNeeded(); + return sWALSyncMode; + } + + private static void initIfNeeded() { + if (sInitialized || sCallingGlobalSettings) { + return; + } + ActivityThread activityThread = ActivityThread.currentActivityThread(); + Application app = activityThread == null ? null : activityThread.getApplication(); + String flags = null; + if (app == null) { + Log.w(TAG, "Cannot read global setting " + + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS + " - " + + "Application state not available"); + } else { + try { + sCallingGlobalSettings = true; + flags = Settings.Global.getString(app.getContentResolver(), + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS); + } finally { + sCallingGlobalSettings = false; + } + } + + init(flags); + } + + /** + * @hide + */ + @VisibleForTesting + public static void init(String flags) { + if (TextUtils.isEmpty(flags)) { + sInitialized = true; + return; + } + KeyValueListParser parser = new KeyValueListParser(','); + try { + parser.setString(flags); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Setting has invalid format: " + flags, e); + sInitialized = true; + return; + } + sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported", + SQLiteGlobal.isCompatibilityWalSupported()); + sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode()); + Log.i(TAG, "Read compatibility WAL flags: compatibility_wal_supported=" + + sCompatibilityWalSupported + ", wal_syncmode=" + sWALSyncMode); + sFlagsSet = true; + sInitialized = true; + } + + /** + * @hide + */ + @VisibleForTesting + public static void reset() { + sInitialized = false; + sFlagsSet = false; + sCompatibilityWalSupported = false; + sWALSyncMode = null; + } +} diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 2c93a7fe26cd..7717b8d36123 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -296,7 +296,11 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen && mConfiguration.syncMode == null && mConfiguration.useCompatibilityWal; if (walEnabled || useCompatibilityWal) { setJournalMode("WAL"); - setSyncMode(SQLiteGlobal.getWALSyncMode()); + if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) { + setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode()); + } else { + setSyncMode(SQLiteGlobal.getWALSyncMode()); + } } else { setJournalMode(mConfiguration.journalMode == null ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode); diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java index 5adb11964c8c..b211700328b9 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -1094,6 +1094,12 @@ public final class SQLiteConnectionPool implements Closeable { printer.println(" Open: " + mIsOpen); printer.println(" Max connections: " + mMaxConnectionPoolSize); printer.println(" Total execution time: " + mTotalExecutionTimeCounter); + if (SQLiteCompatibilityWalFlags.areFlagsSet()) { + printer.println(" Compatibility WAL settings: compatibility_wal_supported=" + + SQLiteCompatibilityWalFlags + .isCompatibilityWalSupported() + ", wal_syncmode=" + + SQLiteCompatibilityWalFlags.getWALSyncMode()); + } if (mConfiguration.isLookasideConfigSet()) { printer.println(" Lookaside config: sz=" + mConfiguration.lookasideSlotSize + " cnt=" + mConfiguration.lookasideSlotCount); diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 09bb9c69dc09..c1c0812e129e 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -289,6 +289,10 @@ public final class SQLiteDatabase extends SQLiteClosable { mConfigurationLocked.journalMode = journalMode; mConfigurationLocked.syncMode = syncMode; mConfigurationLocked.useCompatibilityWal = SQLiteGlobal.isCompatibilityWalSupported(); + if (!mConfigurationLocked.isInMemoryDb() && SQLiteCompatibilityWalFlags.areFlagsSet()) { + mConfigurationLocked.useCompatibilityWal = SQLiteCompatibilityWalFlags + .isCompatibilityWalSupported(); + } } @Override diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4ecbdf587600..abc16cec269d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11145,6 +11145,19 @@ public final class Settings { "notification_snooze_options"; /** + * 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) + * + * @hide + */ + public static final String SQLITE_COMPATIBILITY_WAL_FLAGS = + "sqlite_compatibility_wal_flags"; + + /** * Enable GNSS Raw Measurements Full Tracking? * 0 = no * 1 = yes diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java new file mode 100644 index 000000000000..230655de8a00 --- /dev/null +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.database.sqlite; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.database.DatabaseUtils; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; + +/** + * Tests for {@link SQLiteCompatibilityWalFlags} + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class SQLiteCompatibilityWalFlagsTest { + + private SQLiteDatabase mDatabase; + + @After + public void tearDown() { + SQLiteCompatibilityWalFlags.reset(); + if (mDatabase != null) { + mDatabase.close(); + SQLiteDatabase.deleteDatabase(new File(mDatabase.getPath())); + } + } + + @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()); + + SQLiteCompatibilityWalFlags.init("wal_syncmode=VALUE"); + assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); + assertEquals(SQLiteGlobal.isCompatibilityWalSupported(), + SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); + assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode()); + + SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true"); + assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); + assertEquals(SQLiteGlobal.getWALSyncMode(), + SQLiteCompatibilityWalFlags.getWALSyncMode()); + assertTrue(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); + + SQLiteCompatibilityWalFlags.reset(); + SQLiteCompatibilityWalFlags.init("Invalid value"); + assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet()); + } + + @Test + public void testApplyFlags() { + Context ctx = InstrumentationRegistry.getContext(); + + SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true,wal_syncmode=NORMAL"); + mDatabase = SQLiteDatabase + .openOrCreateDatabase(ctx.getDatabasePath("SQLiteCompatibilityWalFlagsTest"), null); + String journalMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA journal_mode", null); + assertEquals("WAL", journalMode.toUpperCase()); + String syncMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA synchronous", null); + assertEquals("Normal mode (1) is expected", "1", syncMode); + } + + +} diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index b03f0540064f..907a1b843c0c 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -335,6 +335,7 @@ public class SettingsBackupTest { Settings.Global.SMS_SHORT_CODES_UPDATE_CONTENT_URL, Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL, Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS, + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, Settings.Global.STORAGE_BENCHMARK_INTERVAL, Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD, Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS, |