Chromium Code Reviews| 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/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 53 scoped_refptr<IndexedDBDatabaseCallbacks> callbacks, | 53 scoped_refptr<IndexedDBDatabaseCallbacks> callbacks, |
| 54 const std::set<int64>& object_store_ids, | 54 const std::set<int64>& object_store_ids, |
| 55 indexed_db::TransactionMode mode, | 55 indexed_db::TransactionMode mode, |
| 56 IndexedDBDatabase* database) | 56 IndexedDBDatabase* database) |
| 57 : id_(id), | 57 : id_(id), |
| 58 object_store_ids_(object_store_ids), | 58 object_store_ids_(object_store_ids), |
| 59 mode_(mode), | 59 mode_(mode), |
| 60 used_(false), | 60 used_(false), |
| 61 state_(CREATED), | 61 state_(CREATED), |
| 62 commit_pending_(false), | 62 commit_pending_(false), |
| 63 blob_write_success_(false), | |
| 63 callbacks_(callbacks), | 64 callbacks_(callbacks), |
| 64 database_(database), | 65 database_(database), |
| 65 transaction_(database->backing_store()), | 66 transaction_(database->backing_store()), |
| 66 backing_store_transaction_begun_(false), | 67 backing_store_transaction_begun_(false), |
| 67 should_process_queue_(false), | 68 should_process_queue_(false), |
| 68 pending_preemptive_events_(0) { | 69 pending_preemptive_events_(0) { |
| 69 database_->transaction_coordinator().DidCreateTransaction(this); | 70 database_->transaction_coordinator().DidCreateTransaction(this); |
| 70 | 71 |
| 71 diagnostics_.tasks_scheduled = 0; | 72 diagnostics_.tasks_scheduled = 0; |
| 72 diagnostics_.tasks_completed = 0; | 73 diagnostics_.tasks_completed = 0; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 88 | 89 |
| 89 used_ = true; | 90 used_ = true; |
| 90 task_queue_.push(task); | 91 task_queue_.push(task); |
| 91 ++diagnostics_.tasks_scheduled; | 92 ++diagnostics_.tasks_scheduled; |
| 92 abort_task_stack_.push(abort_task); | 93 abort_task_stack_.push(abort_task); |
| 93 RunTasksIfStarted(); | 94 RunTasksIfStarted(); |
| 94 } | 95 } |
| 95 | 96 |
| 96 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, | 97 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, |
| 97 Operation task) { | 98 Operation task) { |
| 98 if (state_ == FINISHED) | 99 if (IsStatePastRunning()) |
| 99 return; | 100 return; |
| 100 | 101 |
| 101 used_ = true; | 102 used_ = true; |
| 102 if (type == IndexedDBDatabase::NORMAL_TASK) { | 103 if (type == IndexedDBDatabase::NORMAL_TASK) { |
| 103 task_queue_.push(task); | 104 task_queue_.push(task); |
| 104 ++diagnostics_.tasks_scheduled; | 105 ++diagnostics_.tasks_scheduled; |
| 105 } else { | 106 } else { |
| 106 preemptive_task_queue_.push(task); | 107 preemptive_task_queue_.push(task); |
| 107 } | 108 } |
| 108 RunTasksIfStarted(); | 109 RunTasksIfStarted(); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 state_ = STARTED; | 200 state_ = STARTED; |
| 200 database_->TransactionStarted(this); | 201 database_->TransactionStarted(this); |
| 201 diagnostics_.start_time = base::Time::Now(); | 202 diagnostics_.start_time = base::Time::Now(); |
| 202 | 203 |
| 203 if (!used_) | 204 if (!used_) |
| 204 return; | 205 return; |
| 205 | 206 |
| 206 RunTasksIfStarted(); | 207 RunTasksIfStarted(); |
| 207 } | 208 } |
| 208 | 209 |
| 210 class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback { | |
| 211 public: | |
| 212 BlobWriteCallbackImpl(scoped_refptr<IndexedDBTransaction> transaction) | |
| 213 : transaction_(transaction) {} | |
| 214 virtual ~BlobWriteCallbackImpl() {} | |
| 215 virtual void didSucceed() { transaction_->BlobWriteComplete(true); } | |
|
jsbell
2013/12/20 00:44:20
Nit: Chromium naming style
ericu
2014/02/20 00:50:29
Done.
| |
| 216 virtual void didFail() { transaction_->BlobWriteComplete(false); } | |
| 217 | |
| 218 private: | |
| 219 scoped_refptr<IndexedDBTransaction> transaction_; | |
| 220 }; | |
| 221 | |
| 222 void IndexedDBTransaction::BlobWriteComplete(bool success) { | |
| 223 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); | |
| 224 if (state_ == FINISHED) // aborted | |
| 225 return; | |
| 226 DCHECK_EQ(state_, COMMITTING); | |
| 227 if (success) | |
| 228 CommitPhaseTwo(); | |
| 229 else | |
| 230 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, | |
| 231 "Failed to write blobs.")); | |
| 232 } | |
| 233 | |
| 209 void IndexedDBTransaction::Commit() { | 234 void IndexedDBTransaction::Commit() { |
| 210 IDB_TRACE("IndexedDBTransaction::Commit"); | 235 IDB_TRACE("IndexedDBTransaction::Commit"); |
| 211 | 236 |
| 212 // In multiprocess ports, front-end may have requested a commit but | 237 // In multiprocess ports, front-end may have requested a commit but |
| 213 // an abort has already been initiated asynchronously by the | 238 // an abort has already been initiated asynchronously by the |
| 214 // back-end. | 239 // back-end. |
| 215 if (state_ == FINISHED) | 240 if (IsStatePastRunning()) |
|
jsbell
2013/12/20 00:44:20
Can state_ ever be COMMITTING here? The DCHECK(!us
ericu
2014/02/20 00:50:29
You're right that it shouldn't ever happen. Howev
| |
| 216 return; | 241 return; |
| 217 | 242 |
| 218 DCHECK(!used_ || state_ == STARTED); | 243 DCHECK(!used_ || state_ == STARTED); |
| 219 commit_pending_ = true; | 244 commit_pending_ = true; |
| 220 | 245 |
| 221 // Front-end has requested a commit, but there may be tasks like | 246 // Front-end has requested a commit, but there may be tasks like |
| 222 // create_index which are considered synchronous by the front-end | 247 // create_index which are considered synchronous by the front-end |
| 223 // but are processed asynchronously. | 248 // but are processed asynchronously. |
| 224 if (HasPendingTasks()) | 249 if (HasPendingTasks()) |
| 225 return; | 250 return; |
| 226 | 251 |
| 252 state_ = COMMITTING; | |
| 253 | |
| 254 if (!used_) | |
| 255 CommitPhaseTwo(); | |
| 256 else { | |
| 257 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback( | |
| 258 new BlobWriteCallbackImpl(this)); | |
| 259 // CommitPhaseOne will call the callback synchronously if there are no blobs | |
| 260 // to write. | |
| 261 if (!transaction_.CommitPhaseOne(callback)) | |
| 262 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, | |
| 263 "Error processing blob journal.")); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 void IndexedDBTransaction::CommitPhaseTwo() { | |
| 268 DCHECK_EQ(state_, COMMITTING); | |
| 269 | |
| 227 // The last reference to this object may be released while performing the | 270 // The last reference to this object may be released while performing the |
| 228 // commit steps below. We therefore take a self reference to keep ourselves | 271 // commit steps below. We therefore take a self reference to keep ourselves |
| 229 // alive while executing this method. | 272 // alive while executing this method. |
| 230 scoped_refptr<IndexedDBTransaction> protect(this); | 273 scoped_refptr<IndexedDBTransaction> protect(this); |
| 231 | 274 |
| 232 // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843 | 275 // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843 |
|
jsbell
2013/12/20 00:44:20
This should be resolved; needs a rebase?
ericu
2014/02/20 00:50:29
Done.
| |
| 233 abort_task_stack_.clear(); | 276 abort_task_stack_.clear(); |
| 234 | 277 |
| 235 state_ = FINISHED; | 278 state_ = FINISHED; |
| 236 | 279 |
| 237 bool committed = !used_ || transaction_.Commit(); | 280 bool committed = !used_ || transaction_.CommitPhaseTwo(); |
| 238 | 281 |
| 239 // Backing store resources (held via cursors) must be released | 282 // Backing store resources (held via cursors) must be released |
| 240 // before script callbacks are fired, as the script callbacks may | 283 // before script callbacks are fired, as the script callbacks may |
| 241 // release references and allow the backing store itself to be | 284 // release references and allow the backing store itself to be |
| 242 // released, and order is critical. | 285 // released, and order is critical. |
| 243 CloseOpenCursors(); | 286 CloseOpenCursors(); |
| 244 transaction_.Reset(); | 287 transaction_.Reset(); |
| 245 | 288 |
| 246 // Transactions must also be marked as completed before the | 289 // Transactions must also be marked as completed before the |
| 247 // front-end is notified, as the transaction completion unblocks | 290 // front-end is notified, as the transaction completion unblocks |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 backing_store_transaction_begun_ = true; | 322 backing_store_transaction_begun_ = true; |
| 280 } | 323 } |
| 281 | 324 |
| 282 // The last reference to this object may be released while performing the | 325 // The last reference to this object may be released while performing the |
| 283 // tasks. Take take a self reference to keep this object alive so that | 326 // tasks. Take take a self reference to keep this object alive so that |
| 284 // the loop termination conditions can be checked. | 327 // the loop termination conditions can be checked. |
| 285 scoped_refptr<IndexedDBTransaction> protect(this); | 328 scoped_refptr<IndexedDBTransaction> protect(this); |
| 286 | 329 |
| 287 TaskQueue* task_queue = | 330 TaskQueue* task_queue = |
| 288 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; | 331 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; |
| 289 while (!task_queue->empty() && state_ != FINISHED) { | 332 while (!task_queue->empty() && !IsStatePastRunning()) { |
| 290 DCHECK_EQ(STARTED, state_); | 333 DCHECK_EQ(state_, STARTED); |
| 291 Operation task(task_queue->pop()); | 334 Operation task(task_queue->pop()); |
| 292 task.Run(this); | 335 task.Run(this); |
| 293 if (!pending_preemptive_events_) { | 336 if (!pending_preemptive_events_) { |
| 294 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled); | 337 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled); |
| 295 ++diagnostics_.tasks_completed; | 338 ++diagnostics_.tasks_completed; |
| 296 } | 339 } |
| 297 | 340 |
| 298 // Event itself may change which queue should be processed next. | 341 // Event itself may change which queue should be processed next. |
| 299 task_queue = | 342 task_queue = |
| 300 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; | 343 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; |
| 301 } | 344 } |
| 302 | 345 |
| 303 // If there are no pending tasks, we haven't already committed/aborted, | 346 // If there are no pending tasks, we haven't already committed/aborted, |
| 304 // and the front-end requested a commit, it is now safe to do so. | 347 // and the front-end requested a commit, it is now safe to do so. |
| 305 if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) | 348 if (!HasPendingTasks() && !IsStatePastRunning() && commit_pending_) |
|
jsbell
2013/12/20 00:44:20
FYI, if you rebase, a test will appear below this
ericu
2014/02/20 00:50:29
Hmm...I'm not sure about that one. It looks like
jsbell
2014/02/20 22:55:50
There shouldn't be; commit_pending_ should only be
| |
| 306 Commit(); | 349 Commit(); |
| 307 } | 350 } |
| 308 | 351 |
| 309 void IndexedDBTransaction::CloseOpenCursors() { | 352 void IndexedDBTransaction::CloseOpenCursors() { |
| 310 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); | 353 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); |
| 311 i != open_cursors_.end(); | 354 i != open_cursors_.end(); |
| 312 ++i) | 355 ++i) |
| 313 (*i)->Close(); | 356 (*i)->Close(); |
| 314 open_cursors_.clear(); | 357 open_cursors_.clear(); |
| 315 } | 358 } |
| 316 | 359 |
| 317 } // namespace content | 360 } // namespace content |
| OLD | NEW |