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