Loading core/java/android/database/sqlite/SQLiteConnectionPool.java +113 −73 Original line number Diff line number Diff line Loading @@ -92,13 +92,25 @@ public final class SQLiteConnectionPool implements Closeable { new ArrayList<SQLiteConnection>(); private SQLiteConnection mAvailablePrimaryConnection; // Describes what should happen to an acquired connection when it is returned to the pool. enum AcquiredConnectionStatus { // The connection should be returned to the pool as usual. NORMAL, // The connection must be reconfigured before being returned. RECONFIGURE, // The connection must be closed and discarded. DISCARD, } // Weak references to all acquired connections. The associated value // is a boolean that indicates whether the connection must be reconfigured // before being returned to the available connection list. // indicates whether the connection must be reconfigured before being // returned to the available connection list or discarded. // For example, the prepared statement cache size may have changed and // need to be updated. private final WeakHashMap<SQLiteConnection, Boolean> mAcquiredConnections = new WeakHashMap<SQLiteConnection, Boolean>(); // need to be updated in preparation for the next client. private final WeakHashMap<SQLiteConnection, AcquiredConnectionStatus> mAcquiredConnections = new WeakHashMap<SQLiteConnection, AcquiredConnectionStatus>(); /** * Connection flag: Read-only. Loading Loading @@ -168,7 +180,7 @@ public final class SQLiteConnectionPool implements Closeable { private void open() { // Open the primary connection. // This might throw if the database is corrupt. mAvailablePrimaryConnection = openConnectionLocked( mAvailablePrimaryConnection = openConnectionLocked(mConfiguration, true /*primaryConnection*/); // might throw // Mark the pool as being open for business. Loading Loading @@ -209,16 +221,7 @@ public final class SQLiteConnectionPool implements Closeable { mIsOpen = false; final int count = mAvailableNonPrimaryConnections.size(); for (int i = 0; i < count; i++) { closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i)); } mAvailableNonPrimaryConnections.clear(); if (mAvailablePrimaryConnection != null) { closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection); mAvailablePrimaryConnection = null; } closeAvailableConnectionsAndLogExceptionsLocked(); final int pendingCount = mAcquiredConnections.size(); if (pendingCount != 0) { Loading Loading @@ -254,20 +257,26 @@ public final class SQLiteConnectionPool implements Closeable { synchronized (mLock) { throwIfClosedLocked(); final boolean poolSizeChanged = mConfiguration.maxConnectionPoolSize != configuration.maxConnectionPoolSize; mConfiguration.updateParametersFrom(configuration); if (mConfiguration.openFlags != configuration.openFlags) { // 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 // the new mode in which case existing connections will remain untouched. SQLiteConnection newPrimaryConnection = openConnectionLocked(configuration, true /*primaryConnection*/); // might throw if (poolSizeChanged) { int availableCount = mAvailableNonPrimaryConnections.size(); while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) { SQLiteConnection connection = mAvailableNonPrimaryConnections.remove(availableCount); closeConnectionAndLogExceptionsLocked(connection); } } closeAvailableConnectionsAndLogExceptionsLocked(); discardAcquiredConnectionsLocked(); mAvailablePrimaryConnection = newPrimaryConnection; mConfiguration.updateParametersFrom(configuration); } else { // Reconfigure the database connections in place. mConfiguration.updateParametersFrom(configuration); closeExcessConnectionsAndLogExceptionsLocked(); reconfigureAllConnectionsLocked(); } wakeConnectionWaitersLocked(); } Loading Loading @@ -310,8 +319,8 @@ public final class SQLiteConnectionPool implements Closeable { */ public void releaseConnection(SQLiteConnection connection) { synchronized (mLock) { Boolean mustReconfigure = mAcquiredConnections.remove(connection); if (mustReconfigure == null) { AcquiredConnectionStatus status = mAcquiredConnections.remove(connection); if (status == null) { throw new IllegalStateException("Cannot perform this operation " + "because the specified connection was not acquired " + "from this pool or has already been released."); Loading @@ -320,18 +329,8 @@ public final class SQLiteConnectionPool implements Closeable { if (!mIsOpen) { closeConnectionAndLogExceptionsLocked(connection); } else if (connection.isPrimaryConnection()) { if (recycleConnectionLocked(connection, status)) { assert mAvailablePrimaryConnection == null; try { if (mustReconfigure == Boolean.TRUE) { connection.reconfigure(mConfiguration); // might throw } } catch (RuntimeException ex) { Log.e(TAG, "Failed to reconfigure released primary connection, closing it: " + connection, ex); closeConnectionAndLogExceptionsLocked(connection); connection = null; } if (connection != null) { mAvailablePrimaryConnection = connection; } wakeConnectionWaitersLocked(); Loading @@ -339,22 +338,31 @@ public final class SQLiteConnectionPool implements Closeable { mConfiguration.maxConnectionPoolSize - 1) { closeConnectionAndLogExceptionsLocked(connection); } else { if (recycleConnectionLocked(connection, status)) { mAvailableNonPrimaryConnections.add(connection); } wakeConnectionWaitersLocked(); } } } // Can't throw. private boolean recycleConnectionLocked(SQLiteConnection connection, AcquiredConnectionStatus status) { if (status == AcquiredConnectionStatus.RECONFIGURE) { try { if (mustReconfigure == Boolean.TRUE) { connection.reconfigure(mConfiguration); // might throw } } catch (RuntimeException ex) { Log.e(TAG, "Failed to reconfigure released non-primary connection, " + "closing it: " + connection, ex); closeConnectionAndLogExceptionsLocked(connection); connection = null; Log.e(TAG, "Failed to reconfigure released connection, closing it: " + connection, ex); status = AcquiredConnectionStatus.DISCARD; } if (connection != null) { mAvailableNonPrimaryConnections.add(connection); } wakeConnectionWaitersLocked(); } if (status == AcquiredConnectionStatus.DISCARD) { closeConnectionAndLogExceptionsLocked(connection); return false; } return true; } /** Loading Loading @@ -407,9 +415,10 @@ public final class SQLiteConnectionPool implements Closeable { } // Might throw. private SQLiteConnection openConnectionLocked(boolean primaryConnection) { private SQLiteConnection openConnectionLocked(SQLiteDatabaseConfiguration configuration, boolean primaryConnection) { final int connectionId = mNextConnectionId++; return SQLiteConnection.open(this, mConfiguration, return SQLiteConnection.open(this, configuration, connectionId, primaryConnection); // might throw } Loading Loading @@ -442,6 +451,30 @@ public final class SQLiteConnectionPool implements Closeable { mConnectionLeaked.set(true); } // Can't throw. private void closeAvailableConnectionsAndLogExceptionsLocked() { final int count = mAvailableNonPrimaryConnections.size(); for (int i = 0; i < count; i++) { closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i)); } mAvailableNonPrimaryConnections.clear(); if (mAvailablePrimaryConnection != null) { closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection); mAvailablePrimaryConnection = null; } } // Can't throw. private void closeExcessConnectionsAndLogExceptionsLocked() { int availableCount = mAvailableNonPrimaryConnections.size(); while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) { SQLiteConnection connection = mAvailableNonPrimaryConnections.remove(availableCount); closeConnectionAndLogExceptionsLocked(connection); } } // Can't throw. private void closeConnectionAndLogExceptionsLocked(SQLiteConnection connection) { try { Loading @@ -452,9 +485,13 @@ public final class SQLiteConnectionPool implements Closeable { } } // Can't throw. private void discardAcquiredConnectionsLocked() { markAcquiredConnectionsLocked(AcquiredConnectionStatus.DISCARD); } // Can't throw. private void reconfigureAllConnectionsLocked() { boolean wake = false; if (mAvailablePrimaryConnection != null) { try { mAvailablePrimaryConnection.reconfigure(mConfiguration); // might throw Loading @@ -463,7 +500,6 @@ public final class SQLiteConnectionPool implements Closeable { + mAvailablePrimaryConnection, ex); closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection); mAvailablePrimaryConnection = null; wake = true; } } Loading @@ -478,27 +514,30 @@ public final class SQLiteConnectionPool implements Closeable { closeConnectionAndLogExceptionsLocked(connection); mAvailableNonPrimaryConnections.remove(i--); count -= 1; wake = true; } } markAcquiredConnectionsLocked(AcquiredConnectionStatus.RECONFIGURE); } // Can't throw. private void markAcquiredConnectionsLocked(AcquiredConnectionStatus status) { if (!mAcquiredConnections.isEmpty()) { ArrayList<SQLiteConnection> keysToUpdate = new ArrayList<SQLiteConnection>( mAcquiredConnections.size()); for (Map.Entry<SQLiteConnection, Boolean> entry : mAcquiredConnections.entrySet()) { if (entry.getValue() != Boolean.TRUE) { for (Map.Entry<SQLiteConnection, AcquiredConnectionStatus> entry : mAcquiredConnections.entrySet()) { AcquiredConnectionStatus oldStatus = entry.getValue(); if (status != oldStatus && oldStatus != AcquiredConnectionStatus.DISCARD) { keysToUpdate.add(entry.getKey()); } } final int updateCount = keysToUpdate.size(); for (int i = 0; i < updateCount; i++) { mAcquiredConnections.put(keysToUpdate.get(i), Boolean.TRUE); mAcquiredConnections.put(keysToUpdate.get(i), status); } } if (wake) { wakeConnectionWaitersLocked(); } } // Might throw. Loading Loading @@ -658,8 +697,7 @@ public final class SQLiteConnectionPool implements Closeable { int activeConnections = 0; int idleConnections = 0; if (!mAcquiredConnections.isEmpty()) { for (Map.Entry<SQLiteConnection, Boolean> entry : mAcquiredConnections.entrySet()) { final SQLiteConnection connection = entry.getKey(); for (SQLiteConnection connection : mAcquiredConnections.keySet()) { String description = connection.describeCurrentOperationUnsafe(); if (description != null) { requests.add(description); Loading Loading @@ -769,7 +807,8 @@ public final class SQLiteConnectionPool implements Closeable { // Uhoh. No primary connection! Either this is the first time we asked // for it, or maybe it leaked? connection = openConnectionLocked(true /*primaryConnection*/); // might throw connection = openConnectionLocked(mConfiguration, true /*primaryConnection*/); // might throw finishAcquireConnectionLocked(connection, connectionFlags); // might throw return connection; } Loading Loading @@ -807,7 +846,8 @@ public final class SQLiteConnectionPool implements Closeable { if (openConnections >= mConfiguration.maxConnectionPoolSize) { return null; } connection = openConnectionLocked(false /*primaryConnection*/); // might throw connection = openConnectionLocked(mConfiguration, false /*primaryConnection*/); // might throw finishAcquireConnectionLocked(connection, connectionFlags); // might throw return connection; } Loading @@ -818,7 +858,7 @@ public final class SQLiteConnectionPool implements Closeable { final boolean readOnly = (connectionFlags & CONNECTION_FLAG_READ_ONLY) != 0; connection.setOnlyAllowReadOnlyOperations(readOnly); mAcquiredConnections.put(connection, Boolean.FALSE); mAcquiredConnections.put(connection, AcquiredConnectionStatus.NORMAL); } catch (RuntimeException ex) { Log.e(TAG, "Failed to prepare acquired connection for session, closing it: " + connection +", connectionFlags=" + connectionFlags); Loading Loading @@ -858,7 +898,7 @@ public final class SQLiteConnectionPool implements Closeable { private void throwIfClosedLocked() { if (!mIsOpen) { throw new IllegalStateException("Cannot perform this operation " + "because the connection pool have been closed."); + "because the connection pool has been closed."); } } Loading Loading @@ -922,11 +962,11 @@ public final class SQLiteConnectionPool implements Closeable { printer.println(" Acquired connections:"); if (!mAcquiredConnections.isEmpty()) { for (Map.Entry<SQLiteConnection, Boolean> entry : for (Map.Entry<SQLiteConnection, AcquiredConnectionStatus> entry : mAcquiredConnections.entrySet()) { final SQLiteConnection connection = entry.getKey(); connection.dumpUnsafe(indentedPrinter, verbose); indentedPrinter.println(" Pending reconfiguration: " + entry.getValue()); indentedPrinter.println(" Status: " + entry.getValue()); } } else { indentedPrinter.println("<none>"); Loading core/java/android/database/sqlite/SQLiteDatabase.java +32 −22 Original line number Diff line number Diff line Loading @@ -677,6 +677,38 @@ public class SQLiteDatabase extends SQLiteClosable { return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler); } /** * Reopens the database in read-write mode. * If the database is already read-write, does nothing. * * @throws SQLiteException if the database could not be reopened as requested, in which * case it remains open in read only mode. * @throws IllegalStateException if the database is not open. * * @see #isReadOnly() * @hide */ public void reopenReadWrite() { synchronized (mLock) { throwIfNotOpenLocked(); if (!isReadOnlyLocked()) { return; // nothing to do } // Reopen the database in read-write mode. final int oldOpenFlags = mConfigurationLocked.openFlags; mConfigurationLocked.openFlags = (mConfigurationLocked.openFlags & ~OPEN_READ_MASK) | OPEN_READWRITE; try { mConnectionPoolLocked.reconfigure(mConfigurationLocked); } catch (RuntimeException ex) { mConfigurationLocked.openFlags = oldOpenFlags; throw ex; } } } private void open() { try { try { Loading Loading @@ -1902,28 +1934,6 @@ public class SQLiteDatabase extends SQLiteClosable { return true; } /** * Prevent other threads from using the database's primary connection. * * This method is only used by {@link SQLiteOpenHelper} when transitioning from * a readable to a writable database. It should not be used in any other way. * * @see #unlockPrimaryConnection() */ void lockPrimaryConnection() { getThreadSession().beginTransaction(SQLiteSession.TRANSACTION_MODE_DEFERRED, null, SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY, null); } /** * Allow other threads to use the database's primary connection. * * @see #lockPrimaryConnection() */ void unlockPrimaryConnection() { getThreadSession().endTransaction(null); } @Override public String toString() { return "SQLiteDatabase: " + getPath(); Loading core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +8 −8 Original line number Diff line number Diff line Loading @@ -50,17 +50,17 @@ public final class SQLiteDatabaseConfiguration { */ public final String path; /** * The flags used to open the database. */ public final int openFlags; /** * The label to use to describe the database when it appears in logs. * This is derived from the path but is stripped to remove PII. */ public final String label; /** * The flags used to open the database. */ public int openFlags; /** * The maximum number of connections to retain in the connection pool. * Must be at least 1. Loading Loading @@ -103,8 +103,8 @@ public final class SQLiteDatabaseConfiguration { } this.path = path; this.openFlags = openFlags; label = stripPathForLogs(path); this.openFlags = openFlags; // Set default values for optional parameters. maxConnectionPoolSize = 1; Loading @@ -123,7 +123,6 @@ public final class SQLiteDatabaseConfiguration { } this.path = other.path; this.openFlags = other.openFlags; this.label = other.label; updateParametersFrom(other); } Loading @@ -138,11 +137,12 @@ public final class SQLiteDatabaseConfiguration { if (other == null) { throw new IllegalArgumentException("other must not be null."); } if (!path.equals(other.path) || openFlags != other.openFlags) { if (!path.equals(other.path)) { throw new IllegalArgumentException("other configuration must refer to " + "the same database."); } openFlags = other.openFlags; maxConnectionPoolSize = other.maxConnectionPoolSize; maxSqlCacheSize = other.maxSqlCacheSize; locale = other.locale; Loading core/java/android/database/sqlite/SQLiteOpenHelper.java +83 −92 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/database/sqlite/SQLiteConnectionPool.java +113 −73 Original line number Diff line number Diff line Loading @@ -92,13 +92,25 @@ public final class SQLiteConnectionPool implements Closeable { new ArrayList<SQLiteConnection>(); private SQLiteConnection mAvailablePrimaryConnection; // Describes what should happen to an acquired connection when it is returned to the pool. enum AcquiredConnectionStatus { // The connection should be returned to the pool as usual. NORMAL, // The connection must be reconfigured before being returned. RECONFIGURE, // The connection must be closed and discarded. DISCARD, } // Weak references to all acquired connections. The associated value // is a boolean that indicates whether the connection must be reconfigured // before being returned to the available connection list. // indicates whether the connection must be reconfigured before being // returned to the available connection list or discarded. // For example, the prepared statement cache size may have changed and // need to be updated. private final WeakHashMap<SQLiteConnection, Boolean> mAcquiredConnections = new WeakHashMap<SQLiteConnection, Boolean>(); // need to be updated in preparation for the next client. private final WeakHashMap<SQLiteConnection, AcquiredConnectionStatus> mAcquiredConnections = new WeakHashMap<SQLiteConnection, AcquiredConnectionStatus>(); /** * Connection flag: Read-only. Loading Loading @@ -168,7 +180,7 @@ public final class SQLiteConnectionPool implements Closeable { private void open() { // Open the primary connection. // This might throw if the database is corrupt. mAvailablePrimaryConnection = openConnectionLocked( mAvailablePrimaryConnection = openConnectionLocked(mConfiguration, true /*primaryConnection*/); // might throw // Mark the pool as being open for business. Loading Loading @@ -209,16 +221,7 @@ public final class SQLiteConnectionPool implements Closeable { mIsOpen = false; final int count = mAvailableNonPrimaryConnections.size(); for (int i = 0; i < count; i++) { closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i)); } mAvailableNonPrimaryConnections.clear(); if (mAvailablePrimaryConnection != null) { closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection); mAvailablePrimaryConnection = null; } closeAvailableConnectionsAndLogExceptionsLocked(); final int pendingCount = mAcquiredConnections.size(); if (pendingCount != 0) { Loading Loading @@ -254,20 +257,26 @@ public final class SQLiteConnectionPool implements Closeable { synchronized (mLock) { throwIfClosedLocked(); final boolean poolSizeChanged = mConfiguration.maxConnectionPoolSize != configuration.maxConnectionPoolSize; mConfiguration.updateParametersFrom(configuration); if (mConfiguration.openFlags != configuration.openFlags) { // 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 // the new mode in which case existing connections will remain untouched. SQLiteConnection newPrimaryConnection = openConnectionLocked(configuration, true /*primaryConnection*/); // might throw if (poolSizeChanged) { int availableCount = mAvailableNonPrimaryConnections.size(); while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) { SQLiteConnection connection = mAvailableNonPrimaryConnections.remove(availableCount); closeConnectionAndLogExceptionsLocked(connection); } } closeAvailableConnectionsAndLogExceptionsLocked(); discardAcquiredConnectionsLocked(); mAvailablePrimaryConnection = newPrimaryConnection; mConfiguration.updateParametersFrom(configuration); } else { // Reconfigure the database connections in place. mConfiguration.updateParametersFrom(configuration); closeExcessConnectionsAndLogExceptionsLocked(); reconfigureAllConnectionsLocked(); } wakeConnectionWaitersLocked(); } Loading Loading @@ -310,8 +319,8 @@ public final class SQLiteConnectionPool implements Closeable { */ public void releaseConnection(SQLiteConnection connection) { synchronized (mLock) { Boolean mustReconfigure = mAcquiredConnections.remove(connection); if (mustReconfigure == null) { AcquiredConnectionStatus status = mAcquiredConnections.remove(connection); if (status == null) { throw new IllegalStateException("Cannot perform this operation " + "because the specified connection was not acquired " + "from this pool or has already been released."); Loading @@ -320,18 +329,8 @@ public final class SQLiteConnectionPool implements Closeable { if (!mIsOpen) { closeConnectionAndLogExceptionsLocked(connection); } else if (connection.isPrimaryConnection()) { if (recycleConnectionLocked(connection, status)) { assert mAvailablePrimaryConnection == null; try { if (mustReconfigure == Boolean.TRUE) { connection.reconfigure(mConfiguration); // might throw } } catch (RuntimeException ex) { Log.e(TAG, "Failed to reconfigure released primary connection, closing it: " + connection, ex); closeConnectionAndLogExceptionsLocked(connection); connection = null; } if (connection != null) { mAvailablePrimaryConnection = connection; } wakeConnectionWaitersLocked(); Loading @@ -339,22 +338,31 @@ public final class SQLiteConnectionPool implements Closeable { mConfiguration.maxConnectionPoolSize - 1) { closeConnectionAndLogExceptionsLocked(connection); } else { if (recycleConnectionLocked(connection, status)) { mAvailableNonPrimaryConnections.add(connection); } wakeConnectionWaitersLocked(); } } } // Can't throw. private boolean recycleConnectionLocked(SQLiteConnection connection, AcquiredConnectionStatus status) { if (status == AcquiredConnectionStatus.RECONFIGURE) { try { if (mustReconfigure == Boolean.TRUE) { connection.reconfigure(mConfiguration); // might throw } } catch (RuntimeException ex) { Log.e(TAG, "Failed to reconfigure released non-primary connection, " + "closing it: " + connection, ex); closeConnectionAndLogExceptionsLocked(connection); connection = null; Log.e(TAG, "Failed to reconfigure released connection, closing it: " + connection, ex); status = AcquiredConnectionStatus.DISCARD; } if (connection != null) { mAvailableNonPrimaryConnections.add(connection); } wakeConnectionWaitersLocked(); } if (status == AcquiredConnectionStatus.DISCARD) { closeConnectionAndLogExceptionsLocked(connection); return false; } return true; } /** Loading Loading @@ -407,9 +415,10 @@ public final class SQLiteConnectionPool implements Closeable { } // Might throw. private SQLiteConnection openConnectionLocked(boolean primaryConnection) { private SQLiteConnection openConnectionLocked(SQLiteDatabaseConfiguration configuration, boolean primaryConnection) { final int connectionId = mNextConnectionId++; return SQLiteConnection.open(this, mConfiguration, return SQLiteConnection.open(this, configuration, connectionId, primaryConnection); // might throw } Loading Loading @@ -442,6 +451,30 @@ public final class SQLiteConnectionPool implements Closeable { mConnectionLeaked.set(true); } // Can't throw. private void closeAvailableConnectionsAndLogExceptionsLocked() { final int count = mAvailableNonPrimaryConnections.size(); for (int i = 0; i < count; i++) { closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i)); } mAvailableNonPrimaryConnections.clear(); if (mAvailablePrimaryConnection != null) { closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection); mAvailablePrimaryConnection = null; } } // Can't throw. private void closeExcessConnectionsAndLogExceptionsLocked() { int availableCount = mAvailableNonPrimaryConnections.size(); while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) { SQLiteConnection connection = mAvailableNonPrimaryConnections.remove(availableCount); closeConnectionAndLogExceptionsLocked(connection); } } // Can't throw. private void closeConnectionAndLogExceptionsLocked(SQLiteConnection connection) { try { Loading @@ -452,9 +485,13 @@ public final class SQLiteConnectionPool implements Closeable { } } // Can't throw. private void discardAcquiredConnectionsLocked() { markAcquiredConnectionsLocked(AcquiredConnectionStatus.DISCARD); } // Can't throw. private void reconfigureAllConnectionsLocked() { boolean wake = false; if (mAvailablePrimaryConnection != null) { try { mAvailablePrimaryConnection.reconfigure(mConfiguration); // might throw Loading @@ -463,7 +500,6 @@ public final class SQLiteConnectionPool implements Closeable { + mAvailablePrimaryConnection, ex); closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection); mAvailablePrimaryConnection = null; wake = true; } } Loading @@ -478,27 +514,30 @@ public final class SQLiteConnectionPool implements Closeable { closeConnectionAndLogExceptionsLocked(connection); mAvailableNonPrimaryConnections.remove(i--); count -= 1; wake = true; } } markAcquiredConnectionsLocked(AcquiredConnectionStatus.RECONFIGURE); } // Can't throw. private void markAcquiredConnectionsLocked(AcquiredConnectionStatus status) { if (!mAcquiredConnections.isEmpty()) { ArrayList<SQLiteConnection> keysToUpdate = new ArrayList<SQLiteConnection>( mAcquiredConnections.size()); for (Map.Entry<SQLiteConnection, Boolean> entry : mAcquiredConnections.entrySet()) { if (entry.getValue() != Boolean.TRUE) { for (Map.Entry<SQLiteConnection, AcquiredConnectionStatus> entry : mAcquiredConnections.entrySet()) { AcquiredConnectionStatus oldStatus = entry.getValue(); if (status != oldStatus && oldStatus != AcquiredConnectionStatus.DISCARD) { keysToUpdate.add(entry.getKey()); } } final int updateCount = keysToUpdate.size(); for (int i = 0; i < updateCount; i++) { mAcquiredConnections.put(keysToUpdate.get(i), Boolean.TRUE); mAcquiredConnections.put(keysToUpdate.get(i), status); } } if (wake) { wakeConnectionWaitersLocked(); } } // Might throw. Loading Loading @@ -658,8 +697,7 @@ public final class SQLiteConnectionPool implements Closeable { int activeConnections = 0; int idleConnections = 0; if (!mAcquiredConnections.isEmpty()) { for (Map.Entry<SQLiteConnection, Boolean> entry : mAcquiredConnections.entrySet()) { final SQLiteConnection connection = entry.getKey(); for (SQLiteConnection connection : mAcquiredConnections.keySet()) { String description = connection.describeCurrentOperationUnsafe(); if (description != null) { requests.add(description); Loading Loading @@ -769,7 +807,8 @@ public final class SQLiteConnectionPool implements Closeable { // Uhoh. No primary connection! Either this is the first time we asked // for it, or maybe it leaked? connection = openConnectionLocked(true /*primaryConnection*/); // might throw connection = openConnectionLocked(mConfiguration, true /*primaryConnection*/); // might throw finishAcquireConnectionLocked(connection, connectionFlags); // might throw return connection; } Loading Loading @@ -807,7 +846,8 @@ public final class SQLiteConnectionPool implements Closeable { if (openConnections >= mConfiguration.maxConnectionPoolSize) { return null; } connection = openConnectionLocked(false /*primaryConnection*/); // might throw connection = openConnectionLocked(mConfiguration, false /*primaryConnection*/); // might throw finishAcquireConnectionLocked(connection, connectionFlags); // might throw return connection; } Loading @@ -818,7 +858,7 @@ public final class SQLiteConnectionPool implements Closeable { final boolean readOnly = (connectionFlags & CONNECTION_FLAG_READ_ONLY) != 0; connection.setOnlyAllowReadOnlyOperations(readOnly); mAcquiredConnections.put(connection, Boolean.FALSE); mAcquiredConnections.put(connection, AcquiredConnectionStatus.NORMAL); } catch (RuntimeException ex) { Log.e(TAG, "Failed to prepare acquired connection for session, closing it: " + connection +", connectionFlags=" + connectionFlags); Loading Loading @@ -858,7 +898,7 @@ public final class SQLiteConnectionPool implements Closeable { private void throwIfClosedLocked() { if (!mIsOpen) { throw new IllegalStateException("Cannot perform this operation " + "because the connection pool have been closed."); + "because the connection pool has been closed."); } } Loading Loading @@ -922,11 +962,11 @@ public final class SQLiteConnectionPool implements Closeable { printer.println(" Acquired connections:"); if (!mAcquiredConnections.isEmpty()) { for (Map.Entry<SQLiteConnection, Boolean> entry : for (Map.Entry<SQLiteConnection, AcquiredConnectionStatus> entry : mAcquiredConnections.entrySet()) { final SQLiteConnection connection = entry.getKey(); connection.dumpUnsafe(indentedPrinter, verbose); indentedPrinter.println(" Pending reconfiguration: " + entry.getValue()); indentedPrinter.println(" Status: " + entry.getValue()); } } else { indentedPrinter.println("<none>"); Loading
core/java/android/database/sqlite/SQLiteDatabase.java +32 −22 Original line number Diff line number Diff line Loading @@ -677,6 +677,38 @@ public class SQLiteDatabase extends SQLiteClosable { return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler); } /** * Reopens the database in read-write mode. * If the database is already read-write, does nothing. * * @throws SQLiteException if the database could not be reopened as requested, in which * case it remains open in read only mode. * @throws IllegalStateException if the database is not open. * * @see #isReadOnly() * @hide */ public void reopenReadWrite() { synchronized (mLock) { throwIfNotOpenLocked(); if (!isReadOnlyLocked()) { return; // nothing to do } // Reopen the database in read-write mode. final int oldOpenFlags = mConfigurationLocked.openFlags; mConfigurationLocked.openFlags = (mConfigurationLocked.openFlags & ~OPEN_READ_MASK) | OPEN_READWRITE; try { mConnectionPoolLocked.reconfigure(mConfigurationLocked); } catch (RuntimeException ex) { mConfigurationLocked.openFlags = oldOpenFlags; throw ex; } } } private void open() { try { try { Loading Loading @@ -1902,28 +1934,6 @@ public class SQLiteDatabase extends SQLiteClosable { return true; } /** * Prevent other threads from using the database's primary connection. * * This method is only used by {@link SQLiteOpenHelper} when transitioning from * a readable to a writable database. It should not be used in any other way. * * @see #unlockPrimaryConnection() */ void lockPrimaryConnection() { getThreadSession().beginTransaction(SQLiteSession.TRANSACTION_MODE_DEFERRED, null, SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY, null); } /** * Allow other threads to use the database's primary connection. * * @see #lockPrimaryConnection() */ void unlockPrimaryConnection() { getThreadSession().endTransaction(null); } @Override public String toString() { return "SQLiteDatabase: " + getPath(); Loading
core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +8 −8 Original line number Diff line number Diff line Loading @@ -50,17 +50,17 @@ public final class SQLiteDatabaseConfiguration { */ public final String path; /** * The flags used to open the database. */ public final int openFlags; /** * The label to use to describe the database when it appears in logs. * This is derived from the path but is stripped to remove PII. */ public final String label; /** * The flags used to open the database. */ public int openFlags; /** * The maximum number of connections to retain in the connection pool. * Must be at least 1. Loading Loading @@ -103,8 +103,8 @@ public final class SQLiteDatabaseConfiguration { } this.path = path; this.openFlags = openFlags; label = stripPathForLogs(path); this.openFlags = openFlags; // Set default values for optional parameters. maxConnectionPoolSize = 1; Loading @@ -123,7 +123,6 @@ public final class SQLiteDatabaseConfiguration { } this.path = other.path; this.openFlags = other.openFlags; this.label = other.label; updateParametersFrom(other); } Loading @@ -138,11 +137,12 @@ public final class SQLiteDatabaseConfiguration { if (other == null) { throw new IllegalArgumentException("other must not be null."); } if (!path.equals(other.path) || openFlags != other.openFlags) { if (!path.equals(other.path)) { throw new IllegalArgumentException("other configuration must refer to " + "the same database."); } openFlags = other.openFlags; maxConnectionPoolSize = other.maxConnectionPoolSize; maxSqlCacheSize = other.maxSqlCacheSize; locale = other.locale; Loading
core/java/android/database/sqlite/SQLiteOpenHelper.java +83 −92 File changed.Preview size limit exceeded, changes collapsed. Show changes