1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRANSACTION_H_
6#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRANSACTION_H_
7
8#include <queue>
9#include <set>
10#include <stack>
11
12#include "base/basictypes.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/scoped_ptr.h"
15#include "base/time/time.h"
16#include "base/timer/timer.h"
17#include "content/browser/indexed_db/indexed_db_backing_store.h"
18#include "content/browser/indexed_db/indexed_db_database.h"
19#include "content/browser/indexed_db/indexed_db_database_error.h"
20
21namespace content {
22
23class BlobWriteCallbackImpl;
24class IndexedDBCursor;
25class IndexedDBDatabaseCallbacks;
26
27class CONTENT_EXPORT IndexedDBTransaction
28    : public NON_EXPORTED_BASE(base::RefCounted<IndexedDBTransaction>) {
29 public:
30  typedef base::Callback<void(IndexedDBTransaction*)> Operation;
31
32  IndexedDBTransaction(
33      int64 id,
34      scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
35      const std::set<int64>& object_store_ids,
36      indexed_db::TransactionMode,
37      IndexedDBDatabase* db,
38      IndexedDBBackingStore::Transaction* backing_store_transaction);
39
40  virtual void Abort();
41  void Commit();
42  void Abort(const IndexedDBDatabaseError& error);
43
44  // Called by the transaction coordinator when this transaction is unblocked.
45  void Start();
46
47  indexed_db::TransactionMode mode() const { return mode_; }
48  const std::set<int64>& scope() const { return object_store_ids_; }
49
50  void ScheduleTask(Operation task) {
51    ScheduleTask(IndexedDBDatabase::NORMAL_TASK, task);
52  }
53  void ScheduleTask(IndexedDBDatabase::TaskType, Operation task);
54  void ScheduleAbortTask(Operation abort_task);
55  void RegisterOpenCursor(IndexedDBCursor* cursor);
56  void UnregisterOpenCursor(IndexedDBCursor* cursor);
57  void AddPreemptiveEvent() { pending_preemptive_events_++; }
58  void DidCompletePreemptiveEvent() {
59    pending_preemptive_events_--;
60    DCHECK_GE(pending_preemptive_events_, 0);
61  }
62  IndexedDBBackingStore::Transaction* BackingStoreTransaction() {
63    return transaction_.get();
64  }
65  int64 id() const { return id_; }
66
67  IndexedDBDatabase* database() const { return database_; }
68  IndexedDBDatabaseCallbacks* connection() const { return callbacks_; }
69
70  enum State {
71    CREATED,     // Created, but not yet started by coordinator.
72    STARTED,     // Started by the coordinator.
73    COMMITTING,  // In the process of committing, possibly waiting for blobs
74                 // to be written.
75    FINISHED,    // Either aborted or committed.
76  };
77
78  State state() const { return state_; }
79  bool IsTimeoutTimerRunning() const { return timeout_timer_.IsRunning(); }
80
81  struct Diagnostics {
82    base::Time creation_time;
83    base::Time start_time;
84    int tasks_scheduled;
85    int tasks_completed;
86  };
87
88  const Diagnostics& diagnostics() const { return diagnostics_; }
89
90 private:
91  friend class BlobWriteCallbackImpl;
92
93  FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTestMode, AbortPreemptive);
94  FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTest, Timeout);
95  FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTest,
96                           SchedulePreemptiveTask);
97  FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTestMode,
98                           ScheduleNormalTask);
99
100  friend class base::RefCounted<IndexedDBTransaction>;
101  virtual ~IndexedDBTransaction();
102
103  void RunTasksIfStarted();
104
105  bool IsTaskQueueEmpty() const;
106  bool HasPendingTasks() const;
107
108  void BlobWriteComplete(bool success);
109  void ProcessTaskQueue();
110  void CloseOpenCursors();
111  void CommitPhaseTwo();
112  void Timeout();
113
114  const int64 id_;
115  const std::set<int64> object_store_ids_;
116  const indexed_db::TransactionMode mode_;
117
118  bool used_;
119  State state_;
120  bool commit_pending_;
121  scoped_refptr<IndexedDBDatabaseCallbacks> callbacks_;
122  scoped_refptr<IndexedDBDatabase> database_;
123
124  class TaskQueue {
125   public:
126    TaskQueue();
127    ~TaskQueue();
128    bool empty() const { return queue_.empty(); }
129    void push(Operation task) { queue_.push(task); }
130    Operation pop();
131    void clear();
132
133   private:
134    std::queue<Operation> queue_;
135
136    DISALLOW_COPY_AND_ASSIGN(TaskQueue);
137  };
138
139  class TaskStack {
140   public:
141    TaskStack();
142    ~TaskStack();
143    bool empty() const { return stack_.empty(); }
144    void push(Operation task) { stack_.push(task); }
145    Operation pop();
146    void clear();
147
148   private:
149    std::stack<Operation> stack_;
150
151    DISALLOW_COPY_AND_ASSIGN(TaskStack);
152  };
153
154  TaskQueue task_queue_;
155  TaskQueue preemptive_task_queue_;
156  TaskStack abort_task_stack_;
157
158  scoped_ptr<IndexedDBBackingStore::Transaction> transaction_;
159  bool backing_store_transaction_begun_;
160
161  bool should_process_queue_;
162  int pending_preemptive_events_;
163
164  std::set<IndexedDBCursor*> open_cursors_;
165
166  // This timer is started after requests have been processed. If no subsequent
167  // requests are processed before the timer fires, assume the script is
168  // unresponsive and abort to unblock the transaction queue.
169  base::OneShotTimer<IndexedDBTransaction> timeout_timer_;
170
171  Diagnostics diagnostics_;
172};
173
174}  // namespace content
175
176#endif  // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_TRANSACTION_H_
177