OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/indexed_db/indexed_db_transaction.h" | 5 #include "content/browser/indexed_db/indexed_db_transaction.h" |
6 | 6 |
| 7 #include "base/bind.h" |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop/message_loop.h" |
8 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
9 #include "content/browser/indexed_db/indexed_db_backing_store.h" | 11 #include "content/browser/indexed_db/indexed_db_backing_store.h" |
10 #include "content/browser/indexed_db/indexed_db_cursor.h" | 12 #include "content/browser/indexed_db/indexed_db_cursor.h" |
11 #include "content/browser/indexed_db/indexed_db_database.h" | 13 #include "content/browser/indexed_db/indexed_db_database.h" |
12 #include "content/browser/indexed_db/indexed_db_database_callbacks.h" | 14 #include "content/browser/indexed_db/indexed_db_database_callbacks.h" |
13 #include "content/browser/indexed_db/indexed_db_tracing.h" | 15 #include "content/browser/indexed_db/indexed_db_tracing.h" |
14 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h" | 16 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h" |
15 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" | 17 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" |
16 | 18 |
17 namespace content { | 19 namespace content { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 indexed_db::TransactionMode mode, | 71 indexed_db::TransactionMode mode, |
70 IndexedDBDatabase* database) | 72 IndexedDBDatabase* database) |
71 : id_(id), | 73 : id_(id), |
72 object_store_ids_(object_store_ids), | 74 object_store_ids_(object_store_ids), |
73 mode_(mode), | 75 mode_(mode), |
74 state_(UNUSED), | 76 state_(UNUSED), |
75 commit_pending_(false), | 77 commit_pending_(false), |
76 callbacks_(callbacks), | 78 callbacks_(callbacks), |
77 database_(database), | 79 database_(database), |
78 transaction_(database->BackingStore().get()), | 80 transaction_(database->BackingStore().get()), |
| 81 should_process_queue_(false), |
79 pending_preemptive_events_(0) { | 82 pending_preemptive_events_(0) { |
80 database_->transaction_coordinator().DidCreateTransaction(this); | 83 database_->transaction_coordinator().DidCreateTransaction(this); |
81 } | 84 } |
82 | 85 |
83 IndexedDBTransaction::~IndexedDBTransaction() { | 86 IndexedDBTransaction::~IndexedDBTransaction() { |
84 // It shouldn't be possible for this object to get deleted until it's either | 87 // It shouldn't be possible for this object to get deleted until it's either |
85 // complete or aborted. | 88 // complete or aborted. |
86 DCHECK_EQ(state_, FINISHED); | 89 DCHECK_EQ(state_, FINISHED); |
87 DCHECK(preemptive_task_queue_.empty()); | 90 DCHECK(preemptive_task_queue_.empty()); |
88 DCHECK(task_queue_.empty()); | 91 DCHECK(task_queue_.empty()); |
89 DCHECK(abort_task_stack_.empty()); | 92 DCHECK(abort_task_stack_.empty()); |
90 } | 93 } |
91 | 94 |
92 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, | 95 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, |
93 Operation* task, | 96 Operation* task, |
94 Operation* abort_task) { | 97 Operation* abort_task) { |
95 if (state_ == FINISHED) | 98 if (state_ == FINISHED) |
96 return; | 99 return; |
97 | 100 |
98 if (type == IndexedDBDatabase::NORMAL_TASK) | 101 if (type == IndexedDBDatabase::NORMAL_TASK) |
99 task_queue_.push(task); | 102 task_queue_.push(task); |
100 else | 103 else |
101 preemptive_task_queue_.push(task); | 104 preemptive_task_queue_.push(task); |
102 | 105 |
103 if (abort_task) | 106 if (abort_task) |
104 abort_task_stack_.push(abort_task); | 107 abort_task_stack_.push(abort_task); |
105 | 108 |
106 if (state_ == UNUSED) | 109 if (state_ == UNUSED) { |
107 Start(); | 110 Start(); |
108 else if (state_ == RUNNING && !task_timer_.IsRunning()) | 111 } else if (state_ == RUNNING && !should_process_queue_) { |
109 task_timer_.Start(FROM_HERE, | 112 should_process_queue_ = true; |
110 base::TimeDelta::FromSeconds(0), | 113 base::MessageLoop::current()->PostTask( |
111 this, | 114 FROM_HERE, |
112 &IndexedDBTransaction::TaskTimerFired); | 115 base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this)); |
| 116 } |
113 } | 117 } |
114 | 118 |
115 void IndexedDBTransaction::Abort() { | 119 void IndexedDBTransaction::Abort() { |
116 Abort(IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, | 120 Abort(IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, |
117 "Internal error (unknown cause)")); | 121 "Internal error (unknown cause)")); |
118 } | 122 } |
119 | 123 |
120 void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) { | 124 void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) { |
121 IDB_TRACE("IndexedDBTransaction::Abort"); | 125 IDB_TRACE("IndexedDBTransaction::Abort"); |
122 if (state_ == FINISHED) | 126 if (state_ == FINISHED) |
123 return; | 127 return; |
124 | 128 |
125 bool was_running = state_ == RUNNING; | 129 bool was_running = state_ == RUNNING; |
126 | 130 |
127 // The last reference to this object may be released while performing the | 131 // The last reference to this object may be released while performing the |
128 // abort steps below. We therefore take a self reference to keep ourselves | 132 // abort steps below. We therefore take a self reference to keep ourselves |
129 // alive while executing this method. | 133 // alive while executing this method. |
130 scoped_refptr<IndexedDBTransaction> protect(this); | 134 scoped_refptr<IndexedDBTransaction> protect(this); |
131 | 135 |
132 state_ = FINISHED; | 136 state_ = FINISHED; |
133 task_timer_.Stop(); | 137 should_process_queue_ = false; |
134 | 138 |
135 if (was_running) | 139 if (was_running) |
136 transaction_.Rollback(); | 140 transaction_.Rollback(); |
137 | 141 |
138 // Run the abort tasks, if any. | 142 // Run the abort tasks, if any. |
139 while (!abort_task_stack_.empty()) { | 143 while (!abort_task_stack_.empty()) { |
140 scoped_ptr<Operation> task(abort_task_stack_.pop()); | 144 scoped_ptr<Operation> task(abort_task_stack_.pop()); |
141 task->Perform(0); | 145 task->Perform(0); |
142 } | 146 } |
143 preemptive_task_queue_.clear(); | 147 preemptive_task_queue_.clear(); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 | 181 |
178 void IndexedDBTransaction::RegisterOpenCursor(IndexedDBCursor* cursor) { | 182 void IndexedDBTransaction::RegisterOpenCursor(IndexedDBCursor* cursor) { |
179 open_cursors_.insert(cursor); | 183 open_cursors_.insert(cursor); |
180 } | 184 } |
181 | 185 |
182 void IndexedDBTransaction::UnregisterOpenCursor(IndexedDBCursor* cursor) { | 186 void IndexedDBTransaction::UnregisterOpenCursor(IndexedDBCursor* cursor) { |
183 open_cursors_.erase(cursor); | 187 open_cursors_.erase(cursor); |
184 } | 188 } |
185 | 189 |
186 void IndexedDBTransaction::Run() { | 190 void IndexedDBTransaction::Run() { |
187 // TransactionCoordinator has started this transaction. Schedule a timer | 191 // TransactionCoordinator has started this transaction. |
188 // to process the first task. | |
189 DCHECK(state_ == START_PENDING || state_ == RUNNING); | 192 DCHECK(state_ == START_PENDING || state_ == RUNNING); |
190 DCHECK(!task_timer_.IsRunning()); | 193 DCHECK(!should_process_queue_); |
191 | 194 |
192 task_timer_.Start(FROM_HERE, | 195 should_process_queue_ = true; |
193 base::TimeDelta::FromSeconds(0), | 196 base::MessageLoop::current()->PostTask( |
194 this, | 197 FROM_HERE, |
195 &IndexedDBTransaction::TaskTimerFired); | 198 base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this)); |
196 } | 199 } |
197 | 200 |
198 void IndexedDBTransaction::Start() { | 201 void IndexedDBTransaction::Start() { |
199 DCHECK_EQ(state_, UNUSED); | 202 DCHECK_EQ(state_, UNUSED); |
200 | 203 |
201 state_ = START_PENDING; | 204 state_ = START_PENDING; |
202 database_->transaction_coordinator().DidStartTransaction(this); | 205 database_->transaction_coordinator().DidStartTransaction(this); |
203 database_->TransactionStarted(this); | 206 database_->TransactionStarted(this); |
204 } | 207 } |
205 | 208 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 callbacks_->OnAbort( | 257 callbacks_->OnAbort( |
255 id_, | 258 id_, |
256 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, | 259 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, |
257 "Internal error committing transaction.")); | 260 "Internal error committing transaction.")); |
258 database_->TransactionFinishedAndAbortFired(this); | 261 database_->TransactionFinishedAndAbortFired(this); |
259 } | 262 } |
260 | 263 |
261 database_ = NULL; | 264 database_ = NULL; |
262 } | 265 } |
263 | 266 |
264 void IndexedDBTransaction::TaskTimerFired() { | 267 void IndexedDBTransaction::ProcessTaskQueue() { |
265 IDB_TRACE("IndexedDBTransaction::TaskTimerFired"); | 268 IDB_TRACE("IndexedDBTransaction::ProcessTaskQueue"); |
| 269 |
| 270 // May have been aborted. |
| 271 if (!should_process_queue_) |
| 272 return; |
| 273 |
266 DCHECK(!IsTaskQueueEmpty()); | 274 DCHECK(!IsTaskQueueEmpty()); |
| 275 should_process_queue_ = false; |
267 | 276 |
268 if (state_ == START_PENDING) { | 277 if (state_ == START_PENDING) { |
269 transaction_.Begin(); | 278 transaction_.Begin(); |
270 state_ = RUNNING; | 279 state_ = RUNNING; |
271 } | 280 } |
272 | 281 |
273 // The last reference to this object may be released while performing the | 282 // The last reference to this object may be released while performing the |
274 // tasks. Take take a self reference to keep this object alive so that | 283 // tasks. Take take a self reference to keep this object alive so that |
275 // the loop termination conditions can be checked. | 284 // the loop termination conditions can be checked. |
276 scoped_refptr<IndexedDBTransaction> protect(this); | 285 scoped_refptr<IndexedDBTransaction> protect(this); |
(...skipping 18 matching lines...) Expand all Loading... |
295 | 304 |
296 void IndexedDBTransaction::CloseOpenCursors() { | 305 void IndexedDBTransaction::CloseOpenCursors() { |
297 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); | 306 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); |
298 i != open_cursors_.end(); | 307 i != open_cursors_.end(); |
299 ++i) | 308 ++i) |
300 (*i)->Close(); | 309 (*i)->Close(); |
301 open_cursors_.clear(); | 310 open_cursors_.clear(); |
302 } | 311 } |
303 | 312 |
304 } // namespace content | 313 } // namespace content |
OLD | NEW |