Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: content/browser/indexed_db/indexed_db_transaction.cc

Issue 15659013: Revert "Migrate the IndexedDB backend from Blink to Chromium" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 #include "content/browser/indexed_db/indexed_db_transaction.h"
6
7 #include <vector>
8 #include "base/logging.h"
9 #include "base/utf_string_conversions.h"
10 #include "content/browser/indexed_db/indexed_db_backing_store.h"
11 #include "content/browser/indexed_db/indexed_db_cursor_impl.h"
12 #include "content/browser/indexed_db/indexed_db_database_callbacks_wrapper.h"
13 #include "content/browser/indexed_db/indexed_db_database_impl.h"
14 #include "content/browser/indexed_db/indexed_db_tracing.h"
15 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
16 #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabaseExcep tion.h"
17
18 namespace content {
19
20 IndexedDBTransaction::TaskQueue::TaskQueue() {}
21 IndexedDBTransaction::TaskQueue::~TaskQueue() { clear(); }
22
23 void IndexedDBTransaction::TaskQueue::clear() {
24 while (!queue_.empty())
25 scoped_ptr<Operation> task(pop());
26 }
27
28 scoped_ptr<IndexedDBTransaction::Operation>
29 IndexedDBTransaction::TaskQueue::pop() {
30 DCHECK(!queue_.empty());
31 scoped_ptr<Operation> task(queue_.front());
32 queue_.pop();
33 return task.Pass();
34 }
35
36 IndexedDBTransaction::TaskStack::TaskStack() {}
37 IndexedDBTransaction::TaskStack::~TaskStack() { clear(); }
38
39 void IndexedDBTransaction::TaskStack::clear() {
40 while (!stack_.empty())
41 scoped_ptr<Operation> task(pop());
42 }
43
44 scoped_ptr<IndexedDBTransaction::Operation>
45 IndexedDBTransaction::TaskStack::pop() {
46 DCHECK(!stack_.empty());
47 scoped_ptr<Operation> task(stack_.top());
48 stack_.pop();
49 return task.Pass();
50 }
51
52 scoped_refptr<IndexedDBTransaction> IndexedDBTransaction::Create(
53 int64 id,
54 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks,
55 const std::vector<int64>& object_store_ids,
56 indexed_db::TransactionMode mode,
57 IndexedDBDatabaseImpl* database) {
58 std::set<int64> object_store_hash_set;
59 for (size_t i = 0; i < object_store_ids.size(); ++i)
60 object_store_hash_set.insert(object_store_ids[i]);
61
62 return make_scoped_refptr(new IndexedDBTransaction(
63 id, callbacks, object_store_hash_set, mode, database));
64 }
65
66 IndexedDBTransaction::IndexedDBTransaction(
67 int64 id,
68 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks,
69 const std::set<int64>& object_store_ids,
70 indexed_db::TransactionMode mode,
71 IndexedDBDatabaseImpl* database)
72 : id_(id),
73 object_store_ids_(object_store_ids),
74 mode_(mode),
75 state_(UNUSED),
76 commit_pending_(false),
77 callbacks_(callbacks),
78 database_(database),
79 transaction_(database->BackingStore().get()),
80 pending_preemptive_events_(0) {
81 database_->transaction_coordinator().DidCreateTransaction(this);
82 }
83
84 IndexedDBTransaction::~IndexedDBTransaction() {
85 // It shouldn't be possible for this object to get deleted until it's either
86 // complete or aborted.
87 DCHECK_EQ(state_, FINISHED);
88 DCHECK(preemptive_task_queue_.empty());
89 DCHECK(task_queue_.empty());
90 DCHECK(abort_task_stack_.empty());
91 }
92
93 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type,
94 Operation* task,
95 Operation* abort_task) {
96 if (state_ == FINISHED)
97 return;
98
99 if (type == IndexedDBDatabase::NORMAL_TASK)
100 task_queue_.push(task);
101 else
102 preemptive_task_queue_.push(task);
103
104 if (abort_task)
105 abort_task_stack_.push(abort_task);
106
107 if (state_ == UNUSED)
108 Start();
109 else if (state_ == RUNNING && !task_timer_.IsRunning())
110 task_timer_.Start(FROM_HERE,
111 base::TimeDelta::FromSeconds(0),
112 this,
113 &IndexedDBTransaction::TaskTimerFired);
114 }
115
116 void IndexedDBTransaction::Abort() {
117 Abort(IndexedDBDatabaseError::Create(
118 WebKit::WebIDBDatabaseExceptionUnknownError,
119 ASCIIToUTF16("Internal error (unknown cause)")));
120 }
121
122 void IndexedDBTransaction::Abort(scoped_refptr<IndexedDBDatabaseError> error) {
123 IDB_TRACE("IndexedDBTransaction::abort");
124 if (state_ == FINISHED)
125 return;
126
127 bool was_running = state_ == RUNNING;
128
129 // The last reference to this object may be released while performing the
130 // abort steps below. We therefore take a self reference to keep ourselves
131 // alive while executing this method.
132 scoped_refptr<IndexedDBTransaction> protect(this);
133
134 state_ = FINISHED;
135 task_timer_.Stop();
136
137 if (was_running)
138 transaction_.Rollback();
139
140 // Run the abort tasks, if any.
141 while (!abort_task_stack_.empty()) {
142 scoped_ptr<Operation> task(abort_task_stack_.pop());
143 task->Perform(0);
144 }
145 preemptive_task_queue_.clear();
146 task_queue_.clear();
147
148 // Backing store resources (held via cursors) must be released
149 // before script callbacks are fired, as the script callbacks may
150 // release references and allow the backing store itself to be
151 // released, and order is critical.
152 CloseOpenCursors();
153 transaction_.Reset();
154
155 // Transactions must also be marked as completed before the
156 // front-end is notified, as the transaction completion unblocks
157 // operations like closing connections.
158 database_->transaction_coordinator().DidFinishTransaction(this);
159 #ifndef NDEBUG
160 DCHECK(!database_->transaction_coordinator().IsActive(this));
161 #endif
162 database_->TransactionFinished(this);
163
164 if (callbacks_)
165 callbacks_->OnAbort(id_, error);
166
167 database_->TransactionFinishedAndAbortFired(this);
168
169 database_ = NULL;
170 }
171
172 bool IndexedDBTransaction::IsTaskQueueEmpty() const {
173 return preemptive_task_queue_.empty() && task_queue_.empty();
174 }
175
176 bool IndexedDBTransaction::HasPendingTasks() const {
177 return pending_preemptive_events_ || !IsTaskQueueEmpty();
178 }
179
180 void IndexedDBTransaction::RegisterOpenCursor(IndexedDBCursorImpl* cursor) {
181 open_cursors_.insert(cursor);
182 }
183
184 void IndexedDBTransaction::UnregisterOpenCursor(IndexedDBCursorImpl* cursor) {
185 open_cursors_.erase(cursor);
186 }
187
188 void IndexedDBTransaction::Run() {
189 // TransactionCoordinator has started this transaction. Schedule a timer
190 // to process the first task.
191 DCHECK(state_ == START_PENDING || state_ == RUNNING);
192 DCHECK(!task_timer_.IsRunning());
193
194 task_timer_.Start(FROM_HERE,
195 base::TimeDelta::FromSeconds(0),
196 this,
197 &IndexedDBTransaction::TaskTimerFired);
198 }
199
200 void IndexedDBTransaction::Start() {
201 DCHECK_EQ(state_, UNUSED);
202
203 state_ = START_PENDING;
204 database_->transaction_coordinator().DidStartTransaction(this);
205 database_->TransactionStarted(this);
206 }
207
208 void IndexedDBTransaction::Commit() {
209 IDB_TRACE("IndexedDBTransaction::commit");
210
211 // In multiprocess ports, front-end may have requested a commit but
212 // an abort has already been initiated asynchronously by the
213 // back-end.
214 if (state_ == FINISHED)
215 return;
216
217 DCHECK(state_ == UNUSED || state_ == RUNNING);
218 commit_pending_ = true;
219
220 // Front-end has requested a commit, but there may be tasks like
221 // create_index which are considered synchronous by the front-end
222 // but are processed asynchronously.
223 if (HasPendingTasks())
224 return;
225
226 // The last reference to this object may be released while performing the
227 // commit steps below. We therefore take a self reference to keep ourselves
228 // alive while executing this method.
229 scoped_refptr<IndexedDBTransaction> protect(this);
230
231 // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843
232 abort_task_stack_.clear();
233
234 bool unused = state_ == UNUSED;
235 state_ = FINISHED;
236
237 bool committed = unused || transaction_.Commit();
238
239 // Backing store resources (held via cursors) must be released
240 // before script callbacks are fired, as the script callbacks may
241 // release references and allow the backing store itself to be
242 // released, and order is critical.
243 CloseOpenCursors();
244 transaction_.Reset();
245
246 // Transactions must also be marked as completed before the
247 // front-end is notified, as the transaction completion unblocks
248 // operations like closing connections.
249 if (!unused)
250 database_->transaction_coordinator().DidFinishTransaction(this);
251 database_->TransactionFinished(this);
252
253 if (committed) {
254 callbacks_->OnComplete(id_);
255 database_->TransactionFinishedAndCompleteFired(this);
256 } else {
257 callbacks_->OnAbort(
258 id_,
259 IndexedDBDatabaseError::Create(
260 WebKit::WebIDBDatabaseExceptionUnknownError,
261 ASCIIToUTF16("Internal error committing transaction.")));
262 database_->TransactionFinishedAndAbortFired(this);
263 }
264
265 database_ = NULL;
266 }
267
268 void IndexedDBTransaction::TaskTimerFired() {
269 IDB_TRACE("IndexedDBTransaction::task_timer_fired");
270 DCHECK(!IsTaskQueueEmpty());
271
272 if (state_ == START_PENDING) {
273 transaction_.begin();
274 state_ = RUNNING;
275 }
276
277 // The last reference to this object may be released while performing the
278 // tasks. Take take a self reference to keep this object alive so that
279 // the loop termination conditions can be checked.
280 scoped_refptr<IndexedDBTransaction> protect(this);
281
282 TaskQueue* task_queue =
283 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
284 while (!task_queue->empty() && state_ != FINISHED) {
285 DCHECK_EQ(state_, RUNNING);
286 scoped_ptr<Operation> task(task_queue->pop());
287 task->Perform(this);
288
289 // Event itself may change which queue should be processed next.
290 task_queue =
291 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
292 }
293
294 // If there are no pending tasks, we haven't already committed/aborted,
295 // and the front-end requested a commit, it is now safe to do so.
296 if (!HasPendingTasks() && state_ != FINISHED && commit_pending_)
297 Commit();
298 }
299
300 void IndexedDBTransaction::CloseOpenCursors() {
301 for (std::set<IndexedDBCursorImpl*>::iterator i = open_cursors_.begin();
302 i != open_cursors_.end();
303 ++i)
304 (*i)->Close();
305 open_cursors_.clear();
306 }
307
308 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/indexed_db/indexed_db_transaction.h ('k') | content/browser/indexed_db/indexed_db_transaction_coordinator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698