Merge change 23474 into eclair

* changes:
  Breaking sleep after yield into small quanta.
This commit is contained in:
Android (Google) Code Review
2009-09-01 13:03:58 -07:00

View File

@@ -62,53 +62,53 @@ public class SQLiteDatabase extends SQLiteClosable {
*/ */
public enum ConflictAlgorithm { public enum ConflictAlgorithm {
/** /**
* When a constraint violation occurs, an immediate ROLLBACK occurs, * When a constraint violation occurs, an immediate ROLLBACK occurs,
* thus ending the current transaction, and the command aborts with a * thus ending the current transaction, and the command aborts with a
* return code of SQLITE_CONSTRAINT. If no transaction is active * return code of SQLITE_CONSTRAINT. If no transaction is active
* (other than the implied transaction that is created on every command) * (other than the implied transaction that is created on every command)
* then this algorithm works the same as ABORT. * then this algorithm works the same as ABORT.
*/ */
ROLLBACK("ROLLBACK"), ROLLBACK("ROLLBACK"),
/** /**
* When a constraint violation occurs,no ROLLBACK is executed * When a constraint violation occurs,no ROLLBACK is executed
* so changes from prior commands within the same transaction * so changes from prior commands within the same transaction
* are preserved. This is the default behavior. * are preserved. This is the default behavior.
*/ */
ABORT("ABORT"), ABORT("ABORT"),
/** /**
* When a constraint violation occurs, the command aborts with a return * When a constraint violation occurs, the command aborts with a return
* code SQLITE_CONSTRAINT. But any changes to the database that * code SQLITE_CONSTRAINT. But any changes to the database that
* the command made prior to encountering the constraint violation * the command made prior to encountering the constraint violation
* are preserved and are not backed out. * are preserved and are not backed out.
*/ */
FAIL("FAIL"), FAIL("FAIL"),
/** /**
* When a constraint violation occurs, the one row that contains * When a constraint violation occurs, the one row that contains
* the constraint violation is not inserted or changed. * the constraint violation is not inserted or changed.
* But the command continues executing normally. Other rows before and * But the command continues executing normally. Other rows before and
* after the row that contained the constraint violation continue to be * after the row that contained the constraint violation continue to be
* inserted or updated normally. No error is returned. * inserted or updated normally. No error is returned.
*/ */
IGNORE("IGNORE"), IGNORE("IGNORE"),
/** /**
* When a UNIQUE constraint violation occurs, the pre-existing rows that * When a UNIQUE constraint violation occurs, the pre-existing rows that
* are causing the constraint violation are removed prior to inserting * are causing the constraint violation are removed prior to inserting
* or updating the current row. Thus the insert or update always occurs. * or updating the current row. Thus the insert or update always occurs.
* The command continues executing normally. No error is returned. * The command continues executing normally. No error is returned.
* If a NOT NULL constraint violation occurs, the NULL value is replaced * If a NOT NULL constraint violation occurs, the NULL value is replaced
* by the default value for that column. If the column has no default * by the default value for that column. If the column has no default
* value, then the ABORT algorithm is used. If a CHECK constraint * value, then the ABORT algorithm is used. If a CHECK constraint
* violation occurs then the IGNORE algorithm is used. When this conflict * violation occurs then the IGNORE algorithm is used. When this conflict
* resolution strategy deletes rows in order to satisfy a constraint, * resolution strategy deletes rows in order to satisfy a constraint,
* it does not invoke delete triggers on those rows. * it does not invoke delete triggers on those rows.
* This behavior might change in a future release. * This behavior might change in a future release.
*/ */
REPLACE("REPLACE"); REPLACE("REPLACE");
private final String mValue; private final String mValue;
ConflictAlgorithm(String value) { ConflictAlgorithm(String value) {
mValue = value; mValue = value;
@@ -117,7 +117,7 @@ public class SQLiteDatabase extends SQLiteClosable {
return mValue; return mValue;
} }
} }
/** /**
* Maximum Length Of A LIKE Or GLOB Pattern * Maximum Length Of A LIKE Or GLOB Pattern
* The pattern matching algorithm used in the default LIKE and GLOB implementation * The pattern matching algorithm used in the default LIKE and GLOB implementation
@@ -180,17 +180,19 @@ public class SQLiteDatabase extends SQLiteClosable {
private long mLockAcquiredWallTime = 0L; private long mLockAcquiredWallTime = 0L;
private long mLockAcquiredThreadTime = 0L; private long mLockAcquiredThreadTime = 0L;
// limit the frequency of complaints about each database to one within 20 sec // limit the frequency of complaints about each database to one within 20 sec
// unless run command adb shell setprop log.tag.Database VERBOSE // unless run command adb shell setprop log.tag.Database VERBOSE
private static final int LOCK_WARNING_WINDOW_IN_MS = 20000; private static final int LOCK_WARNING_WINDOW_IN_MS = 20000;
/** If the lock is held this long then a warning will be printed when it is released. */ /** If the lock is held this long then a warning will be printed when it is released. */
private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300; private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300;
private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100; private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000; private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
private static final int SLEEP_AFTER_YIELD_QUANTUM = 500;
private long mLastLockMessageTime = 0L; private long mLastLockMessageTime = 0L;
/** Used by native code, do not rename */ /** Used by native code, do not rename */
/* package */ int mNativeHandle = 0; /* package */ int mNativeHandle = 0;
@@ -205,15 +207,15 @@ public class SQLiteDatabase extends SQLiteClosable {
/** The optional factory to use when creating new Cursors */ /** The optional factory to use when creating new Cursors */
private CursorFactory mFactory; private CursorFactory mFactory;
private WeakHashMap<SQLiteClosable, Object> mPrograms; private WeakHashMap<SQLiteClosable, Object> mPrograms;
private final RuntimeException mLeakedException; private final RuntimeException mLeakedException;
// package visible, since callers will access directly to minimize overhead in the case // package visible, since callers will access directly to minimize overhead in the case
// that logging is not enabled. // that logging is not enabled.
/* package */ final boolean mLogStats; /* package */ final boolean mLogStats;
/** /**
* @param closable * @param closable
*/ */
@@ -225,7 +227,7 @@ public class SQLiteDatabase extends SQLiteClosable {
unlock(); unlock();
} }
} }
void removeSQLiteClosable(SQLiteClosable closable) { void removeSQLiteClosable(SQLiteClosable closable) {
lock(); lock();
try { try {
@@ -233,8 +235,8 @@ public class SQLiteDatabase extends SQLiteClosable {
} finally { } finally {
unlock(); unlock();
} }
} }
@Override @Override
protected void onAllReferencesReleased() { protected void onAllReferencesReleased() {
if (isOpen()) { if (isOpen()) {
@@ -245,10 +247,10 @@ public class SQLiteDatabase extends SQLiteClosable {
/** /**
* Attempts to release memory that SQLite holds but does not require to * Attempts to release memory that SQLite holds but does not require to
* operate properly. Typically this memory will come from the page cache. * operate properly. Typically this memory will come from the page cache.
* *
* @return the number of bytes actually released * @return the number of bytes actually released
*/ */
static public native int releaseMemory(); static public native int releaseMemory();
/** /**
* Control whether or not the SQLiteDatabase is made thread-safe by using locks * Control whether or not the SQLiteDatabase is made thread-safe by using locks
@@ -284,7 +286,7 @@ public class SQLiteDatabase extends SQLiteClosable {
* touch the native sqlite3* object since it is single threaded and uses * touch the native sqlite3* object since it is single threaded and uses
* a polling lock contention algorithm. The lock is recursive, and may be acquired * a polling lock contention algorithm. The lock is recursive, and may be acquired
* multiple times by the same thread. This is a no-op if mLockingEnabled is false. * multiple times by the same thread. This is a no-op if mLockingEnabled is false.
* *
* @see #unlock() * @see #unlock()
*/ */
/* package */ void lock() { /* package */ void lock() {
@@ -320,7 +322,7 @@ public class SQLiteDatabase extends SQLiteClosable {
/** /**
* Releases the database lock. This is a no-op if mLockingEnabled is false. * Releases the database lock. This is a no-op if mLockingEnabled is false.
* *
* @see #unlock() * @see #unlock()
*/ */
/* package */ void unlock() { /* package */ void unlock() {
@@ -350,7 +352,7 @@ public class SQLiteDatabase extends SQLiteClosable {
private void checkLockHoldTime() { private void checkLockHoldTime() {
// Use elapsed real-time since the CPU may sleep when waiting for IO // Use elapsed real-time since the CPU may sleep when waiting for IO
long elapsedTime = SystemClock.elapsedRealtime(); long elapsedTime = SystemClock.elapsedRealtime();
long lockedTime = elapsedTime - mLockAcquiredWallTime; long lockedTime = elapsedTime - mLockAcquiredWallTime;
if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT && if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
!Log.isLoggable(TAG, Log.VERBOSE) && !Log.isLoggable(TAG, Log.VERBOSE) &&
(elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) { (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
@@ -567,10 +569,21 @@ public class SQLiteDatabase extends SQLiteClosable {
} }
} }
if (sleepAfterYieldDelay > 0) { if (sleepAfterYieldDelay > 0) {
try { // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to
Thread.sleep(sleepAfterYieldDelay); // check if anyone is using the database. If the database is not contended,
} catch (InterruptedException e) { // retake the lock and return.
Thread.interrupted(); long remainingDelay = sleepAfterYieldDelay;
while (remainingDelay > 0) {
try {
Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ?
remainingDelay : SLEEP_AFTER_YIELD_QUANTUM);
} catch (InterruptedException e) {
Thread.interrupted();
}
remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM;
if (mLock.getQueueLength() == 0) {
break;
}
} }
} }
beginTransaction(); beginTransaction();
@@ -720,9 +733,9 @@ public class SQLiteDatabase extends SQLiteClosable {
if (program != null) { if (program != null) {
program.onAllReferencesReleasedFromContainer(); program.onAllReferencesReleasedFromContainer();
} }
} }
} }
/** /**
* Native call to close the database. * Native call to close the database.
*/ */
@@ -1157,8 +1170,8 @@ public class SQLiteDatabase extends SQLiteClosable {
/** /**
* Runs the provided SQL and returns a cursor over the result set. * Runs the provided SQL and returns a cursor over the result set.
* The cursor will read an initial set of rows and the return to the caller. * The cursor will read an initial set of rows and the return to the caller.
* It will continue to read in batches and send data changed notifications * It will continue to read in batches and send data changed notifications
* when the later batches are ready. * when the later batches are ready.
* @param sql the SQL query. The SQL string must not be ; terminated * @param sql the SQL query. The SQL string must not be ; terminated
* @param selectionArgs You may include ?s in where clause in the query, * @param selectionArgs You may include ?s in where clause in the query,
@@ -1167,19 +1180,19 @@ public class SQLiteDatabase extends SQLiteClosable {
* @param initialRead set the initial count of items to read from the cursor * @param initialRead set the initial count of items to read from the cursor
* @param maxRead set the count of items to read on each iteration after the first * @param maxRead set the count of items to read on each iteration after the first
* @return A {@link Cursor} object, which is positioned before the first entry * @return A {@link Cursor} object, which is positioned before the first entry
* *
* This work is incomplete and not fully tested or reviewed, so currently * This work is incomplete and not fully tested or reviewed, so currently
* hidden. * hidden.
* @hide * @hide
*/ */
public Cursor rawQuery(String sql, String[] selectionArgs, public Cursor rawQuery(String sql, String[] selectionArgs,
int initialRead, int maxRead) { int initialRead, int maxRead) {
SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory( SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
null, sql, selectionArgs, null); null, sql, selectionArgs, null);
c.setLoadStyle(initialRead, maxRead); c.setLoadStyle(initialRead, maxRead);
return c; return c;
} }
/** /**
* Convenience method for inserting a row into the database. * Convenience method for inserting a row into the database.
* *
@@ -1232,7 +1245,7 @@ public class SQLiteDatabase extends SQLiteClosable {
*/ */
public long replace(String table, String nullColumnHack, ContentValues initialValues) { public long replace(String table, String nullColumnHack, ContentValues initialValues) {
try { try {
return insertWithOnConflict(table, nullColumnHack, initialValues, return insertWithOnConflict(table, nullColumnHack, initialValues,
ConflictAlgorithm.REPLACE); ConflictAlgorithm.REPLACE);
} catch (SQLException e) { } catch (SQLException e) {
Log.e(TAG, "Error inserting " + initialValues, e); Log.e(TAG, "Error inserting " + initialValues, e);
@@ -1254,7 +1267,7 @@ public class SQLiteDatabase extends SQLiteClosable {
*/ */
public long replaceOrThrow(String table, String nullColumnHack, public long replaceOrThrow(String table, String nullColumnHack,
ContentValues initialValues) throws SQLException { ContentValues initialValues) throws SQLException {
return insertWithOnConflict(table, nullColumnHack, initialValues, return insertWithOnConflict(table, nullColumnHack, initialValues,
ConflictAlgorithm.REPLACE); ConflictAlgorithm.REPLACE);
} }
@@ -1410,7 +1423,7 @@ public class SQLiteDatabase extends SQLiteClosable {
public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
return updateWithOnConflict(table, values, whereClause, whereArgs, null); return updateWithOnConflict(table, values, whereClause, whereArgs, null);
} }
/** /**
* Convenience method for updating rows in the database. * Convenience method for updating rows in the database.
* *
@@ -1423,7 +1436,7 @@ public class SQLiteDatabase extends SQLiteClosable {
* @return the number of rows affected * @return the number of rows affected
* @hide * @hide
*/ */
public int updateWithOnConflict(String table, ContentValues values, public int updateWithOnConflict(String table, ContentValues values,
String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) { String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) {
if (!isOpen()) { if (!isOpen()) {
throw new IllegalStateException("database not open"); throw new IllegalStateException("database not open");
@@ -1440,7 +1453,7 @@ public class SQLiteDatabase extends SQLiteClosable {
sql.append(algorithm.value()); sql.append(algorithm.value());
sql.append(" "); sql.append(" ");
} }
sql.append(table); sql.append(table);
sql.append(" SET "); sql.append(" SET ");
@@ -1601,7 +1614,7 @@ public class SQLiteDatabase extends SQLiteClosable {
mFlags = flags; mFlags = flags;
mPath = path; mPath = path;
mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats")); mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
mLeakedException = new IllegalStateException(path + mLeakedException = new IllegalStateException(path +
" SQLiteDatabase created and never closed"); " SQLiteDatabase created and never closed");
mFactory = factory; mFactory = factory;