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