summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-03-21 17:24:05 -0700
committerJeff Brown <jeffbrown@google.com>2012-03-21 18:08:09 -0700
commite67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fc (patch)
treed8d0206806fc245148ac7cf12ad3c8f7312f1d09 /core
parent3e6792232aa0ce3e650eaa03529c9eb2fe023ca9 (diff)
downloadframeworks_base-e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fc.zip
frameworks_base-e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fc.tar.gz
frameworks_base-e67ca420e4eb6ddf8ceefeb0d9dcc47d9ca189fc.tar.bz2
Throw if WAL enabled/disabled when connections are in use.
Changing WAL mode requires obtaining an exclusive lock on the database and can only be done when there are NO other active database connections. Check that this is really the case, and bail with a useful error message if an application attempts to change WAL mode while transactions are in progress. Expose disableWriteAheadLogging() in the API. Change-Id: I87599de3b88c53dcd75677aefd72e40de216c2c1
Diffstat (limited to 'core')
-rw-r--r--core/java/android/database/sqlite/SQLiteConnectionPool.java42
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java65
2 files changed, 94 insertions, 13 deletions
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 3562e89..00d3309 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -257,7 +257,34 @@ public final class SQLiteConnectionPool implements Closeable {
synchronized (mLock) {
throwIfClosedLocked();
+ boolean restrictToOneConnection = false;
+ if (mConfiguration.journalMode.equalsIgnoreCase("WAL")
+ != configuration.journalMode.equalsIgnoreCase("WAL")) {
+ // 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()) {
+ throw new IllegalStateException("Write Ahead Logging (WAL) mode cannot "
+ + "be enabled or disabled while there are transactions in "
+ + "progress. Finish all transactions and release all active "
+ + "database connections first.");
+ }
+
+ // Close all non-primary connections. This should happen immediately
+ // 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) {
+ closeAvailableConnectionsAndLogExceptionsLocked();
+ }
+
// Try to reopen the primary connection using the new open flags then
// close and discard all existing connections.
// This might throw if the database is corrupt or cannot be opened in
@@ -453,11 +480,7 @@ public final class SQLiteConnectionPool implements Closeable {
// Can't throw.
private void closeAvailableConnectionsAndLogExceptionsLocked() {
- final int count = mAvailableNonPrimaryConnections.size();
- for (int i = 0; i < count; i++) {
- closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i));
- }
- mAvailableNonPrimaryConnections.clear();
+ closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
if (mAvailablePrimaryConnection != null) {
closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection);
@@ -466,6 +489,15 @@ public final class SQLiteConnectionPool implements Closeable {
}
// Can't throw.
+ private void closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked() {
+ final int count = mAvailableNonPrimaryConnections.size();
+ for (int i = 0; i < count; i++) {
+ closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i));
+ }
+ mAvailableNonPrimaryConnections.clear();
+ }
+
+ // Can't throw.
private void closeExcessConnectionsAndLogExceptionsLocked() {
int availableCount = mAvailableNonPrimaryConnections.size();
while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index bf32ea7..e575c26 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -834,8 +834,14 @@ public final class SQLiteDatabase extends SQLiteClosable {
synchronized (mLock) {
throwIfNotOpenLocked();
+
mConfigurationLocked.customFunctions.add(wrapper);
- mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.customFunctions.remove(wrapper);
+ throw ex;
+ }
}
}
@@ -1733,8 +1739,15 @@ public final class SQLiteDatabase extends SQLiteClosable {
synchronized (mLock) {
throwIfNotOpenLocked();
+
+ final Locale oldLocale = mConfigurationLocked.locale;
mConfigurationLocked.locale = locale;
- mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.locale = oldLocale;
+ throw ex;
+ }
}
}
@@ -1759,8 +1772,15 @@ public final class SQLiteDatabase extends SQLiteClosable {
synchronized (mLock) {
throwIfNotOpenLocked();
+
+ final int oldMaxSqlCacheSize = mConfigurationLocked.maxSqlCacheSize;
mConfigurationLocked.maxSqlCacheSize = cacheSize;
- mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.maxSqlCacheSize = oldMaxSqlCacheSize;
+ throw ex;
+ }
}
}
@@ -1805,6 +1825,10 @@ public final class SQLiteDatabase extends SQLiteClosable {
* </p>
*
* @return true if write-ahead-logging is set. false otherwise
+ *
+ * @throw 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.
*/
public boolean enableWriteAheadLogging() {
synchronized (mLock) {
@@ -1835,18 +1859,32 @@ public final class SQLiteDatabase extends SQLiteClosable {
return false;
}
- mIsWALEnabledLocked = true;
+ final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize;
+ final String oldSyncMode = mConfigurationLocked.syncMode;
+ final String oldJournalMode = mConfigurationLocked.journalMode;
mConfigurationLocked.maxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize();
mConfigurationLocked.syncMode = SQLiteGlobal.getWALSyncMode();
mConfigurationLocked.journalMode = "WAL";
- mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize;
+ mConfigurationLocked.syncMode = oldSyncMode;
+ mConfigurationLocked.journalMode = oldJournalMode;
+ throw ex;
+ }
+
+ mIsWALEnabledLocked = true;
}
return true;
}
/**
* This method disables the features enabled by {@link #enableWriteAheadLogging()}.
- * @hide
+ *
+ * @throw 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.
*/
public void disableWriteAheadLogging() {
synchronized (mLock) {
@@ -1856,11 +1894,22 @@ public final class SQLiteDatabase extends SQLiteClosable {
return;
}
- mIsWALEnabledLocked = false;
+ final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize;
+ final String oldSyncMode = mConfigurationLocked.syncMode;
+ final String oldJournalMode = mConfigurationLocked.journalMode;
mConfigurationLocked.maxConnectionPoolSize = 1;
mConfigurationLocked.syncMode = SQLiteGlobal.getDefaultSyncMode();
mConfigurationLocked.journalMode = SQLiteGlobal.getDefaultJournalMode();
- mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ try {
+ mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+ } catch (RuntimeException ex) {
+ mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize;
+ mConfigurationLocked.syncMode = oldSyncMode;
+ mConfigurationLocked.journalMode = oldJournalMode;
+ throw ex;
+ }
+
+ mIsWALEnabledLocked = false;
}
}