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,
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    blink::WebIDBTransactionMode 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());
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK_EQ(pending_preemptive_events_, 0);
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(task_queue_.empty());
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(abort_task_stack_.empty());
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid IndexedDBTransaction::ScheduleTask(blink::WebIDBTaskType type,
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                        Operation task) {
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_NE(state_, COMMITTING);
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  timeout_timer_.Stop();
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  used_ = true;
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (type == blink::WebIDBTaskTypeNormal) {
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task_queue_.push(task);
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ++diagnostics_.tasks_scheduled;
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  } else {
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    preemptive_task_queue_.push(task);
102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RunTasksIfStarted();
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void IndexedDBTransaction::ScheduleAbortTask(Operation abort_task) {
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_NE(FINISHED, state_);
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(used_);
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  abort_task_stack_.push(abort_task);
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void IndexedDBTransaction::RunTasksIfStarted() {
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(used_);
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Not started by the coordinator yet.
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (state_ != STARTED)
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // A task is already posted.
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (should_process_queue_)
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  should_process_queue_ = true;
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this));
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Abort() {
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                               "Internal error (unknown cause)"));
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) {
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBTransaction::Abort", "txn.id", id());
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // abort steps below. We therefore take a self reference to keep ourselves
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // alive while executing this method.
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  timeout_timer_.Stop();
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  state_ = FINISHED;
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  should_process_queue_ = false;
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (backing_store_transaction_begun_)
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    transaction_->Rollback();
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Run the abort tasks, if any.
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (!abort_task_stack_.empty())
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    abort_task_stack_.pop().Run(NULL);
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  preemptive_task_queue_.clear();
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  pending_preemptive_events_ = 0;
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  task_queue_.clear();
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Backing store resources (held via cursors) must be released
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // before script callbacks are fired, as the script callbacks may
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // release references and allow the backing store itself to be
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // released, and order is critical.
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CloseOpenCursors();
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  transaction_->Reset();
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Transactions must also be marked as completed before the
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // front-end is notified, as the transaction completion unblocks
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // operations like closing connections.
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidFinishTransaction(this);
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#ifndef NDEBUG
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!database_->transaction_coordinator().IsActive(this));
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (callbacks_.get())
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnAbort(id_, error);
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  database_->TransactionFinished(this, false);
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_ = NULL;
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool IndexedDBTransaction::IsTaskQueueEmpty() const {
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return preemptive_task_queue_.empty() && task_queue_.empty();
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool IndexedDBTransaction::HasPendingTasks() const {
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return pending_preemptive_events_ || !IsTaskQueueEmpty();
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::RegisterOpenCursor(IndexedDBCursor* cursor) {
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.insert(cursor);
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::UnregisterOpenCursor(IndexedDBCursor* cursor) {
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.erase(cursor);
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void IndexedDBTransaction::Start() {
1997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TransactionCoordinator has started this transaction.
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK_EQ(CREATED, state_);
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  state_ = STARTED;
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  diagnostics_.start_time = base::Time::Now();
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!used_)
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RunTasksIfStarted();
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback {
21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public:
212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  explicit BlobWriteCallbackImpl(
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      scoped_refptr<IndexedDBTransaction> transaction)
21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      : transaction_(transaction) {}
21546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual void Run(bool succeeded) OVERRIDE {
21646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    transaction_->BlobWriteComplete(succeeded);
21746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
21846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
21946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) protected:
22046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual ~BlobWriteCallbackImpl() {}
22146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
22246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) private:
22346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<IndexedDBTransaction> transaction_;
22446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void IndexedDBTransaction::BlobWriteComplete(bool success) {
22746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  IDB_TRACE("IndexedDBTransaction::BlobWriteComplete");
22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (state_ == FINISHED)  // aborted
22946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_EQ(state_, COMMITTING);
23146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (success)
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    CommitPhaseTwo();
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  else
23446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError,
23546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 "Failed to write blobs."));
23646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdochleveldb::Status IndexedDBTransaction::Commit() {
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBTransaction::Commit", "txn.id", id());
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  timeout_timer_.Stop();
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // In multiprocess ports, front-end may have requested a commit but
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // an abort has already been initiated asynchronously by the
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // back-end.
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (state_ == FINISHED)
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return leveldb::Status::OK();
24846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_NE(state_, COMMITTING);
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!used_ || state_ == STARTED);
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  commit_pending_ = true;
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Front-end has requested a commit, but there may be tasks like
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // create_index which are considered synchronous by the front-end
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // but are processed asynchronously.
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (HasPendingTasks())
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return leveldb::Status::OK();
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
25946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  state_ = COMMITTING;
26046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  leveldb::Status s;
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!used_) {
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    s = CommitPhaseTwo();
264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else {
26546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback(
26646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        new BlobWriteCallbackImpl(this));
26746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // CommitPhaseOne will call the callback synchronously if there are no blobs
26846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // to write.
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    s = transaction_->CommitPhaseOne(callback);
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!s.ok())
27146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError,
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                   "Error processing blob journal."));
27346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return s;
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdochleveldb::Status IndexedDBTransaction::CommitPhaseTwo() {
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Abort may have been called just as the blob write completed.
28046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (state_ == FINISHED)
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return leveldb::Status::OK();
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_EQ(state_, COMMITTING);
28446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // commit steps below. We therefore take a self reference to keep ourselves
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // alive while executing this method.
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  state_ = FINISHED;
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  leveldb::Status s;
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool committed;
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!used_) {
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    committed = true;
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    s = transaction_->CommitPhaseTwo();
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    committed = s.ok();
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Backing store resources (held via cursors) must be released
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // before script callbacks are fired, as the script callbacks may
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // release references and allow the backing store itself to be
304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // released, and order is critical.
305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CloseOpenCursors();
306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  transaction_->Reset();
307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Transactions must also be marked as completed before the
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // front-end is notified, as the transaction completion unblocks
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // operations like closing connections.
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_->transaction_coordinator().DidFinishTransaction(this);
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (committed) {
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    abort_task_stack_.clear();
315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnComplete(id_);
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    database_->TransactionFinished(this, true);
317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    while (!abort_task_stack_.empty())
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      abort_task_stack_.pop().Run(NULL);
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnAbort(
322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        id_,
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
3247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               "Internal error committing transaction."));
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    database_->TransactionFinished(this, false);
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    database_->TransactionCommitFailed(s);
327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  database_ = NULL;
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return s;
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid IndexedDBTransaction::ProcessTaskQueue() {
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBTransaction::ProcessTaskQueue", "txn.id", id());
3357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // May have been aborted.
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!should_process_queue_)
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!IsTaskQueueEmpty());
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  should_process_queue_ = false;
342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!backing_store_transaction_begun_) {
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    transaction_->Begin();
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    backing_store_transaction_begun_ = true;
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The last reference to this object may be released while performing the
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // tasks. Take take a self reference to keep this object alive so that
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the loop termination conditions can be checked.
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBTransaction> protect(this);
352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TaskQueue* task_queue =
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!task_queue->empty() && state_ != FINISHED) {
35646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DCHECK_EQ(state_, STARTED);
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Operation task(task_queue->pop());
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    task.Run(this);
359d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!pending_preemptive_events_) {
360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled);
361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ++diagnostics_.tasks_completed;
362d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Event itself may change which queue should be processed next.
365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    task_queue =
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If there are no pending tasks, we haven't already committed/aborted,
370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // and the front-end requested a commit, it is now safe to do so.
371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) {
372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Commit();
373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
376a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The transaction may have been aborted while processing tasks.
377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (state_ == FINISHED)
378a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
38046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(state_ == STARTED);
38146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Otherwise, start a timer in case the front-end gets wedged and
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // never requests further activity. Read-only transactions don't
384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // block other transactions, so don't time those out.
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (mode_ != blink::WebIDBTransactionModeReadOnly) {
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_timer_.Start(
387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeDelta::FromSeconds(kInactivityTimeoutPeriodSeconds),
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&IndexedDBTransaction::Timeout, this));
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void IndexedDBTransaction::Timeout() {
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Abort(IndexedDBDatabaseError(
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      blink::WebIDBDatabaseExceptionTimeoutError,
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::ASCIIToUTF16("Transaction timed out due to inactivity.")));
397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
398868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
399868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransaction::CloseOpenCursors() {
400868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin();
401868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != open_cursors_.end();
402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       ++i)
403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (*i)->Close();
404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  open_cursors_.clear();
405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace content
408