// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRANSACTION_H_ #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRANSACTION_H_ #include <queue> #include <set> #include <stack> #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "content/browser/indexed_db/indexed_db_backing_store.h" #include "content/browser/indexed_db/indexed_db_database.h" #include "content/browser/indexed_db/indexed_db_database_error.h" #include "third_party/WebKit/public/platform/WebIDBTypes.h" namespace content { class BlobWriteCallbackImpl; class IndexedDBCursor; class IndexedDBDatabaseCallbacks; class CONTENT_EXPORT IndexedDBTransaction : public NON_EXPORTED_BASE(base::RefCounted<IndexedDBTransaction>) { public: typedef base::Callback<void(IndexedDBTransaction*)> Operation; enum State { CREATED, // Created, but not yet started by coordinator. STARTED, // Started by the coordinator. COMMITTING, // In the process of committing, possibly waiting for blobs // to be written. FINISHED, // Either aborted or committed. }; IndexedDBTransaction( int64 id, scoped_refptr<IndexedDBDatabaseCallbacks> callbacks, const std::set<int64>& object_store_ids, blink::WebIDBTransactionMode, IndexedDBDatabase* db, IndexedDBBackingStore::Transaction* backing_store_transaction); virtual void Abort(); leveldb::Status Commit(); void Abort(const IndexedDBDatabaseError& error); // Called by the transaction coordinator when this transaction is unblocked. void Start(); blink::WebIDBTransactionMode mode() const { return mode_; } const std::set<int64>& scope() const { return object_store_ids_; } void ScheduleTask(Operation task) { ScheduleTask(blink::WebIDBTaskTypeNormal, task); } void ScheduleTask(blink::WebIDBTaskType, Operation task); void ScheduleAbortTask(Operation abort_task); void RegisterOpenCursor(IndexedDBCursor* cursor); void UnregisterOpenCursor(IndexedDBCursor* cursor); void AddPreemptiveEvent() { pending_preemptive_events_++; } void DidCompletePreemptiveEvent() { pending_preemptive_events_--; DCHECK_GE(pending_preemptive_events_, 0); } IndexedDBBackingStore::Transaction* BackingStoreTransaction() { return transaction_.get(); } int64 id() const { return id_; } IndexedDBDatabase* database() const { return database_.get(); } IndexedDBDatabaseCallbacks* connection() const { return callbacks_.get(); } State state() const { return state_; } bool IsTimeoutTimerRunning() const { return timeout_timer_.IsRunning(); } struct Diagnostics { base::Time creation_time; base::Time start_time; int tasks_scheduled; int tasks_completed; }; const Diagnostics& diagnostics() const { return diagnostics_; } private: friend class BlobWriteCallbackImpl; FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTestMode, AbortPreemptive); FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTest, Timeout); FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTest, SchedulePreemptiveTask); FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTestMode, ScheduleNormalTask); friend class base::RefCounted<IndexedDBTransaction>; virtual ~IndexedDBTransaction(); void RunTasksIfStarted(); bool IsTaskQueueEmpty() const; bool HasPendingTasks() const; void BlobWriteComplete(bool success); void ProcessTaskQueue(); void CloseOpenCursors(); leveldb::Status CommitPhaseTwo(); void Timeout(); const int64 id_; const std::set<int64> object_store_ids_; const blink::WebIDBTransactionMode mode_; bool used_; State state_; bool commit_pending_; scoped_refptr<IndexedDBDatabaseCallbacks> callbacks_; scoped_refptr<IndexedDBDatabase> database_; class TaskQueue { public: TaskQueue(); ~TaskQueue(); bool empty() const { return queue_.empty(); } void push(Operation task) { queue_.push(task); } Operation pop(); void clear(); private: std::queue<Operation> queue_; DISALLOW_COPY_AND_ASSIGN(TaskQueue); }; class TaskStack { public: TaskStack(); ~TaskStack(); bool empty() const { return stack_.empty(); } void push(Operation task) { stack_.push(task); } Operation pop(); void clear(); private: std::stack<Operation> stack_; DISALLOW_COPY_AND_ASSIGN(TaskStack); }; TaskQueue task_queue_; TaskQueue preemptive_task_queue_; TaskStack abort_task_stack_; scoped_ptr<IndexedDBBackingStore::Transaction> transaction_; bool backing_store_transaction_begun_; bool should_process_queue_; int pending_preemptive_events_; std::set<IndexedDBCursor*> open_cursors_; // This timer is started after requests have been processed. If no subsequent // requests are processed before the timer fires, assume the script is // unresponsive and abort to unblock the transaction queue. base::OneShotTimer<IndexedDBTransaction> timeout_timer_; Diagnostics diagnostics_; }; } // namespace content #endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRANSACTION_H_