Merge "Support enabling WAL using a flag when DB is opened."
This commit is contained in:
@@ -5204,6 +5204,7 @@ package android.content {
|
||||
field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
|
||||
field public static final java.lang.String LOCATION_SERVICE = "location";
|
||||
field public static final int MODE_APPEND = 32768; // 0x8000
|
||||
field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
|
||||
field public static final int MODE_MULTI_PROCESS = 4; // 0x4
|
||||
field public static final int MODE_PRIVATE = 0; // 0x0
|
||||
field public static final int MODE_WORLD_READABLE = 1; // 0x1
|
||||
@@ -7334,6 +7335,7 @@ package android.database.sqlite {
|
||||
method public deprecated boolean isDbLockedByOtherThreads();
|
||||
method public boolean isOpen();
|
||||
method public boolean isReadOnly();
|
||||
method public boolean isWriteAheadLoggingEnabled();
|
||||
method public deprecated void markTableSyncable(java.lang.String, java.lang.String);
|
||||
method public deprecated void markTableSyncable(java.lang.String, java.lang.String, java.lang.String);
|
||||
method public boolean needUpgrade(int);
|
||||
@@ -7375,6 +7377,7 @@ package android.database.sqlite {
|
||||
field public static final int CONFLICT_REPLACE = 5; // 0x5
|
||||
field public static final int CONFLICT_ROLLBACK = 1; // 0x1
|
||||
field public static final int CREATE_IF_NECESSARY = 268435456; // 0x10000000
|
||||
field public static final int ENABLE_WRITE_AHEAD_LOGGING = 536870912; // 0x20000000
|
||||
field public static final int MAX_SQL_CACHE_SIZE = 100; // 0x64
|
||||
field public static final int NO_LOCALIZED_COLLATORS = 16; // 0x10
|
||||
field public static final int OPEN_READONLY = 1; // 0x1
|
||||
@@ -7438,6 +7441,7 @@ package android.database.sqlite {
|
||||
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void onOpen(android.database.sqlite.SQLiteDatabase);
|
||||
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
|
||||
method public void setWriteAheadLoggingEnabled(boolean);
|
||||
}
|
||||
|
||||
public class SQLiteOutOfMemoryException extends android.database.sqlite.SQLiteException {
|
||||
|
||||
@@ -766,17 +766,18 @@ class ContextImpl extends Context {
|
||||
|
||||
@Override
|
||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
|
||||
File f = validateFilePath(name, true);
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
|
||||
setFilePermissionsFromMode(f.getPath(), mode, 0);
|
||||
return db;
|
||||
return openOrCreateDatabase(name, mode, factory, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
|
||||
DatabaseErrorHandler errorHandler) {
|
||||
File f = validateFilePath(name, true);
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f.getPath(), factory, errorHandler);
|
||||
int flags = SQLiteDatabase.CREATE_IF_NECESSARY;
|
||||
if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) {
|
||||
flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;
|
||||
}
|
||||
SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler);
|
||||
setFilePermissionsFromMode(f.getPath(), mode, 0);
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,16 @@ public abstract class Context {
|
||||
*/
|
||||
public static final int MODE_MULTI_PROCESS = 0x0004;
|
||||
|
||||
/**
|
||||
* Database open flag: when set, the database is opened with write-ahead
|
||||
* logging enabled by default.
|
||||
*
|
||||
* @see #openOrCreateDatabase(String, int, CursorFactory)
|
||||
* @see #openOrCreateDatabase(String, int, CursorFactory, DatabaseErrorHandler)
|
||||
* @see SQLiteDatabase#enableWriteAheadLogging
|
||||
*/
|
||||
public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 0x0008;
|
||||
|
||||
/**
|
||||
* Flag for {@link #bindService}: automatically create the service as long
|
||||
* as the binding exists. Note that while this will create the service,
|
||||
@@ -691,6 +701,7 @@ public abstract class Context {
|
||||
* @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
|
||||
* default operation, {@link #MODE_WORLD_READABLE}
|
||||
* and {@link #MODE_WORLD_WRITEABLE} to control permissions.
|
||||
* Use {@link #MODE_ENABLE_WRITE_AHEAD_LOGGING} to enable write-ahead logging by default.
|
||||
* @param factory An optional factory class that is called to instantiate a
|
||||
* cursor when query is called.
|
||||
*
|
||||
@@ -700,6 +711,7 @@ public abstract class Context {
|
||||
* @see #MODE_PRIVATE
|
||||
* @see #MODE_WORLD_READABLE
|
||||
* @see #MODE_WORLD_WRITEABLE
|
||||
* @see #MODE_ENABLE_WRITE_AHEAD_LOGGING
|
||||
* @see #deleteDatabase
|
||||
*/
|
||||
public abstract SQLiteDatabase openOrCreateDatabase(String name,
|
||||
@@ -716,6 +728,7 @@ public abstract class Context {
|
||||
* @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
|
||||
* default operation, {@link #MODE_WORLD_READABLE}
|
||||
* and {@link #MODE_WORLD_WRITEABLE} to control permissions.
|
||||
* Use {@link #MODE_ENABLE_WRITE_AHEAD_LOGGING} to enable write-ahead logging by default.
|
||||
* @param factory An optional factory class that is called to instantiate a
|
||||
* cursor when query is called.
|
||||
* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
|
||||
@@ -726,6 +739,7 @@ public abstract class Context {
|
||||
* @see #MODE_PRIVATE
|
||||
* @see #MODE_WORLD_READABLE
|
||||
* @see #MODE_WORLD_WRITEABLE
|
||||
* @see #MODE_ENABLE_WRITE_AHEAD_LOGGING
|
||||
* @see #deleteDatabase
|
||||
*/
|
||||
public abstract SQLiteDatabase openOrCreateDatabase(String name,
|
||||
|
||||
@@ -269,7 +269,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
|
||||
|
||||
private void setWalModeFromConfiguration() {
|
||||
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
|
||||
if (mConfiguration.walEnabled) {
|
||||
if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
|
||||
setJournalMode("WAL");
|
||||
setSyncMode(SQLiteGlobal.getWALSyncMode());
|
||||
} else {
|
||||
@@ -389,7 +389,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
|
||||
}
|
||||
|
||||
// Remember what changed.
|
||||
boolean walModeChanged = configuration.walEnabled != mConfiguration.walEnabled;
|
||||
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
|
||||
& SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
|
||||
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
|
||||
|
||||
// Update configuration parameters.
|
||||
|
||||
@@ -81,6 +81,7 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
private final Object mLock = new Object();
|
||||
private final AtomicBoolean mConnectionLeaked = new AtomicBoolean();
|
||||
private final SQLiteDatabaseConfiguration mConfiguration;
|
||||
private int mMaxConnectionPoolSize;
|
||||
private boolean mIsOpen;
|
||||
private int mNextConnectionId;
|
||||
|
||||
@@ -146,6 +147,7 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
|
||||
private SQLiteConnectionPool(SQLiteDatabaseConfiguration configuration) {
|
||||
mConfiguration = new SQLiteDatabaseConfiguration(configuration);
|
||||
setMaxConnectionPoolSizeLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,8 +259,9 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
synchronized (mLock) {
|
||||
throwIfClosedLocked();
|
||||
|
||||
boolean restrictToOneConnection = false;
|
||||
if (mConfiguration.walEnabled != configuration.walEnabled) {
|
||||
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
|
||||
& SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
|
||||
if (walModeChanged) {
|
||||
// WAL mode can only be changed if there are no acquired connections
|
||||
// because we need to close all but the primary connection first.
|
||||
if (!mAcquiredConnections.isEmpty()) {
|
||||
@@ -272,15 +275,13 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
// because none of them are in use.
|
||||
closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
|
||||
assert mAvailableNonPrimaryConnections.isEmpty();
|
||||
|
||||
restrictToOneConnection = true;
|
||||
}
|
||||
|
||||
if (mConfiguration.openFlags != configuration.openFlags) {
|
||||
// If we are changing open flags and WAL mode at the same time, then
|
||||
// we have no choice but to close the primary connection beforehand
|
||||
// because there can only be one connection open when we change WAL mode.
|
||||
if (restrictToOneConnection) {
|
||||
if (walModeChanged) {
|
||||
closeAvailableConnectionsAndLogExceptionsLocked();
|
||||
}
|
||||
|
||||
@@ -296,9 +297,11 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
|
||||
mAvailablePrimaryConnection = newPrimaryConnection;
|
||||
mConfiguration.updateParametersFrom(configuration);
|
||||
setMaxConnectionPoolSizeLocked();
|
||||
} else {
|
||||
// Reconfigure the database connections in place.
|
||||
mConfiguration.updateParametersFrom(configuration);
|
||||
setMaxConnectionPoolSizeLocked();
|
||||
|
||||
closeExcessConnectionsAndLogExceptionsLocked();
|
||||
reconfigureAllConnectionsLocked();
|
||||
@@ -360,8 +363,7 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
mAvailablePrimaryConnection = connection;
|
||||
}
|
||||
wakeConnectionWaitersLocked();
|
||||
} else if (mAvailableNonPrimaryConnections.size() >=
|
||||
mConfiguration.maxConnectionPoolSize - 1) {
|
||||
} else if (mAvailableNonPrimaryConnections.size() >= mMaxConnectionPoolSize - 1) {
|
||||
closeConnectionAndLogExceptionsLocked(connection);
|
||||
} else {
|
||||
if (recycleConnectionLocked(connection, status)) {
|
||||
@@ -499,7 +501,7 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
// Can't throw.
|
||||
private void closeExcessConnectionsAndLogExceptionsLocked() {
|
||||
int availableCount = mAvailableNonPrimaryConnections.size();
|
||||
while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) {
|
||||
while (availableCount-- > mMaxConnectionPoolSize - 1) {
|
||||
SQLiteConnection connection =
|
||||
mAvailableNonPrimaryConnections.remove(availableCount);
|
||||
closeConnectionAndLogExceptionsLocked(connection);
|
||||
@@ -874,7 +876,7 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
if (mAvailablePrimaryConnection != null) {
|
||||
openConnections += 1;
|
||||
}
|
||||
if (openConnections >= mConfiguration.maxConnectionPoolSize) {
|
||||
if (openConnections >= mMaxConnectionPoolSize) {
|
||||
return null;
|
||||
}
|
||||
connection = openConnectionLocked(mConfiguration,
|
||||
@@ -926,6 +928,18 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
return (connectionFlags & CONNECTION_FLAG_INTERACTIVE) != 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
private void setMaxConnectionPoolSizeLocked() {
|
||||
if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
|
||||
mMaxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize();
|
||||
} else {
|
||||
// TODO: We don't actually need to restrict the connection pool size to 1
|
||||
// for non-WAL databases. There might be reasons to use connection pooling
|
||||
// with other journal modes. For now, enabling connection pooling and
|
||||
// using WAL are the same thing in the API.
|
||||
mMaxConnectionPoolSize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void throwIfClosedLocked() {
|
||||
if (!mIsOpen) {
|
||||
throw new IllegalStateException("Cannot perform this operation "
|
||||
@@ -972,7 +986,7 @@ public final class SQLiteConnectionPool implements Closeable {
|
||||
synchronized (mLock) {
|
||||
printer.println("Connection pool for " + mConfiguration.path + ":");
|
||||
printer.println(" Open: " + mIsOpen);
|
||||
printer.println(" Max connections: " + mConfiguration.maxConnectionPoolSize);
|
||||
printer.println(" Max connections: " + mMaxConnectionPoolSize);
|
||||
|
||||
printer.println(" Available primary connection:");
|
||||
if (mAvailablePrimaryConnection != null) {
|
||||
|
||||
@@ -231,6 +231,18 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
*/
|
||||
public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing
|
||||
|
||||
/**
|
||||
* Open flag: Flag for {@link #openDatabase} to open the database file with
|
||||
* write-ahead logging enabled by default. Using this flag is more efficient
|
||||
* than calling {@link #enableWriteAheadLogging}.
|
||||
*
|
||||
* Write-ahead logging cannot be used with read-only databases so the value of
|
||||
* this flag is ignored if the database is opened read-only.
|
||||
*
|
||||
* @see #enableWriteAheadLogging
|
||||
*/
|
||||
public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
|
||||
|
||||
/**
|
||||
* Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
|
||||
*
|
||||
@@ -654,7 +666,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* @throws SQLiteException if the database cannot be opened
|
||||
*/
|
||||
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
|
||||
return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler());
|
||||
return openDatabase(path, factory, flags, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -694,7 +706,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
|
||||
*/
|
||||
public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
|
||||
return openDatabase(path, factory, CREATE_IF_NECESSARY);
|
||||
return openDatabase(path, factory, CREATE_IF_NECESSARY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1781,56 +1793,84 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method enables parallel execution of queries from multiple threads on the same database.
|
||||
* It does this by opening multiple handles to the database and using a different
|
||||
* database handle for each query.
|
||||
* This method enables parallel execution of queries from multiple threads on the
|
||||
* same database. It does this by opening multiple connections to the database
|
||||
* and using a different database connection for each query. The database
|
||||
* journal mode is also changed to enable writes to proceed concurrently with reads.
|
||||
* <p>
|
||||
* If a transaction is in progress on one connection handle and say, a table is updated in the
|
||||
* transaction, then query on the same table on another connection handle will block for the
|
||||
* transaction to complete. But this method enables such queries to execute by having them
|
||||
* return old version of the data from the table. Most often it is the data that existed in the
|
||||
* table prior to the above transaction updates on that table.
|
||||
* <p>
|
||||
* Maximum number of simultaneous handles used to execute queries in parallel is
|
||||
* When write-ahead logging is not enabled (the default), it is not possible for
|
||||
* reads and writes to occur on the database at the same time. Before modifying the
|
||||
* database, the writer implicitly acquires an exclusive lock on the database which
|
||||
* prevents readers from accessing the database until the write is completed.
|
||||
* </p><p>
|
||||
* In contrast, when write-ahead logging is enabled (by calling this method), write
|
||||
* operations occur in a separate log file which allows reads to proceed concurrently.
|
||||
* While a write is in progress, readers on other threads will perceive the state
|
||||
* of the database as it was before the write began. When the write completes, readers
|
||||
* on other threads will then perceive the new state of the database.
|
||||
* </p><p>
|
||||
* It is a good idea to enable write-ahead logging whenever a database will be
|
||||
* concurrently accessed and modified by multiple threads at the same time.
|
||||
* However, write-ahead logging uses significantly more memory than ordinary
|
||||
* journaling because there are multiple connections to the same database.
|
||||
* So if a database will only be used by a single thread, or if optimizing
|
||||
* concurrency is not very important, then write-ahead logging should be disabled.
|
||||
* </p><p>
|
||||
* After calling this method, execution of queries in parallel is enabled as long as
|
||||
* the database remains open. To disable execution of queries in parallel, either
|
||||
* call {@link #disableWriteAheadLogging} or close the database and reopen it.
|
||||
* </p><p>
|
||||
* The maximum number of connections used to execute queries in parallel is
|
||||
* dependent upon the device memory and possibly other properties.
|
||||
* <p>
|
||||
* After calling this method, execution of queries in parallel is enabled as long as this
|
||||
* database handle is open. To disable execution of queries in parallel, database should
|
||||
* be closed and reopened.
|
||||
* <p>
|
||||
* </p><p>
|
||||
* If a query is part of a transaction, then it is executed on the same database handle the
|
||||
* transaction was begun.
|
||||
* <p>
|
||||
* If the database has any attached databases, then execution of queries in paralel is NOT
|
||||
* possible. In such cases, a message is printed to logcat and false is returned.
|
||||
* <p>
|
||||
* This feature is not available for :memory: databases. In such cases,
|
||||
* a message is printed to logcat and false is returned.
|
||||
* <p>
|
||||
* A typical way to use this method is the following:
|
||||
* <pre>
|
||||
* SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
|
||||
* CREATE_IF_NECESSARY, myDatabaseErrorHandler);
|
||||
* db.enableWriteAheadLogging();
|
||||
* </pre>
|
||||
* <p>
|
||||
* </p><p>
|
||||
* Writers should use {@link #beginTransactionNonExclusive()} or
|
||||
* {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)}
|
||||
* to start a trsnsaction.
|
||||
* Non-exclusive mode allows database file to be in readable by threads executing queries.
|
||||
* to start a transaction. Non-exclusive mode allows database file to be in readable
|
||||
* by other threads executing queries.
|
||||
* </p><p>
|
||||
* If the database has any attached databases, then execution of queries in parallel is NOT
|
||||
* possible. Likewise, write-ahead logging is not supported for read-only databases
|
||||
* or memory databases. In such cases, {@link #enableWriteAheadLogging} returns false.
|
||||
* </p><p>
|
||||
* The best way to enable write-ahead logging is to pass the
|
||||
* {@link #ENABLE_WRITE_AHEAD_LOGGING} flag to {@link #openDatabase}. This is
|
||||
* more efficient than calling {@link #enableWriteAheadLogging}.
|
||||
* <code><pre>
|
||||
* SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
|
||||
* SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING,
|
||||
* myDatabaseErrorHandler);
|
||||
* db.enableWriteAheadLogging();
|
||||
* </pre></code>
|
||||
* </p><p>
|
||||
* Another way to enable write-ahead logging is to call {@link #enableWriteAheadLogging}
|
||||
* after opening the database.
|
||||
* <code><pre>
|
||||
* SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
|
||||
* SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler);
|
||||
* db.enableWriteAheadLogging();
|
||||
* </pre></code>
|
||||
* </p><p>
|
||||
* See also <a href="http://sqlite.org/wal.html">SQLite Write-Ahead Logging</a> for
|
||||
* more details about how write-ahead logging works.
|
||||
* </p>
|
||||
*
|
||||
* @return true if write-ahead-logging is set. false otherwise
|
||||
* @return True if write-ahead logging is enabled.
|
||||
*
|
||||
* @throws IllegalStateException if there are transactions in progress at the
|
||||
* time this method is called. WAL mode can only be changed when there are no
|
||||
* transactions in progress.
|
||||
*
|
||||
* @see #ENABLE_WRITE_AHEAD_LOGGING
|
||||
* @see #disableWriteAheadLogging
|
||||
*/
|
||||
public boolean enableWriteAheadLogging() {
|
||||
synchronized (mLock) {
|
||||
throwIfNotOpenLocked();
|
||||
|
||||
if (mConfigurationLocked.walEnabled) {
|
||||
if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1855,14 +1895,11 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize;
|
||||
mConfigurationLocked.maxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize();
|
||||
mConfigurationLocked.walEnabled = true;
|
||||
mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
|
||||
try {
|
||||
mConnectionPoolLocked.reconfigure(mConfigurationLocked);
|
||||
} catch (RuntimeException ex) {
|
||||
mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize;
|
||||
mConfigurationLocked.walEnabled = false;
|
||||
mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -1875,28 +1912,43 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* @throws IllegalStateException if there are transactions in progress at the
|
||||
* time this method is called. WAL mode can only be changed when there are no
|
||||
* transactions in progress.
|
||||
*
|
||||
* @see #enableWriteAheadLogging
|
||||
*/
|
||||
public void disableWriteAheadLogging() {
|
||||
synchronized (mLock) {
|
||||
throwIfNotOpenLocked();
|
||||
|
||||
if (!mConfigurationLocked.walEnabled) {
|
||||
if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize;
|
||||
mConfigurationLocked.maxConnectionPoolSize = 1;
|
||||
mConfigurationLocked.walEnabled = false;
|
||||
mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
|
||||
try {
|
||||
mConnectionPoolLocked.reconfigure(mConfigurationLocked);
|
||||
} catch (RuntimeException ex) {
|
||||
mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize;
|
||||
mConfigurationLocked.walEnabled = true;
|
||||
mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if write-ahead logging has been enabled for this database.
|
||||
*
|
||||
* @return True if write-ahead logging has been enabled for this database.
|
||||
*
|
||||
* @see #enableWriteAheadLogging
|
||||
* @see #ENABLE_WRITE_AHEAD_LOGGING
|
||||
*/
|
||||
public boolean isWriteAheadLoggingEnabled() {
|
||||
synchronized (mLock) {
|
||||
throwIfNotOpenLocked();
|
||||
|
||||
return (mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect statistics about all open databases in the current process.
|
||||
* Used by bug report.
|
||||
|
||||
@@ -61,14 +61,6 @@ public final class SQLiteDatabaseConfiguration {
|
||||
*/
|
||||
public int openFlags;
|
||||
|
||||
/**
|
||||
* The maximum number of connections to retain in the connection pool.
|
||||
* Must be at least 1.
|
||||
*
|
||||
* Default is 1.
|
||||
*/
|
||||
public int maxConnectionPoolSize;
|
||||
|
||||
/**
|
||||
* The maximum size of the prepared statement cache for each database connection.
|
||||
* Must be non-negative.
|
||||
@@ -84,13 +76,6 @@ public final class SQLiteDatabaseConfiguration {
|
||||
*/
|
||||
public Locale locale;
|
||||
|
||||
/**
|
||||
* True if WAL mode is enabled.
|
||||
*
|
||||
* Default is false.
|
||||
*/
|
||||
public boolean walEnabled;
|
||||
|
||||
/**
|
||||
* The custom functions to register.
|
||||
*/
|
||||
@@ -114,7 +99,6 @@ public final class SQLiteDatabaseConfiguration {
|
||||
this.openFlags = openFlags;
|
||||
|
||||
// Set default values for optional parameters.
|
||||
maxConnectionPoolSize = 1;
|
||||
maxSqlCacheSize = 25;
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
@@ -150,10 +134,8 @@ public final class SQLiteDatabaseConfiguration {
|
||||
}
|
||||
|
||||
openFlags = other.openFlags;
|
||||
maxConnectionPoolSize = other.maxConnectionPoolSize;
|
||||
maxSqlCacheSize = other.maxSqlCacheSize;
|
||||
locale = other.locale;
|
||||
walEnabled = other.walEnabled;
|
||||
customFunctions.clear();
|
||||
customFunctions.addAll(other.customFunctions);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ public abstract class SQLiteOpenHelper {
|
||||
|
||||
private SQLiteDatabase mDatabase;
|
||||
private boolean mIsInitializing;
|
||||
private boolean mEnableWriteAheadLogging;
|
||||
private final DatabaseErrorHandler mErrorHandler;
|
||||
|
||||
/**
|
||||
@@ -74,7 +75,7 @@ public abstract class SQLiteOpenHelper {
|
||||
* newer, {@link #onDowngrade} will be used to downgrade the database
|
||||
*/
|
||||
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
|
||||
this(context, name, factory, version, new DefaultDatabaseErrorHandler());
|
||||
this(context, name, factory, version, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,14 +93,11 @@ 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
|
||||
* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
|
||||
* corruption.
|
||||
* corruption, or null to use the default error handler.
|
||||
*/
|
||||
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
|
||||
DatabaseErrorHandler errorHandler) {
|
||||
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
|
||||
if (errorHandler == null) {
|
||||
throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null.");
|
||||
}
|
||||
|
||||
mContext = context;
|
||||
mName = name;
|
||||
@@ -116,6 +114,32 @@ public abstract class SQLiteOpenHelper {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the use of write-ahead logging for the database.
|
||||
*
|
||||
* Write-ahead logging cannot be used with read-only databases so the value of
|
||||
* this flag is ignored if the database is opened read-only.
|
||||
*
|
||||
* @param enabled True if write-ahead logging should be enabled, false if it
|
||||
* should be disabled.
|
||||
*
|
||||
* @see SQLiteDatabase#enableWriteAheadLogging()
|
||||
*/
|
||||
public void setWriteAheadLoggingEnabled(boolean enabled) {
|
||||
synchronized (this) {
|
||||
if (mEnableWriteAheadLogging != enabled) {
|
||||
if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
|
||||
if (enabled) {
|
||||
mDatabase.enableWriteAheadLogging();
|
||||
} else {
|
||||
mDatabase.disableWriteAheadLogging();
|
||||
}
|
||||
}
|
||||
mEnableWriteAheadLogging = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and/or open a database that will be used for reading and writing.
|
||||
* The first time this is called, the database will be opened and
|
||||
@@ -197,7 +221,9 @@ public abstract class SQLiteOpenHelper {
|
||||
db = SQLiteDatabase.openDatabase(path, mFactory,
|
||||
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
|
||||
} else {
|
||||
db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
|
||||
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
|
||||
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
|
||||
mFactory, mErrorHandler);
|
||||
}
|
||||
} catch (SQLiteException ex) {
|
||||
if (writable) {
|
||||
|
||||
@@ -84,6 +84,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||
public DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
mContext = context;
|
||||
setWriteAheadLoggingEnabled(true);
|
||||
}
|
||||
|
||||
public static boolean isValidTable(String name) {
|
||||
|
||||
@@ -260,7 +260,6 @@ public class SettingsProvider extends ContentProvider {
|
||||
// Watch for external modifications to the database file,
|
||||
// keeping our cache in sync.
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
db.enableWriteAheadLogging();
|
||||
sObserverInstance = new SettingsFileObserver(db.getPath());
|
||||
sObserverInstance.startWatching();
|
||||
startAsyncCachePopulation();
|
||||
|
||||
Reference in New Issue
Block a user