indexed_db_transaction.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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)
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int64 kInactivityTimeoutPeriodSeconds = 60;
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskQueue::TaskQueue() {}
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskQueue::~TaskQueue() { clear(); }
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::TaskQueue::clear() {
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!queue_.empty())
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    queue_.pop();
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)IndexedDBTransaction::Operation IndexedDBTransaction::TaskQueue::pop() {
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!queue_.empty());
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Operation task(queue_.front());
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  queue_.pop();
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return task;
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskStack::TaskStack() {}
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::TaskStack::~TaskStack() { clear(); }
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::TaskStack::clear() {
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!stack_.empty())
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    stack_.pop();
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)IndexedDBTransaction::Operation IndexedDBTransaction::TaskStack::pop() {
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!stack_.empty());
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Operation task(stack_.top());
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  stack_.pop();
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return task;
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,
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    IndexedDBDatabase* database,
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    IndexedDBBackingStore::Transaction* backing_store_transaction)
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : id_(id),
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      object_store_ids_(object_store_ids),
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      mode_(mode),
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      used_(false),
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      state_(CREATED),
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      commit_pending_(false),
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      callbacks_(callbacks),
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      database_(database),
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      transaction_(backing_store_transaction),
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      backing_store_transaction_begun_(false),
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      should_process_queue_(false),
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      pending_preemptive_events_(0) {
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidCreateTransaction(this);
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  diagnostics_.tasks_scheduled = 0;
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  diagnostics_.tasks_completed = 0;
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  diagnostics_.creation_time = base::Time::Now();
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransaction::~IndexedDBTransaction() {
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // It shouldn't be possible for this object to get deleted until it's either
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // complete or aborted.
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(state_, FINISHED);
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(preemptive_task_queue_.empty());
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(task_queue_.empty());
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(abort_task_stack_.empty());
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void IndexedDBTransaction::ScheduleTask(Operation task, Operation abort_task) {
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (state_ == FINISHED)
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  timeout_timer_.Stop();
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  used_ = true;
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  task_queue_.push(task);
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ++diagnostics_.tasks_scheduled;
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  abort_task_stack_.push(abort_task);
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RunTasksIfStarted();
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type,
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                        Operation task) {
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  timeout_timer_.Stop();
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  used_ = true;
107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (type == IndexedDBDatabase::NORMAL_TASK) {
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task_queue_.push(task);
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ++diagnostics_.tasks_scheduled;
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  } else {
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    preemptive_task_queue_.push(task);
112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RunTasksIfStarted();
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void IndexedDBTransaction::RunTasksIfStarted() {
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(used_);
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Not started by the coordinator yet.
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (state_ != STARTED)
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // A task is already posted.
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (should_process_queue_)
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  should_process_queue_ = true;
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this));
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Abort() {
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                               "Internal error (unknown cause)"));
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) {
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  IDB_TRACE("IndexedDBTransaction::Abort");
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // abort steps below. We therefore take a self reference to keep ourselves
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // alive while executing this method.
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  timeout_timer_.Stop();
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  state_ = FINISHED;
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  should_process_queue_ = false;
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (backing_store_transaction_begun_)
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    transaction_->Rollback();
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Run the abort tasks, if any.
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (!abort_task_stack_.empty())
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    abort_task_stack_.pop().Run(NULL);
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  preemptive_task_queue_.clear();
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  task_queue_.clear();
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Backing store resources (held via cursors) must be released
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // before script callbacks are fired, as the script callbacks may
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // release references and allow the backing store itself to be
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // released, and order is critical.
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CloseOpenCursors();
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  transaction_->Reset();
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Transactions must also be marked as completed before the
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // front-end is notified, as the transaction completion unblocks
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // operations like closing connections.
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidFinishTransaction(this);
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#ifndef NDEBUG
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!database_->transaction_coordinator().IsActive(this));
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (callbacks_.get())
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnAbort(id_, error);
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  database_->TransactionFinished(this, false);
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_ = NULL;
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool IndexedDBTransaction::IsTaskQueueEmpty() const {
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return preemptive_task_queue_.empty() && task_queue_.empty();
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool IndexedDBTransaction::HasPendingTasks() const {
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return pending_preemptive_events_ || !IsTaskQueueEmpty();
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::RegisterOpenCursor(IndexedDBCursor* cursor) {
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.insert(cursor);
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::UnregisterOpenCursor(IndexedDBCursor* cursor) {
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.erase(cursor);
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void IndexedDBTransaction::Start() {
2027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TransactionCoordinator has started this transaction.
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK_EQ(CREATED, state_);
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  state_ = STARTED;
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  diagnostics_.start_time = base::Time::Now();
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!used_)
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RunTasksIfStarted();
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Commit() {
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  IDB_TRACE("IndexedDBTransaction::Commit");
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // In multiprocess ports, front-end may have requested a commit but
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // an abort has already been initiated asynchronously by the
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // back-end.
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!used_ || state_ == STARTED);
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  commit_pending_ = true;
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Front-end has requested a commit, but there may be tasks like
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // create_index which are considered synchronous by the front-end
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // but are processed asynchronously.
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (HasPendingTasks())
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // commit steps below. We therefore take a self reference to keep ourselves
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // alive while executing this method.
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  timeout_timer_.Stop();
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  state_ = FINISHED;
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool committed = !used_ || transaction_->Commit().ok();
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Backing store resources (held via cursors) must be released
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // before script callbacks are fired, as the script callbacks may
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // release references and allow the backing store itself to be
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // released, and order is critical.
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CloseOpenCursors();
247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  transaction_->Reset();
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Transactions must also be marked as completed before the
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // front-end is notified, as the transaction completion unblocks
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // operations like closing connections.
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidFinishTransaction(this);
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (committed) {
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    abort_task_stack_.clear();
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnComplete(id_);
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    database_->TransactionFinished(this, true);
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    while (!abort_task_stack_.empty())
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      abort_task_stack_.pop().Run(NULL);
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnAbort(
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        id_,
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               "Internal error committing transaction."));
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    database_->TransactionFinished(this, false);
2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    database_->TransactionCommitFailed();
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_ = NULL;
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid IndexedDBTransaction::ProcessTaskQueue() {
2747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IDB_TRACE("IndexedDBTransaction::ProcessTaskQueue");
2757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // May have been aborted.
2777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!should_process_queue_)
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!IsTaskQueueEmpty());
2817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  should_process_queue_ = false;
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!backing_store_transaction_begun_) {
284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    transaction_->Begin();
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    backing_store_transaction_begun_ = true;
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // tasks. Take take a self reference to keep this object alive so that
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the loop termination conditions can be checked.
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TaskQueue* task_queue =
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!task_queue->empty() && state_ != FINISHED) {
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK_EQ(STARTED, state_);
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Operation task(task_queue->pop());
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    task.Run(this);
299d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!pending_preemptive_events_) {
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled);
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ++diagnostics_.tasks_completed;
302d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Event itself may change which queue should be processed next.
305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task_queue =
306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If there are no pending tasks, we haven't already committed/aborted,
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // and the front-end requested a commit, it is now safe to do so.
311a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) {
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Commit();
313a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The transaction may have been aborted while processing tasks.
317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (state_ == FINISHED)
318a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
319a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Otherwise, start a timer in case the front-end gets wedged and
321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // never requests further activity. Read-only transactions don't
322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // block other transactions, so don't time those out.
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (mode_ != indexed_db::TRANSACTION_READ_ONLY) {
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_timer_.Start(
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeDelta::FromSeconds(kInactivityTimeoutPeriodSeconds),
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&IndexedDBTransaction::Timeout, this));
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void IndexedDBTransaction::Timeout() {
332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Abort(IndexedDBDatabaseError(
333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      blink::WebIDBDatabaseExceptionTimeoutError,
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::ASCIIToUTF16("Transaction timed out due to inactivity.")));
335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::CloseOpenCursors() {
338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin();
339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != open_cursors_.end();
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       ++i)
341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (*i)->Close();
342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.clear();
343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace content
346