diff options
| author | 2018-09-25 15:12:15 +0000 | |
|---|---|---|
| committer | 2018-09-25 15:12:15 +0000 | |
| commit | 0f88f865bdce7cb15dc9872a2728cd593d5ac66e (patch) | |
| tree | 17fb4348f68a2355e238f7b0e994fd651c5ed9e7 | |
| parent | 45fda272111f43fe570540e9cf75772efa5c6cff (diff) | |
| parent | 0939c5a2b313d7fc32ca5e1a6c161b0089e141e9 (diff) | |
Merge "Truncate(*1) it if WAL file is too big when opening DB" into pi-dev
7 files changed, 81 insertions, 0 deletions
diff --git a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java index 5bf3a7c43640..06c069c583b5 100644 --- a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java +++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java @@ -41,6 +41,7 @@ public class SQLiteCompatibilityWalFlags { private static volatile boolean sFlagsSet; private static volatile boolean sCompatibilityWalSupported; 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 private static volatile boolean sCallingGlobalSettings; @@ -71,6 +72,19 @@ public class SQLiteCompatibilityWalFlags { return sWALSyncMode; } + /** + * Override {@link com.android.internal.R.integer#db_wal_truncate_size}. + * + * @return the value set in the global setting, or -1 if a value is not set. + * + * @hide + */ + @VisibleForTesting + public static long getTruncateSize() { + initIfNeeded(); + return sTruncateSize; + } + private static void initIfNeeded() { if (sInitialized || sCallingGlobalSettings) { return; @@ -115,6 +129,7 @@ public class SQLiteCompatibilityWalFlags { sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported", SQLiteGlobal.isCompatibilityWalSupported()); 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; diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 101fb821f4ce..9c639a5a9867 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -32,6 +32,7 @@ import android.util.Printer; import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; +import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -303,6 +304,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } else { setSyncMode(SQLiteGlobal.getWALSyncMode()); } + maybeTruncateWalFile(); } else { setJournalMode(mConfiguration.journalMode == null ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode); @@ -312,6 +314,40 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } } + /** + * If the WAL file exists and larger than a threshold, truncate it by executing + * PRAGMA wal_checkpoint. + */ + private void maybeTruncateWalFile() { + final long threshold = SQLiteGlobal.getWALTruncateSize(); + if (DEBUG) { + Log.d(TAG, "Truncate threshold=" + threshold); + } + if (threshold == 0) { + return; + } + + final File walFile = new File(mConfiguration.path + "-wal"); + if (!walFile.isFile()) { + return; + } + final long size = walFile.length(); + if (size < threshold) { + if (DEBUG) { + Log.d(TAG, walFile.getAbsolutePath() + " " + size + " bytes: No need to truncate"); + } + return; + } + + Log.i(TAG, walFile.getAbsolutePath() + " " + size + " bytes: Bigger than " + + threshold + "; truncating"); + try { + executeForString("PRAGMA wal_checkpoint(TRUNCATE)", null, null); + } catch (SQLiteException e) { + Log.w(TAG, "Failed to truncate the -wal file", e); + } + } + private void setSyncMode(String newValue) { String value = executeForString("PRAGMA synchronous", null, null); if (!canonicalizeSyncMode(value).equalsIgnoreCase( diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java index e6b6acf7b8ee..67e5f65d5a1f 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -164,4 +164,21 @@ public final class SQLiteGlobal { com.android.internal.R.integer.db_default_idle_connection_timeout)); } + /** + * When opening a database, if the WAL file is larger than this size, we'll truncate it. + * + * (If it's 0, we do not truncate.) + * + * @hide + */ + public static long getWALTruncateSize() { + final long setting = SQLiteCompatibilityWalFlags.getTruncateSize(); + if (setting >= 0) { + return setting; + } + return SystemProperties.getInt("debug.sqlite.wal.truncatesize", + Resources.getSystem().getInteger( + com.android.internal.R.integer.db_wal_truncate_size)); + } + } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fbe6f3ee7dff..e00ff205c082 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12777,6 +12777,7 @@ public final class Settings { * Supported keys: * compatibility_wal_supported (boolean) * wal_syncmode (String) + * truncate_size (int) * * @hide */ diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a9d69c1bcbbe..a10c1975339d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1873,6 +1873,10 @@ truncate it after committing the transaction. --> <integer name="db_journal_size_limit">524288</integer> + <!-- When opening a database with WAL enabled and if the wal file already exists and larger + than this size in bytes, we'll truncate it. --> + <integer name="db_wal_truncate_size">1048576</integer> + <!-- The database synchronization mode when using the default journal mode. FULL is safest and preserves durability at the cost of extra fsyncs. NORMAL also preserves durability in non-WAL modes and uses checksums to ensure diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a3ed1b0526d0..95af9a602577 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3415,4 +3415,6 @@ <java-symbol type="string" name="config_misprovisionedDeviceModel" /> <java-symbol type="string" name="config_misprovisionedBrandValue" /> + + <java-symbol type="integer" name="db_wal_truncate_size" /> </resources> diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java index 230655de8a00..551a58ed7cb5 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java @@ -62,18 +62,24 @@ public class SQLiteCompatibilityWalFlagsTest { assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); assertFalse(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); assertEquals("OFF", SQLiteCompatibilityWalFlags.getWALSyncMode()); + assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize()); SQLiteCompatibilityWalFlags.init("wal_syncmode=VALUE"); assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); assertEquals(SQLiteGlobal.isCompatibilityWalSupported(), SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode()); + assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize()); SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true"); assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet()); assertEquals(SQLiteGlobal.getWALSyncMode(), SQLiteCompatibilityWalFlags.getWALSyncMode()); assertTrue(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported()); + assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize()); + + SQLiteCompatibilityWalFlags.init("truncate_size=1024"); + assertEquals(1024, SQLiteCompatibilityWalFlags.getTruncateSize()); SQLiteCompatibilityWalFlags.reset(); SQLiteCompatibilityWalFlags.init("Invalid value"); |