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 ee38d0b914d84be5a3e9dceecde3a027bf60371e..4f3f0adeee3905ee3650ebe7fa79a54d24f5ac19 100644 |
--- a/content/browser/indexed_db/indexed_db_transaction.cc |
+++ b/content/browser/indexed_db/indexed_db_transaction.cc |
@@ -59,17 +59,21 @@ IndexedDBTransaction::IndexedDBTransaction( |
mode_(mode), |
state_(UNUSED), |
commit_pending_(false), |
+ blob_write_success_(false), |
callbacks_(callbacks), |
database_(database), |
transaction_(database->BackingStore().get()), |
should_process_queue_(false), |
pending_preemptive_events_(0) { |
+ fprintf(stderr, "ERICU: IndexedDBTransaction::IndexedDBTransaction(%p).\n", |
+ this); |
database_->transaction_coordinator().DidCreateTransaction(this); |
} |
IndexedDBTransaction::~IndexedDBTransaction() { |
// It shouldn't be possible for this object to get deleted until it's either |
// complete or aborted. |
+ fprintf(stderr, "ERICU: IndexedDBTransaction::~IndexedDBTransaction.\n"); |
DCHECK_EQ(state_, FINISHED); |
DCHECK(preemptive_task_queue_.empty()); |
DCHECK(task_queue_.empty()); |
@@ -86,7 +90,7 @@ void IndexedDBTransaction::ScheduleTask(Operation task, Operation abort_task) { |
void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, |
Operation task) { |
- if (state_ == FINISHED) |
+ if (IsStatePastRunning()) |
return; |
if (type == IndexedDBDatabase::NORMAL_TASK) |
@@ -195,13 +199,29 @@ void IndexedDBTransaction::Start() { |
database_->TransactionStarted(this); |
} |
+class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback { |
+ public: |
+ BlobWriteCallbackImpl(scoped_refptr<IndexedDBTransaction> transaction) |
+ : transaction_(transaction) { } |
+ virtual ~BlobWriteCallbackImpl() { } |
+ virtual void didSucceed() { |
+ transaction_->BlobWriteComplete(true); |
+ } |
+ virtual void didFail() { |
+ transaction_->BlobWriteComplete(false); |
+ } |
+ private: |
+ scoped_refptr<IndexedDBTransaction> transaction_; |
+}; |
+ |
void IndexedDBTransaction::Commit() { |
IDB_TRACE("IndexedDBTransaction::Commit"); |
+ fprintf(stderr, "ERICU: IndexedDBTransaction::Commit.\n"); |
// 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 (IsStatePastRunning()) |
return; |
DCHECK(state_ == UNUSED || state_ == RUNNING); |
@@ -213,44 +233,19 @@ void IndexedDBTransaction::Commit() { |
if (HasPendingTasks()) |
return; |
- // 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. |
- scoped_refptr<IndexedDBTransaction> protect(this); |
- |
- // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843 |
- abort_task_stack_.clear(); |
- |
bool unused = state_ == UNUSED; |
- state_ = FINISHED; |
- |
- bool committed = unused || transaction_.Commit(); |
- |
- // Backing store resources (held via cursors) must be released |
- // before script callbacks are fired, as the script callbacks may |
- // release references and allow the backing store itself to be |
- // released, and order is critical. |
- CloseOpenCursors(); |
- transaction_.Reset(); |
- |
- // Transactions must also be marked as completed before the |
- // front-end is notified, as the transaction completion unblocks |
- // operations like closing connections. |
- database_->transaction_coordinator().DidFinishTransaction(this); |
- database_->TransactionFinished(this); |
- |
- if (committed) { |
- callbacks_->OnComplete(id_); |
- database_->TransactionFinishedAndCompleteFired(this); |
- } else { |
- callbacks_->OnAbort( |
- id_, |
- IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, |
- "Internal error committing transaction.")); |
- database_->TransactionFinishedAndAbortFired(this); |
+ state_ = COMMITTING; |
+ |
+ if (unused) |
+ CommitPhaseTwo(WAS_NOT_USED, DO_COMMIT); |
+ 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)) |
+ CommitPhaseTwo(WAS_USED, SKIP_COMMIT); |
} |
- |
- database_ = NULL; |
} |
void IndexedDBTransaction::ProcessTaskQueue() { |
@@ -275,7 +270,7 @@ void IndexedDBTransaction::ProcessTaskQueue() { |
TaskQueue* task_queue = |
pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; |
- while (!task_queue->empty() && state_ != FINISHED) { |
+ while (!task_queue->empty() && !IsStatePastRunning()) { |
DCHECK_EQ(state_, RUNNING); |
Operation task(task_queue->pop()); |
task.Run(this); |
@@ -287,10 +282,23 @@ 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() && !IsStatePastRunning() && commit_pending_) |
Commit(); |
} |
+void IndexedDBTransaction::BlobWriteComplete(bool success) |
+{ |
+ IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); |
+ if (state_ == FINISHED) // aborted |
+ return; |
+ DCHECK_EQ(state_, COMMITTING); |
+ if (success) |
+ CommitPhaseTwo(WAS_USED, DO_COMMIT); |
+ else |
+ Abort(IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionDataError, |
+ "Failed to write blobs")); |
+} |
+ |
void IndexedDBTransaction::CloseOpenCursors() { |
for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); |
i != open_cursors_.end(); |
@@ -299,4 +307,49 @@ void IndexedDBTransaction::CloseOpenCursors() { |
open_cursors_.clear(); |
} |
+void IndexedDBTransaction::CommitPhaseTwo(TransactionUseState use_state, |
+ ShouldSkipCommit skip_commit) { |
+ DCHECK_EQ(state_, COMMITTING); |
+ state_ = FINISHED; |
+ |
+ // 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. |
+ scoped_refptr<IndexedDBTransaction> protect(this); |
+ |
+ // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843 |
+ abort_task_stack_.clear(); |
+ |
+ state_ = FINISHED; |
+ |
+ bool committed = (use_state == WAS_NOT_USED) || |
jsbell
2013/09/13 00:12:21
Seems like use_state and skip_commit effectively h
ericu
2013/11/20 23:05:39
No--we skip_commit if we've failed or aborted, but
|
+ ((skip_commit == DO_COMMIT) && transaction_.CommitPhaseTwo()); |
+ |
+ // Backing store resources (held via cursors) must be released |
+ // before script callbacks are fired, as the script callbacks may |
+ // release references and allow the backing store itself to be |
+ // released, and order is critical. |
+ CloseOpenCursors(); |
+ transaction_.Reset(); |
+ |
+ // Transactions must also be marked as completed before the |
+ // front-end is notified, as the transaction completion unblocks |
+ // operations like closing connections. |
+ database_->transaction_coordinator().DidFinishTransaction(this); |
+ database_->TransactionFinished(this); |
+ |
+ if (committed) { |
+ callbacks_->OnComplete(id_); |
+ database_->TransactionFinishedAndCompleteFired(this); |
+ } else { |
+ callbacks_->OnAbort( |
+ id_, |
+ IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, |
+ "Internal error committing transaction.")); |
+ database_->TransactionFinishedAndAbortFired(this); |
+ } |
+ |
+ database_ = NULL; |
+} |
+ |
} // namespace content |