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

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

Issue 2506773002: [IndexedDB] Integrating failures and corruption with transaction (Closed)
Patch Set: removed extra log statements Created 4 years 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
OLDNEW
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/location.h" 8 #include "base/location.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
11 #include "base/single_thread_task_runner.h" 11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/threading/thread_task_runner_handle.h"
15 #include "content/browser/indexed_db/indexed_db_backing_store.h" 15 #include "content/browser/indexed_db/indexed_db_backing_store.h"
16 #include "content/browser/indexed_db/indexed_db_cursor.h" 16 #include "content/browser/indexed_db/indexed_db_cursor.h"
17 #include "content/browser/indexed_db/indexed_db_database.h" 17 #include "content/browser/indexed_db/indexed_db_database.h"
18 #include "content/browser/indexed_db/indexed_db_database_callbacks.h" 18 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
19 #include "content/browser/indexed_db/indexed_db_factory.h"
19 #include "content/browser/indexed_db/indexed_db_tracing.h" 20 #include "content/browser/indexed_db/indexed_db_tracing.h"
20 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h" 21 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
21 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseExc eption.h" 22 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseExc eption.h"
22 #include "third_party/leveldatabase/env_chromium.h" 23 #include "third_party/leveldatabase/env_chromium.h"
23 24
24 namespace content { 25 namespace content {
25 26
26 namespace { 27 namespace {
27 28
28 const int64_t kInactivityTimeoutPeriodSeconds = 60; 29 const int64_t kInactivityTimeoutPeriodSeconds = 60;
29 30
30 // Helper for posting a task to call IndexedDBTransaction::Commit when we know 31 // Helper for posting a task to call IndexedDBTransaction::Commit when we know
31 // the transaction had no requests and therefore the commit must succeed. 32 // the transaction had no requests and therefore the commit must succeed.
32 void CommitUnused(scoped_refptr<IndexedDBTransaction> transaction) { 33 void CommitUnused(scoped_refptr<IndexedDBTransaction> transaction) {
33 leveldb::Status status = transaction->Commit(); 34 leveldb::Status status = transaction->Commit();
34 DCHECK(status.ok()); 35 DCHECK(status.ok());
35 } 36 }
36 37
38 // The database will be closed during this call.
39 void ReportError(leveldb::Status status,
40 const scoped_refptr<IndexedDBDatabase> database,
41 IndexedDBFactory* factory) {
42 DCHECK(!status.ok());
43 if (status.IsCorruption()) {
44 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
45 base::ASCIIToUTF16(status.ToString()));
46 factory->HandleBackingStoreCorruption(database->origin(), error);
47 } else {
48 factory->HandleBackingStoreFailure(database->origin());
49 }
50 }
51
52
53
37 } // namespace 54 } // namespace
38 55
39 IndexedDBTransaction::TaskQueue::TaskQueue() {} 56 IndexedDBTransaction::TaskQueue::TaskQueue() {}
40 IndexedDBTransaction::TaskQueue::~TaskQueue() { clear(); } 57 IndexedDBTransaction::TaskQueue::~TaskQueue() { clear(); }
41 58
42 void IndexedDBTransaction::TaskQueue::clear() { 59 void IndexedDBTransaction::TaskQueue::clear() {
43 while (!queue_.empty()) 60 while (!queue_.empty())
44 queue_.pop(); 61 queue_.pop();
45 } 62 }
46 63
47 IndexedDBTransaction::Operation IndexedDBTransaction::TaskQueue::pop() { 64 IndexedDBTransaction::Operation IndexedDBTransaction::TaskQueue::pop() {
48 DCHECK(!queue_.empty()); 65 DCHECK(!queue_.empty());
49 Operation task(queue_.front()); 66 Operation task = std::move(queue_.front());
50 queue_.pop(); 67 queue_.pop();
51 return task; 68 return task;
52 } 69 }
53 70
54 IndexedDBTransaction::TaskStack::TaskStack() {} 71 IndexedDBTransaction::TaskStack::TaskStack() {}
55 IndexedDBTransaction::TaskStack::~TaskStack() { clear(); } 72 IndexedDBTransaction::TaskStack::~TaskStack() { clear(); }
56 73
57 void IndexedDBTransaction::TaskStack::clear() { 74 void IndexedDBTransaction::TaskStack::clear() {
58 while (!stack_.empty()) 75 while (!stack_.empty())
59 stack_.pop(); 76 stack_.pop();
60 } 77 }
61 78
62 IndexedDBTransaction::Operation IndexedDBTransaction::TaskStack::pop() { 79 IndexedDBTransaction::AbortOperation IndexedDBTransaction::TaskStack::pop() {
63 DCHECK(!stack_.empty()); 80 DCHECK(!stack_.empty());
64 Operation task(stack_.top()); 81 AbortOperation task = std::move(stack_.top());
65 stack_.pop(); 82 stack_.pop();
66 return task; 83 return task;
67 } 84 }
68 85
69 IndexedDBTransaction::IndexedDBTransaction( 86 IndexedDBTransaction::IndexedDBTransaction(
70 int64_t id, 87 int64_t id,
71 base::WeakPtr<IndexedDBConnection> connection, 88 base::WeakPtr<IndexedDBConnection> connection,
72 const std::set<int64_t>& object_store_ids, 89 const std::set<int64_t>& object_store_ids,
73 blink::WebIDBTransactionMode mode, 90 blink::WebIDBTransactionMode mode,
74 IndexedDBBackingStore::Transaction* backing_store_transaction) 91 IndexedDBBackingStore::Transaction* backing_store_transaction)
75 : id_(id), 92 : id_(id),
76 object_store_ids_(object_store_ids), 93 object_store_ids_(object_store_ids),
77 mode_(mode), 94 mode_(mode),
78 used_(false),
79 state_(CREATED),
80 commit_pending_(false),
81 connection_(std::move(connection)), 95 connection_(std::move(connection)),
82 transaction_(backing_store_transaction), 96 transaction_(backing_store_transaction) {
83 backing_store_transaction_begun_(false),
84 should_process_queue_(false),
85 pending_preemptive_events_(0) {
86 callbacks_ = connection_->callbacks(); 97 callbacks_ = connection_->callbacks();
87 database_ = connection_->database(); 98 database_ = connection_->database();
88 99
89 database_->transaction_coordinator().DidCreateTransaction(this); 100 database_->transaction_coordinator().DidCreateTransaction(this);
90 101
91 diagnostics_.tasks_scheduled = 0; 102 diagnostics_.tasks_scheduled = 0;
92 diagnostics_.tasks_completed = 0; 103 diagnostics_.tasks_completed = 0;
93 diagnostics_.creation_time = base::Time::Now(); 104 diagnostics_.creation_time = base::Time::Now();
94 } 105 }
95 106
96 IndexedDBTransaction::~IndexedDBTransaction() { 107 IndexedDBTransaction::~IndexedDBTransaction() {
97 // It shouldn't be possible for this object to get deleted until it's either 108 // It shouldn't be possible for this object to get deleted until it's either
98 // complete or aborted. 109 // complete or aborted.
99 DCHECK_EQ(state_, FINISHED); 110 DCHECK_EQ(state_, FINISHED);
100 DCHECK(preemptive_task_queue_.empty()); 111 DCHECK(preemptive_task_queue_.empty());
101 DCHECK_EQ(pending_preemptive_events_, 0); 112 DCHECK_EQ(pending_preemptive_events_, 0);
102 DCHECK(task_queue_.empty()); 113 DCHECK(task_queue_.empty());
103 DCHECK(abort_task_stack_.empty()); 114 DCHECK(abort_task_stack_.empty());
104 DCHECK(pending_observers_.empty()); 115 DCHECK(pending_observers_.empty());
116 DCHECK(!processing_event_queue_);
105 } 117 }
106 118
107 void IndexedDBTransaction::ScheduleTask(blink::WebIDBTaskType type, 119 void IndexedDBTransaction::ScheduleTask(blink::WebIDBTaskType type,
108 Operation task) { 120 Operation task) {
109 DCHECK_NE(state_, COMMITTING); 121 DCHECK_NE(state_, COMMITTING);
110 if (state_ == FINISHED) 122 if (state_ == FINISHED)
111 return; 123 return;
112 124
113 timeout_timer_.Stop(); 125 timeout_timer_.Stop();
114 used_ = true; 126 used_ = true;
115 if (type == blink::WebIDBTaskTypeNormal) { 127 if (type == blink::WebIDBTaskTypeNormal) {
116 task_queue_.push(task); 128 task_queue_.push(task);
117 ++diagnostics_.tasks_scheduled; 129 ++diagnostics_.tasks_scheduled;
118 } else { 130 } else {
119 preemptive_task_queue_.push(task); 131 preemptive_task_queue_.push(task);
120 } 132 }
121 RunTasksIfStarted(); 133 RunTasksIfStarted();
122 } 134 }
123 135
124 void IndexedDBTransaction::ScheduleAbortTask(Operation abort_task) { 136 void IndexedDBTransaction::ScheduleAbortTask(AbortOperation abort_task) {
125 DCHECK_NE(FINISHED, state_); 137 DCHECK_NE(FINISHED, state_);
126 DCHECK(used_); 138 DCHECK(used_);
127 abort_task_stack_.push(abort_task); 139 abort_task_stack_.push(std::move(abort_task));
128 } 140 }
129 141
130 void IndexedDBTransaction::RunTasksIfStarted() { 142 void IndexedDBTransaction::RunTasksIfStarted() {
131 DCHECK(used_); 143 DCHECK(used_);
132 144
133 // Not started by the coordinator yet. 145 // Not started by the coordinator yet.
134 if (state_ != STARTED) 146 if (state_ != STARTED)
135 return; 147 return;
136 148
137 // A task is already posted. 149 // A task is already posted.
(...skipping 23 matching lines...) Expand all
161 timeout_timer_.Stop(); 173 timeout_timer_.Stop();
162 174
163 state_ = FINISHED; 175 state_ = FINISHED;
164 should_process_queue_ = false; 176 should_process_queue_ = false;
165 177
166 if (backing_store_transaction_begun_) 178 if (backing_store_transaction_begun_)
167 transaction_->Rollback(); 179 transaction_->Rollback();
168 180
169 // Run the abort tasks, if any. 181 // Run the abort tasks, if any.
170 while (!abort_task_stack_.empty()) 182 while (!abort_task_stack_.empty())
171 abort_task_stack_.pop().Run(NULL); 183 abort_task_stack_.pop().Run();
172 184
173 preemptive_task_queue_.clear(); 185 preemptive_task_queue_.clear();
174 pending_preemptive_events_ = 0; 186 pending_preemptive_events_ = 0;
175 task_queue_.clear(); 187 task_queue_.clear();
176 188
177 // Backing store resources (held via cursors) must be released 189 // Backing store resources (held via cursors) must be released
178 // before script callbacks are fired, as the script callbacks may 190 // before script callbacks are fired, as the script callbacks may
179 // release references and allow the backing store itself to be 191 // release references and allow the backing store itself to be
180 // released, and order is critical. 192 // released, and order is critical.
181 CloseOpenCursors(); 193 CloseOpenCursors();
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 261
250 private: 262 private:
251 scoped_refptr<IndexedDBTransaction> transaction_; 263 scoped_refptr<IndexedDBTransaction> transaction_;
252 }; 264 };
253 265
254 void IndexedDBTransaction::BlobWriteComplete(bool success) { 266 void IndexedDBTransaction::BlobWriteComplete(bool success) {
255 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); 267 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete");
256 if (state_ == FINISHED) // aborted 268 if (state_ == FINISHED) // aborted
257 return; 269 return;
258 DCHECK_EQ(state_, COMMITTING); 270 DCHECK_EQ(state_, COMMITTING);
259 if (success) 271
260 CommitPhaseTwo(); 272 if (!success) {
261 else
262 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, 273 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError,
263 "Failed to write blobs.")); 274 "Failed to write blobs."));
275 return;
276 }
277 // Save the database as |this| can be destroyed in the next line.
278 scoped_refptr<IndexedDBDatabase> database = database_;
279 leveldb::Status s = CommitPhaseTwo();
280 if (!s.ok())
281 ReportError(s, database, database->factory());
264 } 282 }
265 283
266 leveldb::Status IndexedDBTransaction::Commit() { 284 leveldb::Status IndexedDBTransaction::Commit() {
267 IDB_TRACE1("IndexedDBTransaction::Commit", "txn.id", id()); 285 IDB_TRACE1("IndexedDBTransaction::Commit", "txn.id", id());
268 286
269 timeout_timer_.Stop(); 287 timeout_timer_.Stop();
270 288
271 // In multiprocess ports, front-end may have requested a commit but 289 // In multiprocess ports, front-end may have requested a commit but
272 // an abort has already been initiated asynchronously by the 290 // an abort has already been initiated asynchronously by the
273 // back-end. 291 // back-end.
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 callbacks_->OnComplete(id_); 378 callbacks_->OnComplete(id_);
361 } 379 }
362 if (!pending_observers_.empty() && connection_) { 380 if (!pending_observers_.empty() && connection_) {
363 connection_->ActivatePendingObservers(std::move(pending_observers_)); 381 connection_->ActivatePendingObservers(std::move(pending_observers_));
364 pending_observers_.clear(); 382 pending_observers_.clear();
365 } 383 }
366 384
367 database_->TransactionFinished(this, true); 385 database_->TransactionFinished(this, true);
368 } else { 386 } else {
369 while (!abort_task_stack_.empty()) 387 while (!abort_task_stack_.empty())
370 abort_task_stack_.pop().Run(NULL); 388 abort_task_stack_.pop().Run();
371 389
372 IndexedDBDatabaseError error; 390 IndexedDBDatabaseError error;
373 if (leveldb_env::IndicatesDiskFull(s)) { 391 if (leveldb_env::IndicatesDiskFull(s)) {
374 error = IndexedDBDatabaseError( 392 error = IndexedDBDatabaseError(
375 blink::WebIDBDatabaseExceptionQuotaError, 393 blink::WebIDBDatabaseExceptionQuotaError,
376 "Encountered disk full while committing transaction."); 394 "Encountered disk full while committing transaction.");
377 } else { 395 } else {
378 error = IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 396 error = IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
379 "Internal error committing transaction."); 397 "Internal error committing transaction.");
380 } 398 }
381 callbacks_->OnAbort(id_, error); 399 callbacks_->OnAbort(id_, error);
382 400
383 database_->TransactionFinished(this, false); 401 database_->TransactionFinished(this, false);
384 database_->TransactionCommitFailed(s);
385 } 402 }
386 403
387 database_ = NULL; 404 database_ = NULL;
388 return s; 405 return s;
389 } 406 }
390 407
391 void IndexedDBTransaction::ProcessTaskQueue() { 408 void IndexedDBTransaction::ProcessTaskQueue() {
392 IDB_TRACE1("IndexedDBTransaction::ProcessTaskQueue", "txn.id", id()); 409 IDB_TRACE1("IndexedDBTransaction::ProcessTaskQueue", "txn.id", id());
393 410
411 DCHECK(!processing_event_queue_);
412
394 // May have been aborted. 413 // May have been aborted.
395 if (!should_process_queue_) 414 if (!should_process_queue_)
396 return; 415 return;
397 416
417 processing_event_queue_ = true;
418
398 DCHECK(!IsTaskQueueEmpty()); 419 DCHECK(!IsTaskQueueEmpty());
399 should_process_queue_ = false; 420 should_process_queue_ = false;
400 421
401 if (!backing_store_transaction_begun_) { 422 if (!backing_store_transaction_begun_) {
402 transaction_->Begin(); 423 transaction_->Begin();
403 backing_store_transaction_begun_ = true; 424 backing_store_transaction_begun_ = true;
404 } 425 }
405 426
406 // The last reference to this object may be released while performing the 427 // The last reference to this object may be released while performing the
407 // tasks. Take take a self reference to keep this object alive so that 428 // tasks. Take take a self reference to keep this object alive so that
408 // the loop termination conditions can be checked. 429 // the loop termination conditions can be checked.
409 scoped_refptr<IndexedDBTransaction> protect(this); 430 scoped_refptr<IndexedDBTransaction> protect(this);
410 431
411 TaskQueue* task_queue = 432 TaskQueue* task_queue =
412 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; 433 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
413 while (!task_queue->empty() && state_ != FINISHED) { 434 while (!task_queue->empty() && state_ != FINISHED) {
414 DCHECK_EQ(state_, STARTED); 435 DCHECK_EQ(state_, STARTED);
415 Operation task(task_queue->pop()); 436 Operation task(task_queue->pop());
416 task.Run(this); 437 leveldb::Status result = task.Run(this);
417 if (!pending_preemptive_events_) { 438 if (!pending_preemptive_events_) {
418 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled); 439 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled);
419 ++diagnostics_.tasks_completed; 440 ++diagnostics_.tasks_completed;
420 } 441 }
442 if (!result.ok()) {
443 processing_event_queue_ = false;
444 if (!result.ok())
445 ReportError(result, database_, database_->factory());
446 return;
447 }
421 448
422 // Event itself may change which queue should be processed next. 449 // Event itself may change which queue should be processed next.
423 task_queue = 450 task_queue =
424 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; 451 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
425 } 452 }
426 453
427 // If there are no pending tasks, we haven't already committed/aborted, 454 // If there are no pending tasks, we haven't already committed/aborted,
428 // and the front-end requested a commit, it is now safe to do so. 455 // and the front-end requested a commit, it is now safe to do so.
429 if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) { 456 if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) {
430 Commit(); 457 leveldb::Status result = Commit();
458 processing_event_queue_ = false;
459 if (!result.ok())
460 ReportError(result, database_, database_->factory());
431 return; 461 return;
432 } 462 }
433 463
434 // The transaction may have been aborted while processing tasks. 464 // The transaction may have been aborted while processing tasks.
435 if (state_ == FINISHED) 465 if (state_ == FINISHED) {
466 processing_event_queue_ = false;
436 return; 467 return;
468 }
437 469
438 DCHECK(state_ == STARTED); 470 DCHECK(state_ == STARTED);
439 471
440 // Otherwise, start a timer in case the front-end gets wedged and 472 // Otherwise, start a timer in case the front-end gets wedged and
441 // never requests further activity. Read-only transactions don't 473 // never requests further activity. Read-only transactions don't
442 // block other transactions, so don't time those out. 474 // block other transactions, so don't time those out.
443 if (mode_ != blink::WebIDBTransactionModeReadOnly) { 475 if (mode_ != blink::WebIDBTransactionModeReadOnly) {
444 timeout_timer_.Start(FROM_HERE, GetInactivityTimeout(), 476 timeout_timer_.Start(FROM_HERE, GetInactivityTimeout(),
445 base::Bind(&IndexedDBTransaction::Timeout, this)); 477 base::Bind(&IndexedDBTransaction::Timeout, this));
446 } 478 }
479 processing_event_queue_ = false;
447 } 480 }
448 481
449 base::TimeDelta IndexedDBTransaction::GetInactivityTimeout() const { 482 base::TimeDelta IndexedDBTransaction::GetInactivityTimeout() const {
450 return base::TimeDelta::FromSeconds(kInactivityTimeoutPeriodSeconds); 483 return base::TimeDelta::FromSeconds(kInactivityTimeoutPeriodSeconds);
451 } 484 }
452 485
453 void IndexedDBTransaction::Timeout() { 486 void IndexedDBTransaction::Timeout() {
454 Abort(IndexedDBDatabaseError( 487 Abort(IndexedDBDatabaseError(
455 blink::WebIDBDatabaseExceptionTimeoutError, 488 blink::WebIDBDatabaseExceptionTimeoutError,
456 base::ASCIIToUTF16("Transaction timed out due to inactivity."))); 489 base::ASCIIToUTF16("Transaction timed out due to inactivity.")));
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 void IndexedDBTransaction::RecordObserverForLastObservation( 530 void IndexedDBTransaction::RecordObserverForLastObservation(
498 int32_t connection_id, 531 int32_t connection_id,
499 int32_t observer_id) { 532 int32_t observer_id) {
500 auto it = connection_changes_map_.find(connection_id); 533 auto it = connection_changes_map_.find(connection_id);
501 DCHECK(it != connection_changes_map_.end()); 534 DCHECK(it != connection_changes_map_.end());
502 it->second->observation_index_map[observer_id].push_back( 535 it->second->observation_index_map[observer_id].push_back(
503 it->second->observations.size() - 1); 536 it->second->observations.size() - 1);
504 } 537 }
505 538
506 } // namespace content 539 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/indexed_db/indexed_db_transaction.h ('k') | content/browser/indexed_db/indexed_db_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698