diff options
| author | 2018-08-24 23:30:18 +0000 | |
|---|---|---|
| committer | 2018-08-24 23:30:18 +0000 | |
| commit | 8084b2b25dc9439a9425107d9628a15becb5e546 (patch) | |
| tree | 763b03aa74a2b50bfe82236ef79edcef7efaa0d8 | |
| parent | f15c333ddcd9c406d71245120d3d200f47588fed (diff) | |
| parent | 96e06002edc374511c545d96ae9b2b7c1e8d78ec (diff) | |
Merge "Truncate(*1) it if WAL file is too big when opening DB"
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 3ca852a34594..5c4f16a7cf3d 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -33,6 +33,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; @@ -308,6 +309,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } else { setSyncMode(SQLiteGlobal.getWALSyncMode()); } + maybeTruncateWalFile(); } else { setJournalMode(mConfiguration.journalMode == null ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode); @@ -317,6 +319,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 7980af12b821..bffed8dcfdf2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13114,6 +13114,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 c664abf55100..289c898a923c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1868,6 +1868,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 9cf6ac6a61af..53588303fcd5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3449,4 +3449,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"); |