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

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: Merge fixes [builds, untested] Created 7 years, 3 months 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 int64 id, 52 int64 id,
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 state_(UNUSED), 60 state_(UNUSED),
61 commit_pending_(false), 61 commit_pending_(false),
62 blob_write_success_(false),
62 callbacks_(callbacks), 63 callbacks_(callbacks),
63 database_(database), 64 database_(database),
64 transaction_(database->BackingStore().get()), 65 transaction_(database->BackingStore().get()),
65 should_process_queue_(false), 66 should_process_queue_(false),
66 pending_preemptive_events_(0) { 67 pending_preemptive_events_(0) {
68 fprintf(stderr, "ERICU: IndexedDBTransaction::IndexedDBTransaction(%p).\n",
69 this);
67 database_->transaction_coordinator().DidCreateTransaction(this); 70 database_->transaction_coordinator().DidCreateTransaction(this);
68 } 71 }
69 72
70 IndexedDBTransaction::~IndexedDBTransaction() { 73 IndexedDBTransaction::~IndexedDBTransaction() {
71 // It shouldn't be possible for this object to get deleted until it's either 74 // It shouldn't be possible for this object to get deleted until it's either
72 // complete or aborted. 75 // complete or aborted.
76 fprintf(stderr, "ERICU: IndexedDBTransaction::~IndexedDBTransaction.\n");
73 DCHECK_EQ(state_, FINISHED); 77 DCHECK_EQ(state_, FINISHED);
74 DCHECK(preemptive_task_queue_.empty()); 78 DCHECK(preemptive_task_queue_.empty());
75 DCHECK(task_queue_.empty()); 79 DCHECK(task_queue_.empty());
76 DCHECK(abort_task_stack_.empty()); 80 DCHECK(abort_task_stack_.empty());
77 } 81 }
78 82
79 void IndexedDBTransaction::ScheduleTask(Operation task, Operation abort_task) { 83 void IndexedDBTransaction::ScheduleTask(Operation task, Operation abort_task) {
80 if (state_ == FINISHED) 84 if (state_ == FINISHED)
81 return; 85 return;
82 task_queue_.push(task); 86 task_queue_.push(task);
83 abort_task_stack_.push(abort_task); 87 abort_task_stack_.push(abort_task);
84 EnsureTasksRunning(); 88 EnsureTasksRunning();
85 } 89 }
86 90
87 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type, 91 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type,
88 Operation task) { 92 Operation task) {
89 if (state_ == FINISHED) 93 if (IsStatePastRunning())
90 return; 94 return;
91 95
92 if (type == IndexedDBDatabase::NORMAL_TASK) 96 if (type == IndexedDBDatabase::NORMAL_TASK)
93 task_queue_.push(task); 97 task_queue_.push(task);
94 else 98 else
95 preemptive_task_queue_.push(task); 99 preemptive_task_queue_.push(task);
96 EnsureTasksRunning(); 100 EnsureTasksRunning();
97 } 101 }
98 102
99 void IndexedDBTransaction::EnsureTasksRunning() { 103 void IndexedDBTransaction::EnsureTasksRunning() {
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 } 192 }
189 193
190 void IndexedDBTransaction::Start() { 194 void IndexedDBTransaction::Start() {
191 DCHECK_EQ(state_, UNUSED); 195 DCHECK_EQ(state_, UNUSED);
192 196
193 state_ = START_PENDING; 197 state_ = START_PENDING;
194 database_->transaction_coordinator().DidStartTransaction(this); 198 database_->transaction_coordinator().DidStartTransaction(this);
195 database_->TransactionStarted(this); 199 database_->TransactionStarted(this);
196 } 200 }
197 201
202 class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback {
203 public:
204 BlobWriteCallbackImpl(scoped_refptr<IndexedDBTransaction> transaction)
205 : transaction_(transaction) { }
206 virtual ~BlobWriteCallbackImpl() { }
207 virtual void didSucceed() {
208 transaction_->BlobWriteComplete(true);
209 }
210 virtual void didFail() {
211 transaction_->BlobWriteComplete(false);
212 }
213 private:
214 scoped_refptr<IndexedDBTransaction> transaction_;
215 };
216
198 void IndexedDBTransaction::Commit() { 217 void IndexedDBTransaction::Commit() {
199 IDB_TRACE("IndexedDBTransaction::Commit"); 218 IDB_TRACE("IndexedDBTransaction::Commit");
219 fprintf(stderr, "ERICU: IndexedDBTransaction::Commit.\n");
200 220
201 // In multiprocess ports, front-end may have requested a commit but 221 // In multiprocess ports, front-end may have requested a commit but
202 // an abort has already been initiated asynchronously by the 222 // an abort has already been initiated asynchronously by the
203 // back-end. 223 // back-end.
204 if (state_ == FINISHED) 224 if (IsStatePastRunning())
205 return; 225 return;
206 226
207 DCHECK(state_ == UNUSED || state_ == RUNNING); 227 DCHECK(state_ == UNUSED || state_ == RUNNING);
208 commit_pending_ = true; 228 commit_pending_ = true;
209 229
210 // Front-end has requested a commit, but there may be tasks like 230 // Front-end has requested a commit, but there may be tasks like
211 // create_index which are considered synchronous by the front-end 231 // create_index which are considered synchronous by the front-end
212 // but are processed asynchronously. 232 // but are processed asynchronously.
213 if (HasPendingTasks()) 233 if (HasPendingTasks())
214 return; 234 return;
215 235
216 // The last reference to this object may be released while performing the 236 bool unused = state_ == UNUSED;
217 // commit steps below. We therefore take a self reference to keep ourselves 237 state_ = COMMITTING;
218 // alive while executing this method.
219 scoped_refptr<IndexedDBTransaction> protect(this);
220 238
221 // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843 239 if (unused)
222 abort_task_stack_.clear(); 240 CommitPhaseTwo(WAS_NOT_USED, DO_COMMIT);
223 241 else {
224 bool unused = state_ == UNUSED; 242 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback(
225 state_ = FINISHED; 243 new BlobWriteCallbackImpl(this));
226 244 // CommitPhaseOne will call the callback synchronously if there are no blobs
227 bool committed = unused || transaction_.Commit(); 245 // to write.
228 246 if (!transaction_.CommitPhaseOne(callback))
229 // Backing store resources (held via cursors) must be released 247 CommitPhaseTwo(WAS_USED, SKIP_COMMIT);
230 // before script callbacks are fired, as the script callbacks may
231 // release references and allow the backing store itself to be
232 // released, and order is critical.
233 CloseOpenCursors();
234 transaction_.Reset();
235
236 // Transactions must also be marked as completed before the
237 // front-end is notified, as the transaction completion unblocks
238 // operations like closing connections.
239 database_->transaction_coordinator().DidFinishTransaction(this);
240 database_->TransactionFinished(this);
241
242 if (committed) {
243 callbacks_->OnComplete(id_);
244 database_->TransactionFinishedAndCompleteFired(this);
245 } else {
246 callbacks_->OnAbort(
247 id_,
248 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
249 "Internal error committing transaction."));
250 database_->TransactionFinishedAndAbortFired(this);
251 } 248 }
252
253 database_ = NULL;
254 } 249 }
255 250
256 void IndexedDBTransaction::ProcessTaskQueue() { 251 void IndexedDBTransaction::ProcessTaskQueue() {
257 IDB_TRACE("IndexedDBTransaction::ProcessTaskQueue"); 252 IDB_TRACE("IndexedDBTransaction::ProcessTaskQueue");
258 253
259 // May have been aborted. 254 // May have been aborted.
260 if (!should_process_queue_) 255 if (!should_process_queue_)
261 return; 256 return;
262 257
263 DCHECK(!IsTaskQueueEmpty()); 258 DCHECK(!IsTaskQueueEmpty());
264 should_process_queue_ = false; 259 should_process_queue_ = false;
265 260
266 if (state_ == START_PENDING) { 261 if (state_ == START_PENDING) {
267 transaction_.Begin(); 262 transaction_.Begin();
268 state_ = RUNNING; 263 state_ = RUNNING;
269 } 264 }
270 265
271 // The last reference to this object may be released while performing the 266 // The last reference to this object may be released while performing the
272 // tasks. Take take a self reference to keep this object alive so that 267 // tasks. Take take a self reference to keep this object alive so that
273 // the loop termination conditions can be checked. 268 // the loop termination conditions can be checked.
274 scoped_refptr<IndexedDBTransaction> protect(this); 269 scoped_refptr<IndexedDBTransaction> protect(this);
275 270
276 TaskQueue* task_queue = 271 TaskQueue* task_queue =
277 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; 272 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
278 while (!task_queue->empty() && state_ != FINISHED) { 273 while (!task_queue->empty() && !IsStatePastRunning()) {
279 DCHECK_EQ(state_, RUNNING); 274 DCHECK_EQ(state_, RUNNING);
280 Operation task(task_queue->pop()); 275 Operation task(task_queue->pop());
281 task.Run(this); 276 task.Run(this);
282 277
283 // Event itself may change which queue should be processed next. 278 // Event itself may change which queue should be processed next.
284 task_queue = 279 task_queue =
285 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_; 280 pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
286 } 281 }
287 282
288 // If there are no pending tasks, we haven't already committed/aborted, 283 // If there are no pending tasks, we haven't already committed/aborted,
289 // and the front-end requested a commit, it is now safe to do so. 284 // and the front-end requested a commit, it is now safe to do so.
290 if (!HasPendingTasks() && state_ != FINISHED && commit_pending_) 285 if (!HasPendingTasks() && !IsStatePastRunning() && commit_pending_)
291 Commit(); 286 Commit();
292 } 287 }
293 288
289 void IndexedDBTransaction::BlobWriteComplete(bool success)
290 {
291 IDB_TRACE("IndexedDBTransaction::BlobWriteComplete");
292 if (state_ == FINISHED) // aborted
293 return;
294 DCHECK_EQ(state_, COMMITTING);
295 if (success)
296 CommitPhaseTwo(WAS_USED, DO_COMMIT);
297 else
298 Abort(IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionDataError,
299 "Failed to write blobs"));
300 }
301
294 void IndexedDBTransaction::CloseOpenCursors() { 302 void IndexedDBTransaction::CloseOpenCursors() {
295 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin(); 303 for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin();
296 i != open_cursors_.end(); 304 i != open_cursors_.end();
297 ++i) 305 ++i)
298 (*i)->Close(); 306 (*i)->Close();
299 open_cursors_.clear(); 307 open_cursors_.clear();
300 } 308 }
301 309
310 void IndexedDBTransaction::CommitPhaseTwo(TransactionUseState use_state,
311 ShouldSkipCommit skip_commit) {
312 DCHECK_EQ(state_, COMMITTING);
313 state_ = FINISHED;
314
315 // The last reference to this object may be released while performing the
316 // commit steps below. We therefore take a self reference to keep ourselves
317 // alive while executing this method.
318 scoped_refptr<IndexedDBTransaction> protect(this);
319
320 // TODO(jsbell): Run abort tasks if commit fails? http://crbug.com/241843
321 abort_task_stack_.clear();
322
323 state_ = FINISHED;
324
325 bool committed = (use_state == WAS_NOT_USED) ||
jsbell 2013/09/13 00:12:21 Seems like use_state and skip_commit effectively h
ericu 2013/11/20 23:05:39 No--we skip_commit if we've failed or aborted, but
326 ((skip_commit == DO_COMMIT) && transaction_.CommitPhaseTwo());
327
328 // Backing store resources (held via cursors) must be released
329 // before script callbacks are fired, as the script callbacks may
330 // release references and allow the backing store itself to be
331 // released, and order is critical.
332 CloseOpenCursors();
333 transaction_.Reset();
334
335 // Transactions must also be marked as completed before the
336 // front-end is notified, as the transaction completion unblocks
337 // operations like closing connections.
338 database_->transaction_coordinator().DidFinishTransaction(this);
339 database_->TransactionFinished(this);
340
341 if (committed) {
342 callbacks_->OnComplete(id_);
343 database_->TransactionFinishedAndCompleteFired(this);
344 } else {
345 callbacks_->OnAbort(
346 id_,
347 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
348 "Internal error committing transaction."));
349 database_->TransactionFinishedAndAbortFired(this);
350 }
351
352 database_ = NULL;
353 }
354
302 } // namespace content 355 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698