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

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

Issue 2472213003: [IndexedDB] Refactoring to remove ref ptrs and host transaction ids. (Closed)
Patch Set: updated unittests Created 4 years, 1 month 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"
(...skipping 13 matching lines...) Expand all
24 #include "third_party/leveldatabase/env_chromium.h" 24 #include "third_party/leveldatabase/env_chromium.h"
25 25
26 namespace content { 26 namespace content {
27 27
28 namespace { 28 namespace {
29 29
30 const int64_t kInactivityTimeoutPeriodSeconds = 60; 30 const int64_t kInactivityTimeoutPeriodSeconds = 60;
31 31
32 // Helper for posting a task to call IndexedDBTransaction::Commit when we know 32 // Helper for posting a task to call IndexedDBTransaction::Commit when we know
33 // the transaction had no requests and therefore the commit must succeed. 33 // the transaction had no requests and therefore the commit must succeed.
34 void CommitUnused(scoped_refptr<IndexedDBTransaction> transaction) { 34 void CommitUnused(base::WeakPtr<IndexedDBTransaction> transaction) {
35 if (!transaction)
36 return;
35 leveldb::Status status = transaction->Commit(); 37 leveldb::Status status = transaction->Commit();
36 DCHECK(status.ok()); 38 DCHECK(status.ok());
37 } 39 }
38 40
39 } // namespace 41 } // namespace
40 42
41 IndexedDBTransaction::TaskQueue::TaskQueue() {} 43 IndexedDBTransaction::TaskQueue::TaskQueue() {}
42 IndexedDBTransaction::TaskQueue::~TaskQueue() { clear(); } 44 IndexedDBTransaction::TaskQueue::~TaskQueue() { clear(); }
43 45
44 void IndexedDBTransaction::TaskQueue::clear() { 46 void IndexedDBTransaction::TaskQueue::clear() {
(...skipping 18 matching lines...) Expand all
63 65
64 IndexedDBTransaction::Operation IndexedDBTransaction::TaskStack::pop() { 66 IndexedDBTransaction::Operation IndexedDBTransaction::TaskStack::pop() {
65 DCHECK(!stack_.empty()); 67 DCHECK(!stack_.empty());
66 Operation task(stack_.top()); 68 Operation task(stack_.top());
67 stack_.pop(); 69 stack_.pop();
68 return task; 70 return task;
69 } 71 }
70 72
71 IndexedDBTransaction::IndexedDBTransaction( 73 IndexedDBTransaction::IndexedDBTransaction(
72 int64_t id, 74 int64_t id,
73 base::WeakPtr<IndexedDBConnection> connection, 75 IndexedDBConnection* connection,
74 const std::set<int64_t>& object_store_ids, 76 const std::set<int64_t>& object_store_ids,
75 blink::WebIDBTransactionMode mode, 77 blink::WebIDBTransactionMode mode,
76 IndexedDBBackingStore::Transaction* backing_store_transaction) 78 IndexedDBBackingStore::Transaction* backing_store_transaction)
77 : id_(id), 79 : id_(id),
78 object_store_ids_(object_store_ids), 80 object_store_ids_(object_store_ids),
79 mode_(mode), 81 mode_(mode),
80 used_(false), 82 used_(false),
81 state_(CREATED), 83 state_(CREATED),
82 commit_pending_(false), 84 commit_pending_(false),
83 connection_(std::move(connection)), 85 connection_(std::move(connection)),
86 size_(0),
84 transaction_(backing_store_transaction), 87 transaction_(backing_store_transaction),
85 backing_store_transaction_begun_(false), 88 backing_store_transaction_begun_(false),
86 should_process_queue_(false), 89 should_process_queue_(false),
87 pending_preemptive_events_(0) { 90 pending_preemptive_events_(0),
91 ptr_factory_(this) {
88 callbacks_ = connection_->callbacks(); 92 callbacks_ = connection_->callbacks();
89 database_ = connection_->database(); 93 database_ = connection_->database();
90 94
91 database_->transaction_coordinator().DidCreateTransaction(this);
92
93 diagnostics_.tasks_scheduled = 0; 95 diagnostics_.tasks_scheduled = 0;
94 diagnostics_.tasks_completed = 0; 96 diagnostics_.tasks_completed = 0;
95 diagnostics_.creation_time = base::Time::Now(); 97 diagnostics_.creation_time = base::Time::Now();
96 } 98 }
97 99
98 IndexedDBTransaction::~IndexedDBTransaction() { 100 IndexedDBTransaction::~IndexedDBTransaction() {
99 // It shouldn't be possible for this object to get deleted until it's either 101 // It shouldn't be possible for this object to get deleted until it's either
100 // complete or aborted. 102 // complete or aborted.
101 DCHECK_EQ(state_, FINISHED); 103 DCHECK_EQ(state_, FINISHED);
102 DCHECK(preemptive_task_queue_.empty()); 104 DCHECK(preemptive_task_queue_.empty());
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 // Not started by the coordinator yet. 137 // Not started by the coordinator yet.
136 if (state_ != STARTED) 138 if (state_ != STARTED)
137 return; 139 return;
138 140
139 // A task is already posted. 141 // A task is already posted.
140 if (should_process_queue_) 142 if (should_process_queue_)
141 return; 143 return;
142 144
143 should_process_queue_ = true; 145 should_process_queue_ = true;
144 base::ThreadTaskRunnerHandle::Get()->PostTask( 146 base::ThreadTaskRunnerHandle::Get()->PostTask(
145 FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this)); 147 FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue,
148 ptr_factory_.GetWeakPtr()));
146 } 149 }
147 150
148 void IndexedDBTransaction::Abort() { 151 void IndexedDBTransaction::Abort() {
149 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 152 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
150 "Internal error (unknown cause)")); 153 "Internal error (unknown cause)"));
151 } 154 }
152 155
153 void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) { 156 void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) {
154 IDB_TRACE1("IndexedDBTransaction::Abort", "txn.id", id()); 157 IDB_TRACE1("IndexedDBTransaction::Abort", "txn.id", id());
155 if (state_ == FINISHED) 158 if (state_ == FINISHED)
156 return; 159 return;
157 160
158 // The last reference to this object may be released while performing the
159 // abort steps below. We therefore take a self reference to keep ourselves
160 // alive while executing this method.
161 scoped_refptr<IndexedDBTransaction> protect(this);
162
163 timeout_timer_.Stop(); 161 timeout_timer_.Stop();
164 162
165 state_ = FINISHED; 163 state_ = FINISHED;
166 should_process_queue_ = false; 164 should_process_queue_ = false;
167 165
168 if (backing_store_transaction_begun_) 166 if (backing_store_transaction_begun_)
169 transaction_->Rollback(); 167 transaction_->Rollback();
170 168
171 // Run the abort tasks, if any. 169 // Run the abort tasks, if any.
172 while (!abort_task_stack_.empty()) 170 while (!abort_task_stack_.empty())
(...skipping 12 matching lines...) Expand all
185 183
186 // Transactions must also be marked as completed before the 184 // Transactions must also be marked as completed before the
187 // front-end is notified, as the transaction completion unblocks 185 // front-end is notified, as the transaction completion unblocks
188 // operations like closing connections. 186 // operations like closing connections.
189 database_->transaction_coordinator().DidFinishTransaction(this); 187 database_->transaction_coordinator().DidFinishTransaction(this);
190 #ifndef NDEBUG 188 #ifndef NDEBUG
191 DCHECK(!database_->transaction_coordinator().IsActive(this)); 189 DCHECK(!database_->transaction_coordinator().IsActive(this));
192 #endif 190 #endif
193 191
194 if (callbacks_.get()) 192 if (callbacks_.get())
195 callbacks_->OnAbort(id_, error); 193 callbacks_->OnAbort(*this, error);
196 194
197 database_->TransactionFinished(this, false); 195 database_->TransactionFinished(this, false);
198 196
199 database_ = NULL;
200 connection_ = nullptr;
201 pending_observers_.clear(); 197 pending_observers_.clear();
198 // This destroys our object.
cmumford 2016/11/04 23:33:13 Nit: avoid first person language. Maybe something
dmurph 2016/11/07 20:05:23 Done.
199 connection_->EraseTransaction(id_);
202 } 200 }
203 201
204 bool IndexedDBTransaction::IsTaskQueueEmpty() const { 202 bool IndexedDBTransaction::IsTaskQueueEmpty() const {
205 return preemptive_task_queue_.empty() && task_queue_.empty(); 203 return preemptive_task_queue_.empty() && task_queue_.empty();
206 } 204 }
207 205
208 bool IndexedDBTransaction::HasPendingTasks() const { 206 bool IndexedDBTransaction::HasPendingTasks() const {
209 return pending_preemptive_events_ || !IsTaskQueueEmpty(); 207 return pending_preemptive_events_ || !IsTaskQueueEmpty();
210 } 208 }
211 209
(...skipping 10 matching lines...) Expand all
222 DCHECK_EQ(CREATED, state_); 220 DCHECK_EQ(CREATED, state_);
223 state_ = STARTED; 221 state_ = STARTED;
224 diagnostics_.start_time = base::Time::Now(); 222 diagnostics_.start_time = base::Time::Now();
225 223
226 if (!used_) { 224 if (!used_) {
227 if (commit_pending_) { 225 if (commit_pending_) {
228 // The transaction has never had requests issued against it, but the 226 // The transaction has never had requests issued against it, but the
229 // front-end previously requested a commit; do the commit now, but not 227 // front-end previously requested a commit; do the commit now, but not
230 // re-entrantly as that may renter the coordinator. 228 // re-entrantly as that may renter the coordinator.
231 base::ThreadTaskRunnerHandle::Get()->PostTask( 229 base::ThreadTaskRunnerHandle::Get()->PostTask(
232 FROM_HERE, base::Bind(&CommitUnused, make_scoped_refptr(this))); 230 FROM_HERE, base::Bind(&CommitUnused, ptr_factory_.GetWeakPtr()));
233 } 231 }
234 return; 232 return;
235 } 233 }
236 234
237 RunTasksIfStarted(); 235 RunTasksIfStarted();
238 } 236 }
239 237
240 class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback { 238 class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback {
241 public: 239 public:
242 explicit BlobWriteCallbackImpl( 240 explicit BlobWriteCallbackImpl(
243 scoped_refptr<IndexedDBTransaction> transaction) 241 base::WeakPtr<IndexedDBTransaction> transaction)
244 : transaction_(transaction) {} 242 : transaction_(std::move(transaction)) {}
245 void Run(bool succeeded) override { 243 void Run(bool succeeded) override {
244 if (!transaction_)
245 return;
246 transaction_->BlobWriteComplete(succeeded); 246 transaction_->BlobWriteComplete(succeeded);
247 } 247 }
248 248
249 protected: 249 protected:
250 ~BlobWriteCallbackImpl() override {} 250 ~BlobWriteCallbackImpl() override {}
251 251
252 private: 252 private:
253 scoped_refptr<IndexedDBTransaction> transaction_; 253 base::WeakPtr<IndexedDBTransaction> transaction_;
254 }; 254 };
255 255
256 void IndexedDBTransaction::BlobWriteComplete(bool success) { 256 void IndexedDBTransaction::BlobWriteComplete(bool success) {
257 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete"); 257 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete");
258 if (state_ == FINISHED) // aborted 258 if (state_ == FINISHED) // aborted
259 return; 259 return;
260 DCHECK_EQ(state_, COMMITTING); 260 DCHECK_EQ(state_, COMMITTING);
261 if (success) 261 if (success)
262 CommitPhaseTwo(); 262 CommitPhaseTwo();
263 else 263 else
(...skipping 28 matching lines...) Expand all
292 if (HasPendingTasks()) 292 if (HasPendingTasks())
293 return leveldb::Status::OK(); 293 return leveldb::Status::OK();
294 294
295 state_ = COMMITTING; 295 state_ = COMMITTING;
296 296
297 leveldb::Status s; 297 leveldb::Status s;
298 if (!used_) { 298 if (!used_) {
299 s = CommitPhaseTwo(); 299 s = CommitPhaseTwo();
300 } else { 300 } else {
301 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback( 301 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback(
302 new BlobWriteCallbackImpl(this)); 302 new BlobWriteCallbackImpl(ptr_factory_.GetWeakPtr()));
303 // CommitPhaseOne will call the callback synchronously if there are no blobs 303 // CommitPhaseOne will call the callback synchronously if there are no blobs
304 // to write. 304 // to write.
305 s = transaction_->CommitPhaseOne(callback); 305 s = transaction_->CommitPhaseOne(callback);
306 if (!s.ok()) 306 if (!s.ok())
307 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError, 307 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError,
308 "Error processing blob journal.")); 308 "Error processing blob journal."));
309 } 309 }
310 310
311 return s; 311 return s;
312 } 312 }
313 313
314 leveldb::Status IndexedDBTransaction::CommitPhaseTwo() { 314 leveldb::Status IndexedDBTransaction::CommitPhaseTwo() {
315 // Abort may have been called just as the blob write completed. 315 // Abort may have been called just as the blob write completed.
316 if (state_ == FINISHED) 316 if (state_ == FINISHED)
317 return leveldb::Status::OK(); 317 return leveldb::Status::OK();
318 318
319 DCHECK_EQ(state_, COMMITTING); 319 DCHECK_EQ(state_, COMMITTING);
320 320
321 // The last reference to this object may be released while performing the
322 // commit steps below. We therefore take a self reference to keep ourselves
323 // alive while executing this method.
324 scoped_refptr<IndexedDBTransaction> protect(this);
325
326 state_ = FINISHED; 321 state_ = FINISHED;
327 322
328 leveldb::Status s; 323 leveldb::Status s;
329 bool committed; 324 bool committed;
330 if (!used_) { 325 if (!used_) {
331 committed = true; 326 committed = true;
332 } else { 327 } else {
333 s = transaction_->CommitPhaseTwo(); 328 s = transaction_->CommitPhaseTwo();
334 committed = s.ok(); 329 committed = s.ok();
335 } 330 }
(...skipping 16 matching lines...) Expand all
352 // SendObservations must be called before OnComplete to ensure consistency 347 // SendObservations must be called before OnComplete to ensure consistency
353 // of callbacks at renderer. 348 // of callbacks at renderer.
354 if (!connection_changes_map_.empty()) { 349 if (!connection_changes_map_.empty()) {
355 database_->SendObservations(std::move(connection_changes_map_)); 350 database_->SendObservations(std::move(connection_changes_map_));
356 connection_changes_map_.clear(); 351 connection_changes_map_.clear();
357 } 352 }
358 { 353 {
359 IDB_TRACE1( 354 IDB_TRACE1(
360 "IndexedDBTransaction::CommitPhaseTwo.TransactionCompleteCallbacks", 355 "IndexedDBTransaction::CommitPhaseTwo.TransactionCompleteCallbacks",
361 "txn.id", id()); 356 "txn.id", id());
362 callbacks_->OnComplete(id_); 357 callbacks_->OnComplete(*this);
363 } 358 }
364 if (!pending_observers_.empty() && connection_) { 359 if (!pending_observers_.empty() && connection_) {
365 connection_->ActivatePendingObservers(std::move(pending_observers_)); 360 connection_->ActivatePendingObservers(std::move(pending_observers_));
366 pending_observers_.clear(); 361 pending_observers_.clear();
367 } 362 }
368 363
369 database_->TransactionFinished(this, true); 364 database_->TransactionFinished(this, true);
370 } else { 365 } else {
371 while (!abort_task_stack_.empty()) 366 while (!abort_task_stack_.empty())
372 abort_task_stack_.pop().Run(NULL); 367 abort_task_stack_.pop().Run(NULL);
373 368
374 IndexedDBDatabaseError error; 369 IndexedDBDatabaseError error;
375 if (leveldb_env::IndicatesDiskFull(s)) { 370 if (leveldb_env::IndicatesDiskFull(s)) {
376 error = IndexedDBDatabaseError( 371 error = IndexedDBDatabaseError(
377 blink::WebIDBDatabaseExceptionQuotaError, 372 blink::WebIDBDatabaseExceptionQuotaError,
378 "Encountered disk full while committing transaction."); 373 "Encountered disk full while committing transaction.");
379 } else { 374 } else {
380 error = IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 375 error = IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
381 "Internal error committing transaction."); 376 "Internal error committing transaction.");
382 } 377 }
383 callbacks_->OnAbort(id_, error); 378 callbacks_->OnAbort(*this, error);
384 379
385 database_->TransactionFinished(this, false); 380 database_->TransactionFinished(this, false);
386 database_->TransactionCommitFailed(s); 381 database_->TransactionCommitFailed(s);
387 } 382 }
388 383
389 database_ = NULL; 384 pending_observers_.clear();
385 // This destroys our object.
386 connection_->EraseTransaction(id_);
390 return s; 387 return s;
391 } 388 }
392 389
393 void IndexedDBTransaction::ProcessTaskQueue() { 390 void IndexedDBTransaction::ProcessTaskQueue() {
394 IDB_TRACE1("IndexedDBTransaction::ProcessTaskQueue", "txn.id", id()); 391 IDB_TRACE1("IndexedDBTransaction::ProcessTaskQueue", "txn.id", id());
395 392
396 // May have been aborted. 393 // May have been aborted.
397 if (!should_process_queue_) 394 if (!should_process_queue_)
398 return; 395 return;
399 396
400 DCHECK(!IsTaskQueueEmpty()); 397 DCHECK(!IsTaskQueueEmpty());
401 should_process_queue_ = false; 398 should_process_queue_ = false;
402 399
403 if (!backing_store_transaction_begun_) { 400 if (!backing_store_transaction_begun_) {
404 transaction_->Begin(); 401 transaction_->Begin();
405 backing_store_transaction_begun_ = true; 402 backing_store_transaction_begun_ = true;
406 } 403 }
407 404
408 // The last reference to this object may be released while performing the
409 // tasks. Take take a self reference to keep this object alive so that
410 // the loop termination conditions can be checked.
411 scoped_refptr<IndexedDBTransaction> protect(this);
412
413 TaskQueue* task_queue = 405 TaskQueue* task_queue =
414 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; 406 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
415 while (!task_queue->empty() && state_ != FINISHED) { 407 while (!task_queue->empty() && state_ != FINISHED) {
416 DCHECK_EQ(state_, STARTED); 408 DCHECK_EQ(state_, STARTED);
417 Operation task(task_queue->pop()); 409 Operation task(task_queue->pop());
418 task.Run(this); 410 task.Run(this);
419 if (!pending_preemptive_events_) { 411 if (!pending_preemptive_events_) {
420 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled); 412 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled);
421 ++diagnostics_.tasks_completed; 413 ++diagnostics_.tasks_completed;
422 } 414 }
(...skipping 13 matching lines...) Expand all
436 // The transaction may have been aborted while processing tasks. 428 // The transaction may have been aborted while processing tasks.
437 if (state_ == FINISHED) 429 if (state_ == FINISHED)
438 return; 430 return;
439 431
440 DCHECK(state_ == STARTED); 432 DCHECK(state_ == STARTED);
441 433
442 // Otherwise, start a timer in case the front-end gets wedged and 434 // Otherwise, start a timer in case the front-end gets wedged and
443 // never requests further activity. Read-only transactions don't 435 // never requests further activity. Read-only transactions don't
444 // block other transactions, so don't time those out. 436 // block other transactions, so don't time those out.
445 if (mode_ != blink::WebIDBTransactionModeReadOnly) { 437 if (mode_ != blink::WebIDBTransactionModeReadOnly) {
446 timeout_timer_.Start(FROM_HERE, GetInactivityTimeout(), 438 timeout_timer_.Start(
447 base::Bind(&IndexedDBTransaction::Timeout, this)); 439 FROM_HERE, GetInactivityTimeout(),
440 base::Bind(&IndexedDBTransaction::Timeout, ptr_factory_.GetWeakPtr()));
448 } 441 }
449 } 442 }
450 443
451 base::TimeDelta IndexedDBTransaction::GetInactivityTimeout() const { 444 base::TimeDelta IndexedDBTransaction::GetInactivityTimeout() const {
452 return base::TimeDelta::FromSeconds(kInactivityTimeoutPeriodSeconds); 445 return base::TimeDelta::FromSeconds(kInactivityTimeoutPeriodSeconds);
453 } 446 }
454 447
455 void IndexedDBTransaction::Timeout() { 448 void IndexedDBTransaction::Timeout() {
456 Abort(IndexedDBDatabaseError( 449 Abort(IndexedDBDatabaseError(
457 blink::WebIDBDatabaseExceptionTimeoutError, 450 blink::WebIDBDatabaseExceptionTimeoutError,
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 491
499 void IndexedDBTransaction::RecordObserverForLastObservation( 492 void IndexedDBTransaction::RecordObserverForLastObservation(
500 int32_t connection_id, 493 int32_t connection_id,
501 int32_t observer_id) { 494 int32_t observer_id) {
502 auto it = connection_changes_map_.find(connection_id); 495 auto it = connection_changes_map_.find(connection_id);
503 DCHECK(it != connection_changes_map_.end()); 496 DCHECK(it != connection_changes_map_.end());
504 it->second->RecordObserverForLastObservation(observer_id); 497 it->second->RecordObserverForLastObservation(observer_id);
505 } 498 }
506 499
507 } // namespace content 500 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698