1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_transaction.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/bind.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/message_loop/message_loop.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_backing_store.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_cursor.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_database.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/browser/indexed_db/indexed_db_database_callbacks.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_tracing.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace content {
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskQueue::TaskQueue() {}
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskQueue::~TaskQueue() { clear(); }
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::TaskQueue::clear() {
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!queue_.empty())
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<Operation> task(pop());
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)scoped_ptr<IndexedDBTransaction::Operation>
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskQueue::pop() {
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!queue_.empty());
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<Operation> task(queue_.front());
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  queue_.pop();
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return task.Pass();
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskStack::TaskStack() {}
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskStack::~TaskStack() { clear(); }
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::TaskStack::clear() {
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!stack_.empty())
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<Operation> task(pop());
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)scoped_ptr<IndexedDBTransaction::Operation>
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskStack::pop() {
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!stack_.empty());
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<Operation> task(stack_.top());
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  stack_.pop();
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return task.Pass();
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::IndexedDBTransaction(
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int64 id,
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::set<int64>& object_store_ids,
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    indexed_db::TransactionMode mode,
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBDatabase* database)
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : id_(id),
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      object_store_ids_(object_store_ids),
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      mode_(mode),
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      state_(UNUSED),
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      commit_pending_(false),
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      callbacks_(callbacks),
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      database_(database),
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      transaction_(database->BackingStore().get()),
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      should_process_queue_(false),
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      pending_preemptive_events_(0) {
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidCreateTransaction(this);
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::~IndexedDBTransaction() {
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // It shouldn't be possible for this object to get deleted until it's either
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // complete or aborted.
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(state_, FINISHED);
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(preemptive_task_queue_.empty());
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(task_queue_.empty());
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(abort_task_stack_.empty());
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type,
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                        Operation* task,
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                        Operation* abort_task) {
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (type == IndexedDBDatabase::NORMAL_TASK)
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task_queue_.push(task);
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  else
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    preemptive_task_queue_.push(task);
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (abort_task)
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    abort_task_stack_.push(abort_task);
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (state_ == UNUSED) {
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Start();
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else if (state_ == RUNNING && !should_process_queue_) {
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    should_process_queue_ = true;
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::MessageLoop::current()->PostTask(
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this));
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Abort() {
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Abort(IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                               "Internal error (unknown cause)"));
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) {
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  IDB_TRACE("IndexedDBTransaction::Abort");
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool was_running = state_ == RUNNING;
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // abort steps below. We therefore take a self reference to keep ourselves
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // alive while executing this method.
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  state_ = FINISHED;
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  should_process_queue_ = false;
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (was_running)
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transaction_.Rollback();
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Run the abort tasks, if any.
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!abort_task_stack_.empty()) {
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<Operation> task(abort_task_stack_.pop());
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task->Perform(0);
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  preemptive_task_queue_.clear();
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  task_queue_.clear();
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Backing store resources (held via cursors) must be released
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // before script callbacks are fired, as the script callbacks may
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // release references and allow the backing store itself to be
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // released, and order is critical.
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CloseOpenCursors();
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction_.Reset();
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Transactions must also be marked as completed before the
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // front-end is notified, as the transaction completion unblocks
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // operations like closing connections.
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidFinishTransaction(this);
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#ifndef NDEBUG
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!database_->transaction_coordinator().IsActive(this));
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->TransactionFinished(this);
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (callbacks_.get())
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnAbort(id_, error);
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->TransactionFinishedAndAbortFired(this);
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_ = NULL;
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool IndexedDBTransaction::IsTaskQueueEmpty() const {
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return preemptive_task_queue_.empty() && task_queue_.empty();
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool IndexedDBTransaction::HasPendingTasks() const {
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return pending_preemptive_events_ || !IsTaskQueueEmpty();
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::RegisterOpenCursor(IndexedDBCursor* cursor) {
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.insert(cursor);
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::UnregisterOpenCursor(IndexedDBCursor* cursor) {
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.erase(cursor);
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Run() {
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TransactionCoordinator has started this transaction.
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(state_ == START_PENDING || state_ == RUNNING);
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!should_process_queue_);
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  should_process_queue_ = true;
1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::MessageLoop::current()->PostTask(
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this));
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Start() {
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(state_, UNUSED);
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  state_ = START_PENDING;
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidStartTransaction(this);
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->TransactionStarted(this);
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Commit() {
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  IDB_TRACE("IndexedDBTransaction::Commit");
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // In multiprocess ports, front-end may have requested a commit but
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // an abort has already been initiated asynchronously by the
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // back-end.
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(state_ == UNUSED || state_ == RUNNING);
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  commit_pending_ = true;
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Front-end has requested a commit, but there may be tasks like
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // create_index which are considered synchronous by the front-end
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // but are processed asynchronously.
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (HasPendingTasks())
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // commit steps below. We therefore take a self reference to keep ourselves
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // alive while executing this method.
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  abort_task_stack_.clear();
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool unused = state_ == UNUSED;
220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  state_ = FINISHED;
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool committed = unused || transaction_.Commit();
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Backing store resources (held via cursors) must be released
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // before script callbacks are fired, as the script callbacks may
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // release references and allow the backing store itself to be
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // released, and order is critical.
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CloseOpenCursors();
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction_.Reset();
230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Transactions must also be marked as completed before the
232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // front-end is notified, as the transaction completion unblocks
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // operations like closing connections.
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidFinishTransaction(this);
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->TransactionFinished(this);
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (committed) {
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnComplete(id_);
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    database_->TransactionFinishedAndCompleteFired(this);
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnAbort(
242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        id_,
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               "Internal error committing transaction."));
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    database_->TransactionFinishedAndAbortFired(this);
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_ = NULL;
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid IndexedDBTransaction::ProcessTaskQueue() {
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IDB_TRACE("IndexedDBTransaction::ProcessTaskQueue");
2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // May have been aborted.
2557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!should_process_queue_)
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!IsTaskQueueEmpty());
2597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  should_process_queue_ = false;
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == START_PENDING) {
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    transaction_.Begin();
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    state_ = RUNNING;
264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // tasks. Take take a self reference to keep this object alive so that
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the loop termination conditions can be checked.
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TaskQueue* task_queue =
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!task_queue->empty() && state_ != FINISHED) {
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(state_, RUNNING);
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<Operation> task(task_queue->pop());
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task->Perform(this);
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Event itself may change which queue should be processed next.
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task_queue =
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If there are no pending tasks, we haven't already committed/aborted,
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // and the front-end requested a commit, it is now safe to do so.
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!HasPendingTasks() && state_ != FINISHED && commit_pending_)
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Commit();
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::CloseOpenCursors() {
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin();
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != open_cursors_.end();
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       ++i)
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (*i)->Close();
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.clear();
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace content
298