Index: content/browser/indexed_db/indexed_db_transaction.cc |
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc |
index bb7fc03c5bf07f4461db299134a56c5a417d4694..31a342458010042092e55cb52f89ceeff33c0284 100644 |
--- a/content/browser/indexed_db/indexed_db_transaction.cc |
+++ b/content/browser/indexed_db/indexed_db_transaction.cc |
@@ -87,7 +87,7 @@ IndexedDBTransaction::~IndexedDBTransaction() { |
} |
void IndexedDBTransaction::ScheduleTask(Operation task, Operation abort_task) { |
- if (state_ == FINISHED) |
+ if (IsStatePastStarted()) |
return; |
timeout_timer_.Stop(); |
@@ -100,7 +100,7 @@ void IndexedDBTransaction::ScheduleTask(Operation task, Operation abort_task) { |
void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, |
Operation task) { |
- if (state_ == FINISHED) |
+ if (IsStatePastStarted()) |
return; |
timeout_timer_.Stop(); |
@@ -212,14 +212,41 @@ void IndexedDBTransaction::Start() { |
RunTasksIfStarted(); |
} |
+class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback { |
+ public: |
+ BlobWriteCallbackImpl(scoped_refptr<IndexedDBTransaction> transaction) |
+ : transaction_(transaction) {} |
+ virtual ~BlobWriteCallbackImpl() {} |
+ virtual void Run(bool succeeded) { |
+ transaction_->BlobWriteComplete(succeeded); |
+ } |
+ |
+ private: |
+ scoped_refptr<IndexedDBTransaction> transaction_; |
+}; |
+ |
+void IndexedDBTransaction::BlobWriteComplete(bool success) { |
+ IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); |
+ if (state_ == FINISHED) // aborted |
+ return; |
+ DCHECK_EQ(state_, COMMITTING); |
+ if (success) |
+ CommitPhaseTwo(); |
+ else |
+ Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, |
+ "Failed to write blobs.")); |
+} |
+ |
void IndexedDBTransaction::Commit() { |
IDB_TRACE("IndexedDBTransaction::Commit"); |
// In multiprocess ports, front-end may have requested a commit but |
// an abort has already been initiated asynchronously by the |
// back-end. |
- if (state_ == FINISHED) |
+ if (IsStatePastStarted()) { |
+ DCHECK(state_ == FINISHED); |
return; |
+ } |
DCHECK(!used_ || state_ == STARTED); |
commit_pending_ = true; |
@@ -230,6 +257,24 @@ void IndexedDBTransaction::Commit() { |
if (HasPendingTasks()) |
return; |
+ state_ = COMMITTING; |
+ |
+ if (!used_) |
+ CommitPhaseTwo(); |
+ else { |
+ scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback( |
+ new BlobWriteCallbackImpl(this)); |
+ // CommitPhaseOne will call the callback synchronously if there are no blobs |
+ // to write. |
+ if (!transaction_->CommitPhaseOne(callback).ok()) |
+ Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, |
+ "Error processing blob journal.")); |
+ } |
+} |
+ |
+void IndexedDBTransaction::CommitPhaseTwo() { |
jsbell
2014/05/20 22:02:19
Is it possible for an Abort() to slip in between C
ericu
2014/05/21 18:14:47
Ah, yes it is. For CommitPhaseTwo to be called af
|
+ DCHECK_EQ(state_, COMMITTING); |
+ |
// The last reference to this object may be released while performing the |
// commit steps below. We therefore take a self reference to keep ourselves |
// alive while executing this method. |
@@ -239,7 +284,7 @@ void IndexedDBTransaction::Commit() { |
state_ = FINISHED; |
- bool committed = !used_ || transaction_->Commit().ok(); |
+ bool committed = !used_ || transaction_->CommitPhaseTwo().ok(); |
// Backing store resources (held via cursors) must be released |
// before script callbacks are fired, as the script callbacks may |
@@ -294,8 +339,8 @@ void IndexedDBTransaction::ProcessTaskQueue() { |
TaskQueue* task_queue = |
pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; |
- while (!task_queue->empty() && state_ != FINISHED) { |
- DCHECK_EQ(STARTED, state_); |
+ while (!task_queue->empty() && !IsStatePastStarted()) { |
+ DCHECK_EQ(state_, STARTED); |
Operation task(task_queue->pop()); |
task.Run(this); |
if (!pending_preemptive_events_) { |
@@ -310,7 +355,7 @@ void IndexedDBTransaction::ProcessTaskQueue() { |
// If there are no pending tasks, we haven't already committed/aborted, |
// and the front-end requested a commit, it is now safe to do so. |
- if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) { |
+ if (!HasPendingTasks() && !IsStatePastStarted() && commit_pending_) { |
Commit(); |
return; |
} |