 Chromium Code Reviews
 Chromium Code Reviews Issue 18023022:
  Blob support for IDB [Chromium]  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 18023022:
  Blob support for IDB [Chromium]  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 // complete or aborted. | 81 // complete or aborted. | 
| 82 DCHECK_EQ(state_, FINISHED); | 82 DCHECK_EQ(state_, FINISHED); | 
| 83 DCHECK(preemptive_task_queue_.empty()); | 83 DCHECK(preemptive_task_queue_.empty()); | 
| 84 DCHECK_EQ(pending_preemptive_events_, 0); | 84 DCHECK_EQ(pending_preemptive_events_, 0); | 
| 85 DCHECK(task_queue_.empty()); | 85 DCHECK(task_queue_.empty()); | 
| 86 DCHECK(abort_task_stack_.empty()); | 86 DCHECK(abort_task_stack_.empty()); | 
| 87 } | 87 } | 
| 88 | 88 | 
| 89 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, | 89 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, | 
| 90 Operation task) { | 90 Operation task) { | 
| 91 if (state_ == FINISHED) | 91 if (IsStatePastStarted()) | 
| 92 return; | 92 return; | 
| 93 | 93 | 
| 94 timeout_timer_.Stop(); | 94 timeout_timer_.Stop(); | 
| 95 used_ = true; | 95 used_ = true; | 
| 96 if (type == IndexedDBDatabase::NORMAL_TASK) { | 96 if (type == IndexedDBDatabase::NORMAL_TASK) { | 
| 97 task_queue_.push(task); | 97 task_queue_.push(task); | 
| 98 ++diagnostics_.tasks_scheduled; | 98 ++diagnostics_.tasks_scheduled; | 
| 99 } else { | 99 } else { | 
| 100 preemptive_task_queue_.push(task); | 100 preemptive_task_queue_.push(task); | 
| 101 } | 101 } | 
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 DCHECK_EQ(CREATED, state_); | 199 DCHECK_EQ(CREATED, state_); | 
| 200 state_ = STARTED; | 200 state_ = STARTED; | 
| 201 diagnostics_.start_time = base::Time::Now(); | 201 diagnostics_.start_time = base::Time::Now(); | 
| 202 | 202 | 
| 203 if (!used_) | 203 if (!used_) | 
| 204 return; | 204 return; | 
| 205 | 205 | 
| 206 RunTasksIfStarted(); | 206 RunTasksIfStarted(); | 
| 207 } | 207 } | 
| 208 | 208 | 
| 209 class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback { | |
| 210 public: | |
| 211 BlobWriteCallbackImpl(scoped_refptr<IndexedDBTransaction> transaction) | |
| 212 : transaction_(transaction) {} | |
| 213 virtual void Run(bool succeeded) OVERRIDE { | |
| 214 transaction_->BlobWriteComplete(succeeded); | |
| 215 } | |
| 216 | |
| 217 protected: | |
| 218 virtual ~BlobWriteCallbackImpl() {} | |
| 219 | |
| 220 private: | |
| 221 scoped_refptr<IndexedDBTransaction> transaction_; | |
| 222 }; | |
| 223 | |
| 224 void IndexedDBTransaction::BlobWriteComplete(bool success) { | |
| 225 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); | |
| 226 if (state_ == FINISHED) // aborted | |
| 227 return; | |
| 228 DCHECK_EQ(state_, COMMITTING); | |
| 229 if (success) | |
| 230 CommitPhaseTwo(); | |
| 231 else | |
| 232 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, | |
| 233 "Failed to write blobs.")); | |
| 234 } | |
| 235 | |
| 209 void IndexedDBTransaction::Commit() { | 236 void IndexedDBTransaction::Commit() { | 
| 210 IDB_TRACE("IndexedDBTransaction::Commit"); | 237 IDB_TRACE("IndexedDBTransaction::Commit"); | 
| 211 | 238 | 
| 212 // In multiprocess ports, front-end may have requested a commit but | 239 // In multiprocess ports, front-end may have requested a commit but | 
| 213 // an abort has already been initiated asynchronously by the | 240 // an abort has already been initiated asynchronously by the | 
| 214 // back-end. | 241 // back-end. | 
| 215 if (state_ == FINISHED) | 242 if (IsStatePastStarted()) { | 
| 243 DCHECK(state_ == FINISHED); | |
| 216 return; | 244 return; | 
| 245 } | |
| 217 | 246 | 
| 218 DCHECK(!used_ || state_ == STARTED); | 247 DCHECK(!used_ || state_ == STARTED); | 
| 219 commit_pending_ = true; | 248 commit_pending_ = true; | 
| 220 | 249 | 
| 221 // Front-end has requested a commit, but there may be tasks like | 250 // Front-end has requested a commit, but there may be tasks like | 
| 222 // create_index which are considered synchronous by the front-end | 251 // create_index which are considered synchronous by the front-end | 
| 223 // but are processed asynchronously. | 252 // but are processed asynchronously. | 
| 224 if (HasPendingTasks()) | 253 if (HasPendingTasks()) | 
| 225 return; | 254 return; | 
| 226 | 255 | 
| 256 state_ = COMMITTING; | |
| 257 | |
| 258 if (!used_) | |
| 259 CommitPhaseTwo(); | |
| 260 else { | |
| 261 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback( | |
| 262 new BlobWriteCallbackImpl(this)); | |
| 263 // CommitPhaseOne will call the callback synchronously if there are no blobs | |
| 264 // to write. | |
| 265 if (!transaction_->CommitPhaseOne(callback).ok()) | |
| 
cmumford
2014/05/28 22:35:02
Are we still preserving the ability to distinguish
 
ericu
2014/05/28 22:50:43
This change doesn't worsen corruption reporting.
 | |
| 266 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, | |
| 267 "Error processing blob journal.")); | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 void IndexedDBTransaction::CommitPhaseTwo() { | |
| 272 // Abort may have been called just as the blob write completed. | |
| 273 if (state_ == FINISHED) | |
| 274 return; | |
| 275 | |
| 276 DCHECK_EQ(state_, COMMITTING); | |
| 277 | |
| 227 // The last reference to this object may be released while performing the | 278 // 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 | 279 // commit steps below. We therefore take a self reference to keep ourselves | 
| 229 // alive while executing this method. | 280 // alive while executing this method. | 
| 230 scoped_refptr<IndexedDBTransaction> protect(this); | 281 scoped_refptr<IndexedDBTransaction> protect(this); | 
| 231 | 282 | 
| 232 timeout_timer_.Stop(); | 283 timeout_timer_.Stop(); | 
| 233 | 284 | 
| 234 state_ = FINISHED; | 285 state_ = FINISHED; | 
| 235 | 286 | 
| 236 bool committed = !used_ || transaction_->Commit().ok(); | 287 bool committed = !used_ || transaction_->CommitPhaseTwo().ok(); | 
| 237 | 288 | 
| 238 // Backing store resources (held via cursors) must be released | 289 // Backing store resources (held via cursors) must be released | 
| 239 // before script callbacks are fired, as the script callbacks may | 290 // before script callbacks are fired, as the script callbacks may | 
| 240 // release references and allow the backing store itself to be | 291 // release references and allow the backing store itself to be | 
| 241 // released, and order is critical. | 292 // released, and order is critical. | 
| 242 CloseOpenCursors(); | 293 CloseOpenCursors(); | 
| 243 transaction_->Reset(); | 294 transaction_->Reset(); | 
| 244 | 295 | 
| 245 // Transactions must also be marked as completed before the | 296 // Transactions must also be marked as completed before the | 
| 246 // front-end is notified, as the transaction completion unblocks | 297 // front-end is notified, as the transaction completion unblocks | 
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 backing_store_transaction_begun_ = true; | 332 backing_store_transaction_begun_ = true; | 
| 282 } | 333 } | 
| 283 | 334 | 
| 284 // The last reference to this object may be released while performing the | 335 // The last reference to this object may be released while performing the | 
| 285 // tasks. Take take a self reference to keep this object alive so that | 336 // tasks. Take take a self reference to keep this object alive so that | 
| 286 // the loop termination conditions can be checked. | 337 // the loop termination conditions can be checked. | 
| 287 scoped_refptr<IndexedDBTransaction> protect(this); | 338 scoped_refptr<IndexedDBTransaction> protect(this); | 
| 288 | 339 | 
| 289 TaskQueue* task_queue = | 340 TaskQueue* task_queue = | 
| 290 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; | 341 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; | 
| 291 while (!task_queue->empty() && state_ != FINISHED) { | 342 while (!task_queue->empty() && !IsStatePastStarted()) { | 
| 292 DCHECK_EQ(STARTED, state_); | 343 DCHECK_EQ(state_, STARTED); | 
| 293 Operation task(task_queue->pop()); | 344 Operation task(task_queue->pop()); | 
| 294 task.Run(this); | 345 task.Run(this); | 
| 295 if (!pending_preemptive_events_) { | 346 if (!pending_preemptive_events_) { | 
| 296 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled); | 347 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled); | 
| 297 ++diagnostics_.tasks_completed; | 348 ++diagnostics_.tasks_completed; | 
| 298 } | 349 } | 
| 299 | 350 | 
| 300 // Event itself may change which queue should be processed next. | 351 // Event itself may change which queue should be processed next. | 
| 301 task_queue = | 352 task_queue = | 
| 302 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; | 353 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; | 
| 303 } | 354 } | 
| 304 | 355 | 
| 305 // If there are no pending tasks, we haven't already committed/aborted, | 356 // If there are no pending tasks, we haven't already committed/aborted, | 
| 306 // and the front-end requested a commit, it is now safe to do so. | 357 // and the front-end requested a commit, it is now safe to do so. | 
| 307 if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) { | 358 if (!HasPendingTasks() && !IsStatePastStarted() && commit_pending_) { | 
| 308 Commit(); | 359 Commit(); | 
| 309 return; | 360 return; | 
| 310 } | 361 } | 
| 311 | 362 | 
| 312 // The transaction may have been aborted while processing tasks. | 363 // The transaction may have been aborted while processing tasks. | 
| 313 if (state_ == FINISHED) | 364 if (state_ == FINISHED) | 
| 314 return; | 365 return; | 
| 315 | 366 | 
| 316 // Otherwise, start a timer in case the front-end gets wedged and | 367 // Otherwise, start a timer in case the front-end gets wedged and | 
| 317 // never requests further activity. Read-only transactions don't | 368 // never requests further activity. Read-only transactions don't | 
| (...skipping 14 matching lines...) Expand all Loading... | |
| 332 | 383 | 
| 333 void IndexedDBTransaction::CloseOpenCursors() { | 384 void IndexedDBTransaction::CloseOpenCursors() { | 
| 334 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); | 385 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); | 
| 335 i != open_cursors_.end(); | 386 i != open_cursors_.end(); | 
| 336 ++i) | 387 ++i) | 
| 337 (*i)->Close(); | 388 (*i)->Close(); | 
| 338 open_cursors_.clear(); | 389 open_cursors_.clear(); | 
| 339 } | 390 } | 
| 340 | 391 | 
| 341 } // namespace content | 392 } // namespace content | 
| OLD | NEW |