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