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