Merge "Apps can now specify journal/synchronous mode"

This commit is contained in:
Fyodor Kupolov
2017-11-14 17:53:06 +00:00
committed by Android (Google) Code Review
8 changed files with 178 additions and 24 deletions

View File

@@ -12136,9 +12136,11 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
method public android.database.DatabaseErrorHandler getErrorHandler();
method public long getIdleConnectionTimeout();
method public java.lang.String getJournalMode();
method public int getLookasideSlotCount();
method public int getLookasideSlotSize();
method public int getOpenFlags();
method public java.lang.String getSynchronousMode();
}
public static final class SQLiteDatabase.OpenParams.Builder {
@@ -12150,8 +12152,10 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String);
}
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
@@ -12198,6 +12202,7 @@ package android.database.sqlite {
public abstract class SQLiteOpenHelper {
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
method public synchronized void close();
method public java.lang.String getDatabaseName();
method public android.database.sqlite.SQLiteDatabase getReadableDatabase();

View File

@@ -12883,9 +12883,11 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
method public android.database.DatabaseErrorHandler getErrorHandler();
method public long getIdleConnectionTimeout();
method public java.lang.String getJournalMode();
method public int getLookasideSlotCount();
method public int getLookasideSlotSize();
method public int getOpenFlags();
method public java.lang.String getSynchronousMode();
}
public static final class SQLiteDatabase.OpenParams.Builder {
@@ -12897,8 +12899,10 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String);
}
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
@@ -12945,6 +12949,7 @@ package android.database.sqlite {
public abstract class SQLiteOpenHelper {
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
method public synchronized void close();
method public java.lang.String getDatabaseName();
method public android.database.sqlite.SQLiteDatabase getReadableDatabase();

View File

@@ -12226,9 +12226,11 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
method public android.database.DatabaseErrorHandler getErrorHandler();
method public long getIdleConnectionTimeout();
method public java.lang.String getJournalMode();
method public int getLookasideSlotCount();
method public int getLookasideSlotSize();
method public int getOpenFlags();
method public java.lang.String getSynchronousMode();
}
public static final class SQLiteDatabase.OpenParams.Builder {
@@ -12240,8 +12242,10 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String);
}
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
@@ -12335,6 +12339,7 @@ package android.database.sqlite {
public abstract class SQLiteOpenHelper {
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
method public synchronized void close();
method public java.lang.String getDatabaseName();
method public android.database.sqlite.SQLiteDatabase getReadableDatabase();

View File

@@ -289,14 +289,19 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
private void setWalModeFromConfiguration() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
boolean walEnabled =
final boolean walEnabled =
(mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
if (walEnabled || mConfiguration.useCompatibilityWal) {
// Use compatibility WAL unless an app explicitly set journal/synchronous mode
final boolean useCompatibilityWal = mConfiguration.journalMode == null
&& mConfiguration.syncMode == null && mConfiguration.useCompatibilityWal;
if (walEnabled || useCompatibilityWal) {
setJournalMode("WAL");
setSyncMode(SQLiteGlobal.getWALSyncMode());
} else {
setJournalMode(SQLiteGlobal.getDefaultJournalMode());
setSyncMode(SQLiteGlobal.getDefaultSyncMode());
setJournalMode(mConfiguration.journalMode == null
? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode);
setSyncMode(mConfiguration.syncMode == null
? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode);
}
}
}
@@ -310,12 +315,10 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
}
private static String canonicalizeSyncMode(String value) {
if (value.equals("0")) {
return "OFF";
} else if (value.equals("1")) {
return "NORMAL";
} else if (value.equals("2")) {
return "FULL";
switch (value) {
case "0": return "OFF";
case "1": return "NORMAL";
case "2": return "FULL";
}
return value;
}

View File

@@ -262,7 +262,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
private SQLiteDatabase(final String path, final int openFlags,
CursorFactory cursorFactory, DatabaseErrorHandler errorHandler,
int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs) {
int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs,
String journalMode, String syncMode) {
mCursorFactory = cursorFactory;
mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
@@ -285,6 +286,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
}
}
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
mConfigurationLocked.journalMode = journalMode;
mConfigurationLocked.syncMode = syncMode;
mConfigurationLocked.useCompatibilityWal = SQLiteGlobal.isCompatibilityWalSupported();
}
@@ -721,7 +724,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags,
openParams.mCursorFactory, openParams.mErrorHandler,
openParams.mLookasideSlotSize, openParams.mLookasideSlotCount,
openParams.mIdleConnectionTimeout);
openParams.mIdleConnectionTimeout, openParams.mJournalMode, openParams.mSyncMode);
db.open();
return db;
}
@@ -747,7 +750,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
*/
public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
@DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler) {
SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1);
SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1, null,
null);
db.open();
return db;
}
@@ -2302,17 +2306,21 @@ public final class SQLiteDatabase extends SQLiteClosable {
private final DatabaseErrorHandler mErrorHandler;
private final int mLookasideSlotSize;
private final int mLookasideSlotCount;
private long mIdleConnectionTimeout;
private final long mIdleConnectionTimeout;
private final String mJournalMode;
private final String mSyncMode;
private OpenParams(int openFlags, CursorFactory cursorFactory,
DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount,
long idleConnectionTimeout) {
long idleConnectionTimeout, String journalMode, String syncMode) {
mOpenFlags = openFlags;
mCursorFactory = cursorFactory;
mErrorHandler = errorHandler;
mLookasideSlotSize = lookasideSlotSize;
mLookasideSlotCount = lookasideSlotCount;
mIdleConnectionTimeout = idleConnectionTimeout;
mJournalMode = journalMode;
mSyncMode = syncMode;
}
/**
@@ -2378,6 +2386,28 @@ public final class SQLiteDatabase extends SQLiteClosable {
return mIdleConnectionTimeout;
}
/**
* Returns <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>.
* This journal mode will only be used if {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING}
* flag is not set, otherwise a platform will use "WAL" journal mode.
* @see Builder#setJournalMode(String)
*/
@Nullable
public String getJournalMode() {
return mJournalMode;
}
/**
* Returns <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>.
* This value will only be used when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag
* is not set, otherwise a system wide default will be used.
* @see Builder#setSynchronousMode(String)
*/
@Nullable
public String getSynchronousMode() {
return mSyncMode;
}
/**
* Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with
* {@code this} parameters.
@@ -2398,6 +2428,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
private int mOpenFlags;
private CursorFactory mCursorFactory;
private DatabaseErrorHandler mErrorHandler;
private String mJournalMode;
private String mSyncMode;
public Builder() {
}
@@ -2408,6 +2440,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
mOpenFlags = params.mOpenFlags;
mCursorFactory = params.mCursorFactory;
mErrorHandler = params.mErrorHandler;
mJournalMode = params.mJournalMode;
mSyncMode = params.mSyncMode;
}
/**
@@ -2539,6 +2573,30 @@ public final class SQLiteDatabase extends SQLiteClosable {
return this;
}
/**
* Sets <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>
* to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set.
*/
@NonNull
public Builder setJournalMode(@NonNull String journalMode) {
Preconditions.checkNotNull(journalMode);
mJournalMode = journalMode;
return this;
}
/**
* Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>
* to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set.
* @return
*/
@NonNull
public Builder setSynchronousMode(@NonNull String syncMode) {
Preconditions.checkNotNull(syncMode);
mSyncMode = syncMode;
return this;
}
/**
* Creates an instance of {@link OpenParams} with the options that were previously set
* on this builder
@@ -2546,7 +2604,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
@NonNull
public OpenParams build() {
return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize,
mLookasideSlotCount, mIdleConnectionTimeout);
mLookasideSlotCount, mIdleConnectionTimeout, mJournalMode, mSyncMode);
}
}
}
@@ -2561,4 +2619,6 @@ public final class SQLiteDatabase extends SQLiteClosable {
})
@Retention(RetentionPolicy.SOURCE)
public @interface DatabaseOpenFlags {}
}

View File

@@ -119,6 +119,18 @@ public final class SQLiteDatabaseConfiguration {
*/
public boolean useCompatibilityWal;
/**
* Journal mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set.
* <p>Default is returned by {@link SQLiteGlobal#getDefaultJournalMode()}
*/
public String journalMode;
/**
* Synchronous mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set.
* <p>Default is returned by {@link SQLiteGlobal#getDefaultSyncMode()}
*/
public String syncMode;
/**
* Creates a database configuration with the required parameters for opening a
* database and default values for all other parameters.
@@ -180,6 +192,8 @@ public final class SQLiteDatabaseConfiguration {
lookasideSlotCount = other.lookasideSlotCount;
idleConnectionTimeoutMs = other.idleConnectionTimeoutMs;
useCompatibilityWal = other.useCompatibilityWal;
journalMode = other.journalMode;
syncMode = other.syncMode;
}
/**

View File

@@ -17,6 +17,8 @@
package android.database.sqlite;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.SQLException;
@@ -24,6 +26,8 @@ import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.os.FileUtils;
import android.util.Log;
import com.android.internal.util.Preconditions;
import java.io.File;
/**
@@ -69,7 +73,8 @@ public abstract class SQLiteOpenHelper {
* {@link #onUpgrade} will be used to upgrade the database; if the database is
* newer, {@link #onDowngrade} will be used to downgrade the database
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
public SQLiteOpenHelper(@NonNull Context context, @Nullable String name,
@Nullable CursorFactory factory, int version) {
this(context, name, factory, version, null);
}
@@ -90,11 +95,32 @@ public abstract class SQLiteOpenHelper {
* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
* corruption, or null to use the default error handler.
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
DatabaseErrorHandler errorHandler) {
public SQLiteOpenHelper(@NonNull Context context, @Nullable String name,
@Nullable CursorFactory factory, int version,
@Nullable DatabaseErrorHandler errorHandler) {
this(context, name, factory, version, 0, errorHandler);
}
/**
* Create a helper object to create, open, and/or manage a database.
* This method always returns very quickly. The database is not actually
* created or opened until one of {@link #getWritableDatabase} or
* {@link #getReadableDatabase} is called.
*
* @param context to use to open or create the database
* @param name of the database file, or null for an in-memory database
* @param version number of the database (starting at 1); if the database is older,
* {@link #onUpgrade} will be used to upgrade the database; if the database is
* newer, {@link #onDowngrade} will be used to downgrade the database
* @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}.
* Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be
* set when the helper opens the database
*/
public SQLiteOpenHelper(@NonNull Context context, @Nullable String name, int version,
@NonNull SQLiteDatabase.OpenParams openParams) {
this(context, name, version, 0, openParams.toBuilder());
}
/**
* Same as {@link #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)}
* but also accepts an integer minimumSupportedVersion as a convenience for upgrading very old
@@ -118,17 +144,27 @@ public abstract class SQLiteOpenHelper {
* @see #onUpgrade(SQLiteDatabase, int, int)
* @hide
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
int minimumSupportedVersion, DatabaseErrorHandler errorHandler) {
public SQLiteOpenHelper(@NonNull Context context, @Nullable String name,
@Nullable CursorFactory factory, int version,
int minimumSupportedVersion, @Nullable DatabaseErrorHandler errorHandler) {
this(context, name, version, minimumSupportedVersion,
new SQLiteDatabase.OpenParams.Builder());
mOpenParamsBuilder.setCursorFactory(factory);
mOpenParamsBuilder.setErrorHandler(errorHandler);
}
private SQLiteOpenHelper(@NonNull Context context, @Nullable String name, int version,
int minimumSupportedVersion,
@NonNull SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
Preconditions.checkNotNull(context);
Preconditions.checkNotNull(openParamsBuilder);
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
mContext = context;
mName = name;
mNewVersion = version;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
mOpenParamsBuilder = new SQLiteDatabase.OpenParams.Builder();
mOpenParamsBuilder.setCursorFactory(factory);
mOpenParamsBuilder.setErrorHandler(errorHandler);
mOpenParamsBuilder = openParamsBuilder;
mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
}

View File

@@ -16,6 +16,7 @@
package android.database;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -61,6 +62,10 @@ public class SQLiteOpenHelperTest {
super(context, name, null, 1);
}
TestHelper(Context context, String name, int version, SQLiteDatabase.OpenParams params) {
super(context, name, version, params);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@@ -168,4 +173,25 @@ public class SQLiteOpenHelperTest {
}
assertTrue("No dbstat found for " + dbName, dbStatFound);
}
@Test
public void testOpenParamsConstructor() {
SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
.setJournalMode("DELETE")
.setSynchronousMode("OFF")
.build();
TestHelper helper = new TestHelper(mContext, "openhelper_test_constructor", 1, params);
mHelpersToClose.add(helper);
String journalMode = DatabaseUtils
.stringForQuery(helper.getReadableDatabase(), "PRAGMA journal_mode", null);
assertEquals("DELETE", journalMode.toUpperCase());
String syncMode = DatabaseUtils
.stringForQuery(helper.getReadableDatabase(), "PRAGMA synchronous", null);
assertEquals("0", syncMode);
}
}