Roll src/third_party/WebKit c63b89c:29324ab (svn 202546:202547)
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_database.cc
blob31d0e69224510ec3b28d2178b911f81455e67225
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.
5 #include "content/browser/indexed_db/indexed_db_database.h"
7 #include <math.h>
8 #include <limits>
9 #include <set>
11 #include "base/auto_reset.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "content/browser/indexed_db/indexed_db_blob_info.h"
20 #include "content/browser/indexed_db/indexed_db_class_factory.h"
21 #include "content/browser/indexed_db/indexed_db_connection.h"
22 #include "content/browser/indexed_db/indexed_db_context_impl.h"
23 #include "content/browser/indexed_db/indexed_db_cursor.h"
24 #include "content/browser/indexed_db/indexed_db_factory.h"
25 #include "content/browser/indexed_db/indexed_db_index_writer.h"
26 #include "content/browser/indexed_db/indexed_db_pending_connection.h"
27 #include "content/browser/indexed_db/indexed_db_return_value.h"
28 #include "content/browser/indexed_db/indexed_db_tracing.h"
29 #include "content/browser/indexed_db/indexed_db_transaction.h"
30 #include "content/browser/indexed_db/indexed_db_value.h"
31 #include "content/common/indexed_db/indexed_db_constants.h"
32 #include "content/common/indexed_db/indexed_db_key_path.h"
33 #include "content/common/indexed_db/indexed_db_key_range.h"
34 #include "storage/browser/blob/blob_data_handle.h"
35 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
36 #include "third_party/leveldatabase/env_chromium.h"
38 using base::ASCIIToUTF16;
39 using base::Int64ToString16;
40 using blink::WebIDBKeyTypeNumber;
42 namespace content {
44 namespace {
46 // Used for WebCore.IndexedDB.Schema.ObjectStore.KeyPathType and
47 // WebCore.IndexedDB.Schema.Index.KeyPathType histograms. Do not
48 // modify (delete, re-order, renumber) these values other than
49 // the _MAX value.
50 enum HistogramIDBKeyPathType {
51 KEY_PATH_TYPE_NONE = 0,
52 KEY_PATH_TYPE_STRING = 1,
53 KEY_PATH_TYPE_ARRAY = 2,
54 KEY_PATH_TYPE_MAX = 3, // Keep as last/max entry, for histogram range.
57 HistogramIDBKeyPathType HistogramKeyPathType(const IndexedDBKeyPath& key_path) {
58 switch (key_path.type()) {
59 case blink::WebIDBKeyPathTypeNull:
60 return KEY_PATH_TYPE_NONE;
61 case blink::WebIDBKeyPathTypeString:
62 return KEY_PATH_TYPE_STRING;
63 case blink::WebIDBKeyPathTypeArray:
64 return KEY_PATH_TYPE_ARRAY;
66 NOTREACHED();
67 return KEY_PATH_TYPE_NONE;
70 } // namespace
72 // PendingUpgradeCall has a scoped_ptr<IndexedDBConnection> because it owns the
73 // in-progress connection.
74 class IndexedDBDatabase::PendingUpgradeCall {
75 public:
76 PendingUpgradeCall(scoped_refptr<IndexedDBCallbacks> callbacks,
77 scoped_ptr<IndexedDBConnection> connection,
78 int64 transaction_id,
79 int64 version)
80 : callbacks_(callbacks),
81 connection_(connection.Pass()),
82 version_(version),
83 transaction_id_(transaction_id) {}
84 scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
85 // Takes ownership of the connection object.
86 scoped_ptr<IndexedDBConnection> ReleaseConnection() WARN_UNUSED_RESULT {
87 return connection_.Pass();
89 int64 version() const { return version_; }
90 int64 transaction_id() const { return transaction_id_; }
92 private:
93 scoped_refptr<IndexedDBCallbacks> callbacks_;
94 scoped_ptr<IndexedDBConnection> connection_;
95 int64 version_;
96 const int64 transaction_id_;
99 // PendingSuccessCall has a IndexedDBConnection* because the connection is now
100 // owned elsewhere, but we need to cancel the success call if that connection
101 // closes before it is sent.
102 class IndexedDBDatabase::PendingSuccessCall {
103 public:
104 PendingSuccessCall(scoped_refptr<IndexedDBCallbacks> callbacks,
105 IndexedDBConnection* connection,
106 int64 version)
107 : callbacks_(callbacks), connection_(connection), version_(version) {}
108 scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
109 IndexedDBConnection* connection() const { return connection_; }
110 int64 version() const { return version_; }
112 private:
113 scoped_refptr<IndexedDBCallbacks> callbacks_;
114 IndexedDBConnection* connection_;
115 int64 version_;
118 class IndexedDBDatabase::PendingDeleteCall {
119 public:
120 explicit PendingDeleteCall(scoped_refptr<IndexedDBCallbacks> callbacks)
121 : callbacks_(callbacks) {}
122 scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
124 private:
125 scoped_refptr<IndexedDBCallbacks> callbacks_;
128 scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create(
129 const base::string16& name,
130 IndexedDBBackingStore* backing_store,
131 IndexedDBFactory* factory,
132 const Identifier& unique_identifier,
133 leveldb::Status* s) {
134 scoped_refptr<IndexedDBDatabase> database =
135 IndexedDBClassFactory::Get()->CreateIndexedDBDatabase(
136 name, backing_store, factory, unique_identifier);
137 *s = database->OpenInternal();
138 if (s->ok())
139 return database;
140 else
141 return NULL;
144 namespace {
145 const base::string16::value_type kNoStringVersion[] = {0};
148 IndexedDBDatabase::IndexedDBDatabase(const base::string16& name,
149 IndexedDBBackingStore* backing_store,
150 IndexedDBFactory* factory,
151 const Identifier& unique_identifier)
152 : backing_store_(backing_store),
153 metadata_(name,
154 kInvalidId,
155 kNoStringVersion,
156 IndexedDBDatabaseMetadata::NO_INT_VERSION,
157 kInvalidId),
158 identifier_(unique_identifier),
159 factory_(factory) {
160 DCHECK(factory != NULL);
163 void IndexedDBDatabase::AddObjectStore(
164 const IndexedDBObjectStoreMetadata& object_store,
165 int64 new_max_object_store_id) {
166 DCHECK(metadata_.object_stores.find(object_store.id) ==
167 metadata_.object_stores.end());
168 if (new_max_object_store_id != IndexedDBObjectStoreMetadata::kInvalidId) {
169 DCHECK_LT(metadata_.max_object_store_id, new_max_object_store_id);
170 metadata_.max_object_store_id = new_max_object_store_id;
172 metadata_.object_stores[object_store.id] = object_store;
175 void IndexedDBDatabase::RemoveObjectStore(int64 object_store_id) {
176 DCHECK(metadata_.object_stores.find(object_store_id) !=
177 metadata_.object_stores.end());
178 metadata_.object_stores.erase(object_store_id);
181 void IndexedDBDatabase::AddIndex(int64 object_store_id,
182 const IndexedDBIndexMetadata& index,
183 int64 new_max_index_id) {
184 DCHECK(metadata_.object_stores.find(object_store_id) !=
185 metadata_.object_stores.end());
186 IndexedDBObjectStoreMetadata object_store =
187 metadata_.object_stores[object_store_id];
189 DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end());
190 object_store.indexes[index.id] = index;
191 if (new_max_index_id != IndexedDBIndexMetadata::kInvalidId) {
192 DCHECK_LT(object_store.max_index_id, new_max_index_id);
193 object_store.max_index_id = new_max_index_id;
195 metadata_.object_stores[object_store_id] = object_store;
198 void IndexedDBDatabase::RemoveIndex(int64 object_store_id, int64 index_id) {
199 DCHECK(metadata_.object_stores.find(object_store_id) !=
200 metadata_.object_stores.end());
201 IndexedDBObjectStoreMetadata object_store =
202 metadata_.object_stores[object_store_id];
204 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end());
205 object_store.indexes.erase(index_id);
206 metadata_.object_stores[object_store_id] = object_store;
209 leveldb::Status IndexedDBDatabase::OpenInternal() {
210 bool success = false;
211 leveldb::Status s = backing_store_->GetIDBDatabaseMetaData(
212 metadata_.name, &metadata_, &success);
213 DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success
214 << " id = " << metadata_.id;
215 if (!s.ok())
216 return s;
217 if (success)
218 return backing_store_->GetObjectStores(metadata_.id,
219 &metadata_.object_stores);
221 return backing_store_->CreateIDBDatabaseMetaData(
222 metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id);
225 IndexedDBDatabase::~IndexedDBDatabase() {
226 DCHECK(transactions_.empty());
227 DCHECK(pending_open_calls_.empty());
228 DCHECK(pending_delete_calls_.empty());
231 size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const {
232 return kMaxIDBMessageSizeInBytes;
235 scoped_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection(
236 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks,
237 int child_process_id) {
238 scoped_ptr<IndexedDBConnection> connection(
239 new IndexedDBConnection(this, database_callbacks));
240 connections_.insert(connection.get());
241 backing_store_->GrantChildProcessPermissions(child_process_id);
242 return connection.Pass();
245 IndexedDBTransaction* IndexedDBDatabase::GetTransaction(
246 int64 transaction_id) const {
247 TransactionMap::const_iterator trans_iterator =
248 transactions_.find(transaction_id);
249 if (trans_iterator == transactions_.end())
250 return NULL;
251 return trans_iterator->second;
254 bool IndexedDBDatabase::ValidateObjectStoreId(int64 object_store_id) const {
255 if (!ContainsKey(metadata_.object_stores, object_store_id)) {
256 DLOG(ERROR) << "Invalid object_store_id";
257 return false;
259 return true;
262 bool IndexedDBDatabase::ValidateObjectStoreIdAndIndexId(int64 object_store_id,
263 int64 index_id) const {
264 if (!ValidateObjectStoreId(object_store_id))
265 return false;
266 const IndexedDBObjectStoreMetadata& object_store_metadata =
267 metadata_.object_stores.find(object_store_id)->second;
268 if (!ContainsKey(object_store_metadata.indexes, index_id)) {
269 DLOG(ERROR) << "Invalid index_id";
270 return false;
272 return true;
275 bool IndexedDBDatabase::ValidateObjectStoreIdAndOptionalIndexId(
276 int64 object_store_id,
277 int64 index_id) const {
278 if (!ValidateObjectStoreId(object_store_id))
279 return false;
280 const IndexedDBObjectStoreMetadata& object_store_metadata =
281 metadata_.object_stores.find(object_store_id)->second;
282 if (index_id != IndexedDBIndexMetadata::kInvalidId &&
283 !ContainsKey(object_store_metadata.indexes, index_id)) {
284 DLOG(ERROR) << "Invalid index_id";
285 return false;
287 return true;
290 bool IndexedDBDatabase::ValidateObjectStoreIdAndNewIndexId(
291 int64 object_store_id,
292 int64 index_id) const {
293 if (!ValidateObjectStoreId(object_store_id))
294 return false;
295 const IndexedDBObjectStoreMetadata& object_store_metadata =
296 metadata_.object_stores.find(object_store_id)->second;
297 if (ContainsKey(object_store_metadata.indexes, index_id)) {
298 DLOG(ERROR) << "Invalid index_id";
299 return false;
301 return true;
304 void IndexedDBDatabase::CreateObjectStore(int64 transaction_id,
305 int64 object_store_id,
306 const base::string16& name,
307 const IndexedDBKeyPath& key_path,
308 bool auto_increment) {
309 IDB_TRACE1("IndexedDBDatabase::CreateObjectStore", "txn.id", transaction_id);
310 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
311 if (!transaction)
312 return;
313 DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
315 if (ContainsKey(metadata_.object_stores, object_store_id)) {
316 DLOG(ERROR) << "Invalid object_store_id";
317 return;
320 UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.Schema.ObjectStore.KeyPathType",
321 HistogramKeyPathType(key_path), KEY_PATH_TYPE_MAX);
322 UMA_HISTOGRAM_BOOLEAN("WebCore.IndexedDB.Schema.ObjectStore.AutoIncrement",
323 auto_increment);
325 // Store creation is done synchronously, as it may be followed by
326 // index creation (also sync) since preemptive OpenCursor/SetIndexKeys
327 // may follow.
328 IndexedDBObjectStoreMetadata object_store_metadata(
329 name,
330 object_store_id,
331 key_path,
332 auto_increment,
333 IndexedDBDatabase::kMinimumIndexId);
335 leveldb::Status s =
336 backing_store_->CreateObjectStore(transaction->BackingStoreTransaction(),
337 transaction->database()->id(),
338 object_store_metadata.id,
339 object_store_metadata.name,
340 object_store_metadata.key_path,
341 object_store_metadata.auto_increment);
342 if (!s.ok()) {
343 IndexedDBDatabaseError error(
344 blink::WebIDBDatabaseExceptionUnknownError,
345 ASCIIToUTF16("Internal error creating object store '") +
346 object_store_metadata.name + ASCIIToUTF16("'."));
347 transaction->Abort(error);
348 if (s.IsCorruption())
349 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
350 error);
351 return;
354 AddObjectStore(object_store_metadata, object_store_id);
355 transaction->ScheduleAbortTask(
356 base::Bind(&IndexedDBDatabase::CreateObjectStoreAbortOperation,
357 this,
358 object_store_id));
361 void IndexedDBDatabase::DeleteObjectStore(int64 transaction_id,
362 int64 object_store_id) {
363 IDB_TRACE1("IndexedDBDatabase::DeleteObjectStore", "txn.id", transaction_id);
364 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
365 if (!transaction)
366 return;
367 DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
369 if (!ValidateObjectStoreId(object_store_id))
370 return;
372 transaction->ScheduleTask(
373 base::Bind(&IndexedDBDatabase::DeleteObjectStoreOperation,
374 this,
375 object_store_id));
378 void IndexedDBDatabase::CreateIndex(int64 transaction_id,
379 int64 object_store_id,
380 int64 index_id,
381 const base::string16& name,
382 const IndexedDBKeyPath& key_path,
383 bool unique,
384 bool multi_entry) {
385 IDB_TRACE1("IndexedDBDatabase::CreateIndex", "txn.id", transaction_id);
386 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
387 if (!transaction)
388 return;
389 DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
391 if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id))
392 return;
394 UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.Schema.Index.KeyPathType",
395 HistogramKeyPathType(key_path), KEY_PATH_TYPE_MAX);
396 UMA_HISTOGRAM_BOOLEAN("WebCore.IndexedDB.Schema.Index.Unique", unique);
397 UMA_HISTOGRAM_BOOLEAN("WebCore.IndexedDB.Schema.Index.MultiEntry",
398 multi_entry);
400 // Index creation is done synchronously since preemptive
401 // OpenCursor/SetIndexKeys may follow.
402 const IndexedDBIndexMetadata index_metadata(
403 name, index_id, key_path, unique, multi_entry);
405 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(),
406 transaction->database()->id(),
407 object_store_id,
408 index_metadata.id,
409 index_metadata.name,
410 index_metadata.key_path,
411 index_metadata.unique,
412 index_metadata.multi_entry).ok()) {
413 base::string16 error_string =
414 ASCIIToUTF16("Internal error creating index '") +
415 index_metadata.name + ASCIIToUTF16("'.");
416 transaction->Abort(IndexedDBDatabaseError(
417 blink::WebIDBDatabaseExceptionUnknownError, error_string));
418 return;
421 AddIndex(object_store_id, index_metadata, index_id);
422 transaction->ScheduleAbortTask(
423 base::Bind(&IndexedDBDatabase::CreateIndexAbortOperation,
424 this,
425 object_store_id,
426 index_id));
429 void IndexedDBDatabase::CreateIndexAbortOperation(
430 int64 object_store_id,
431 int64 index_id,
432 IndexedDBTransaction* transaction) {
433 DCHECK(!transaction);
434 IDB_TRACE("IndexedDBDatabase::CreateIndexAbortOperation");
435 RemoveIndex(object_store_id, index_id);
438 void IndexedDBDatabase::DeleteIndex(int64 transaction_id,
439 int64 object_store_id,
440 int64 index_id) {
441 IDB_TRACE1("IndexedDBDatabase::DeleteIndex", "txn.id", transaction_id);
442 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
443 if (!transaction)
444 return;
445 DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
447 if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id))
448 return;
450 transaction->ScheduleTask(
451 base::Bind(&IndexedDBDatabase::DeleteIndexOperation,
452 this,
453 object_store_id,
454 index_id));
457 void IndexedDBDatabase::DeleteIndexOperation(
458 int64 object_store_id,
459 int64 index_id,
460 IndexedDBTransaction* transaction) {
461 IDB_TRACE1(
462 "IndexedDBDatabase::DeleteIndexOperation", "txn.id", transaction->id());
464 const IndexedDBIndexMetadata index_metadata =
465 metadata_.object_stores[object_store_id].indexes[index_id];
467 leveldb::Status s =
468 backing_store_->DeleteIndex(transaction->BackingStoreTransaction(),
469 transaction->database()->id(),
470 object_store_id,
471 index_id);
472 if (!s.ok()) {
473 base::string16 error_string =
474 ASCIIToUTF16("Internal error deleting index '") +
475 index_metadata.name + ASCIIToUTF16("'.");
476 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
477 error_string);
478 transaction->Abort(error);
479 if (s.IsCorruption())
480 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
481 error);
482 return;
485 RemoveIndex(object_store_id, index_id);
486 transaction->ScheduleAbortTask(
487 base::Bind(&IndexedDBDatabase::DeleteIndexAbortOperation,
488 this,
489 object_store_id,
490 index_metadata));
493 void IndexedDBDatabase::DeleteIndexAbortOperation(
494 int64 object_store_id,
495 const IndexedDBIndexMetadata& index_metadata,
496 IndexedDBTransaction* transaction) {
497 DCHECK(!transaction);
498 IDB_TRACE("IndexedDBDatabase::DeleteIndexAbortOperation");
499 AddIndex(object_store_id, index_metadata, IndexedDBIndexMetadata::kInvalidId);
502 void IndexedDBDatabase::Commit(int64 transaction_id) {
503 // The frontend suggests that we commit, but we may have previously initiated
504 // an abort, and so have disposed of the transaction. on_abort has already
505 // been dispatched to the frontend, so it will find out about that
506 // asynchronously.
507 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
508 if (transaction) {
509 scoped_refptr<IndexedDBFactory> factory = factory_;
510 leveldb::Status s = transaction->Commit();
511 if (s.IsCorruption()) {
512 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
513 "Internal error committing transaction.");
514 factory->HandleBackingStoreCorruption(identifier_.first, error);
519 void IndexedDBDatabase::Abort(int64 transaction_id) {
520 // If the transaction is unknown, then it has already been aborted by the
521 // backend before this call so it is safe to ignore it.
522 IDB_TRACE1("IndexedDBDatabase::Abort", "txn.id", transaction_id);
523 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
524 if (transaction)
525 transaction->Abort();
528 void IndexedDBDatabase::Abort(int64 transaction_id,
529 const IndexedDBDatabaseError& error) {
530 IDB_TRACE1("IndexedDBDatabase::Abort(error)", "txn.id", transaction_id);
531 // If the transaction is unknown, then it has already been aborted by the
532 // backend before this call so it is safe to ignore it.
533 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
534 if (transaction)
535 transaction->Abort(error);
538 void IndexedDBDatabase::GetAll(int64 transaction_id,
539 int64 object_store_id,
540 int64 index_id,
541 scoped_ptr<IndexedDBKeyRange> key_range,
542 bool key_only,
543 int64 max_count,
544 scoped_refptr<IndexedDBCallbacks> callbacks) {
545 IDB_TRACE1("IndexedDBDatabase::GetAll", "txn.id", transaction_id);
546 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
547 if (!transaction)
548 return;
550 if (!ValidateObjectStoreId(object_store_id))
551 return;
553 transaction->ScheduleTask(base::Bind(
554 &IndexedDBDatabase::GetAllOperation, this, object_store_id, index_id,
555 Passed(&key_range),
556 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
557 max_count, callbacks));
560 void IndexedDBDatabase::Get(int64 transaction_id,
561 int64 object_store_id,
562 int64 index_id,
563 scoped_ptr<IndexedDBKeyRange> key_range,
564 bool key_only,
565 scoped_refptr<IndexedDBCallbacks> callbacks) {
566 IDB_TRACE1("IndexedDBDatabase::Get", "txn.id", transaction_id);
567 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
568 if (!transaction)
569 return;
571 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
572 return;
574 transaction->ScheduleTask(base::Bind(
575 &IndexedDBDatabase::GetOperation,
576 this,
577 object_store_id,
578 index_id,
579 Passed(&key_range),
580 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
581 callbacks));
584 void IndexedDBDatabase::GetOperation(
585 int64 object_store_id,
586 int64 index_id,
587 scoped_ptr<IndexedDBKeyRange> key_range,
588 indexed_db::CursorType cursor_type,
589 scoped_refptr<IndexedDBCallbacks> callbacks,
590 IndexedDBTransaction* transaction) {
591 IDB_TRACE1("IndexedDBDatabase::GetOperation", "txn.id", transaction->id());
593 DCHECK(metadata_.object_stores.find(object_store_id) !=
594 metadata_.object_stores.end());
595 const IndexedDBObjectStoreMetadata& object_store_metadata =
596 metadata_.object_stores[object_store_id];
598 const IndexedDBKey* key;
600 leveldb::Status s;
601 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
602 if (key_range->IsOnlyKey()) {
603 key = &key_range->lower();
604 } else {
605 if (index_id == IndexedDBIndexMetadata::kInvalidId) {
606 DCHECK_NE(cursor_type, indexed_db::CURSOR_KEY_ONLY);
607 // ObjectStore Retrieval Operation
608 backing_store_cursor = backing_store_->OpenObjectStoreCursor(
609 transaction->BackingStoreTransaction(),
610 id(),
611 object_store_id,
612 *key_range,
613 blink::WebIDBCursorDirectionNext,
614 &s);
615 } else if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
616 // Index Value Retrieval Operation
617 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
618 transaction->BackingStoreTransaction(),
619 id(),
620 object_store_id,
621 index_id,
622 *key_range,
623 blink::WebIDBCursorDirectionNext,
624 &s);
625 } else {
626 // Index Referenced Value Retrieval Operation
627 backing_store_cursor = backing_store_->OpenIndexCursor(
628 transaction->BackingStoreTransaction(),
629 id(),
630 object_store_id,
631 index_id,
632 *key_range,
633 blink::WebIDBCursorDirectionNext,
634 &s);
637 if (!s.ok()) {
638 DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
639 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
640 "Internal error deleting data in range");
641 if (s.IsCorruption()) {
642 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
643 error);
647 if (!backing_store_cursor) {
648 callbacks->OnSuccess();
649 return;
652 key = &backing_store_cursor->key();
655 scoped_ptr<IndexedDBKey> primary_key;
656 if (index_id == IndexedDBIndexMetadata::kInvalidId) {
657 // Object Store Retrieval Operation
658 IndexedDBReturnValue value;
659 s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
660 id(),
661 object_store_id,
662 *key,
663 &value);
664 if (!s.ok()) {
665 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
666 "Internal error in GetRecord.");
667 callbacks->OnError(error);
669 if (s.IsCorruption())
670 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
671 error);
672 return;
675 if (value.empty()) {
676 callbacks->OnSuccess();
677 return;
680 if (object_store_metadata.auto_increment &&
681 !object_store_metadata.key_path.IsNull()) {
682 value.primary_key = *key;
683 value.key_path = object_store_metadata.key_path;
686 callbacks->OnSuccess(&value);
687 return;
690 // From here we are dealing only with indexes.
691 s = backing_store_->GetPrimaryKeyViaIndex(
692 transaction->BackingStoreTransaction(),
693 id(),
694 object_store_id,
695 index_id,
696 *key,
697 &primary_key);
698 if (!s.ok()) {
699 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
700 "Internal error in GetPrimaryKeyViaIndex.");
701 callbacks->OnError(error);
702 if (s.IsCorruption())
703 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
704 error);
705 return;
707 if (!primary_key) {
708 callbacks->OnSuccess();
709 return;
711 if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
712 // Index Value Retrieval Operation
713 callbacks->OnSuccess(*primary_key);
714 return;
717 // Index Referenced Value Retrieval Operation
718 IndexedDBReturnValue value;
719 s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
720 id(),
721 object_store_id,
722 *primary_key,
723 &value);
724 if (!s.ok()) {
725 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
726 "Internal error in GetRecord.");
727 callbacks->OnError(error);
728 if (s.IsCorruption())
729 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
730 error);
731 return;
734 if (value.empty()) {
735 callbacks->OnSuccess();
736 return;
738 if (object_store_metadata.auto_increment &&
739 !object_store_metadata.key_path.IsNull()) {
740 value.primary_key = *primary_key;
741 value.key_path = object_store_metadata.key_path;
743 callbacks->OnSuccess(&value);
746 void IndexedDBDatabase::GetAllOperation(
747 int64 object_store_id,
748 int64 index_id,
749 scoped_ptr<IndexedDBKeyRange> key_range,
750 indexed_db::CursorType cursor_type,
751 int64 max_count,
752 scoped_refptr<IndexedDBCallbacks> callbacks,
753 IndexedDBTransaction* transaction) {
754 IDB_TRACE1("IndexedDBDatabase::GetAllOperation", "txn.id", transaction->id());
756 DCHECK_GT(max_count, 0);
758 DCHECK(metadata_.object_stores.find(object_store_id) !=
759 metadata_.object_stores.end());
760 const IndexedDBObjectStoreMetadata& object_store_metadata =
761 metadata_.object_stores[object_store_id];
763 leveldb::Status s;
765 scoped_ptr<IndexedDBBackingStore::Cursor> cursor;
767 if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
768 // Retrieving keys
769 if (index_id == IndexedDBIndexMetadata::kInvalidId) {
770 // Object Store: Key Retrieval Operation
771 cursor = backing_store_->OpenObjectStoreKeyCursor(
772 transaction->BackingStoreTransaction(), id(), object_store_id,
773 *key_range, blink::WebIDBCursorDirectionNext, &s);
774 } else {
775 // Index Value: (Primary Key) Retrieval Operation
776 cursor = backing_store_->OpenIndexKeyCursor(
777 transaction->BackingStoreTransaction(), id(), object_store_id,
778 index_id, *key_range, blink::WebIDBCursorDirectionNext, &s);
780 } else {
781 // Retrieving values
782 if (index_id == IndexedDBIndexMetadata::kInvalidId) {
783 // Object Store: Value Retrieval Operation
784 cursor = backing_store_->OpenObjectStoreCursor(
785 transaction->BackingStoreTransaction(), id(), object_store_id,
786 *key_range, blink::WebIDBCursorDirectionNext, &s);
787 } else {
788 // Object Store: Referenced Value Retrieval Operation
789 cursor = backing_store_->OpenIndexCursor(
790 transaction->BackingStoreTransaction(), id(), object_store_id,
791 index_id, *key_range, blink::WebIDBCursorDirectionNext, &s);
795 if (!s.ok()) {
796 DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
797 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
798 "Internal error in GetAllOperation");
799 callbacks->OnError(error);
800 if (s.IsCorruption()) {
801 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
802 error);
804 return;
807 std::vector<IndexedDBKey> found_keys;
808 std::vector<IndexedDBReturnValue> found_values;
809 if (!cursor) {
810 // Doesn't matter if key or value array here - will be empty array when it
811 // hits JavaScript.
812 callbacks->OnSuccessArray(&found_values, object_store_metadata.key_path);
813 return;
816 bool did_first_seek = false;
817 bool generated_key = object_store_metadata.auto_increment &&
818 !object_store_metadata.key_path.IsNull();
820 size_t response_size = kMaxIDBMessageOverhead;
821 int64 num_found_items = 0;
822 while (num_found_items++ < max_count) {
823 bool cursor_valid;
824 if (did_first_seek) {
825 cursor_valid = cursor->Continue(&s);
826 } else {
827 cursor_valid = cursor->FirstSeek(&s);
828 did_first_seek = true;
830 if (!s.ok()) {
831 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
832 "Internal error in GetAllOperation.");
833 callbacks->OnError(error);
834 if (s.IsCorruption())
835 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
836 error);
837 return;
840 if (!cursor_valid)
841 break;
843 IndexedDBReturnValue return_value;
844 IndexedDBKey return_key;
846 if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
847 return_key = cursor->primary_key();
848 } else {
849 // Retrieving values
850 return_value.swap(*cursor->value());
851 if (!return_value.empty() && generated_key) {
852 return_value.primary_key = cursor->primary_key();
853 return_value.key_path = object_store_metadata.key_path;
857 if (cursor_type == indexed_db::CURSOR_KEY_ONLY)
858 response_size += return_key.size_estimate();
859 else
860 response_size += return_value.SizeEstimate();
861 if (response_size > GetMaxMessageSizeInBytes()) {
862 callbacks->OnError(
863 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
864 "Maximum IPC message size exceeded."));
865 return;
868 if (cursor_type == indexed_db::CURSOR_KEY_ONLY)
869 found_keys.push_back(return_key);
870 else
871 found_values.push_back(return_value);
874 if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
875 // IndexedDBKey already supports an array of values so we can leverage this
876 // to return an array of keys - no need to create our own array of keys.
877 callbacks->OnSuccess(IndexedDBKey(found_keys));
878 } else {
879 callbacks->OnSuccessArray(&found_values, object_store_metadata.key_path);
883 static scoped_ptr<IndexedDBKey> GenerateKey(
884 IndexedDBBackingStore* backing_store,
885 IndexedDBTransaction* transaction,
886 int64 database_id,
887 int64 object_store_id) {
888 const int64 max_generator_value =
889 9007199254740992LL; // Maximum integer storable as ECMAScript number.
890 int64 current_number;
891 leveldb::Status s = backing_store->GetKeyGeneratorCurrentNumber(
892 transaction->BackingStoreTransaction(),
893 database_id,
894 object_store_id,
895 &current_number);
896 if (!s.ok()) {
897 LOG(ERROR) << "Failed to GetKeyGeneratorCurrentNumber";
898 return make_scoped_ptr(new IndexedDBKey());
900 if (current_number < 0 || current_number > max_generator_value)
901 return make_scoped_ptr(new IndexedDBKey());
903 return make_scoped_ptr(new IndexedDBKey(current_number, WebIDBKeyTypeNumber));
906 static leveldb::Status UpdateKeyGenerator(IndexedDBBackingStore* backing_store,
907 IndexedDBTransaction* transaction,
908 int64 database_id,
909 int64 object_store_id,
910 const IndexedDBKey& key,
911 bool check_current) {
912 DCHECK_EQ(WebIDBKeyTypeNumber, key.type());
913 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber(
914 transaction->BackingStoreTransaction(),
915 database_id,
916 object_store_id,
917 static_cast<int64>(floor(key.number())) + 1,
918 check_current);
921 struct IndexedDBDatabase::PutOperationParams {
922 PutOperationParams() {}
923 int64 object_store_id;
924 IndexedDBValue value;
925 ScopedVector<storage::BlobDataHandle> handles;
926 scoped_ptr<IndexedDBKey> key;
927 blink::WebIDBPutMode put_mode;
928 scoped_refptr<IndexedDBCallbacks> callbacks;
929 std::vector<IndexKeys> index_keys;
931 private:
932 DISALLOW_COPY_AND_ASSIGN(PutOperationParams);
935 void IndexedDBDatabase::Put(int64 transaction_id,
936 int64 object_store_id,
937 IndexedDBValue* value,
938 ScopedVector<storage::BlobDataHandle>* handles,
939 scoped_ptr<IndexedDBKey> key,
940 blink::WebIDBPutMode put_mode,
941 scoped_refptr<IndexedDBCallbacks> callbacks,
942 const std::vector<IndexKeys>& index_keys) {
943 IDB_TRACE1("IndexedDBDatabase::Put", "txn.id", transaction_id);
944 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
945 if (!transaction)
946 return;
947 DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
949 if (!ValidateObjectStoreId(object_store_id))
950 return;
952 DCHECK(key);
953 DCHECK(value);
954 scoped_ptr<PutOperationParams> params(new PutOperationParams());
955 params->object_store_id = object_store_id;
956 params->value.swap(*value);
957 params->handles.swap(*handles);
958 params->key = key.Pass();
959 params->put_mode = put_mode;
960 params->callbacks = callbacks;
961 params->index_keys = index_keys;
962 transaction->ScheduleTask(base::Bind(
963 &IndexedDBDatabase::PutOperation, this, base::Passed(&params)));
966 void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
967 IndexedDBTransaction* transaction) {
968 IDB_TRACE1("IndexedDBDatabase::PutOperation", "txn.id", transaction->id());
969 DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
970 bool key_was_generated = false;
972 DCHECK(metadata_.object_stores.find(params->object_store_id) !=
973 metadata_.object_stores.end());
974 const IndexedDBObjectStoreMetadata& object_store =
975 metadata_.object_stores[params->object_store_id];
976 DCHECK(object_store.auto_increment || params->key->IsValid());
978 scoped_ptr<IndexedDBKey> key;
979 if (params->put_mode != blink::WebIDBPutModeCursorUpdate &&
980 object_store.auto_increment && !params->key->IsValid()) {
981 scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey(
982 backing_store_.get(), transaction, id(), params->object_store_id);
983 key_was_generated = true;
984 if (!auto_inc_key->IsValid()) {
985 params->callbacks->OnError(
986 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError,
987 "Maximum key generator value reached."));
988 return;
990 key = auto_inc_key.Pass();
991 } else {
992 key = params->key.Pass();
995 DCHECK(key->IsValid());
997 IndexedDBBackingStore::RecordIdentifier record_identifier;
998 if (params->put_mode == blink::WebIDBPutModeAddOnly) {
999 bool found = false;
1000 leveldb::Status s = backing_store_->KeyExistsInObjectStore(
1001 transaction->BackingStoreTransaction(),
1002 id(),
1003 params->object_store_id,
1004 *key,
1005 &record_identifier,
1006 &found);
1007 if (!s.ok()) {
1008 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1009 "Internal error checking key existence.");
1010 params->callbacks->OnError(error);
1011 if (s.IsCorruption())
1012 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1013 error);
1014 return;
1016 if (found) {
1017 params->callbacks->OnError(
1018 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError,
1019 "Key already exists in the object store."));
1020 return;
1024 ScopedVector<IndexWriter> index_writers;
1025 base::string16 error_message;
1026 bool obeys_constraints = false;
1027 bool backing_store_success = MakeIndexWriters(transaction,
1028 backing_store_.get(),
1029 id(),
1030 object_store,
1031 *key,
1032 key_was_generated,
1033 params->index_keys,
1034 &index_writers,
1035 &error_message,
1036 &obeys_constraints);
1037 if (!backing_store_success) {
1038 params->callbacks->OnError(IndexedDBDatabaseError(
1039 blink::WebIDBDatabaseExceptionUnknownError,
1040 "Internal error: backing store error updating index keys."));
1041 return;
1043 if (!obeys_constraints) {
1044 params->callbacks->OnError(IndexedDBDatabaseError(
1045 blink::WebIDBDatabaseExceptionConstraintError, error_message));
1046 return;
1049 // Before this point, don't do any mutation. After this point, rollback the
1050 // transaction in case of error.
1051 leveldb::Status s =
1052 backing_store_->PutRecord(transaction->BackingStoreTransaction(),
1053 id(),
1054 params->object_store_id,
1055 *key,
1056 &params->value,
1057 &params->handles,
1058 &record_identifier);
1059 if (!s.ok()) {
1060 IndexedDBDatabaseError error(
1061 blink::WebIDBDatabaseExceptionUnknownError,
1062 "Internal error: backing store error performing put/add.");
1063 params->callbacks->OnError(error);
1064 if (s.IsCorruption())
1065 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1066 error);
1067 return;
1070 for (size_t i = 0; i < index_writers.size(); ++i) {
1071 IndexWriter* index_writer = index_writers[i];
1072 index_writer->WriteIndexKeys(record_identifier,
1073 backing_store_.get(),
1074 transaction->BackingStoreTransaction(),
1075 id(),
1076 params->object_store_id);
1079 if (object_store.auto_increment &&
1080 params->put_mode != blink::WebIDBPutModeCursorUpdate &&
1081 key->type() == WebIDBKeyTypeNumber) {
1082 leveldb::Status s = UpdateKeyGenerator(backing_store_.get(),
1083 transaction,
1084 id(),
1085 params->object_store_id,
1086 *key,
1087 !key_was_generated);
1088 if (!s.ok()) {
1089 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1090 "Internal error updating key generator.");
1091 params->callbacks->OnError(error);
1092 if (s.IsCorruption())
1093 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1094 error);
1095 return;
1099 params->callbacks->OnSuccess(*key);
1102 void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
1103 int64 object_store_id,
1104 scoped_ptr<IndexedDBKey> primary_key,
1105 const std::vector<IndexKeys>& index_keys) {
1106 IDB_TRACE1("IndexedDBDatabase::SetIndexKeys", "txn.id", transaction_id);
1107 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
1108 if (!transaction)
1109 return;
1110 DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
1112 // TODO(alecflett): This method could be asynchronous, but we need to
1113 // evaluate if it's worth the extra complexity.
1114 IndexedDBBackingStore::RecordIdentifier record_identifier;
1115 bool found = false;
1116 leveldb::Status s = backing_store_->KeyExistsInObjectStore(
1117 transaction->BackingStoreTransaction(),
1118 metadata_.id,
1119 object_store_id,
1120 *primary_key,
1121 &record_identifier,
1122 &found);
1123 if (!s.ok()) {
1124 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1125 "Internal error setting index keys.");
1126 transaction->Abort(error);
1127 if (s.IsCorruption())
1128 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1129 error);
1130 return;
1132 if (!found) {
1133 transaction->Abort(IndexedDBDatabaseError(
1134 blink::WebIDBDatabaseExceptionUnknownError,
1135 "Internal error setting index keys for object store."));
1136 return;
1139 ScopedVector<IndexWriter> index_writers;
1140 base::string16 error_message;
1141 bool obeys_constraints = false;
1142 DCHECK(metadata_.object_stores.find(object_store_id) !=
1143 metadata_.object_stores.end());
1144 const IndexedDBObjectStoreMetadata& object_store_metadata =
1145 metadata_.object_stores[object_store_id];
1146 bool backing_store_success = MakeIndexWriters(transaction,
1147 backing_store_.get(),
1148 id(),
1149 object_store_metadata,
1150 *primary_key,
1151 false,
1152 index_keys,
1153 &index_writers,
1154 &error_message,
1155 &obeys_constraints);
1156 if (!backing_store_success) {
1157 transaction->Abort(IndexedDBDatabaseError(
1158 blink::WebIDBDatabaseExceptionUnknownError,
1159 "Internal error: backing store error updating index keys."));
1160 return;
1162 if (!obeys_constraints) {
1163 transaction->Abort(IndexedDBDatabaseError(
1164 blink::WebIDBDatabaseExceptionConstraintError, error_message));
1165 return;
1168 for (size_t i = 0; i < index_writers.size(); ++i) {
1169 IndexWriter* index_writer = index_writers[i];
1170 index_writer->WriteIndexKeys(record_identifier,
1171 backing_store_.get(),
1172 transaction->BackingStoreTransaction(),
1173 id(),
1174 object_store_id);
1178 void IndexedDBDatabase::SetIndexesReady(int64 transaction_id,
1179 int64,
1180 const std::vector<int64>& index_ids) {
1181 IDB_TRACE1("IndexedDBDatabase::SetIndexesReady", "txn.id", transaction_id);
1182 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
1183 if (!transaction)
1184 return;
1185 DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
1187 transaction->ScheduleTask(
1188 blink::WebIDBTaskTypePreemptive,
1189 base::Bind(&IndexedDBDatabase::SetIndexesReadyOperation,
1190 this,
1191 index_ids.size()));
1194 void IndexedDBDatabase::SetIndexesReadyOperation(
1195 size_t index_count,
1196 IndexedDBTransaction* transaction) {
1197 IDB_TRACE1("IndexedDBDatabase::SetIndexesReadyOperation",
1198 "txn.id",
1199 transaction->id());
1200 for (size_t i = 0; i < index_count; ++i)
1201 transaction->DidCompletePreemptiveEvent();
1204 struct IndexedDBDatabase::OpenCursorOperationParams {
1205 OpenCursorOperationParams() {}
1206 int64 object_store_id;
1207 int64 index_id;
1208 scoped_ptr<IndexedDBKeyRange> key_range;
1209 blink::WebIDBCursorDirection direction;
1210 indexed_db::CursorType cursor_type;
1211 blink::WebIDBTaskType task_type;
1212 scoped_refptr<IndexedDBCallbacks> callbacks;
1214 private:
1215 DISALLOW_COPY_AND_ASSIGN(OpenCursorOperationParams);
1218 void IndexedDBDatabase::OpenCursor(
1219 int64 transaction_id,
1220 int64 object_store_id,
1221 int64 index_id,
1222 scoped_ptr<IndexedDBKeyRange> key_range,
1223 blink::WebIDBCursorDirection direction,
1224 bool key_only,
1225 blink::WebIDBTaskType task_type,
1226 scoped_refptr<IndexedDBCallbacks> callbacks) {
1227 IDB_TRACE1("IndexedDBDatabase::OpenCursor", "txn.id", transaction_id);
1228 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
1229 if (!transaction)
1230 return;
1232 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
1233 return;
1235 scoped_ptr<OpenCursorOperationParams> params(new OpenCursorOperationParams());
1236 params->object_store_id = object_store_id;
1237 params->index_id = index_id;
1238 params->key_range = key_range.Pass();
1239 params->direction = direction;
1240 params->cursor_type =
1241 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE;
1242 params->task_type = task_type;
1243 params->callbacks = callbacks;
1244 transaction->ScheduleTask(base::Bind(
1245 &IndexedDBDatabase::OpenCursorOperation, this, base::Passed(&params)));
1248 void IndexedDBDatabase::OpenCursorOperation(
1249 scoped_ptr<OpenCursorOperationParams> params,
1250 IndexedDBTransaction* transaction) {
1251 IDB_TRACE1(
1252 "IndexedDBDatabase::OpenCursorOperation", "txn.id", transaction->id());
1254 // The frontend has begun indexing, so this pauses the transaction
1255 // until the indexing is complete. This can't happen any earlier
1256 // because we don't want to switch to early mode in case multiple
1257 // indexes are being created in a row, with Put()'s in between.
1258 if (params->task_type == blink::WebIDBTaskTypePreemptive)
1259 transaction->AddPreemptiveEvent();
1261 leveldb::Status s;
1262 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
1263 if (params->index_id == IndexedDBIndexMetadata::kInvalidId) {
1264 if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) {
1265 DCHECK_EQ(params->task_type, blink::WebIDBTaskTypeNormal);
1266 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
1267 transaction->BackingStoreTransaction(),
1268 id(),
1269 params->object_store_id,
1270 *params->key_range,
1271 params->direction,
1272 &s);
1273 } else {
1274 backing_store_cursor = backing_store_->OpenObjectStoreCursor(
1275 transaction->BackingStoreTransaction(),
1276 id(),
1277 params->object_store_id,
1278 *params->key_range,
1279 params->direction,
1280 &s);
1282 } else {
1283 DCHECK_EQ(params->task_type, blink::WebIDBTaskTypeNormal);
1284 if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) {
1285 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
1286 transaction->BackingStoreTransaction(),
1287 id(),
1288 params->object_store_id,
1289 params->index_id,
1290 *params->key_range,
1291 params->direction,
1292 &s);
1293 } else {
1294 backing_store_cursor = backing_store_->OpenIndexCursor(
1295 transaction->BackingStoreTransaction(),
1296 id(),
1297 params->object_store_id,
1298 params->index_id,
1299 *params->key_range,
1300 params->direction,
1301 &s);
1305 if (!s.ok()) {
1306 DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
1307 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1308 "Internal error opening cursor operation");
1309 if (s.IsCorruption()) {
1310 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1311 error);
1315 if (!backing_store_cursor) {
1316 // Why is Success being called?
1317 params->callbacks->OnSuccess(nullptr);
1318 return;
1321 scoped_refptr<IndexedDBCursor> cursor =
1322 new IndexedDBCursor(backing_store_cursor.Pass(),
1323 params->cursor_type,
1324 params->task_type,
1325 transaction);
1326 params->callbacks->OnSuccess(
1327 cursor, cursor->key(), cursor->primary_key(), cursor->Value());
1330 void IndexedDBDatabase::Count(int64 transaction_id,
1331 int64 object_store_id,
1332 int64 index_id,
1333 scoped_ptr<IndexedDBKeyRange> key_range,
1334 scoped_refptr<IndexedDBCallbacks> callbacks) {
1335 IDB_TRACE1("IndexedDBDatabase::Count", "txn.id", transaction_id);
1336 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
1337 if (!transaction)
1338 return;
1340 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
1341 return;
1343 transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::CountOperation,
1344 this,
1345 object_store_id,
1346 index_id,
1347 base::Passed(&key_range),
1348 callbacks));
1351 void IndexedDBDatabase::CountOperation(
1352 int64 object_store_id,
1353 int64 index_id,
1354 scoped_ptr<IndexedDBKeyRange> key_range,
1355 scoped_refptr<IndexedDBCallbacks> callbacks,
1356 IndexedDBTransaction* transaction) {
1357 IDB_TRACE1("IndexedDBDatabase::CountOperation", "txn.id", transaction->id());
1358 uint32 count = 0;
1359 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
1361 leveldb::Status s;
1362 if (index_id == IndexedDBIndexMetadata::kInvalidId) {
1363 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
1364 transaction->BackingStoreTransaction(),
1365 id(),
1366 object_store_id,
1367 *key_range,
1368 blink::WebIDBCursorDirectionNext,
1369 &s);
1370 } else {
1371 backing_store_cursor = backing_store_->OpenIndexKeyCursor(
1372 transaction->BackingStoreTransaction(),
1373 id(),
1374 object_store_id,
1375 index_id,
1376 *key_range,
1377 blink::WebIDBCursorDirectionNext,
1378 &s);
1380 if (!s.ok()) {
1381 DLOG(ERROR) << "Unable perform count operation: " << s.ToString();
1382 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1383 "Internal error performing count operation");
1384 if (s.IsCorruption()) {
1385 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1386 error);
1389 if (!backing_store_cursor) {
1390 callbacks->OnSuccess(count);
1391 return;
1394 do {
1395 ++count;
1396 } while (backing_store_cursor->Continue(&s));
1398 // TODO(cmumford): Check for database corruption.
1400 callbacks->OnSuccess(count);
1403 void IndexedDBDatabase::DeleteRange(
1404 int64 transaction_id,
1405 int64 object_store_id,
1406 scoped_ptr<IndexedDBKeyRange> key_range,
1407 scoped_refptr<IndexedDBCallbacks> callbacks) {
1408 IDB_TRACE1("IndexedDBDatabase::DeleteRange", "txn.id", transaction_id);
1409 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
1410 if (!transaction)
1411 return;
1412 DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
1414 if (!ValidateObjectStoreId(object_store_id))
1415 return;
1417 transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::DeleteRangeOperation,
1418 this,
1419 object_store_id,
1420 base::Passed(&key_range),
1421 callbacks));
1424 void IndexedDBDatabase::DeleteRangeOperation(
1425 int64 object_store_id,
1426 scoped_ptr<IndexedDBKeyRange> key_range,
1427 scoped_refptr<IndexedDBCallbacks> callbacks,
1428 IndexedDBTransaction* transaction) {
1429 IDB_TRACE1(
1430 "IndexedDBDatabase::DeleteRangeOperation", "txn.id", transaction->id());
1431 leveldb::Status s =
1432 backing_store_->DeleteRange(transaction->BackingStoreTransaction(),
1433 id(),
1434 object_store_id,
1435 *key_range);
1436 if (!s.ok()) {
1437 base::string16 error_string =
1438 ASCIIToUTF16("Internal error deleting data in range");
1439 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1440 error_string);
1441 transaction->Abort(error);
1442 if (s.IsCorruption()) {
1443 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1444 error);
1446 return;
1448 callbacks->OnSuccess();
1451 void IndexedDBDatabase::Clear(int64 transaction_id,
1452 int64 object_store_id,
1453 scoped_refptr<IndexedDBCallbacks> callbacks) {
1454 IDB_TRACE1("IndexedDBDatabase::Clear", "txn.id", transaction_id);
1455 IndexedDBTransaction* transaction = GetTransaction(transaction_id);
1456 if (!transaction)
1457 return;
1458 DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
1460 if (!ValidateObjectStoreId(object_store_id))
1461 return;
1463 transaction->ScheduleTask(base::Bind(
1464 &IndexedDBDatabase::ClearOperation, this, object_store_id, callbacks));
1467 void IndexedDBDatabase::ClearOperation(
1468 int64 object_store_id,
1469 scoped_refptr<IndexedDBCallbacks> callbacks,
1470 IndexedDBTransaction* transaction) {
1471 IDB_TRACE1("IndexedDBDatabase::ClearOperation", "txn.id", transaction->id());
1472 leveldb::Status s = backing_store_->ClearObjectStore(
1473 transaction->BackingStoreTransaction(), id(), object_store_id);
1474 if (!s.ok()) {
1475 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1476 "Internal error clearing object store");
1477 callbacks->OnError(error);
1478 if (s.IsCorruption()) {
1479 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1480 error);
1482 return;
1484 callbacks->OnSuccess();
1487 void IndexedDBDatabase::DeleteObjectStoreOperation(
1488 int64 object_store_id,
1489 IndexedDBTransaction* transaction) {
1490 IDB_TRACE1("IndexedDBDatabase::DeleteObjectStoreOperation",
1491 "txn.id",
1492 transaction->id());
1494 const IndexedDBObjectStoreMetadata object_store_metadata =
1495 metadata_.object_stores[object_store_id];
1496 leveldb::Status s =
1497 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(),
1498 transaction->database()->id(),
1499 object_store_id);
1500 if (!s.ok()) {
1501 base::string16 error_string =
1502 ASCIIToUTF16("Internal error deleting object store '") +
1503 object_store_metadata.name + ASCIIToUTF16("'.");
1504 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1505 error_string);
1506 transaction->Abort(error);
1507 if (s.IsCorruption())
1508 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
1509 error);
1510 return;
1513 RemoveObjectStore(object_store_id);
1514 transaction->ScheduleAbortTask(
1515 base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation,
1516 this,
1517 object_store_metadata));
1520 void IndexedDBDatabase::VersionChangeOperation(
1521 int64 version,
1522 scoped_refptr<IndexedDBCallbacks> callbacks,
1523 scoped_ptr<IndexedDBConnection> connection,
1524 IndexedDBTransaction* transaction) {
1525 IDB_TRACE1(
1526 "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id());
1527 int64 old_version = metadata_.int_version;
1528 DCHECK_GT(version, old_version);
1530 if (!backing_store_->UpdateIDBDatabaseIntVersion(
1531 transaction->BackingStoreTransaction(), id(), version)) {
1532 IndexedDBDatabaseError error(
1533 blink::WebIDBDatabaseExceptionUnknownError,
1534 ASCIIToUTF16(
1535 "Internal error writing data to stable storage when "
1536 "updating version."));
1537 callbacks->OnError(error);
1538 transaction->Abort(error);
1539 return;
1542 transaction->ScheduleAbortTask(
1543 base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation,
1544 this,
1545 metadata_.version,
1546 metadata_.int_version));
1547 metadata_.int_version = version;
1548 metadata_.version = kNoStringVersion;
1550 DCHECK(!pending_second_half_open_);
1551 pending_second_half_open_.reset(
1552 new PendingSuccessCall(callbacks, connection.get(), version));
1553 callbacks->OnUpgradeNeeded(old_version, connection.Pass(), metadata());
1556 void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction,
1557 bool committed) {
1558 DCHECK(transactions_.find(transaction->id()) != transactions_.end());
1559 DCHECK_EQ(transactions_[transaction->id()], transaction);
1560 transactions_.erase(transaction->id());
1562 if (transaction->mode() == blink::WebIDBTransactionModeVersionChange) {
1563 if (pending_second_half_open_) {
1564 if (committed) {
1565 DCHECK_EQ(pending_second_half_open_->version(), metadata_.int_version);
1566 DCHECK(metadata_.id != kInvalidId);
1568 // Connection was already minted for OnUpgradeNeeded callback.
1569 scoped_ptr<IndexedDBConnection> connection;
1570 pending_second_half_open_->callbacks()->OnSuccess(connection.Pass(),
1571 this->metadata());
1572 } else {
1573 pending_second_half_open_->callbacks()->OnError(
1574 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError,
1575 "Version change transaction was aborted in "
1576 "upgradeneeded event handler."));
1578 pending_second_half_open_.reset();
1581 // Connection queue is now unblocked.
1582 ProcessPendingCalls();
1586 void IndexedDBDatabase::TransactionCommitFailed(const leveldb::Status& status) {
1587 if (status.IsCorruption()) {
1588 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1589 "Error committing transaction");
1590 factory_->HandleBackingStoreCorruption(backing_store_->origin_url(), error);
1591 } else {
1592 factory_->HandleBackingStoreFailure(backing_store_->origin_url());
1596 size_t IndexedDBDatabase::ConnectionCount() const {
1597 // This does not include pending open calls, as those should not block version
1598 // changes and deletes.
1599 return connections_.size();
1602 size_t IndexedDBDatabase::PendingOpenCount() const {
1603 return pending_open_calls_.size();
1606 size_t IndexedDBDatabase::PendingUpgradeCount() const {
1607 return pending_run_version_change_transaction_call_ ? 1 : 0;
1610 size_t IndexedDBDatabase::RunningUpgradeCount() const {
1611 return pending_second_half_open_ ? 1 : 0;
1614 size_t IndexedDBDatabase::PendingDeleteCount() const {
1615 return pending_delete_calls_.size();
1618 void IndexedDBDatabase::ProcessPendingCalls() {
1619 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) {
1620 DCHECK(pending_run_version_change_transaction_call_->version() >
1621 metadata_.int_version);
1622 scoped_ptr<PendingUpgradeCall> pending_call =
1623 pending_run_version_change_transaction_call_.Pass();
1624 RunVersionChangeTransactionFinal(pending_call->callbacks(),
1625 pending_call->ReleaseConnection(),
1626 pending_call->transaction_id(),
1627 pending_call->version());
1628 DCHECK_EQ(1u, ConnectionCount());
1629 // Fall through would be a no-op, since transaction must complete
1630 // asynchronously.
1631 DCHECK(IsDeleteDatabaseBlocked());
1632 DCHECK(IsOpenConnectionBlocked());
1633 return;
1636 if (!IsDeleteDatabaseBlocked()) {
1637 PendingDeleteCallList pending_delete_calls;
1638 pending_delete_calls_.swap(pending_delete_calls);
1639 while (!pending_delete_calls.empty()) {
1640 // Only the first delete call will delete the database, but each must fire
1641 // callbacks.
1642 scoped_ptr<PendingDeleteCall> pending_delete_call(
1643 pending_delete_calls.front());
1644 pending_delete_calls.pop_front();
1645 DeleteDatabaseFinal(pending_delete_call->callbacks());
1647 // delete_database_final should never re-queue calls.
1648 DCHECK(pending_delete_calls_.empty());
1649 // Fall through when complete, as pending opens may be unblocked.
1652 if (!IsOpenConnectionBlocked()) {
1653 PendingOpenCallList pending_open_calls;
1654 pending_open_calls_.swap(pending_open_calls);
1655 while (!pending_open_calls.empty()) {
1656 OpenConnection(pending_open_calls.front());
1657 pending_open_calls.pop_front();
1662 void IndexedDBDatabase::CreateTransaction(
1663 int64 transaction_id,
1664 IndexedDBConnection* connection,
1665 const std::vector<int64>& object_store_ids,
1666 blink::WebIDBTransactionMode mode) {
1667 IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id);
1668 DCHECK(connections_.count(connection));
1669 DCHECK(transactions_.find(transaction_id) == transactions_.end());
1670 if (transactions_.find(transaction_id) != transactions_.end())
1671 return;
1673 // The transaction will add itself to this database's coordinator, which
1674 // manages the lifetime of the object.
1675 TransactionCreated(IndexedDBClassFactory::Get()->CreateIndexedDBTransaction(
1676 transaction_id, connection->callbacks(),
1677 std::set<int64>(object_store_ids.begin(), object_store_ids.end()), mode,
1678 this, new IndexedDBBackingStore::Transaction(backing_store_.get())));
1681 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) {
1682 transactions_[transaction->id()] = transaction;
1685 bool IndexedDBDatabase::IsOpenConnectionBlocked() const {
1686 return !pending_delete_calls_.empty() ||
1687 transaction_coordinator_.IsRunningVersionChangeTransaction() ||
1688 pending_run_version_change_transaction_call_;
1691 void IndexedDBDatabase::OpenConnection(
1692 const IndexedDBPendingConnection& connection) {
1693 DCHECK(backing_store_.get());
1695 // TODO(jsbell): Should have a priority queue so that higher version
1696 // requests are processed first. http://crbug.com/225850
1697 if (IsOpenConnectionBlocked()) {
1698 // The backing store only detects data loss when it is first opened. The
1699 // presence of existing connections means we didn't even check for data loss
1700 // so there'd better not be any.
1701 DCHECK_NE(blink::WebIDBDataLossTotal, connection.callbacks->data_loss());
1702 pending_open_calls_.push_back(connection);
1703 return;
1706 if (metadata_.id == kInvalidId) {
1707 // The database was deleted then immediately re-opened; OpenInternal()
1708 // recreates it in the backing store.
1709 if (OpenInternal().ok()) {
1710 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
1711 metadata_.int_version);
1712 } else {
1713 base::string16 message;
1714 if (connection.version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
1715 message = ASCIIToUTF16(
1716 "Internal error opening database with no version specified.");
1717 } else {
1718 message =
1719 ASCIIToUTF16("Internal error opening database with version ") +
1720 Int64ToString16(connection.version);
1722 connection.callbacks->OnError(IndexedDBDatabaseError(
1723 blink::WebIDBDatabaseExceptionUnknownError, message));
1724 return;
1728 // We infer that the database didn't exist from its lack of either type of
1729 // version.
1730 bool is_new_database =
1731 metadata_.version == kNoStringVersion &&
1732 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION;
1734 if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) {
1735 // For unit tests only - skip upgrade steps. Calling from script with
1736 // DEFAULT_INT_VERSION throws exception.
1737 // TODO(jsbell): DCHECK that not in unit tests.
1738 DCHECK(is_new_database);
1739 connection.callbacks->OnSuccess(
1740 CreateConnection(connection.database_callbacks,
1741 connection.child_process_id),
1742 this->metadata());
1743 return;
1746 // We may need to change the version.
1747 int64 local_version = connection.version;
1748 if (local_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
1749 if (!is_new_database) {
1750 connection.callbacks->OnSuccess(
1751 CreateConnection(connection.database_callbacks,
1752 connection.child_process_id),
1753 this->metadata());
1754 return;
1756 // Spec says: If no version is specified and no database exists, set
1757 // database version to 1.
1758 local_version = 1;
1761 if (local_version > metadata_.int_version) {
1762 RunVersionChangeTransaction(connection.callbacks,
1763 CreateConnection(connection.database_callbacks,
1764 connection.child_process_id),
1765 connection.transaction_id,
1766 local_version);
1767 return;
1769 if (local_version < metadata_.int_version) {
1770 connection.callbacks->OnError(IndexedDBDatabaseError(
1771 blink::WebIDBDatabaseExceptionVersionError,
1772 ASCIIToUTF16("The requested version (") +
1773 Int64ToString16(local_version) +
1774 ASCIIToUTF16(") is less than the existing version (") +
1775 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(").")));
1776 return;
1778 DCHECK_EQ(local_version, metadata_.int_version);
1779 connection.callbacks->OnSuccess(
1780 CreateConnection(connection.database_callbacks,
1781 connection.child_process_id),
1782 this->metadata());
1785 void IndexedDBDatabase::RunVersionChangeTransaction(
1786 scoped_refptr<IndexedDBCallbacks> callbacks,
1787 scoped_ptr<IndexedDBConnection> connection,
1788 int64 transaction_id,
1789 int64 requested_version) {
1790 DCHECK(callbacks.get());
1791 DCHECK(connections_.count(connection.get()));
1792 if (ConnectionCount() > 1) {
1793 DCHECK_NE(blink::WebIDBDataLossTotal, callbacks->data_loss());
1794 // Front end ensures the event is not fired at connections that have
1795 // close_pending set.
1796 for (const auto* iter : connections_) {
1797 if (iter != connection.get()) {
1798 iter->callbacks()->OnVersionChange(metadata_.int_version,
1799 requested_version);
1802 // OnBlocked will be fired at the request when one of the other
1803 // connections acks that the OnVersionChange was ignored.
1805 DCHECK(!pending_run_version_change_transaction_call_);
1806 pending_run_version_change_transaction_call_.reset(new PendingUpgradeCall(
1807 callbacks, connection.Pass(), transaction_id, requested_version));
1808 return;
1810 RunVersionChangeTransactionFinal(
1811 callbacks, connection.Pass(), transaction_id, requested_version);
1814 void IndexedDBDatabase::RunVersionChangeTransactionFinal(
1815 scoped_refptr<IndexedDBCallbacks> callbacks,
1816 scoped_ptr<IndexedDBConnection> connection,
1817 int64 transaction_id,
1818 int64 requested_version) {
1820 std::vector<int64> object_store_ids;
1821 CreateTransaction(transaction_id,
1822 connection.get(),
1823 object_store_ids,
1824 blink::WebIDBTransactionModeVersionChange);
1826 transactions_[transaction_id]->ScheduleTask(
1827 base::Bind(&IndexedDBDatabase::VersionChangeOperation,
1828 this,
1829 requested_version,
1830 callbacks,
1831 base::Passed(&connection)));
1832 DCHECK(!pending_second_half_open_);
1835 void IndexedDBDatabase::DeleteDatabase(
1836 scoped_refptr<IndexedDBCallbacks> callbacks) {
1838 if (IsDeleteDatabaseBlocked()) {
1839 for (const auto* connection : connections_) {
1840 // Front end ensures the event is not fired at connections that have
1841 // close_pending set.
1842 connection->callbacks()->OnVersionChange(
1843 metadata_.int_version, IndexedDBDatabaseMetadata::NO_INT_VERSION);
1845 // OnBlocked will be fired at the request when one of the other
1846 // connections acks that the OnVersionChange was ignored.
1848 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
1849 return;
1851 DeleteDatabaseFinal(callbacks);
1854 bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const {
1855 return !!ConnectionCount();
1858 void IndexedDBDatabase::DeleteDatabaseFinal(
1859 scoped_refptr<IndexedDBCallbacks> callbacks) {
1860 DCHECK(!IsDeleteDatabaseBlocked());
1861 DCHECK(backing_store_.get());
1862 leveldb::Status s = backing_store_->DeleteDatabase(metadata_.name);
1863 if (!s.ok()) {
1864 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1865 "Internal error deleting database.");
1866 callbacks->OnError(error);
1867 if (s.IsCorruption()) {
1868 GURL origin_url = backing_store_->origin_url();
1869 backing_store_ = NULL;
1870 factory_->HandleBackingStoreCorruption(origin_url, error);
1872 return;
1874 int64 old_version = metadata_.int_version;
1875 metadata_.version = kNoStringVersion;
1876 metadata_.id = kInvalidId;
1877 metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
1878 metadata_.object_stores.clear();
1879 callbacks->OnSuccess(old_version);
1880 factory_->DatabaseDeleted(identifier_);
1883 void IndexedDBDatabase::ForceClose() {
1884 // IndexedDBConnection::ForceClose() may delete this database, so hold ref.
1885 scoped_refptr<IndexedDBDatabase> protect(this);
1886 ConnectionSet::const_iterator it = connections_.begin();
1887 while (it != connections_.end()) {
1888 IndexedDBConnection* connection = *it++;
1889 connection->ForceClose();
1891 DCHECK(connections_.empty());
1894 void IndexedDBDatabase::VersionChangeIgnored() {
1895 if (pending_run_version_change_transaction_call_)
1896 pending_run_version_change_transaction_call_->callbacks()->OnBlocked(
1897 metadata_.int_version);
1899 for (const auto& pending_delete_call : pending_delete_calls_)
1900 pending_delete_call->callbacks()->OnBlocked(metadata_.int_version);
1904 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
1905 DCHECK(connections_.count(connection));
1906 DCHECK(connection->IsConnected());
1907 DCHECK(connection->database() == this);
1909 IDB_TRACE("IndexedDBDatabase::Close");
1911 connections_.erase(connection);
1913 // Abort outstanding transactions from the closing connection. This
1914 // can not happen if the close is requested by the connection itself
1915 // as the front-end defers the close until all transactions are
1916 // complete, but can occur on process termination or forced close.
1918 TransactionMap transactions(transactions_);
1919 for (const auto& it : transactions) {
1920 if (it.second->connection() == connection->callbacks())
1921 it.second->Abort(
1922 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
1923 "Connection is closing."));
1927 if (pending_second_half_open_ &&
1928 pending_second_half_open_->connection() == connection) {
1929 pending_second_half_open_->callbacks()->OnError(
1930 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError,
1931 "The connection was closed."));
1932 pending_second_half_open_.reset();
1935 ProcessPendingCalls();
1937 // TODO(jsbell): Add a test for the pending_open_calls_ cases below.
1938 if (!ConnectionCount() && !pending_open_calls_.size() &&
1939 !pending_delete_calls_.size()) {
1940 DCHECK(transactions_.empty());
1942 const GURL origin_url = backing_store_->origin_url();
1943 backing_store_ = NULL;
1945 factory_->ReleaseDatabase(identifier_, forced);
1949 void IndexedDBDatabase::CreateObjectStoreAbortOperation(
1950 int64 object_store_id,
1951 IndexedDBTransaction* transaction) {
1952 DCHECK(!transaction);
1953 IDB_TRACE("IndexedDBDatabase::CreateObjectStoreAbortOperation");
1954 RemoveObjectStore(object_store_id);
1957 void IndexedDBDatabase::DeleteObjectStoreAbortOperation(
1958 const IndexedDBObjectStoreMetadata& object_store_metadata,
1959 IndexedDBTransaction* transaction) {
1960 DCHECK(!transaction);
1961 IDB_TRACE("IndexedDBDatabase::DeleteObjectStoreAbortOperation");
1962 AddObjectStore(object_store_metadata,
1963 IndexedDBObjectStoreMetadata::kInvalidId);
1966 void IndexedDBDatabase::VersionChangeAbortOperation(
1967 const base::string16& previous_version,
1968 int64 previous_int_version,
1969 IndexedDBTransaction* transaction) {
1970 DCHECK(!transaction);
1971 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation");
1972 metadata_.version = previous_version;
1973 metadata_.int_version = previous_int_version;
1976 } // namespace content