summaryrefslogtreecommitdiffstats
path: root/core/java/android/database
diff options
context:
space:
mode:
authorFred Quintana <fredq@google.com>2009-09-03 12:14:06 -0700
committerFred Quintana <fredq@google.com>2009-09-08 17:25:09 -0700
commitc4516a7b62de525e3d6d5e76851bdfaf12c11f05 (patch)
treec6808a36cddaced64341a1f11a66d3f471d49d22 /core/java/android/database
parentb80f698362e84b83e1c44c92fb76b0fdf1a5ef6d (diff)
downloadframeworks_base-c4516a7b62de525e3d6d5e76851bdfaf12c11f05.zip
frameworks_base-c4516a7b62de525e3d6d5e76851bdfaf12c11f05.tar.gz
frameworks_base-c4516a7b62de525e3d6d5e76851bdfaf12c11f05.tar.bz2
add a transaction monitor
Diffstat (limited to 'core/java/android/database')
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java59
-rw-r--r--core/java/android/database/sqlite/SQLiteDebug.java13
-rw-r--r--core/java/android/database/sqlite/SQLiteTransactionListener.java21
3 files changed, 88 insertions, 5 deletions
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 57bf3f7..4f31ef0 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -175,6 +175,11 @@ public class SQLiteDatabase extends SQLiteClosable {
*/
private boolean mTransactionIsSuccessful;
+ /**
+ * Valid during the life of a transaction.
+ */
+ private SQLiteTransactionListener mTransactionListener;
+
/** Synchronize on this when accessing the database */
private final ReentrantLock mLock = new ReentrantLock(true);
@@ -394,6 +399,31 @@ public class SQLiteDatabase extends SQLiteClosable {
* </pre>
*/
public void beginTransaction() {
+ beginTransactionWithListener(null /* transactionStatusCallback */);
+ }
+
+ /**
+ * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
+ * the work done in that transaction and all of the nested transactions will be committed or
+ * rolled back. The changes will be rolled back if any transaction is ended without being
+ * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
+ *
+ * <p>Here is the standard idiom for transactions:
+ *
+ * <pre>
+ * db.beginTransactionWithListener(listener);
+ * try {
+ * ...
+ * db.setTransactionSuccessful();
+ * } finally {
+ * db.endTransaction();
+ * }
+ * </pre>
+ * @param transactionListener listener that should be notified when the transaction begins,
+ * commits, or is rolled back, either explicitly or by a call to
+ * {@link #yieldIfContendedSafely}.
+ */
+ public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
lockForced();
boolean ok = false;
try {
@@ -413,8 +443,17 @@ public class SQLiteDatabase extends SQLiteClosable {
// This thread didn't already have the lock, so begin a database
// transaction now.
execSQL("BEGIN EXCLUSIVE;");
+ mTransactionListener = transactionListener;
mTransactionIsSuccessful = true;
mInnerTransactionIsSuccessful = false;
+ if (transactionListener != null) {
+ try {
+ transactionListener.onBegin();
+ } catch (RuntimeException e) {
+ execSQL("ROLLBACK;");
+ throw e;
+ }
+ }
ok = true;
} finally {
if (!ok) {
@@ -442,11 +481,27 @@ public class SQLiteDatabase extends SQLiteClosable {
if (mLock.getHoldCount() != 1) {
return;
}
+ RuntimeException savedException = null;
+ if (mTransactionListener != null) {
+ try {
+ if (mTransactionIsSuccessful) {
+ mTransactionListener.onCommit();
+ } else {
+ mTransactionListener.onRollback();
+ }
+ } catch (RuntimeException e) {
+ savedException = e;
+ mTransactionIsSuccessful = false;
+ }
+ }
if (mTransactionIsSuccessful) {
execSQL("COMMIT;");
} else {
try {
execSQL("ROLLBACK;");
+ if (savedException != null) {
+ throw savedException;
+ }
} catch (SQLException e) {
if (Config.LOGD) {
Log.d(TAG, "exception during rollback, maybe the DB previously "
@@ -455,6 +510,7 @@ public class SQLiteDatabase extends SQLiteClosable {
}
}
} finally {
+ mTransactionListener = null;
unlockForced();
if (Config.LOGV) {
Log.v(TAG, "unlocked " + Thread.currentThread()
@@ -561,6 +617,7 @@ public class SQLiteDatabase extends SQLiteClosable {
return false;
}
setTransactionSuccessful();
+ SQLiteTransactionListener transactionListener = mTransactionListener;
endTransaction();
if (checkFullyYielded) {
if (this.isDbLockedByCurrentThread()) {
@@ -586,7 +643,7 @@ public class SQLiteDatabase extends SQLiteClosable {
}
}
}
- beginTransaction();
+ beginTransactionWithListener(transactionListener);
return true;
}
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index d04afb0..84d8879 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -17,6 +17,7 @@
package android.database.sqlite;
import android.util.Config;
+import android.util.Log;
/**
* Provides debugging info about all SQLite databases running in the current process.
@@ -27,23 +28,27 @@ public final class SQLiteDebug {
/**
* Controls the printing of SQL statements as they are executed.
*/
- public static final boolean DEBUG_SQL_STATEMENTS = Config.LOGV;
+ public static final boolean DEBUG_SQL_STATEMENTS =
+ Log.isLoggable("SQLiteStatements", Log.VERBOSE);
/**
* Controls the stack trace reporting of active cursors being
* finalized.
*/
- public static final boolean DEBUG_ACTIVE_CURSOR_FINALIZATION = Config.LOGV;
+ public static final boolean DEBUG_ACTIVE_CURSOR_FINALIZATION =
+ Log.isLoggable("SQLiteCursorClosing", Log.VERBOSE);
/**
* Controls the tracking of time spent holding the database lock.
*/
- public static final boolean DEBUG_LOCK_TIME_TRACKING = false;
+ public static final boolean DEBUG_LOCK_TIME_TRACKING =
+ Log.isLoggable("SQLiteLockTime", Log.VERBOSE);
/**
* Controls the printing of stack traces when tracking the time spent holding the database lock.
*/
- public static final boolean DEBUG_LOCK_TIME_TRACKING_STACK_TRACE = false;
+ public static final boolean DEBUG_LOCK_TIME_TRACKING_STACK_TRACE =
+ Log.isLoggable("SQLiteLockStackTrace", Log.VERBOSE);
/**
* Contains statistics about the active pagers in the current process.
diff --git a/core/java/android/database/sqlite/SQLiteTransactionListener.java b/core/java/android/database/sqlite/SQLiteTransactionListener.java
new file mode 100644
index 0000000..e97ece8
--- /dev/null
+++ b/core/java/android/database/sqlite/SQLiteTransactionListener.java
@@ -0,0 +1,21 @@
+package android.database.sqlite;
+
+/**
+ * A listener for transaction events.
+ */
+public interface SQLiteTransactionListener {
+ /**
+ * Called immediately after the transaction begins.
+ */
+ void onBegin();
+
+ /**
+ * Called immediately before commiting the transaction.
+ */
+ void onCommit();
+
+ /**
+ * Called if the transaction is about to be rolled back.
+ */
+ void onRollback();
+}