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

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

Issue 18023022: Blob support for IDB [Chromium] (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Settle on one name for the live blob journal. Created 7 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 | Annotate | Revision Log
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/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
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
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
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 }
215 virtual ~BlobWriteCallbackImpl() {
216 }
217 virtual void didSucceed() {
218 transaction_->BlobWriteComplete(true);
219 }
220 virtual void didFail() {
221 transaction_->BlobWriteComplete(false);
222 }
223 private:
224 scoped_refptr<IndexedDBTransaction> transaction_;
225 };
226
209 void IndexedDBTransaction::Commit() { 227 void IndexedDBTransaction::Commit() {
210 IDB_TRACE("IndexedDBTransaction::Commit"); 228 IDB_TRACE("IndexedDBTransaction::Commit");
211 229
212 // In multiprocess ports, front-end may have requested a commit but 230 // In multiprocess ports, front-end may have requested a commit but
213 // an abort has already been initiated asynchronously by the 231 // an abort has already been initiated asynchronously by the
214 // back-end. 232 // back-end.
215 if (state_ == FINISHED) 233 if (IsStatePastRunning())
216 return; 234 return;
217 235
218 DCHECK(!used_ || state_ == STARTED); 236 DCHECK(!used_ || state_ == STARTED);
219 commit_pending_ = true; 237 commit_pending_ = true;
220 238
221 // Front-end has requested a commit, but there may be tasks like 239 // Front-end has requested a commit, but there may be tasks like
222 // create_index which are considered synchronous by the front-end 240 // create_index which are considered synchronous by the front-end
223 // but are processed asynchronously. 241 // but are processed asynchronously.
224 if (HasPendingTasks()) 242 if (HasPendingTasks())
225 return; 243 return;
226 244
227 // The last reference to this object may be released while performing the 245 state_ = COMMITTING;
228 // commit steps below. We therefore take a self reference to keep ourselves
229 // alive while executing this method.
230 scoped_refptr<IndexedDBTransaction> protect(this);
231 246
232 // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843 247 if (!used_)
233 abort_task_stack_.clear(); 248 CommitPhaseTwo(WAS_NOT_USED, DO_COMMIT);
234 249 else {
235 state_ = FINISHED; 250 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback(
236 251 new BlobWriteCallbackImpl(this));
237 bool committed = !used_ || transaction_.Commit(); 252 // CommitPhaseOne will call the callback synchronously if there are no blobs
238 253 // to write.
239 // Backing store resources (held via cursors) must be released 254 if (!transaction_.CommitPhaseOne(callback))
240 // before script callbacks are fired, as the script callbacks may 255 CommitPhaseTwo(WAS_USED, SKIP_COMMIT);
241 // release references and allow the backing store itself to be
242 // released, and order is critical.
243 CloseOpenCursors();
244 transaction_.Reset();
245
246 // Transactions must also be marked as completed before the
247 // front-end is notified, as the transaction completion unblocks
248 // operations like closing connections.
249 database_->transaction_coordinator().DidFinishTransaction(this);
250 database_->TransactionFinished(this);
251
252 if (committed) {
253 callbacks_->OnComplete(id_);
254 database_->TransactionFinishedAndCompleteFired(this);
255 } else {
256 callbacks_->OnAbort(
257 id_,
258 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
259 "Internal error committing transaction."));
260 database_->TransactionFinishedAndAbortFired(this);
261 database_->TransactionCommitFailed();
262 } 256 }
263
264 database_ = NULL;
265 } 257 }
266 258
267 void IndexedDBTransaction::ProcessTaskQueue() { 259 void IndexedDBTransaction::ProcessTaskQueue() {
268 IDB_TRACE("IndexedDBTransaction::ProcessTaskQueue"); 260 IDB_TRACE("IndexedDBTransaction::ProcessTaskQueue");
269 261
270 // May have been aborted. 262 // May have been aborted.
271 if (!should_process_queue_) 263 if (!should_process_queue_)
272 return; 264 return;
273 265
274 DCHECK(!IsTaskQueueEmpty()); 266 DCHECK(!IsTaskQueueEmpty());
275 should_process_queue_ = false; 267 should_process_queue_ = false;
276 268
277 if (!backing_store_transaction_begun_) { 269 if (!backing_store_transaction_begun_) {
278 transaction_.Begin(); 270 transaction_.Begin();
279 backing_store_transaction_begun_ = true; 271 backing_store_transaction_begun_ = true;
280 } 272 }
281 273
282 // The last reference to this object may be released while performing the 274 // 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 275 // tasks. Take take a self reference to keep this object alive so that
284 // the loop termination conditions can be checked. 276 // the loop termination conditions can be checked.
285 scoped_refptr<IndexedDBTransaction> protect(this); 277 scoped_refptr<IndexedDBTransaction> protect(this);
286 278
287 TaskQueue* task_queue = 279 TaskQueue* task_queue =
288 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; 280 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
289 while (!task_queue->empty() && state_ != FINISHED) { 281 while (!task_queue->empty() && !IsStatePastRunning()) {
290 DCHECK_EQ(STARTED, state_); 282 DCHECK_EQ(state_, STARTED);
291 Operation task(task_queue->pop()); 283 Operation task(task_queue->pop());
292 task.Run(this); 284 task.Run(this);
293 if (!pending_preemptive_events_) { 285 if (!pending_preemptive_events_) {
294 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled); 286 DCHECK(diagnostics_.tasks_completed < diagnostics_.tasks_scheduled);
295 ++diagnostics_.tasks_completed; 287 ++diagnostics_.tasks_completed;
296 } 288 }
297 289
298 // Event itself may change which queue should be processed next. 290 // Event itself may change which queue should be processed next.
299 task_queue = 291 task_queue =
300 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; 292 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
301 } 293 }
302 294
303 // If there are no pending tasks, we haven't already committed/aborted, 295 // 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. 296 // and the front-end requested a commit, it is now safe to do so.
305 if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) 297 if (!HasPendingTasks() && !IsStatePastRunning() && commit_pending_)
306 Commit(); 298 Commit();
307 } 299 }
308 300
301 void IndexedDBTransaction::BlobWriteComplete(bool success)
302 {
303 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete");
304 if (state_ == FINISHED) // aborted
305 return;
306 DCHECK_EQ(state_, COMMITTING);
307 if (success)
308 CommitPhaseTwo(WAS_USED, DO_COMMIT);
309 else
310 Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError,
311 "Failed to write blobs"));
312 }
313
309 void IndexedDBTransaction::CloseOpenCursors() { 314 void IndexedDBTransaction::CloseOpenCursors() {
310 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); 315 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin();
311 i != open_cursors_.end(); 316 i != open_cursors_.end();
312 ++i) 317 ++i)
313 (*i)->Close(); 318 (*i)->Close();
314 open_cursors_.clear(); 319 open_cursors_.clear();
315 } 320 }
316 321
322 void IndexedDBTransaction::CommitPhaseTwo(TransactionUseState use_state,
323 ShouldSkipCommit skip_commit) {
324 DCHECK_EQ(state_, COMMITTING);
325 state_ = FINISHED;
326
327 // The last reference to this object may be released while performing the
328 // commit steps below. We therefore take a self reference to keep ourselves
329 // alive while executing this method.
330 scoped_refptr<IndexedDBTransaction> protect(this);
331
332 // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843
333 abort_task_stack_.clear();
334
335 state_ = FINISHED;
336
337 bool committed = (use_state == WAS_NOT_USED) ||
338 ((skip_commit == DO_COMMIT) && transaction_.CommitPhaseTwo());
339
340 // Backing store resources (held via cursors) must be released
341 // before script callbacks are fired, as the script callbacks may
342 // release references and allow the backing store itself to be
343 // released, and order is critical.
344 CloseOpenCursors();
345 transaction_.Reset();
346
347 // Transactions must also be marked as completed before the
348 // front-end is notified, as the transaction completion unblocks
349 // operations like closing connections.
350 database_->transaction_coordinator().DidFinishTransaction(this);
351 database_->TransactionFinished(this);
352
353 if (committed) {
354 callbacks_->OnComplete(id_);
355 database_->TransactionFinishedAndCompleteFired(this);
356 } else {
357 callbacks_->OnAbort(
358 id_,
359 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
360 "Internal error committing transaction."));
361 database_->TransactionFinishedAndAbortFired(this);
362 database_->TransactionCommitFailed();
363 }
364
365 database_ = NULL;
366 }
367
317 } // namespace content 368 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698