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