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

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

Issue 15564008: Migrate the IndexedDB backend from Blink to Chromium (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Accessor naming, use LevelDBSlice ctor explicitly Created 7 years, 7 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/indexed_db/indexed_db_database_impl.h"
6
7 #include <math.h>
8 #include <vector>
9
10 #include "base/auto_reset.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/utf_string_conversions.h"
15 #include "content/browser/indexed_db/indexed_db_backing_store.h"
16 #include "content/browser/indexed_db/indexed_db_cursor_impl.h"
17 #include "content/browser/indexed_db/indexed_db_factory_impl.h"
18 #include "content/browser/indexed_db/indexed_db_index_writer.h"
19 #include "content/browser/indexed_db/indexed_db_tracing.h"
20 #include "content/browser/indexed_db/indexed_db_transaction.h"
21 #include "content/common/indexed_db/indexed_db_key_path.h"
22 #include "content/common/indexed_db/indexed_db_key_range.h"
23 #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBDatabaseExcep tion.h"
24
25 using base::Int64ToString16;
26 using WebKit::WebIDBKey;
27
28 namespace content {
29
30 class CreateObjectStoreOperation : public IndexedDBTransaction::Operation {
31 public:
32 CreateObjectStoreOperation(
33 scoped_refptr<IndexedDBBackingStore> backing_store,
34 const IndexedDBObjectStoreMetadata& object_store_metadata)
35 : backing_store_(backing_store),
36 object_store_metadata_(object_store_metadata) {}
37 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
38
39 private:
40 const scoped_refptr<IndexedDBBackingStore> backing_store_;
41 const IndexedDBObjectStoreMetadata object_store_metadata_;
42 };
43
44 class DeleteObjectStoreOperation : public IndexedDBTransaction::Operation {
45 public:
46 DeleteObjectStoreOperation(
47 scoped_refptr<IndexedDBBackingStore> backing_store,
48 const IndexedDBObjectStoreMetadata& object_store_metadata)
49 : backing_store_(backing_store),
50 object_store_metadata_(object_store_metadata) {}
51 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
52
53 private:
54 const scoped_refptr<IndexedDBBackingStore> backing_store_;
55 const IndexedDBObjectStoreMetadata object_store_metadata_;
56 };
57
58 class IndexedDBDatabaseImpl::VersionChangeOperation
59 : public IndexedDBTransaction::Operation {
60 public:
61 VersionChangeOperation(
62 scoped_refptr<IndexedDBDatabaseImpl> database,
63 int64_t transaction_id,
64 int64_t version,
65 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
66 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks)
67 : database_(database),
68 transaction_id_(transaction_id),
69 version_(version),
70 callbacks_(callbacks),
71 database_callbacks_(database_callbacks) {}
72 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
73
74 private:
75 scoped_refptr<IndexedDBDatabaseImpl> database_;
76 int64_t transaction_id_;
77 int64_t version_;
78 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
79 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_;
80 };
81
82 class CreateObjectStoreAbortOperation : public IndexedDBTransaction::Operation {
83 public:
84 CreateObjectStoreAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database,
85 int64_t object_store_id)
86 : database_(database), object_store_id_(object_store_id) {}
87 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
88
89 private:
90 const scoped_refptr<IndexedDBDatabaseImpl> database_;
91 const int64_t object_store_id_;
92 };
93
94 class DeleteObjectStoreAbortOperation : public IndexedDBTransaction::Operation {
95 public:
96 DeleteObjectStoreAbortOperation(
97 scoped_refptr<IndexedDBDatabaseImpl> database,
98 const IndexedDBObjectStoreMetadata& object_store_metadata)
99 : database_(database), object_store_metadata_(object_store_metadata) {}
100 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
101
102 private:
103 scoped_refptr<IndexedDBDatabaseImpl> database_;
104 IndexedDBObjectStoreMetadata object_store_metadata_;
105 };
106
107 class IndexedDBDatabaseImpl::VersionChangeAbortOperation
108 : public IndexedDBTransaction::Operation {
109 public:
110 VersionChangeAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database,
111 const string16& previous_version,
112 int64_t previous_int_version)
113 : database_(database),
114 previous_version_(previous_version),
115 previous_int_version_(previous_int_version) {}
116 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
117
118 private:
119 scoped_refptr<IndexedDBDatabaseImpl> database_;
120 string16 previous_version_;
121 int64_t previous_int_version_;
122 };
123
124 class CreateIndexOperation : public IndexedDBTransaction::Operation {
125 public:
126 CreateIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
127 int64_t object_store_id,
128 const IndexedDBIndexMetadata& index_metadata)
129 : backing_store_(backing_store),
130 object_store_id_(object_store_id),
131 index_metadata_(index_metadata) {}
132 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
133
134 private:
135 const scoped_refptr<IndexedDBBackingStore> backing_store_;
136 const int64_t object_store_id_;
137 const IndexedDBIndexMetadata index_metadata_;
138 };
139
140 class DeleteIndexOperation : public IndexedDBTransaction::Operation {
141 public:
142 DeleteIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
143 int64_t object_store_id,
144 const IndexedDBIndexMetadata& index_metadata)
145 : backing_store_(backing_store),
146 object_store_id_(object_store_id),
147 index_metadata_(index_metadata) {}
148 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
149
150 private:
151 const scoped_refptr<IndexedDBBackingStore> backing_store_;
152 const int64_t object_store_id_;
153 const IndexedDBIndexMetadata index_metadata_;
154 };
155
156 class CreateIndexAbortOperation : public IndexedDBTransaction::Operation {
157 public:
158 CreateIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database,
159 int64_t object_store_id,
160 int64_t index_id)
161 : database_(database),
162 object_store_id_(object_store_id),
163 index_id_(index_id) {}
164 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
165
166 private:
167 const scoped_refptr<IndexedDBDatabaseImpl> database_;
168 const int64_t object_store_id_;
169 const int64_t index_id_;
170 };
171
172 class DeleteIndexAbortOperation : public IndexedDBTransaction::Operation {
173 public:
174 DeleteIndexAbortOperation(scoped_refptr<IndexedDBDatabaseImpl> database,
175 int64_t object_store_id,
176 const IndexedDBIndexMetadata& index_metadata)
177 : database_(database),
178 object_store_id_(object_store_id),
179 index_metadata_(index_metadata) {}
180 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
181
182 private:
183 const scoped_refptr<IndexedDBDatabaseImpl> database_;
184 const int64_t object_store_id_;
185 const IndexedDBIndexMetadata index_metadata_;
186 };
187
188 class GetOperation : public IndexedDBTransaction::Operation {
189 public:
190 GetOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
191 const IndexedDBDatabaseMetadata& metadata,
192 int64_t object_store_id,
193 int64_t index_id,
194 scoped_ptr<IndexedDBKeyRange> key_range,
195 IndexedDB::CursorType cursor_type,
196 scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
197 : backing_store_(backing_store),
198 database_id_(metadata.id),
199 object_store_id_(object_store_id),
200 index_id_(index_id),
201 key_path_(metadata.object_stores.find(object_store_id)
202 ->second.key_path),
203 auto_increment_(metadata.object_stores.find(object_store_id)
204 ->second.auto_increment),
205 key_range_(key_range.Pass()),
206 cursor_type_(cursor_type),
207 callbacks_(callbacks) {
208 DCHECK(metadata.object_stores.find(object_store_id) !=
209 metadata.object_stores.end());
210 DCHECK(metadata.object_stores.find(object_store_id)->second.id ==
211 object_store_id);
212 }
213 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
214
215 private:
216 const scoped_refptr<IndexedDBBackingStore> backing_store_;
217 const int64_t database_id_;
218 const int64_t object_store_id_;
219 const int64_t index_id_;
220 const IndexedDBKeyPath key_path_;
221 const bool auto_increment_;
222 const scoped_ptr<IndexedDBKeyRange> key_range_;
223 const IndexedDB::CursorType cursor_type_;
224 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
225 };
226
227 class PutOperation : public IndexedDBTransaction::Operation {
228 public:
229 PutOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
230 int64_t database_id,
231 const IndexedDBObjectStoreMetadata& object_store,
232 std::vector<char>* value,
233 scoped_ptr<IndexedDBKey> key,
234 IndexedDBDatabase::PutMode put_mode,
235 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
236 const std::vector<int64_t>& index_ids,
237 const std::vector<IndexedDBDatabase::IndexKeys>& index_keys)
238 : backing_store_(backing_store),
239 database_id_(database_id),
240 object_store_(object_store),
241 key_(key.Pass()),
242 put_mode_(put_mode),
243 callbacks_(callbacks),
244 index_ids_(index_ids),
245 index_keys_(index_keys) {
246 value_.swap(*value);
247 }
248 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
249
250 private:
251 const scoped_refptr<IndexedDBBackingStore> backing_store_;
252 const int64_t database_id_;
253 const IndexedDBObjectStoreMetadata object_store_;
254 std::vector<char> value_;
255 scoped_ptr<IndexedDBKey> key_;
256 const IndexedDBDatabase::PutMode put_mode_;
257 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
258 const std::vector<int64_t> index_ids_;
259 const std::vector<IndexedDBDatabase::IndexKeys> index_keys_;
260 };
261
262 class SetIndexesReadyOperation : public IndexedDBTransaction::Operation {
263 public:
264 SetIndexesReadyOperation(size_t index_count) : index_count_(index_count) {}
265 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
266
267 private:
268 const size_t index_count_;
269 };
270
271 class OpenCursorOperation : public IndexedDBTransaction::Operation {
272 public:
273 OpenCursorOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
274 int64_t database_id,
275 int64_t object_store_id,
276 int64_t index_id,
277 scoped_ptr<IndexedDBKeyRange> key_range,
278 IndexedDB::CursorDirection direction,
279 IndexedDB::CursorType cursor_type,
280 IndexedDBDatabase::TaskType task_type,
281 scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
282 : backing_store_(backing_store),
283 database_id_(database_id),
284 object_store_id_(object_store_id),
285 index_id_(index_id),
286 key_range_(key_range.Pass()),
287 direction_(direction),
288 cursor_type_(cursor_type),
289 task_type_(task_type),
290 callbacks_(callbacks) {}
291 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
292
293 private:
294 const scoped_refptr<IndexedDBBackingStore> backing_store_;
295 const int64_t database_id_;
296 const int64_t object_store_id_;
297 const int64_t index_id_;
298 const scoped_ptr<IndexedDBKeyRange> key_range_;
299 const IndexedDB::CursorDirection direction_;
300 const IndexedDB::CursorType cursor_type_;
301 const IndexedDBDatabase::TaskType task_type_;
302 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
303 };
304
305 class CountOperation : public IndexedDBTransaction::Operation {
306 public:
307 CountOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
308 int64_t database_id,
309 int64_t object_store_id,
310 int64_t index_id,
311 scoped_ptr<IndexedDBKeyRange> key_range,
312 scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
313 : backing_store_(backing_store),
314 database_id_(database_id),
315 object_store_id_(object_store_id),
316 index_id_(index_id),
317 key_range_(key_range.Pass()),
318 callbacks_(callbacks) {}
319 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
320
321 private:
322 const scoped_refptr<IndexedDBBackingStore> backing_store_;
323 const int64_t database_id_;
324 const int64_t object_store_id_;
325 const int64_t index_id_;
326 const scoped_ptr<IndexedDBKeyRange> key_range_;
327 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
328 };
329
330 class DeleteRangeOperation : public IndexedDBTransaction::Operation {
331 public:
332 DeleteRangeOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
333 int64_t database_id,
334 int64_t object_store_id,
335 scoped_ptr<IndexedDBKeyRange> key_range,
336 scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
337 : backing_store_(backing_store),
338 database_id_(database_id),
339 object_store_id_(object_store_id),
340 key_range_(key_range.Pass()),
341 callbacks_(callbacks) {}
342 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
343
344 private:
345 const scoped_refptr<IndexedDBBackingStore> backing_store_;
346 const int64_t database_id_;
347 const int64_t object_store_id_;
348 const scoped_ptr<IndexedDBKeyRange> key_range_;
349 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
350 };
351
352 class ClearOperation : public IndexedDBTransaction::Operation {
353 public:
354 ClearOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
355 int64_t database_id,
356 int64_t object_store_id,
357 scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
358 : backing_store_(backing_store),
359 database_id_(database_id),
360 object_store_id_(object_store_id),
361 callbacks_(callbacks) {}
362 virtual void Perform(IndexedDBTransaction*) OVERRIDE;
363
364 private:
365 const scoped_refptr<IndexedDBBackingStore> backing_store_;
366 const int64_t database_id_;
367 const int64_t object_store_id_;
368 const scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
369 };
370
371 class IndexedDBDatabaseImpl::PendingOpenCall {
372 public:
373 PendingOpenCall(
374 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
375 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks,
376 int64_t transaction_id,
377 int64_t version)
378 : callbacks_(callbacks),
379 database_callbacks_(database_callbacks),
380 version_(version),
381 transaction_id_(transaction_id) {}
382 scoped_refptr<IndexedDBCallbacksWrapper> Callbacks() { return callbacks_; }
383 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> DatabaseCallbacks() {
384 return database_callbacks_;
385 }
386 int64_t Version() { return version_; }
387 int64_t TransactionId() const { return transaction_id_; }
388
389 private:
390 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
391 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks_;
392 int64_t version_;
393 const int64_t transaction_id_;
394 };
395
396 class IndexedDBDatabaseImpl::PendingDeleteCall {
397 public:
398 PendingDeleteCall(scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
399 : callbacks_(callbacks) {}
400 scoped_refptr<IndexedDBCallbacksWrapper> Callbacks() { return callbacks_; }
401
402 private:
403 scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
404 };
405
406 scoped_refptr<IndexedDBDatabaseImpl> IndexedDBDatabaseImpl::Create(
407 const string16& name,
408 IndexedDBBackingStore* database,
409 IndexedDBFactoryImpl* factory,
410 const string16& unique_identifier) {
411 scoped_refptr<IndexedDBDatabaseImpl> backend =
412 new IndexedDBDatabaseImpl(name, database, factory, unique_identifier);
413 if (!backend->OpenInternal())
414 return 0;
415 return backend;
416 }
417
418 namespace {
419 const base::string16::value_type kNoStringVersion[] = { 0 };
420 }
421
422 IndexedDBDatabaseImpl::IndexedDBDatabaseImpl(
423 const string16& name,
424 IndexedDBBackingStore* backing_store,
425 IndexedDBFactoryImpl* factory,
426 const string16& unique_identifier)
427 : backing_store_(backing_store),
428 metadata_(name,
429 InvalidId,
430 kNoStringVersion,
431 IndexedDBDatabaseMetadata::NoIntVersion,
432 InvalidId),
433 identifier_(unique_identifier),
434 factory_(factory),
435 running_version_change_transaction_(NULL),
436 closing_connection_(false) {
437 DCHECK(!metadata_.name.empty());
438 }
439
440 void IndexedDBDatabaseImpl::AddObjectStore(
441 const IndexedDBObjectStoreMetadata& object_store,
442 int64_t new_max_object_store_id) {
443 DCHECK(metadata_.object_stores.find(object_store.id) ==
444 metadata_.object_stores.end());
445 if (new_max_object_store_id != IndexedDBObjectStoreMetadata::InvalidId) {
446 DCHECK(metadata_.max_object_store_id < new_max_object_store_id);
447 metadata_.max_object_store_id = new_max_object_store_id;
448 }
449 metadata_.object_stores[object_store.id] = object_store;
450 }
451
452 void IndexedDBDatabaseImpl::RemoveObjectStore(int64_t object_store_id) {
453 DCHECK(metadata_.object_stores.find(object_store_id) !=
454 metadata_.object_stores.end());
455 metadata_.object_stores.erase(object_store_id);
456 }
457
458 void IndexedDBDatabaseImpl::AddIndex(int64_t object_store_id,
459 const IndexedDBIndexMetadata& index,
460 int64_t new_max_index_id) {
461 DCHECK(metadata_.object_stores.find(object_store_id) !=
462 metadata_.object_stores.end());
463 IndexedDBObjectStoreMetadata object_store =
464 metadata_.object_stores[object_store_id];
465
466 DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end());
467 object_store.indexes[index.id] = index;
468 if (new_max_index_id != IndexedDBIndexMetadata::InvalidId) {
469 DCHECK(object_store.max_index_id < new_max_index_id);
470 object_store.max_index_id = new_max_index_id;
471 }
472 metadata_.object_stores[object_store_id] = object_store;
473 }
474
475 void IndexedDBDatabaseImpl::RemoveIndex(int64_t object_store_id,
476 int64_t index_id) {
477 DCHECK(metadata_.object_stores.find(object_store_id) !=
478 metadata_.object_stores.end());
479 IndexedDBObjectStoreMetadata object_store =
480 metadata_.object_stores[object_store_id];
481
482 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end());
483 object_store.indexes.erase(index_id);
484 metadata_.object_stores[object_store_id] = object_store;
485 }
486
487 bool IndexedDBDatabaseImpl::OpenInternal() {
488 bool success = false;
489 bool ok = backing_store_->GetIDBDatabaseMetaData(
490 metadata_.name, &metadata_, success);
491 DCHECK(success == (metadata_.id != InvalidId)) << "success = " << success
492 << " id_ = " << metadata_.id;
493 if (!ok)
494 return false;
495 if (success)
496 return backing_store_->GetObjectStores(metadata_.id,
497 &metadata_.object_stores);
498
499 return backing_store_->CreateIDBDatabaseMetaData(
500 metadata_.name, metadata_.version, metadata_.int_version, metadata_.id);
501 }
502
503 IndexedDBDatabaseImpl::~IndexedDBDatabaseImpl() {
504 DCHECK(transactions_.empty());
505 DCHECK(pending_open_calls_.empty());
506 DCHECK(pending_delete_calls_.empty());
507 }
508
509 scoped_refptr<IndexedDBBackingStore>
510 IndexedDBDatabaseImpl::BackingStore() const {
511 return backing_store_;
512 }
513
514 void IndexedDBDatabaseImpl::CreateObjectStore(int64_t transaction_id,
515 int64_t object_store_id,
516 const string16& name,
517 const IndexedDBKeyPath& key_path,
518 bool auto_increment) {
519 IDB_TRACE("IndexedDBDatabaseImpl::create_object_store");
520 TransactionMap::const_iterator trans_iterator =
521 transactions_.find(transaction_id);
522 if (trans_iterator == transactions_.end())
523 return;
524 IndexedDBTransaction* transaction = trans_iterator->second;
525 DCHECK(transaction->mode() == IndexedDB::TransactionVersionChange);
526
527 DCHECK(metadata_.object_stores.find(object_store_id) ==
528 metadata_.object_stores.end());
529 IndexedDBObjectStoreMetadata object_store_metadata(
530 name,
531 object_store_id,
532 key_path,
533 auto_increment,
534 IndexedDBDatabase::MinimumIndexId);
535
536 transaction->ScheduleTask(
537 new CreateObjectStoreOperation(backing_store_, object_store_metadata),
538 new CreateObjectStoreAbortOperation(this, object_store_id));
539
540 AddObjectStore(object_store_metadata, object_store_id);
541 }
542
543 void CreateObjectStoreOperation::Perform(IndexedDBTransaction* transaction) {
544 IDB_TRACE("CreateObjectStoreOperation");
545 if (!backing_store_->CreateObjectStore(
546 transaction->BackingStoreTransaction(),
547 transaction->database()->id(),
548 object_store_metadata_.id,
549 object_store_metadata_.name,
550 object_store_metadata_.key_path,
551 object_store_metadata_.auto_increment)) {
552 string16 error_string =
553 ASCIIToUTF16("Internal error creating object store '") +
554 object_store_metadata_.name + ASCIIToUTF16("'.");
555
556 scoped_refptr<IndexedDBDatabaseError> error =
557 IndexedDBDatabaseError::Create(
558 WebKit::WebIDBDatabaseExceptionUnknownError, error_string);
559 transaction->Abort(error);
560 return;
561 }
562 }
563
564 void IndexedDBDatabaseImpl::DeleteObjectStore(int64_t transaction_id,
565 int64_t object_store_id) {
566 IDB_TRACE("IndexedDBDatabaseImpl::delete_object_store");
567 TransactionMap::const_iterator trans_iterator =
568 transactions_.find(transaction_id);
569 if (trans_iterator == transactions_.end())
570 return;
571 IndexedDBTransaction* transaction = trans_iterator->second;
572 DCHECK(transaction->mode() == IndexedDB::TransactionVersionChange);
573
574 DCHECK(metadata_.object_stores.find(object_store_id) !=
575 metadata_.object_stores.end());
576 const IndexedDBObjectStoreMetadata& object_store_metadata =
577 metadata_.object_stores[object_store_id];
578
579 transaction->ScheduleTask(
580 new DeleteObjectStoreOperation(backing_store_, object_store_metadata),
581 new DeleteObjectStoreAbortOperation(this, object_store_metadata));
582 RemoveObjectStore(object_store_id);
583 }
584
585 void IndexedDBDatabaseImpl::CreateIndex(int64_t transaction_id,
586 int64_t object_store_id,
587 int64_t index_id,
588 const string16& name,
589 const IndexedDBKeyPath& key_path,
590 bool unique,
591 bool multi_entry) {
592 IDB_TRACE("IndexedDBDatabaseImpl::create_index");
593 TransactionMap::const_iterator trans_iterator =
594 transactions_.find(transaction_id);
595 if (trans_iterator == transactions_.end())
596 return;
597 IndexedDBTransaction* transaction = trans_iterator->second;
598 DCHECK(transaction->mode() == IndexedDB::TransactionVersionChange);
599
600 DCHECK(metadata_.object_stores.find(object_store_id) !=
601 metadata_.object_stores.end());
602 const IndexedDBObjectStoreMetadata object_store =
603 metadata_.object_stores[object_store_id];
604
605 DCHECK(object_store.indexes.find(index_id) == object_store.indexes.end());
606 const IndexedDBIndexMetadata index_metadata(
607 name, index_id, key_path, unique, multi_entry);
608
609 transaction->ScheduleTask(
610 new CreateIndexOperation(backing_store_, object_store_id, index_metadata),
611 new CreateIndexAbortOperation(this, object_store_id, index_id));
612
613 AddIndex(object_store_id, index_metadata, index_id);
614 }
615
616 void CreateIndexOperation::Perform(IndexedDBTransaction* transaction) {
617 IDB_TRACE("CreateIndexOperation");
618 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(),
619 transaction->database()->id(),
620 object_store_id_,
621 index_metadata_.id,
622 index_metadata_.name,
623 index_metadata_.key_path,
624 index_metadata_.unique,
625 index_metadata_.multi_entry)) {
626 string16 error_string = ASCIIToUTF16("Internal error creating index '") +
627 index_metadata_.name + ASCIIToUTF16("'.");
628 transaction->Abort(IndexedDBDatabaseError::Create(
629 WebKit::WebIDBDatabaseExceptionUnknownError, error_string));
630 return;
631 }
632 }
633
634 void CreateIndexAbortOperation::Perform(IndexedDBTransaction* transaction) {
635 IDB_TRACE("CreateIndexAbortOperation");
636 DCHECK(!transaction);
637 database_->RemoveIndex(object_store_id_, index_id_);
638 }
639
640 void IndexedDBDatabaseImpl::DeleteIndex(int64_t transaction_id,
641 int64_t object_store_id,
642 int64_t index_id) {
643 IDB_TRACE("IndexedDBDatabaseImpl::delete_index");
644 TransactionMap::const_iterator trans_iterator =
645 transactions_.find(transaction_id);
646 if (trans_iterator == transactions_.end())
647 return;
648 IndexedDBTransaction* transaction = trans_iterator->second;
649 DCHECK(transaction->mode() == IndexedDB::TransactionVersionChange);
650
651 DCHECK(metadata_.object_stores.find(object_store_id) !=
652 metadata_.object_stores.end());
653 IndexedDBObjectStoreMetadata object_store =
654 metadata_.object_stores[object_store_id];
655
656 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end());
657 const IndexedDBIndexMetadata& index_metadata = object_store.indexes[index_id];
658
659 transaction->ScheduleTask(
660 new DeleteIndexOperation(backing_store_, object_store_id, index_metadata),
661 new DeleteIndexAbortOperation(this, object_store_id, index_metadata));
662
663 RemoveIndex(object_store_id, index_id);
664 }
665
666 void DeleteIndexOperation::Perform(IndexedDBTransaction* transaction) {
667 IDB_TRACE("DeleteIndexOperation");
668 bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(),
669 transaction->database()->id(),
670 object_store_id_,
671 index_metadata_.id);
672 if (!ok) {
673 string16 error_string = ASCIIToUTF16("Internal error deleting index '") +
674 index_metadata_.name + ASCIIToUTF16("'.");
675 scoped_refptr<IndexedDBDatabaseError> error =
676 IndexedDBDatabaseError::Create(
677 WebKit::WebIDBDatabaseExceptionUnknownError, error_string);
678 transaction->Abort(error);
679 }
680 }
681
682 void DeleteIndexAbortOperation::Perform(IndexedDBTransaction* transaction) {
683 IDB_TRACE("DeleteIndexAbortOperation");
684 DCHECK(!transaction);
685 database_->AddIndex(
686 object_store_id_, index_metadata_, IndexedDBIndexMetadata::InvalidId);
687 }
688
689 void IndexedDBDatabaseImpl::Commit(int64_t transaction_id) {
690 // The frontend suggests that we commit, but we may have previously initiated
691 // an abort, and so have disposed of the transaction. on_abort has already
692 // been dispatched to the frontend, so it will find out about that
693 // asynchronously.
694 if (transactions_.find(transaction_id) != transactions_.end())
695 transactions_[transaction_id]->Commit();
696 }
697
698 void IndexedDBDatabaseImpl::Abort(int64_t transaction_id) {
699 // If the transaction is unknown, then it has already been aborted by the
700 // backend before this call so it is safe to ignore it.
701 if (transactions_.find(transaction_id) != transactions_.end())
702 transactions_[transaction_id]->Abort();
703 }
704
705 void IndexedDBDatabaseImpl::Abort(int64_t transaction_id,
706 scoped_refptr<IndexedDBDatabaseError> error) {
707 // If the transaction is unknown, then it has already been aborted by the
708 // backend before this call so it is safe to ignore it.
709 if (transactions_.find(transaction_id) != transactions_.end())
710 transactions_[transaction_id]->Abort(error);
711 }
712
713 void IndexedDBDatabaseImpl::Get(
714 int64_t transaction_id,
715 int64_t object_store_id,
716 int64_t index_id,
717 scoped_ptr<IndexedDBKeyRange> key_range,
718 bool key_only,
719 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
720 IDB_TRACE("IndexedDBDatabaseImpl::get");
721 TransactionMap::const_iterator trans_iterator =
722 transactions_.find(transaction_id);
723 if (trans_iterator == transactions_.end())
724 return;
725 IndexedDBTransaction* transaction = trans_iterator->second;
726
727 transaction->ScheduleTask(new GetOperation(
728 backing_store_,
729 metadata_,
730 object_store_id,
731 index_id,
732 key_range.Pass(),
733 key_only ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue,
734 callbacks));
735 }
736
737 void GetOperation::Perform(IndexedDBTransaction* transaction) {
738 IDB_TRACE("GetOperation");
739
740 const IndexedDBKey* key;
741
742 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
743 if (key_range_->IsOnlyKey()) {
744 key = &key_range_->lower();
745 } else {
746 if (index_id_ == IndexedDBIndexMetadata::InvalidId) {
747 DCHECK(cursor_type_ != IndexedDB::CursorKeyOnly);
748 // ObjectStore Retrieval Operation
749 backing_store_cursor = backing_store_->OpenObjectStoreCursor(
750 transaction->BackingStoreTransaction(),
751 database_id_,
752 object_store_id_,
753 *key_range_,
754 IndexedDB::CursorNext);
755 } else if (cursor_type_ == IndexedDB::CursorKeyOnly) {
756 // Index Value Retrieval Operation
757 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
758 transaction->BackingStoreTransaction(),
759 database_id_,
760 object_store_id_,
761 index_id_,
762 *key_range_,
763 IndexedDB::CursorNext);
764 } else {
765 // Index Referenced Value Retrieval Operation
766 backing_store_cursor = backing_store_->OpenIndexCursor(
767 transaction->BackingStoreTransaction(),
768 database_id_,
769 object_store_id_,
770 index_id_,
771 *key_range_,
772 IndexedDB::CursorNext);
773 }
774
775 if (!backing_store_cursor) {
776 callbacks_->OnSuccess();
777 return;
778 }
779
780 key = &backing_store_cursor->key();
781 }
782
783 scoped_ptr<IndexedDBKey> primary_key;
784 bool ok;
785 if (index_id_ == IndexedDBIndexMetadata::InvalidId) {
786 // Object Store Retrieval Operation
787 std::vector<char> value;
788 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
789 database_id_,
790 object_store_id_,
791 *key,
792 value);
793 if (!ok) {
794 callbacks_->OnError(IndexedDBDatabaseError::Create(
795 WebKit::WebIDBDatabaseExceptionUnknownError,
796 ASCIIToUTF16("Internal error in get_record.")));
797 return;
798 }
799
800 if (value.empty()) {
801 callbacks_->OnSuccess();
802 return;
803 }
804
805 if (auto_increment_ && !key_path_.IsNull()) {
806 callbacks_->OnSuccess(&value, *key, key_path_);
807 return;
808 }
809
810 callbacks_->OnSuccess(&value);
811 return;
812
813 }
814
815 // From here we are dealing only with indexes.
816 ok = backing_store_->GetPrimaryKeyViaIndex(
817 transaction->BackingStoreTransaction(),
818 database_id_,
819 object_store_id_,
820 index_id_,
821 *key,
822 &primary_key);
823 if (!ok) {
824 callbacks_->OnError(IndexedDBDatabaseError::Create(
825 WebKit::WebIDBDatabaseExceptionUnknownError,
826 ASCIIToUTF16("Internal error in get_primary_key_via_index.")));
827 return;
828 }
829 if (!primary_key) {
830 callbacks_->OnSuccess();
831 return;
832 }
833 if (cursor_type_ == IndexedDB::CursorKeyOnly) {
834 // Index Value Retrieval Operation
835 callbacks_->OnSuccess(*primary_key);
836 return;
837 }
838
839 // Index Referenced Value Retrieval Operation
840 std::vector<char> value;
841 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
842 database_id_,
843 object_store_id_,
844 *primary_key,
845 value);
846 if (!ok) {
847 callbacks_->OnError(IndexedDBDatabaseError::Create(
848 WebKit::WebIDBDatabaseExceptionUnknownError,
849 ASCIIToUTF16("Internal error in get_record.")));
850 return;
851 }
852
853 if (value.empty()) {
854 callbacks_->OnSuccess();
855 return;
856 }
857 if (auto_increment_ && !key_path_.IsNull()) {
858 callbacks_->OnSuccess(&value, *primary_key, key_path_);
859 return;
860 }
861 callbacks_->OnSuccess(&value);
862 }
863
864 static scoped_ptr<IndexedDBKey> GenerateKey(
865 scoped_refptr<IndexedDBBackingStore> backing_store,
866 scoped_refptr<IndexedDBTransaction> transaction,
867 int64_t database_id,
868 int64_t object_store_id) {
869 const int64_t max_generator_value =
870 9007199254740992LL; // Maximum integer storable as ECMAScript number.
871 int64_t current_number;
872 bool ok = backing_store->GetKeyGeneratorCurrentNumber(
873 transaction->BackingStoreTransaction(),
874 database_id,
875 object_store_id,
876 current_number);
877 if (!ok) {
878 LOG(ERROR) << "Failed to get_key_generator_current_number";
879 return make_scoped_ptr(new IndexedDBKey());
880 }
881 if (current_number < 0 || current_number > max_generator_value)
882 return make_scoped_ptr(new IndexedDBKey());
883
884 return make_scoped_ptr(
885 new IndexedDBKey(current_number, WebIDBKey::NumberType));
886 }
887
888 static bool UpdateKeyGenerator(
889 scoped_refptr<IndexedDBBackingStore> backing_store,
890 scoped_refptr<IndexedDBTransaction> transaction,
891 int64_t database_id,
892 int64_t object_store_id,
893 const IndexedDBKey* key,
894 bool check_current) {
895 DCHECK(key && key->type() == WebIDBKey::NumberType);
896 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber(
897 transaction->BackingStoreTransaction(),
898 database_id,
899 object_store_id,
900 static_cast<int64_t>(floor(key->number())) + 1,
901 check_current);
902 }
903
904 void IndexedDBDatabaseImpl::Put(
905 int64_t transaction_id,
906 int64_t object_store_id,
907 std::vector<char>* value,
908 scoped_ptr<IndexedDBKey> key,
909 PutMode put_mode,
910 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
911 const std::vector<int64_t>& index_ids,
912 const std::vector<IndexKeys>& index_keys) {
913 IDB_TRACE("IndexedDBDatabaseImpl::put");
914 TransactionMap::const_iterator trans_iterator =
915 transactions_.find(transaction_id);
916 if (trans_iterator == transactions_.end())
917 return;
918 IndexedDBTransaction* transaction = trans_iterator->second;
919 DCHECK(transaction->mode() != IndexedDB::TransactionReadOnly);
920
921 const IndexedDBObjectStoreMetadata object_store_metadata =
922 metadata_.object_stores[object_store_id];
923
924 DCHECK(key);
925 DCHECK(object_store_metadata.auto_increment || key->IsValid());
926 transaction->ScheduleTask(new PutOperation(backing_store_,
927 id(),
928 object_store_metadata,
929 value,
930 key.Pass(),
931 put_mode,
932 callbacks,
933 index_ids,
934 index_keys));
935 }
936
937 void PutOperation::Perform(IndexedDBTransaction* transaction) {
938 IDB_TRACE("PutOperation");
939 DCHECK(transaction->mode() != IndexedDB::TransactionReadOnly);
940 DCHECK(index_ids_.size() == index_keys_.size());
941 bool key_was_generated = false;
942
943 scoped_ptr<IndexedDBKey> key;
944 if (put_mode_ != IndexedDBDatabase::CursorUpdate &&
945 object_store_.auto_increment && !key_->IsValid()) {
946 scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey(
947 backing_store_, transaction, database_id_, object_store_.id);
948 key_was_generated = true;
949 if (!auto_inc_key->IsValid()) {
950 callbacks_->OnError(IndexedDBDatabaseError::Create(
951 WebKit::WebIDBDatabaseExceptionConstraintError,
952 ASCIIToUTF16("Maximum key generator value reached.")));
953 return;
954 }
955 key = auto_inc_key.Pass();
956 } else
957 key = key_.Pass();
958
959 DCHECK(key->IsValid());
960
961 IndexedDBBackingStore::RecordIdentifier record_identifier;
962 if (put_mode_ == IndexedDBDatabase::AddOnly) {
963 bool found = false;
964 bool ok = backing_store_->KeyExistsInObjectStore(
965 transaction->BackingStoreTransaction(),
966 database_id_,
967 object_store_.id,
968 *key.get(),
969 &record_identifier,
970 found);
971 if (!ok) {
972 callbacks_->OnError(IndexedDBDatabaseError::Create(
973 WebKit::WebIDBDatabaseExceptionUnknownError,
974 ASCIIToUTF16("Internal error checking key existence.")));
975 return;
976 }
977 if (found) {
978 callbacks_->OnError(IndexedDBDatabaseError::Create(
979 WebKit::WebIDBDatabaseExceptionConstraintError,
980 ASCIIToUTF16("Key already exists in the object store.")));
981 return;
982 }
983 }
984
985 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers;
986 string16 error_message;
987 bool obeys_constraints = false;
988 bool backing_store_success =
989 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction,
990 backing_store_.get(),
991 database_id_,
992 object_store_,
993 *key,
994 key_was_generated,
995 index_ids_,
996 index_keys_,
997 &index_writers,
998 &error_message,
999 &obeys_constraints);
1000 if (!backing_store_success) {
1001 callbacks_->OnError(IndexedDBDatabaseError::Create(
1002 WebKit::WebIDBDatabaseExceptionUnknownError,
1003 ASCIIToUTF16(
1004 "Internal error: backing store error updating index keys.")));
1005 return;
1006 }
1007 if (!obeys_constraints) {
1008 callbacks_->OnError(IndexedDBDatabaseError::Create(
1009 WebKit::WebIDBDatabaseExceptionConstraintError, error_message));
1010 return;
1011 }
1012
1013 // Before this point, don't do any mutation. After this point, rollback the
1014 // transaction in case of error.
1015 backing_store_success =
1016 backing_store_->PutRecord(transaction->BackingStoreTransaction(),
1017 database_id_,
1018 object_store_.id,
1019 *key.get(),
1020 value_,
1021 &record_identifier);
1022 if (!backing_store_success) {
1023 callbacks_->OnError(IndexedDBDatabaseError::Create(
1024 WebKit::WebIDBDatabaseExceptionUnknownError,
1025 ASCIIToUTF16(
1026 "Internal error: backing store error performing put/add.")));
1027 return;
1028 }
1029
1030 for (size_t i = 0; i < index_writers.size(); ++i) {
1031 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i];
1032 index_writer->WriteIndexKeys(record_identifier,
1033 backing_store_,
1034 transaction->BackingStoreTransaction(),
1035 database_id_,
1036 object_store_.id);
1037 }
1038
1039 if (object_store_.auto_increment &&
1040 put_mode_ != IndexedDBDatabase::CursorUpdate &&
1041 key->type() == WebIDBKey::NumberType) {
1042 bool ok = UpdateKeyGenerator(backing_store_,
1043 transaction,
1044 database_id_,
1045 object_store_.id,
1046 key.get(),
1047 !key_was_generated);
1048 if (!ok) {
1049 callbacks_->OnError(IndexedDBDatabaseError::Create(
1050 WebKit::WebIDBDatabaseExceptionUnknownError,
1051 ASCIIToUTF16("Internal error updating key generator.")));
1052 return;
1053 }
1054 }
1055
1056 callbacks_->OnSuccess(*key);
1057 }
1058
1059 void IndexedDBDatabaseImpl::SetIndexKeys(
1060 int64_t transaction_id,
1061 int64_t object_store_id,
1062 scoped_ptr<IndexedDBKey> primary_key,
1063 const std::vector<int64_t>& index_ids,
1064 const std::vector<IndexKeys>& index_keys) {
1065 IDB_TRACE("IndexedDBDatabaseImpl::set_index_keys");
1066 TransactionMap::const_iterator trans_iterator =
1067 transactions_.find(transaction_id);
1068 if (trans_iterator == transactions_.end())
1069 return;
1070 IndexedDBTransaction* transaction = trans_iterator->second;
1071 DCHECK(transaction->mode() == IndexedDB::TransactionVersionChange);
1072
1073 scoped_refptr<IndexedDBBackingStore> store = BackingStore();
1074 // TODO: This method could be asynchronous, but we need to evaluate if it's
1075 // worth the extra complexity.
1076 IndexedDBBackingStore::RecordIdentifier record_identifier;
1077 bool found = false;
1078 bool ok =
1079 store->KeyExistsInObjectStore(transaction->BackingStoreTransaction(),
1080 metadata_.id,
1081 object_store_id,
1082 *primary_key,
1083 &record_identifier,
1084 found);
1085 if (!ok) {
1086 transaction->Abort(IndexedDBDatabaseError::Create(
1087 WebKit::WebIDBDatabaseExceptionUnknownError,
1088 ASCIIToUTF16("Internal error setting index keys.")));
1089 return;
1090 }
1091 if (!found) {
1092 scoped_refptr<IndexedDBDatabaseError> error =
1093 IndexedDBDatabaseError::Create(
1094 WebKit::WebIDBDatabaseExceptionUnknownError,
1095 ASCIIToUTF16(
1096 "Internal error setting index keys for object store."));
1097 transaction->Abort(error);
1098 return;
1099 }
1100
1101 ScopedVector<IndexedDBObjectStoreImpl::IndexWriter> index_writers;
1102 string16 error_message;
1103 bool obeys_constraints = false;
1104 DCHECK(metadata_.object_stores.find(object_store_id) !=
1105 metadata_.object_stores.end());
1106 const IndexedDBObjectStoreMetadata& object_store_metadata =
1107 metadata_.object_stores[object_store_id];
1108 bool backing_store_success =
1109 IndexedDBObjectStoreImpl::MakeIndexWriters(transaction,
1110 store.get(),
1111 id(),
1112 object_store_metadata,
1113 *primary_key,
1114 false,
1115 index_ids,
1116 index_keys,
1117 &index_writers,
1118 &error_message,
1119 &obeys_constraints);
1120 if (!backing_store_success) {
1121 transaction->Abort(IndexedDBDatabaseError::Create(
1122 WebKit::WebIDBDatabaseExceptionUnknownError,
1123 ASCIIToUTF16(
1124 "Internal error: backing store error updating index keys.")));
1125 return;
1126 }
1127 if (!obeys_constraints) {
1128 transaction->Abort(IndexedDBDatabaseError::Create(
1129 WebKit::WebIDBDatabaseExceptionConstraintError, error_message));
1130 return;
1131 }
1132
1133 for (size_t i = 0; i < index_writers.size(); ++i) {
1134 IndexedDBObjectStoreImpl::IndexWriter* index_writer = index_writers[i];
1135 index_writer->WriteIndexKeys(record_identifier,
1136 store.get(),
1137 transaction->BackingStoreTransaction(),
1138 id(),
1139 object_store_id);
1140 }
1141 }
1142
1143 void IndexedDBDatabaseImpl::SetIndexesReady(
1144 int64_t transaction_id,
1145 int64_t,
1146 const std::vector<int64_t>& index_ids) {
1147 IDB_TRACE("IndexedDBObjectStoreImpl::set_indexes_ready");
1148
1149 TransactionMap::const_iterator trans_iterator =
1150 transactions_.find(transaction_id);
1151 if (trans_iterator == transactions_.end())
1152 return;
1153 IndexedDBTransaction* transaction = trans_iterator->second;
1154
1155 transaction->ScheduleTask(IndexedDBDatabase::PreemptiveTask,
1156 new SetIndexesReadyOperation(index_ids.size()));
1157 }
1158
1159 void SetIndexesReadyOperation::Perform(IndexedDBTransaction* transaction) {
1160 IDB_TRACE("SetIndexesReadyOperation");
1161 for (size_t i = 0; i < index_count_; ++i)
1162 transaction->DidCompletePreemptiveEvent();
1163 }
1164
1165 void IndexedDBDatabaseImpl::OpenCursor(
1166 int64_t transaction_id,
1167 int64_t object_store_id,
1168 int64_t index_id,
1169 scoped_ptr<IndexedDBKeyRange> key_range,
1170 IndexedDB::CursorDirection direction,
1171 bool key_only,
1172 TaskType task_type,
1173 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1174 IDB_TRACE("IndexedDBDatabaseImpl::open_cursor");
1175 TransactionMap::const_iterator trans_iterator =
1176 transactions_.find(transaction_id);
1177 if (trans_iterator == transactions_.end())
1178 return;
1179 IndexedDBTransaction* transaction = trans_iterator->second;
1180
1181 transaction->ScheduleTask(new OpenCursorOperation(
1182 backing_store_,
1183 id(),
1184 object_store_id,
1185 index_id,
1186 key_range.Pass(),
1187 direction,
1188 key_only ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue,
1189 task_type,
1190 callbacks));
1191 }
1192
1193 void OpenCursorOperation::Perform(IndexedDBTransaction* transaction) {
1194 IDB_TRACE("OpenCursorOperation");
1195
1196 // The frontend has begun indexing, so this pauses the transaction
1197 // until the indexing is complete. This can't happen any earlier
1198 // because we don't want to switch to early mode in case multiple
1199 // indexes are being created in a row, with Put()'s in between.
1200 if (task_type_ == IndexedDBDatabase::PreemptiveTask)
1201 transaction->AddPreemptiveEvent();
1202
1203 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
1204 if (index_id_ == IndexedDBIndexMetadata::InvalidId) {
1205 DCHECK(cursor_type_ != IndexedDB::CursorKeyOnly);
1206 backing_store_cursor = backing_store_->OpenObjectStoreCursor(
1207 transaction->BackingStoreTransaction(),
1208 database_id_,
1209 object_store_id_,
1210 *key_range_,
1211 direction_);
1212 } else {
1213 DCHECK(task_type_ == IndexedDBDatabase::NormalTask);
1214 if (cursor_type_ == IndexedDB::CursorKeyOnly) {
1215 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
1216 transaction->BackingStoreTransaction(),
1217 database_id_,
1218 object_store_id_,
1219 index_id_,
1220 *key_range_,
1221 direction_);
1222 } else {
1223 backing_store_cursor = backing_store_->OpenIndexCursor(
1224 transaction->BackingStoreTransaction(),
1225 database_id_,
1226 object_store_id_,
1227 index_id_,
1228 *key_range_,
1229 direction_);
1230 }
1231 }
1232
1233 if (!backing_store_cursor) {
1234 callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
1235 return;
1236 }
1237
1238 IndexedDBDatabase::TaskType task_type(
1239 static_cast<IndexedDBDatabase::TaskType>(task_type_));
1240 scoped_refptr<IndexedDBCursorImpl> cursor =
1241 IndexedDBCursorImpl::Create(backing_store_cursor.Pass(),
1242 cursor_type_,
1243 task_type,
1244 transaction,
1245 object_store_id_);
1246 callbacks_->OnSuccess(
1247 cursor, cursor->key(), cursor->primary_key(), cursor->Value());
1248 }
1249
1250 void IndexedDBDatabaseImpl::Count(
1251 int64_t transaction_id,
1252 int64_t object_store_id,
1253 int64_t index_id,
1254 scoped_ptr<IndexedDBKeyRange> key_range,
1255 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1256 IDB_TRACE("IndexedDBDatabaseImpl::count");
1257 TransactionMap::const_iterator trans_iterator =
1258 transactions_.find(transaction_id);
1259 if (trans_iterator == transactions_.end())
1260 return;
1261 IndexedDBTransaction* transaction = trans_iterator->second;
1262
1263 DCHECK(metadata_.object_stores.find(object_store_id) !=
1264 metadata_.object_stores.end());
1265 transaction->ScheduleTask(new CountOperation(backing_store_,
1266 id(),
1267 object_store_id,
1268 index_id,
1269 key_range.Pass(),
1270 callbacks));
1271 }
1272
1273 void CountOperation::Perform(IndexedDBTransaction* transaction) {
1274 IDB_TRACE("CountOperation");
1275 uint32_t count = 0;
1276 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
1277
1278 if (index_id_ == IndexedDBIndexMetadata::InvalidId) {
1279 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
1280 transaction->BackingStoreTransaction(),
1281 database_id_,
1282 object_store_id_,
1283 *key_range_,
1284 IndexedDB::CursorNext);
1285 } else {
1286 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
1287 transaction->BackingStoreTransaction(),
1288 database_id_,
1289 object_store_id_,
1290 index_id_,
1291 *key_range_,
1292 IndexedDB::CursorNext);
1293 }
1294 if (!backing_store_cursor) {
1295 callbacks_->OnSuccess(count);
1296 return;
1297 }
1298
1299 do {
1300 ++count;
1301 } while (backing_store_cursor->ContinueFunction(0));
1302
1303 callbacks_->OnSuccess(count);
1304 }
1305
1306 void IndexedDBDatabaseImpl::DeleteRange(
1307 int64_t transaction_id,
1308 int64_t object_store_id,
1309 scoped_ptr<IndexedDBKeyRange> key_range,
1310 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1311 IDB_TRACE("IndexedDBDatabaseImpl::delete_range");
1312 TransactionMap::const_iterator trans_iterator =
1313 transactions_.find(transaction_id);
1314 if (trans_iterator == transactions_.end())
1315 return;
1316 IndexedDBTransaction* transaction = trans_iterator->second;
1317
1318 transaction->ScheduleTask(new DeleteRangeOperation(
1319 backing_store_, id(), object_store_id, key_range.Pass(), callbacks));
1320 }
1321
1322 void DeleteRangeOperation::Perform(IndexedDBTransaction* transaction) {
1323 IDB_TRACE("DeleteRangeOperation");
1324 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor =
1325 backing_store_->OpenObjectStoreCursor(
1326 transaction->BackingStoreTransaction(),
1327 database_id_,
1328 object_store_id_,
1329 *key_range_,
1330 IndexedDB::CursorNext);
1331 if (backing_store_cursor) {
1332 do {
1333 if (!backing_store_->DeleteRecord(
1334 transaction->BackingStoreTransaction(),
1335 database_id_,
1336 object_store_id_,
1337 backing_store_cursor->record_identifier())) {
1338 callbacks_->OnError(IndexedDBDatabaseError::Create(
1339 WebKit::WebIDBDatabaseExceptionUnknownError,
1340 ASCIIToUTF16("Internal error deleting data in range")));
1341 return;
1342 }
1343 } while (backing_store_cursor->ContinueFunction(0));
1344 }
1345
1346 callbacks_->OnSuccess();
1347 }
1348
1349 void IndexedDBDatabaseImpl::Clear(
1350 int64_t transaction_id,
1351 int64_t object_store_id,
1352 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1353 IDB_TRACE("IndexedDBDatabaseImpl::clear");
1354 TransactionMap::const_iterator trans_iterator =
1355 transactions_.find(transaction_id);
1356 if (trans_iterator == transactions_.end())
1357 return;
1358 IndexedDBTransaction* transaction = trans_iterator->second;
1359 DCHECK(transaction->mode() != IndexedDB::TransactionReadOnly);
1360
1361 transaction->ScheduleTask(
1362 new ClearOperation(backing_store_, id(), object_store_id, callbacks));
1363 }
1364
1365 void ClearOperation::Perform(IndexedDBTransaction* transaction) {
1366 IDB_TRACE("ObjectStoreClearOperation");
1367 if (!backing_store_->ClearObjectStore(transaction->BackingStoreTransaction(),
1368 database_id_,
1369 object_store_id_)) {
1370 callbacks_->OnError(IndexedDBDatabaseError::Create(
1371 WebKit::WebIDBDatabaseExceptionUnknownError,
1372 ASCIIToUTF16("Internal error clearing object store")));
1373 return;
1374 }
1375 callbacks_->OnSuccess();
1376 }
1377
1378 void DeleteObjectStoreOperation::Perform(IndexedDBTransaction* transaction) {
1379 IDB_TRACE("DeleteObjectStoreOperation");
1380 bool ok =
1381 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(),
1382 transaction->database()->id(),
1383 object_store_metadata_.id);
1384 if (!ok) {
1385 string16 error_string =
1386 ASCIIToUTF16("Internal error deleting object store '") +
1387 object_store_metadata_.name + ASCIIToUTF16("'.");
1388 scoped_refptr<IndexedDBDatabaseError> error =
1389 IndexedDBDatabaseError::Create(
1390 WebKit::WebIDBDatabaseExceptionUnknownError, error_string);
1391 transaction->Abort(error);
1392 }
1393 }
1394
1395 void IndexedDBDatabaseImpl::VersionChangeOperation::Perform(
1396 IndexedDBTransaction* transaction) {
1397 IDB_TRACE("VersionChangeOperation");
1398 int64_t database_id = database_->id();
1399 int64_t old_version = database_->metadata_.int_version;
1400 DCHECK(version_ > old_version);
1401 database_->metadata_.int_version = version_;
1402 if (!database_->backing_store_->UpdateIDBDatabaseIntVersion(
1403 transaction->BackingStoreTransaction(),
1404 database_id,
1405 database_->metadata_.int_version)) {
1406 scoped_refptr<IndexedDBDatabaseError> error =
1407 IndexedDBDatabaseError::Create(
1408 WebKit::WebIDBDatabaseExceptionUnknownError,
1409 ASCIIToUTF16("Internal error writing data to stable storage when "
1410 "updating version."));
1411 callbacks_->OnError(error);
1412 transaction->Abort(error);
1413 return;
1414 }
1415 DCHECK(!database_->pending_second_half_open_);
1416 database_->pending_second_half_open_.reset(new PendingOpenCall(
1417 callbacks_, database_callbacks_, transaction_id_, version_));
1418 callbacks_->OnUpgradeNeeded(old_version, database_, database_->metadata());
1419 }
1420
1421 void IndexedDBDatabaseImpl::TransactionStarted(
1422 IndexedDBTransaction* transaction) {
1423
1424 if (transaction->mode() == IndexedDB::TransactionVersionChange) {
1425 DCHECK(!running_version_change_transaction_);
1426 running_version_change_transaction_ = transaction;
1427 }
1428 }
1429
1430 void IndexedDBDatabaseImpl::TransactionFinished(
1431 IndexedDBTransaction* transaction) {
1432
1433 DCHECK(transactions_.find(transaction->id()) != transactions_.end());
1434 DCHECK(transactions_[transaction->id()] == transaction);
1435 transactions_.erase(transaction->id());
1436 if (transaction->mode() == IndexedDB::TransactionVersionChange) {
1437 DCHECK(transaction == running_version_change_transaction_);
1438 running_version_change_transaction_ = NULL;
1439 }
1440 }
1441
1442 void IndexedDBDatabaseImpl::TransactionFinishedAndAbortFired(
1443 IndexedDBTransaction* transaction) {
1444 if (transaction->mode() == IndexedDB::TransactionVersionChange) {
1445 if (pending_second_half_open_) {
1446 pending_second_half_open_->Callbacks()
1447 ->OnError(IndexedDBDatabaseError::Create(
1448 WebKit::WebIDBDatabaseExceptionAbortError,
1449 ASCIIToUTF16("Version change transaction was aborted in "
1450 "upgradeneeded event handler.")));
1451 pending_second_half_open_.reset();
1452 }
1453 ProcessPendingCalls();
1454 }
1455 }
1456
1457 void IndexedDBDatabaseImpl::TransactionFinishedAndCompleteFired(
1458 IndexedDBTransaction* transaction) {
1459 if (transaction->mode() == IndexedDB::TransactionVersionChange) {
1460 DCHECK(pending_second_half_open_);
1461 if (pending_second_half_open_) {
1462 DCHECK(pending_second_half_open_->Version() == metadata_.int_version);
1463 DCHECK(metadata_.id != InvalidId);
1464 pending_second_half_open_->Callbacks()->OnSuccess(this, this->metadata());
1465 pending_second_half_open_.reset();
1466 }
1467 ProcessPendingCalls();
1468 }
1469 }
1470
1471 size_t IndexedDBDatabaseImpl::ConnectionCount() const {
1472 // This does not include pending open calls, as those should not block version
1473 // changes and deletes.
1474 return database_callbacks_set_.size();
1475 }
1476
1477 void IndexedDBDatabaseImpl::ProcessPendingCalls() {
1478 if (pending_second_half_open_) {
1479 DCHECK(pending_second_half_open_->Version() == metadata_.int_version);
1480 DCHECK(metadata_.id != InvalidId);
1481 scoped_ptr<PendingOpenCall> pending_call = pending_second_half_open_.Pass();
1482 pending_call->Callbacks()->OnSuccess(this, this->metadata());
1483 // Fall through when complete, as pending opens may be unblocked.
1484 }
1485
1486 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) {
1487 DCHECK(pending_run_version_change_transaction_call_->Version() >
1488 metadata_.int_version);
1489 scoped_ptr<PendingOpenCall> pending_call =
1490 pending_run_version_change_transaction_call_.Pass();
1491 RunVersionChangeTransactionFinal(pending_call->Callbacks(),
1492 pending_call->DatabaseCallbacks(),
1493 pending_call->TransactionId(),
1494 pending_call->Version());
1495 DCHECK(ConnectionCount() == 1);
1496 // Fall through would be a no-op, since transaction must complete
1497 // asynchronously.
1498 DCHECK(IsDeleteDatabaseBlocked());
1499 DCHECK(IsOpenConnectionBlocked());
1500 return;
1501 }
1502
1503 if (!IsDeleteDatabaseBlocked()) {
1504 PendingDeleteCallList pending_delete_calls;
1505 pending_delete_calls_.swap(pending_delete_calls);
1506 while (!pending_delete_calls.empty()) {
1507 // Only the first delete call will delete the database, but each must fire
1508 // callbacks.
1509 scoped_ptr<PendingDeleteCall> pending_delete_call(
1510 pending_delete_calls.front());
1511 pending_delete_calls.pop_front();
1512 DeleteDatabaseFinal(pending_delete_call->Callbacks());
1513 }
1514 // delete_database_final should never re-queue calls.
1515 DCHECK(pending_delete_calls_.empty());
1516 // Fall through when complete, as pending opens may be unblocked.
1517 }
1518
1519 if (!IsOpenConnectionBlocked()) {
1520 PendingOpenCallList pending_open_calls;
1521 pending_open_calls_.swap(pending_open_calls);
1522 while (!pending_open_calls.empty()) {
1523 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front());
1524 pending_open_calls.pop_front();
1525 OpenConnection(pending_open_call->Callbacks(),
1526 pending_open_call->DatabaseCallbacks(),
1527 pending_open_call->TransactionId(),
1528 pending_open_call->Version());
1529 }
1530 }
1531 }
1532
1533 void IndexedDBDatabaseImpl::CreateTransaction(
1534 int64_t transaction_id,
1535 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks,
1536 const std::vector<int64_t>& object_store_ids,
1537 unsigned short mode) {
1538
1539 DCHECK(database_callbacks_set_.has(callbacks));
1540
1541 scoped_refptr<IndexedDBTransaction> transaction =
1542 IndexedDBTransaction::Create(
1543 transaction_id,
1544 callbacks,
1545 object_store_ids,
1546 static_cast<IndexedDB::TransactionMode>(mode),
1547 this);
1548 DCHECK(transactions_.find(transaction_id) == transactions_.end());
1549 transactions_[transaction_id] = transaction;
1550 }
1551
1552 bool IndexedDBDatabaseImpl::IsOpenConnectionBlocked() const {
1553 return !pending_delete_calls_.empty() ||
1554 running_version_change_transaction_ ||
1555 pending_run_version_change_transaction_call_;
1556 }
1557
1558 void IndexedDBDatabaseImpl::OpenConnection(
1559 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
1560 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks,
1561 int64_t transaction_id,
1562 int64_t version) {
1563 DCHECK(backing_store_.get());
1564
1565 // TODO: Should have a priority queue so that higher version requests are
1566 // processed first. http://crbug.com/225850
1567 if (IsOpenConnectionBlocked()) {
1568 pending_open_calls_.push_back(new PendingOpenCall(
1569 callbacks, database_callbacks, transaction_id, version));
1570 return;
1571 }
1572
1573 if (metadata_.id == InvalidId) {
1574 // The database was deleted then immediately re-opened; OpenInternal()
1575 // recreates it in the backing store.
1576 if (OpenInternal()) {
1577 DCHECK(metadata_.int_version == IndexedDBDatabaseMetadata::NoIntVersion);
1578 } else {
1579 string16 message;
1580 scoped_refptr<IndexedDBDatabaseError> error;
1581 if (version == IndexedDBDatabaseMetadata::NoIntVersion)
1582 message = ASCIIToUTF16(
1583 "Internal error opening database with no version specified.");
1584 else
1585 message =
1586 ASCIIToUTF16("Internal error opening database with version ") +
1587 Int64ToString16(version);
1588 callbacks->OnError(IndexedDBDatabaseError::Create(
1589 WebKit::WebIDBDatabaseExceptionUnknownError, message));
1590 return;
1591 }
1592 }
1593
1594 // We infer that the database didn't exist from its lack of either type of
1595 // version.
1596 bool is_new_database =
1597 metadata_.version == kNoStringVersion &&
1598 metadata_.int_version == IndexedDBDatabaseMetadata::NoIntVersion;
1599
1600 if (version == IndexedDBDatabaseMetadata::DefaultIntVersion) {
1601 // For unit tests only - skip upgrade steps. Calling from script with
1602 // DefaultIntVersion throws exception.
1603 // TODO(jsbell): Assert that we're executing a unit test.
1604 DCHECK(is_new_database);
1605 database_callbacks_set_.insert(database_callbacks);
1606 callbacks->OnSuccess(this, this->metadata());
1607 return;
1608 }
1609
1610 if (version == IndexedDBDatabaseMetadata::NoIntVersion) {
1611 if (!is_new_database) {
1612 database_callbacks_set_.insert(database_callbacks);
1613 callbacks->OnSuccess(this, this->metadata());
1614 return;
1615 }
1616 // Spec says: If no version is specified and no database exists, set
1617 // database version to 1.
1618 version = 1;
1619 }
1620
1621 if (version > metadata_.int_version) {
1622 database_callbacks_set_.insert(database_callbacks);
1623 RunVersionChangeTransaction(
1624 callbacks, database_callbacks, transaction_id, version);
1625 return;
1626 }
1627 if (version < metadata_.int_version) {
1628 callbacks->OnError(IndexedDBDatabaseError::Create(
1629 WebKit::WebIDBDatabaseExceptionVersionError,
1630 ASCIIToUTF16("The requested version (") + Int64ToString16(version) +
1631 ASCIIToUTF16(") is less than the existing version (") +
1632 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(").")));
1633 return;
1634 }
1635 DCHECK(version == metadata_.int_version);
1636 database_callbacks_set_.insert(database_callbacks);
1637 callbacks->OnSuccess(this, this->metadata());
1638 }
1639
1640 void IndexedDBDatabaseImpl::RunVersionChangeTransaction(
1641 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
1642 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks,
1643 int64_t transaction_id,
1644 int64_t requested_version) {
1645
1646 DCHECK(callbacks);
1647 DCHECK(database_callbacks_set_.has(database_callbacks));
1648 if (ConnectionCount() > 1) {
1649 // Front end ensures the event is not fired at connections that have
1650 // close_pending set.
1651 for (DatabaseCallbacksSet::const_iterator it =
1652 database_callbacks_set_.begin();
1653 it != database_callbacks_set_.end();
1654 ++it) {
1655 if (*it != database_callbacks.get())
1656 (*it)->OnVersionChange(metadata_.int_version, requested_version);
1657 }
1658 // TODO: Remove the call to on_blocked and instead wait until the frontend
1659 // tells us that all the "versionchange" events have been delivered.
1660 // http://crbug.com/100123
1661 callbacks->OnBlocked(metadata_.int_version);
1662
1663 DCHECK(!pending_run_version_change_transaction_call_);
1664 pending_run_version_change_transaction_call_.reset(new PendingOpenCall(
1665 callbacks, database_callbacks, transaction_id, requested_version));
1666 return;
1667 }
1668 RunVersionChangeTransactionFinal(
1669 callbacks, database_callbacks, transaction_id, requested_version);
1670 }
1671
1672 void IndexedDBDatabaseImpl::RunVersionChangeTransactionFinal(
1673 scoped_refptr<IndexedDBCallbacksWrapper> callbacks,
1674 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> database_callbacks,
1675 int64_t transaction_id,
1676 int64_t requested_version) {
1677
1678 std::vector<int64_t> object_store_ids;
1679 CreateTransaction(transaction_id,
1680 database_callbacks,
1681 object_store_ids,
1682 IndexedDB::TransactionVersionChange);
1683 scoped_refptr<IndexedDBTransaction> transaction =
1684 transactions_[transaction_id];
1685
1686 transaction->ScheduleTask(
1687 new VersionChangeOperation(this,
1688 transaction_id,
1689 requested_version,
1690 callbacks,
1691 database_callbacks),
1692 new VersionChangeAbortOperation(
1693 this, metadata_.version, metadata_.int_version));
1694
1695 DCHECK(!pending_second_half_open_);
1696 }
1697
1698 void IndexedDBDatabaseImpl::DeleteDatabase(
1699 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1700
1701 if (IsDeleteDatabaseBlocked()) {
1702 for (DatabaseCallbacksSet::const_iterator it =
1703 database_callbacks_set_.begin();
1704 it != database_callbacks_set_.end();
1705 ++it) {
1706 // Front end ensures the event is not fired at connections that have
1707 // close_pending set.
1708 (*it)->OnVersionChange(metadata_.int_version,
1709 IndexedDBDatabaseMetadata::NoIntVersion);
1710 }
1711 // TODO: Only fire on_blocked if there are open connections after the
1712 // VersionChangeEvents are received, not just set up to fire.
1713 // http://crbug.com/100123
1714 callbacks->OnBlocked(metadata_.int_version);
1715 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
1716 return;
1717 }
1718 DeleteDatabaseFinal(callbacks);
1719 }
1720
1721 bool IndexedDBDatabaseImpl::IsDeleteDatabaseBlocked() const {
1722 return ConnectionCount();
1723 }
1724
1725 void IndexedDBDatabaseImpl::DeleteDatabaseFinal(
1726 scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
1727 DCHECK(!IsDeleteDatabaseBlocked());
1728 DCHECK(backing_store_);
1729 if (!backing_store_->DeleteDatabase(metadata_.name)) {
1730 callbacks->OnError(IndexedDBDatabaseError::Create(
1731 WebKit::WebIDBDatabaseExceptionUnknownError,
1732 ASCIIToUTF16("Internal error deleting database.")));
1733 return;
1734 }
1735 metadata_.version = kNoStringVersion;
1736 metadata_.id = InvalidId;
1737 metadata_.int_version = IndexedDBDatabaseMetadata::NoIntVersion;
1738 metadata_.object_stores.clear();
1739 callbacks->OnSuccess();
1740 }
1741
1742 void IndexedDBDatabaseImpl::Close(
1743 scoped_refptr<IndexedDBDatabaseCallbacksWrapper> callbacks) {
1744 DCHECK(callbacks);
1745 DCHECK(database_callbacks_set_.has(callbacks));
1746
1747 // Close outstanding transactions from the closing connection. This
1748 // can not happen if the close is requested by the connection itself
1749 // as the front-end defers the close until all transactions are
1750 // complete, so something unusual has happened e.g. unexpected
1751 // process termination.
1752 {
1753 TransactionMap transactions(transactions_);
1754 for (TransactionMap::const_iterator it = transactions.begin(),
1755 end = transactions.end();
1756 it != end;
1757 ++it) {
1758 if (it->second->connection() == callbacks)
1759 it->second->Abort(IndexedDBDatabaseError::Create(
1760 WebKit::WebIDBDatabaseExceptionUnknownError,
1761 ASCIIToUTF16("Connection is closing.")));
1762 }
1763 }
1764
1765 database_callbacks_set_.erase(callbacks);
1766 if (pending_second_half_open_ &&
1767 pending_second_half_open_->DatabaseCallbacks() == callbacks) {
1768 pending_second_half_open_->Callbacks()
1769 ->OnError(IndexedDBDatabaseError::Create(
1770 WebKit::WebIDBDatabaseExceptionAbortError,
1771 ASCIIToUTF16("The connection was closed.")));
1772 pending_second_half_open_.reset();
1773 }
1774
1775 // process_pending_calls allows the inspector to process a pending open call
1776 // and call close, reentering IndexedDBDatabaseImpl::close. Then the
1777 // backend would be removed both by the inspector closing its connection, and
1778 // by the connection that first called close.
1779 // To avoid that situation, don't proceed in case of reentrancy.
1780 if (closing_connection_)
1781 return;
1782 base::AutoReset<bool> ClosingConnection(&closing_connection_, true);
1783 ProcessPendingCalls();
1784
1785 // TODO: Add a test for the pending_open_calls_ cases below.
1786 if (!ConnectionCount() && !pending_open_calls_.size() &&
1787 !pending_delete_calls_.size()) {
1788 DCHECK(transactions_.empty());
1789
1790 backing_store_ = NULL;
1791
1792 // This check should only be false in unit tests.
1793 // TODO(jsbell): Assert factory_ || we're executing a unit test.
1794 if (factory_)
1795 factory_->RemoveIDBDatabaseBackend(identifier_);
1796 }
1797 }
1798
1799 void CreateObjectStoreAbortOperation::Perform(
1800 IndexedDBTransaction* transaction) {
1801 IDB_TRACE("CreateObjectStoreAbortOperation");
1802 DCHECK(!transaction);
1803 database_->RemoveObjectStore(object_store_id_);
1804 }
1805
1806 void DeleteObjectStoreAbortOperation::Perform(
1807 IndexedDBTransaction* transaction) {
1808 IDB_TRACE("DeleteObjectStoreAbortOperation");
1809 DCHECK(!transaction);
1810 database_->AddObjectStore(object_store_metadata_,
1811 IndexedDBObjectStoreMetadata::InvalidId);
1812 }
1813
1814 void IndexedDBDatabaseImpl::VersionChangeAbortOperation::Perform(
1815 IndexedDBTransaction* transaction) {
1816 IDB_TRACE("VersionChangeAbortOperation");
1817 DCHECK(!transaction);
1818 database_->metadata_.version = previous_version_;
1819 database_->metadata_.int_version = previous_int_version_;
1820 }
1821
1822 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698