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 <set> 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 27 using base::Int64ToString16; 28 using WebKit::WebIDBKeyTypeNumber; 29 30 namespace content { 31 32 class 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 46 class 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 60 class 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 86 class 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 98 class 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 111 class 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 128 class 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 144 class 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 160 class 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 176 class 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 192 class 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 226 class PutOperation : public IndexedDBTransaction::Operation { 227 public: 228 PutOperation(scoped_refptr<IndexedDBBackingStore> backing_store, 229 int64 database_id, 230 const IndexedDBObjectStoreMetadata& object_store, 231 std::string* 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::string 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 261 class 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 271 class 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 305 class 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 330 class 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 352 class 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. 373 class 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. 399 class 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. 424 class 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 446 class 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 456 scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create( 457 const string16& name, 458 IndexedDBBackingStore* database, 459 IndexedDBFactory* factory, 460 const Identifier& 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 468 namespace { 469 const base::string16::value_type kNoStringVersion[] = {0}; 470 471 template <typename T, typename U> 472 bool Contains(const T& container, const U& item) { 473 return container.find(item) != container.end(); 474 } 475 } 476 477 IndexedDBDatabase::IndexedDBDatabase( 478 const string16& name, 479 IndexedDBBackingStore* backing_store, 480 IndexedDBFactory* factory, 481 const Identifier& unique_identifier) 482 : backing_store_(backing_store), 483 metadata_(name, 484 kInvalidId, 485 kNoStringVersion, 486 IndexedDBDatabaseMetadata::NO_INT_VERSION, 487 kInvalidId), 488 identifier_(unique_identifier), 489 factory_(factory), 490 running_version_change_transaction_(NULL), 491 closing_connection_(false) { 492 DCHECK(!metadata_.name.empty()); 493 } 494 495 void IndexedDBDatabase::AddObjectStore( 496 const IndexedDBObjectStoreMetadata& object_store, 497 int64 new_max_object_store_id) { 498 DCHECK(metadata_.object_stores.find(object_store.id) == 499 metadata_.object_stores.end()); 500 if (new_max_object_store_id != IndexedDBObjectStoreMetadata::kInvalidId) { 501 DCHECK_LT(metadata_.max_object_store_id, new_max_object_store_id); 502 metadata_.max_object_store_id = new_max_object_store_id; 503 } 504 metadata_.object_stores[object_store.id] = object_store; 505 } 506 507 void IndexedDBDatabase::RemoveObjectStore(int64 object_store_id) { 508 DCHECK(metadata_.object_stores.find(object_store_id) != 509 metadata_.object_stores.end()); 510 metadata_.object_stores.erase(object_store_id); 511 } 512 513 void IndexedDBDatabase::AddIndex(int64 object_store_id, 514 const IndexedDBIndexMetadata& index, 515 int64 new_max_index_id) { 516 DCHECK(metadata_.object_stores.find(object_store_id) != 517 metadata_.object_stores.end()); 518 IndexedDBObjectStoreMetadata object_store = 519 metadata_.object_stores[object_store_id]; 520 521 DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end()); 522 object_store.indexes[index.id] = index; 523 if (new_max_index_id != IndexedDBIndexMetadata::kInvalidId) { 524 DCHECK_LT(object_store.max_index_id, new_max_index_id); 525 object_store.max_index_id = new_max_index_id; 526 } 527 metadata_.object_stores[object_store_id] = object_store; 528 } 529 530 void IndexedDBDatabase::RemoveIndex(int64 object_store_id, int64 index_id) { 531 DCHECK(metadata_.object_stores.find(object_store_id) != 532 metadata_.object_stores.end()); 533 IndexedDBObjectStoreMetadata object_store = 534 metadata_.object_stores[object_store_id]; 535 536 DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); 537 object_store.indexes.erase(index_id); 538 metadata_.object_stores[object_store_id] = object_store; 539 } 540 541 bool IndexedDBDatabase::OpenInternal() { 542 bool success = false; 543 bool ok = backing_store_->GetIDBDatabaseMetaData( 544 metadata_.name, &metadata_, &success); 545 DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success 546 << " id = " << metadata_.id; 547 if (!ok) 548 return false; 549 if (success) 550 return backing_store_->GetObjectStores(metadata_.id, 551 &metadata_.object_stores); 552 553 return backing_store_->CreateIDBDatabaseMetaData( 554 metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id); 555 } 556 557 IndexedDBDatabase::~IndexedDBDatabase() { 558 DCHECK(transactions_.empty()); 559 DCHECK(pending_open_calls_.empty()); 560 DCHECK(pending_delete_calls_.empty()); 561 } 562 563 scoped_refptr<IndexedDBBackingStore> IndexedDBDatabase::BackingStore() const { 564 return backing_store_; 565 } 566 567 IndexedDBTransaction* IndexedDBDatabase::GetTransaction( 568 int64 transaction_id) const { 569 TransactionMap::const_iterator trans_iterator = 570 transactions_.find(transaction_id); 571 if (trans_iterator == transactions_.end()) 572 return NULL; 573 return trans_iterator->second; 574 } 575 576 bool IndexedDBDatabase::ValidateObjectStoreId(int64 object_store_id) const { 577 if (!Contains(metadata_.object_stores, object_store_id)) { 578 DLOG(ERROR) << "Invalid object_store_id"; 579 return false; 580 } 581 return true; 582 } 583 584 bool IndexedDBDatabase::ValidateObjectStoreIdAndIndexId(int64 object_store_id, 585 int64 index_id) const { 586 if (!ValidateObjectStoreId(object_store_id)) 587 return false; 588 const IndexedDBObjectStoreMetadata& object_store_metadata = 589 metadata_.object_stores.find(object_store_id)->second; 590 if (!Contains(object_store_metadata.indexes, index_id)) { 591 DLOG(ERROR) << "Invalid index_id"; 592 return false; 593 } 594 return true; 595 } 596 597 bool IndexedDBDatabase::ValidateObjectStoreIdAndOptionalIndexId( 598 int64 object_store_id, 599 int64 index_id) const { 600 if (!ValidateObjectStoreId(object_store_id)) 601 return false; 602 const IndexedDBObjectStoreMetadata& object_store_metadata = 603 metadata_.object_stores.find(object_store_id)->second; 604 if (index_id != IndexedDBIndexMetadata::kInvalidId && 605 !Contains(object_store_metadata.indexes, index_id)) { 606 DLOG(ERROR) << "Invalid index_id"; 607 return false; 608 } 609 return true; 610 } 611 612 bool IndexedDBDatabase::ValidateObjectStoreIdAndNewIndexId( 613 int64 object_store_id, 614 int64 index_id) const { 615 if (!ValidateObjectStoreId(object_store_id)) 616 return false; 617 const IndexedDBObjectStoreMetadata& object_store_metadata = 618 metadata_.object_stores.find(object_store_id)->second; 619 if (Contains(object_store_metadata.indexes, index_id)) { 620 DLOG(ERROR) << "Invalid index_id"; 621 return false; 622 } 623 return true; 624 } 625 626 void IndexedDBDatabase::CreateObjectStore(int64 transaction_id, 627 int64 object_store_id, 628 const string16& name, 629 const IndexedDBKeyPath& key_path, 630 bool auto_increment) { 631 IDB_TRACE("IndexedDBDatabase::CreateObjectStore"); 632 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 633 if (!transaction) 634 return; 635 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 636 637 if (Contains(metadata_.object_stores, object_store_id)) { 638 DLOG(ERROR) << "Invalid object_store_id"; 639 return; 640 } 641 642 IndexedDBObjectStoreMetadata object_store_metadata( 643 name, 644 object_store_id, 645 key_path, 646 auto_increment, 647 IndexedDBDatabase::kMinimumIndexId); 648 649 transaction->ScheduleTask( 650 new CreateObjectStoreOperation(backing_store_, object_store_metadata), 651 new CreateObjectStoreAbortOperation(this, object_store_id)); 652 653 AddObjectStore(object_store_metadata, object_store_id); 654 } 655 656 void CreateObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { 657 IDB_TRACE("CreateObjectStoreOperation"); 658 if (!backing_store_->CreateObjectStore( 659 transaction->BackingStoreTransaction(), 660 transaction->database()->id(), 661 object_store_metadata_.id, 662 object_store_metadata_.name, 663 object_store_metadata_.key_path, 664 object_store_metadata_.auto_increment)) { 665 transaction->Abort(IndexedDBDatabaseError( 666 WebKit::WebIDBDatabaseExceptionUnknownError, 667 ASCIIToUTF16("Internal error creating object store '") + 668 object_store_metadata_.name + ASCIIToUTF16("'."))); 669 return; 670 } 671 } 672 673 void IndexedDBDatabase::DeleteObjectStore(int64 transaction_id, 674 int64 object_store_id) { 675 IDB_TRACE("IndexedDBDatabase::DeleteObjectStore"); 676 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 677 if (!transaction) 678 return; 679 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 680 681 if (!ValidateObjectStoreId(object_store_id)) 682 return; 683 684 const IndexedDBObjectStoreMetadata& object_store_metadata = 685 metadata_.object_stores[object_store_id]; 686 687 transaction->ScheduleTask( 688 new DeleteObjectStoreOperation(backing_store_, object_store_metadata), 689 new DeleteObjectStoreAbortOperation(this, object_store_metadata)); 690 RemoveObjectStore(object_store_id); 691 } 692 693 void IndexedDBDatabase::CreateIndex(int64 transaction_id, 694 int64 object_store_id, 695 int64 index_id, 696 const string16& name, 697 const IndexedDBKeyPath& key_path, 698 bool unique, 699 bool multi_entry) { 700 IDB_TRACE("IndexedDBDatabase::CreateIndex"); 701 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 702 if (!transaction) 703 return; 704 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 705 706 if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id)) 707 return; 708 const IndexedDBIndexMetadata index_metadata( 709 name, index_id, key_path, unique, multi_entry); 710 711 transaction->ScheduleTask( 712 new CreateIndexOperation(backing_store_, object_store_id, index_metadata), 713 new CreateIndexAbortOperation(this, object_store_id, index_id)); 714 715 AddIndex(object_store_id, index_metadata, index_id); 716 } 717 718 void CreateIndexOperation::Perform(IndexedDBTransaction* transaction) { 719 IDB_TRACE("CreateIndexOperation"); 720 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(), 721 transaction->database()->id(), 722 object_store_id_, 723 index_metadata_.id, 724 index_metadata_.name, 725 index_metadata_.key_path, 726 index_metadata_.unique, 727 index_metadata_.multi_entry)) { 728 string16 error_string = ASCIIToUTF16("Internal error creating index '") + 729 index_metadata_.name + ASCIIToUTF16("'."); 730 transaction->Abort(IndexedDBDatabaseError( 731 WebKit::WebIDBDatabaseExceptionUnknownError, error_string)); 732 return; 733 } 734 } 735 736 void CreateIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { 737 IDB_TRACE("CreateIndexAbortOperation"); 738 DCHECK(!transaction); 739 database_->RemoveIndex(object_store_id_, index_id_); 740 } 741 742 void IndexedDBDatabase::DeleteIndex(int64 transaction_id, 743 int64 object_store_id, 744 int64 index_id) { 745 IDB_TRACE("IndexedDBDatabase::DeleteIndex"); 746 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 747 if (!transaction) 748 return; 749 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 750 751 if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id)) 752 return; 753 const IndexedDBIndexMetadata& index_metadata = 754 metadata_.object_stores[object_store_id].indexes[index_id]; 755 756 transaction->ScheduleTask( 757 new DeleteIndexOperation(backing_store_, object_store_id, index_metadata), 758 new DeleteIndexAbortOperation(this, object_store_id, index_metadata)); 759 760 RemoveIndex(object_store_id, index_id); 761 } 762 763 void DeleteIndexOperation::Perform(IndexedDBTransaction* transaction) { 764 IDB_TRACE("DeleteIndexOperation"); 765 bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(), 766 transaction->database()->id(), 767 object_store_id_, 768 index_metadata_.id); 769 if (!ok) { 770 string16 error_string = ASCIIToUTF16("Internal error deleting index '") + 771 index_metadata_.name + ASCIIToUTF16("'."); 772 transaction->Abort(IndexedDBDatabaseError( 773 WebKit::WebIDBDatabaseExceptionUnknownError, error_string)); 774 } 775 } 776 777 void DeleteIndexAbortOperation::Perform(IndexedDBTransaction* transaction) { 778 IDB_TRACE("DeleteIndexAbortOperation"); 779 DCHECK(!transaction); 780 database_->AddIndex( 781 object_store_id_, index_metadata_, IndexedDBIndexMetadata::kInvalidId); 782 } 783 784 void IndexedDBDatabase::Commit(int64 transaction_id) { 785 // The frontend suggests that we commit, but we may have previously initiated 786 // an abort, and so have disposed of the transaction. on_abort has already 787 // been dispatched to the frontend, so it will find out about that 788 // asynchronously. 789 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 790 if (transaction) 791 transaction->Commit(); 792 } 793 794 void IndexedDBDatabase::Abort(int64 transaction_id) { 795 // If the transaction is unknown, then it has already been aborted by the 796 // backend before this call so it is safe to ignore it. 797 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 798 if (transaction) 799 transaction->Abort(); 800 } 801 802 void IndexedDBDatabase::Abort(int64 transaction_id, 803 const IndexedDBDatabaseError& error) { 804 // If the transaction is unknown, then it has already been aborted by the 805 // backend before this call so it is safe to ignore it. 806 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 807 if (transaction) 808 transaction->Abort(error); 809 } 810 811 void IndexedDBDatabase::Get(int64 transaction_id, 812 int64 object_store_id, 813 int64 index_id, 814 scoped_ptr<IndexedDBKeyRange> key_range, 815 bool key_only, 816 scoped_refptr<IndexedDBCallbacks> callbacks) { 817 IDB_TRACE("IndexedDBDatabase::Get"); 818 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 819 if (!transaction) 820 return; 821 822 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) 823 return; 824 const IndexedDBObjectStoreMetadata& object_store_metadata = 825 metadata_.object_stores[object_store_id]; 826 827 transaction->ScheduleTask(new GetOperation( 828 backing_store_, 829 metadata_.id, 830 object_store_id, 831 index_id, 832 object_store_metadata.key_path, 833 object_store_metadata.auto_increment, 834 key_range.Pass(), 835 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, 836 callbacks)); 837 } 838 839 void GetOperation::Perform(IndexedDBTransaction* transaction) { 840 IDB_TRACE("GetOperation"); 841 842 const IndexedDBKey* key; 843 844 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; 845 if (key_range_->IsOnlyKey()) { 846 key = &key_range_->lower(); 847 } else { 848 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { 849 DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY); 850 // ObjectStore Retrieval Operation 851 backing_store_cursor = backing_store_->OpenObjectStoreCursor( 852 transaction->BackingStoreTransaction(), 853 database_id_, 854 object_store_id_, 855 *key_range_, 856 indexed_db::CURSOR_NEXT); 857 } else if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { 858 // Index Value Retrieval Operation 859 backing_store_cursor = backing_store_->OpenIndexKeyCursor( 860 transaction->BackingStoreTransaction(), 861 database_id_, 862 object_store_id_, 863 index_id_, 864 *key_range_, 865 indexed_db::CURSOR_NEXT); 866 } else { 867 // Index Referenced Value Retrieval Operation 868 backing_store_cursor = backing_store_->OpenIndexCursor( 869 transaction->BackingStoreTransaction(), 870 database_id_, 871 object_store_id_, 872 index_id_, 873 *key_range_, 874 indexed_db::CURSOR_NEXT); 875 } 876 877 if (!backing_store_cursor) { 878 callbacks_->OnSuccess(); 879 return; 880 } 881 882 key = &backing_store_cursor->key(); 883 } 884 885 scoped_ptr<IndexedDBKey> primary_key; 886 bool ok; 887 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { 888 // Object Store Retrieval Operation 889 std::string value; 890 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), 891 database_id_, 892 object_store_id_, 893 *key, 894 &value); 895 if (!ok) { 896 callbacks_->OnError( 897 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 898 "Internal error in GetRecord.")); 899 return; 900 } 901 902 if (value.empty()) { 903 callbacks_->OnSuccess(); 904 return; 905 } 906 907 if (auto_increment_ && !key_path_.IsNull()) { 908 callbacks_->OnSuccess(&value, *key, key_path_); 909 return; 910 } 911 912 callbacks_->OnSuccess(&value); 913 return; 914 } 915 916 // From here we are dealing only with indexes. 917 ok = backing_store_->GetPrimaryKeyViaIndex( 918 transaction->BackingStoreTransaction(), 919 database_id_, 920 object_store_id_, 921 index_id_, 922 *key, 923 &primary_key); 924 if (!ok) { 925 callbacks_->OnError( 926 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 927 "Internal error in GetPrimaryKeyViaIndex.")); 928 return; 929 } 930 if (!primary_key) { 931 callbacks_->OnSuccess(); 932 return; 933 } 934 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { 935 // Index Value Retrieval Operation 936 callbacks_->OnSuccess(*primary_key); 937 return; 938 } 939 940 // Index Referenced Value Retrieval Operation 941 std::string value; 942 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), 943 database_id_, 944 object_store_id_, 945 *primary_key, 946 &value); 947 if (!ok) { 948 callbacks_->OnError( 949 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 950 "Internal error in GetRecord.")); 951 return; 952 } 953 954 if (value.empty()) { 955 callbacks_->OnSuccess(); 956 return; 957 } 958 if (auto_increment_ && !key_path_.IsNull()) { 959 callbacks_->OnSuccess(&value, *primary_key, key_path_); 960 return; 961 } 962 callbacks_->OnSuccess(&value); 963 } 964 965 static scoped_ptr<IndexedDBKey> GenerateKey( 966 scoped_refptr<IndexedDBBackingStore> backing_store, 967 scoped_refptr<IndexedDBTransaction> transaction, 968 int64 database_id, 969 int64 object_store_id) { 970 const int64 max_generator_value = 971 9007199254740992LL; // Maximum integer storable as ECMAScript number. 972 int64 current_number; 973 bool ok = backing_store->GetKeyGeneratorCurrentNumber( 974 transaction->BackingStoreTransaction(), 975 database_id, 976 object_store_id, 977 ¤t_number); 978 if (!ok) { 979 LOG(ERROR) << "Failed to GetKeyGeneratorCurrentNumber"; 980 return make_scoped_ptr(new IndexedDBKey()); 981 } 982 if (current_number < 0 || current_number > max_generator_value) 983 return make_scoped_ptr(new IndexedDBKey()); 984 985 return make_scoped_ptr( 986 new IndexedDBKey(current_number, WebIDBKeyTypeNumber)); 987 } 988 989 static bool UpdateKeyGenerator( 990 scoped_refptr<IndexedDBBackingStore> backing_store, 991 scoped_refptr<IndexedDBTransaction> transaction, 992 int64 database_id, 993 int64 object_store_id, 994 const IndexedDBKey* key, 995 bool check_current) { 996 DCHECK(key); 997 DCHECK_EQ(WebIDBKeyTypeNumber, key->type()); 998 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber( 999 transaction->BackingStoreTransaction(), 1000 database_id, 1001 object_store_id, 1002 static_cast<int64>(floor(key->number())) + 1, 1003 check_current); 1004 } 1005 1006 void IndexedDBDatabase::Put(int64 transaction_id, 1007 int64 object_store_id, 1008 std::string* value, 1009 scoped_ptr<IndexedDBKey> key, 1010 PutMode put_mode, 1011 scoped_refptr<IndexedDBCallbacks> callbacks, 1012 const std::vector<int64>& index_ids, 1013 const std::vector<IndexKeys>& index_keys) { 1014 IDB_TRACE("IndexedDBDatabase::Put"); 1015 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1016 if (!transaction) 1017 return; 1018 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 1019 1020 if (!ValidateObjectStoreId(object_store_id)) 1021 return; 1022 const IndexedDBObjectStoreMetadata& object_store_metadata = 1023 metadata_.object_stores[object_store_id]; 1024 1025 DCHECK(key); 1026 DCHECK(object_store_metadata.auto_increment || key->IsValid()); 1027 transaction->ScheduleTask(new PutOperation(backing_store_, 1028 id(), 1029 object_store_metadata, 1030 value, 1031 key.Pass(), 1032 put_mode, 1033 callbacks, 1034 index_ids, 1035 index_keys)); 1036 } 1037 1038 void PutOperation::Perform(IndexedDBTransaction* transaction) { 1039 IDB_TRACE("PutOperation"); 1040 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 1041 DCHECK_EQ(index_ids_.size(), index_keys_.size()); 1042 bool key_was_generated = false; 1043 1044 scoped_ptr<IndexedDBKey> key; 1045 if (put_mode_ != IndexedDBDatabase::CURSOR_UPDATE && 1046 object_store_.auto_increment && !key_->IsValid()) { 1047 scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey( 1048 backing_store_, transaction, database_id_, object_store_.id); 1049 key_was_generated = true; 1050 if (!auto_inc_key->IsValid()) { 1051 callbacks_->OnError( 1052 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionConstraintError, 1053 "Maximum key generator value reached.")); 1054 return; 1055 } 1056 key = auto_inc_key.Pass(); 1057 } else { 1058 key = key_.Pass(); 1059 } 1060 1061 DCHECK(key->IsValid()); 1062 1063 IndexedDBBackingStore::RecordIdentifier record_identifier; 1064 if (put_mode_ == IndexedDBDatabase::ADD_ONLY) { 1065 bool found = false; 1066 bool ok = backing_store_->KeyExistsInObjectStore( 1067 transaction->BackingStoreTransaction(), 1068 database_id_, 1069 object_store_.id, 1070 *key.get(), 1071 &record_identifier, 1072 &found); 1073 if (!ok) { 1074 callbacks_->OnError( 1075 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 1076 "Internal error checking key existence.")); 1077 return; 1078 } 1079 if (found) { 1080 callbacks_->OnError( 1081 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionConstraintError, 1082 "Key already exists in the object store.")); 1083 return; 1084 } 1085 } 1086 1087 ScopedVector<IndexWriter> index_writers; 1088 string16 error_message; 1089 bool obeys_constraints = false; 1090 bool backing_store_success = MakeIndexWriters(transaction, 1091 backing_store_, 1092 database_id_, 1093 object_store_, 1094 *key, 1095 key_was_generated, 1096 index_ids_, 1097 index_keys_, 1098 &index_writers, 1099 &error_message, 1100 &obeys_constraints); 1101 if (!backing_store_success) { 1102 callbacks_->OnError(IndexedDBDatabaseError( 1103 WebKit::WebIDBDatabaseExceptionUnknownError, 1104 "Internal error: backing store error updating index keys.")); 1105 return; 1106 } 1107 if (!obeys_constraints) { 1108 callbacks_->OnError(IndexedDBDatabaseError( 1109 WebKit::WebIDBDatabaseExceptionConstraintError, error_message)); 1110 return; 1111 } 1112 1113 // Before this point, don't do any mutation. After this point, rollback the 1114 // transaction in case of error. 1115 backing_store_success = 1116 backing_store_->PutRecord(transaction->BackingStoreTransaction(), 1117 database_id_, 1118 object_store_.id, 1119 *key.get(), 1120 value_, 1121 &record_identifier); 1122 if (!backing_store_success) { 1123 callbacks_->OnError(IndexedDBDatabaseError( 1124 WebKit::WebIDBDatabaseExceptionUnknownError, 1125 "Internal error: backing store error performing put/add.")); 1126 return; 1127 } 1128 1129 for (size_t i = 0; i < index_writers.size(); ++i) { 1130 IndexWriter* index_writer = index_writers[i]; 1131 index_writer->WriteIndexKeys(record_identifier, 1132 backing_store_, 1133 transaction->BackingStoreTransaction(), 1134 database_id_, 1135 object_store_.id); 1136 } 1137 1138 if (object_store_.auto_increment && 1139 put_mode_ != IndexedDBDatabase::CURSOR_UPDATE && 1140 key->type() == WebIDBKeyTypeNumber) { 1141 bool ok = UpdateKeyGenerator(backing_store_, 1142 transaction, 1143 database_id_, 1144 object_store_.id, 1145 key.get(), 1146 !key_was_generated); 1147 if (!ok) { 1148 callbacks_->OnError( 1149 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 1150 "Internal error updating key generator.")); 1151 return; 1152 } 1153 } 1154 1155 callbacks_->OnSuccess(*key); 1156 } 1157 1158 void IndexedDBDatabase::SetIndexKeys(int64 transaction_id, 1159 int64 object_store_id, 1160 scoped_ptr<IndexedDBKey> primary_key, 1161 const std::vector<int64>& index_ids, 1162 const std::vector<IndexKeys>& index_keys) { 1163 IDB_TRACE("IndexedDBDatabase::SetIndexKeys"); 1164 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1165 if (!transaction) 1166 return; 1167 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 1168 1169 scoped_refptr<IndexedDBBackingStore> store = BackingStore(); 1170 // TODO(alecflett): This method could be asynchronous, but we need to 1171 // evaluate if it's worth the extra complexity. 1172 IndexedDBBackingStore::RecordIdentifier record_identifier; 1173 bool found = false; 1174 bool ok = 1175 store->KeyExistsInObjectStore(transaction->BackingStoreTransaction(), 1176 metadata_.id, 1177 object_store_id, 1178 *primary_key, 1179 &record_identifier, 1180 &found); 1181 if (!ok) { 1182 transaction->Abort( 1183 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 1184 "Internal error setting index keys.")); 1185 return; 1186 } 1187 if (!found) { 1188 transaction->Abort(IndexedDBDatabaseError( 1189 WebKit::WebIDBDatabaseExceptionUnknownError, 1190 "Internal error setting index keys for object store.")); 1191 return; 1192 } 1193 1194 ScopedVector<IndexWriter> index_writers; 1195 string16 error_message; 1196 bool obeys_constraints = false; 1197 DCHECK(metadata_.object_stores.find(object_store_id) != 1198 metadata_.object_stores.end()); 1199 const IndexedDBObjectStoreMetadata& object_store_metadata = 1200 metadata_.object_stores[object_store_id]; 1201 bool backing_store_success = MakeIndexWriters(transaction, 1202 store, 1203 id(), 1204 object_store_metadata, 1205 *primary_key, 1206 false, 1207 index_ids, 1208 index_keys, 1209 &index_writers, 1210 &error_message, 1211 &obeys_constraints); 1212 if (!backing_store_success) { 1213 transaction->Abort(IndexedDBDatabaseError( 1214 WebKit::WebIDBDatabaseExceptionUnknownError, 1215 "Internal error: backing store error updating index keys.")); 1216 return; 1217 } 1218 if (!obeys_constraints) { 1219 transaction->Abort(IndexedDBDatabaseError( 1220 WebKit::WebIDBDatabaseExceptionConstraintError, error_message)); 1221 return; 1222 } 1223 1224 for (size_t i = 0; i < index_writers.size(); ++i) { 1225 IndexWriter* index_writer = index_writers[i]; 1226 index_writer->WriteIndexKeys(record_identifier, 1227 store, 1228 transaction->BackingStoreTransaction(), 1229 id(), 1230 object_store_id); 1231 } 1232 } 1233 1234 void IndexedDBDatabase::SetIndexesReady(int64 transaction_id, 1235 int64, 1236 const std::vector<int64>& index_ids) { 1237 IDB_TRACE("IndexedDBDatabase::SetIndexesReady"); 1238 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1239 if (!transaction) 1240 return; 1241 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 1242 1243 transaction->ScheduleTask(IndexedDBDatabase::PREEMPTIVE_TASK, 1244 new SetIndexesReadyOperation(index_ids.size())); 1245 } 1246 1247 void SetIndexesReadyOperation::Perform(IndexedDBTransaction* transaction) { 1248 IDB_TRACE("SetIndexesReadyOperation"); 1249 for (size_t i = 0; i < index_count_; ++i) 1250 transaction->DidCompletePreemptiveEvent(); 1251 } 1252 1253 void IndexedDBDatabase::OpenCursor( 1254 int64 transaction_id, 1255 int64 object_store_id, 1256 int64 index_id, 1257 scoped_ptr<IndexedDBKeyRange> key_range, 1258 indexed_db::CursorDirection direction, 1259 bool key_only, 1260 TaskType task_type, 1261 scoped_refptr<IndexedDBCallbacks> callbacks) { 1262 IDB_TRACE("IndexedDBDatabase::OpenCursor"); 1263 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1264 if (!transaction) 1265 return; 1266 1267 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) 1268 return; 1269 1270 transaction->ScheduleTask(new OpenCursorOperation( 1271 backing_store_, 1272 id(), 1273 object_store_id, 1274 index_id, 1275 key_range.Pass(), 1276 direction, 1277 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, 1278 task_type, 1279 callbacks)); 1280 } 1281 1282 void OpenCursorOperation::Perform(IndexedDBTransaction* transaction) { 1283 IDB_TRACE("OpenCursorOperation"); 1284 1285 // The frontend has begun indexing, so this pauses the transaction 1286 // until the indexing is complete. This can't happen any earlier 1287 // because we don't want to switch to early mode in case multiple 1288 // indexes are being created in a row, with Put()'s in between. 1289 if (task_type_ == IndexedDBDatabase::PREEMPTIVE_TASK) 1290 transaction->AddPreemptiveEvent(); 1291 1292 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; 1293 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { 1294 DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY); 1295 backing_store_cursor = backing_store_->OpenObjectStoreCursor( 1296 transaction->BackingStoreTransaction(), 1297 database_id_, 1298 object_store_id_, 1299 *key_range_, 1300 direction_); 1301 } else { 1302 DCHECK_EQ(task_type_, IndexedDBDatabase::NORMAL_TASK); 1303 if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) { 1304 backing_store_cursor = backing_store_->OpenIndexKeyCursor( 1305 transaction->BackingStoreTransaction(), 1306 database_id_, 1307 object_store_id_, 1308 index_id_, 1309 *key_range_, 1310 direction_); 1311 } else { 1312 backing_store_cursor = backing_store_->OpenIndexCursor( 1313 transaction->BackingStoreTransaction(), 1314 database_id_, 1315 object_store_id_, 1316 index_id_, 1317 *key_range_, 1318 direction_); 1319 } 1320 } 1321 1322 if (!backing_store_cursor) { 1323 callbacks_->OnSuccess(static_cast<std::string*>(NULL)); 1324 return; 1325 } 1326 1327 scoped_refptr<IndexedDBCursor> cursor = new IndexedDBCursor( 1328 backing_store_cursor.Pass(), cursor_type_, task_type_, transaction); 1329 callbacks_->OnSuccess( 1330 cursor, cursor->key(), cursor->primary_key(), cursor->Value()); 1331 } 1332 1333 void IndexedDBDatabase::Count(int64 transaction_id, 1334 int64 object_store_id, 1335 int64 index_id, 1336 scoped_ptr<IndexedDBKeyRange> key_range, 1337 scoped_refptr<IndexedDBCallbacks> callbacks) { 1338 IDB_TRACE("IndexedDBDatabase::Count"); 1339 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1340 if (!transaction) 1341 return; 1342 1343 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) 1344 return; 1345 1346 transaction->ScheduleTask(new CountOperation(backing_store_, 1347 id(), 1348 object_store_id, 1349 index_id, 1350 key_range.Pass(), 1351 callbacks)); 1352 } 1353 1354 void CountOperation::Perform(IndexedDBTransaction* transaction) { 1355 IDB_TRACE("CountOperation"); 1356 uint32 count = 0; 1357 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; 1358 1359 if (index_id_ == IndexedDBIndexMetadata::kInvalidId) { 1360 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor( 1361 transaction->BackingStoreTransaction(), 1362 database_id_, 1363 object_store_id_, 1364 *key_range_, 1365 indexed_db::CURSOR_NEXT); 1366 } else { 1367 backing_store_cursor = backing_store_->OpenIndexKeyCursor( 1368 transaction->BackingStoreTransaction(), 1369 database_id_, 1370 object_store_id_, 1371 index_id_, 1372 *key_range_, 1373 indexed_db::CURSOR_NEXT); 1374 } 1375 if (!backing_store_cursor) { 1376 callbacks_->OnSuccess(count); 1377 return; 1378 } 1379 1380 do { 1381 ++count; 1382 } while (backing_store_cursor->Continue()); 1383 1384 callbacks_->OnSuccess(count); 1385 } 1386 1387 void IndexedDBDatabase::DeleteRange( 1388 int64 transaction_id, 1389 int64 object_store_id, 1390 scoped_ptr<IndexedDBKeyRange> key_range, 1391 scoped_refptr<IndexedDBCallbacks> callbacks) { 1392 IDB_TRACE("IndexedDBDatabase::DeleteRange"); 1393 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1394 if (!transaction) 1395 return; 1396 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 1397 1398 if (!ValidateObjectStoreId(object_store_id)) 1399 return; 1400 1401 transaction->ScheduleTask(new DeleteRangeOperation( 1402 backing_store_, id(), object_store_id, key_range.Pass(), callbacks)); 1403 } 1404 1405 void DeleteRangeOperation::Perform(IndexedDBTransaction* transaction) { 1406 IDB_TRACE("DeleteRangeOperation"); 1407 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = 1408 backing_store_->OpenObjectStoreCursor( 1409 transaction->BackingStoreTransaction(), 1410 database_id_, 1411 object_store_id_, 1412 *key_range_, 1413 indexed_db::CURSOR_NEXT); 1414 if (backing_store_cursor) { 1415 do { 1416 if (!backing_store_->DeleteRecord( 1417 transaction->BackingStoreTransaction(), 1418 database_id_, 1419 object_store_id_, 1420 backing_store_cursor->record_identifier())) { 1421 callbacks_->OnError( 1422 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 1423 "Internal error deleting data in range")); 1424 return; 1425 } 1426 } while (backing_store_cursor->Continue()); 1427 } 1428 1429 callbacks_->OnSuccess(); 1430 } 1431 1432 void IndexedDBDatabase::Clear(int64 transaction_id, 1433 int64 object_store_id, 1434 scoped_refptr<IndexedDBCallbacks> callbacks) { 1435 IDB_TRACE("IndexedDBDatabase::Clear"); 1436 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1437 if (!transaction) 1438 return; 1439 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 1440 1441 if (!ValidateObjectStoreId(object_store_id)) 1442 return; 1443 1444 transaction->ScheduleTask( 1445 new ClearOperation(backing_store_, id(), object_store_id, callbacks)); 1446 } 1447 1448 void ClearOperation::Perform(IndexedDBTransaction* transaction) { 1449 IDB_TRACE("ObjectStoreClearOperation"); 1450 if (!backing_store_->ClearObjectStore(transaction->BackingStoreTransaction(), 1451 database_id_, 1452 object_store_id_)) { 1453 callbacks_->OnError( 1454 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 1455 "Internal error clearing object store")); 1456 return; 1457 } 1458 callbacks_->OnSuccess(); 1459 } 1460 1461 void DeleteObjectStoreOperation::Perform(IndexedDBTransaction* transaction) { 1462 IDB_TRACE("DeleteObjectStoreOperation"); 1463 bool ok = 1464 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(), 1465 transaction->database()->id(), 1466 object_store_metadata_.id); 1467 if (!ok) { 1468 string16 error_string = 1469 ASCIIToUTF16("Internal error deleting object store '") + 1470 object_store_metadata_.name + ASCIIToUTF16("'."); 1471 transaction->Abort(IndexedDBDatabaseError( 1472 WebKit::WebIDBDatabaseExceptionUnknownError, error_string)); 1473 } 1474 } 1475 1476 void IndexedDBDatabase::VersionChangeOperation::Perform( 1477 IndexedDBTransaction* transaction) { 1478 IDB_TRACE("VersionChangeOperation"); 1479 int64 database_id = database_->id(); 1480 int64 old_version = database_->metadata_.int_version; 1481 DCHECK_GT(version_, old_version); 1482 database_->metadata_.int_version = version_; 1483 if (!database_->backing_store_->UpdateIDBDatabaseIntVersion( 1484 transaction->BackingStoreTransaction(), 1485 database_id, 1486 database_->metadata_.int_version)) { 1487 IndexedDBDatabaseError error( 1488 WebKit::WebIDBDatabaseExceptionUnknownError, 1489 ASCIIToUTF16( 1490 "Internal error writing data to stable storage when " 1491 "updating version.")); 1492 callbacks_->OnError(error); 1493 transaction->Abort(error); 1494 return; 1495 } 1496 DCHECK(!database_->pending_second_half_open_); 1497 1498 database_->pending_second_half_open_.reset(new PendingSuccessCall( 1499 callbacks_, connection_.get(), transaction_id_, version_)); 1500 callbacks_->OnUpgradeNeeded( 1501 old_version, connection_.Pass(), database_->metadata(), data_loss_); 1502 } 1503 1504 void IndexedDBDatabase::TransactionStarted(IndexedDBTransaction* transaction) { 1505 1506 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1507 DCHECK(!running_version_change_transaction_); 1508 running_version_change_transaction_ = transaction; 1509 } 1510 } 1511 1512 void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction) { 1513 1514 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); 1515 DCHECK_EQ(transactions_[transaction->id()], transaction); 1516 transactions_.erase(transaction->id()); 1517 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1518 DCHECK_EQ(transaction, running_version_change_transaction_); 1519 running_version_change_transaction_ = NULL; 1520 } 1521 } 1522 1523 void IndexedDBDatabase::TransactionFinishedAndAbortFired( 1524 IndexedDBTransaction* transaction) { 1525 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1526 if (pending_second_half_open_) { 1527 pending_second_half_open_->Callbacks()->OnError( 1528 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionAbortError, 1529 "Version change transaction was aborted in " 1530 "upgradeneeded event handler.")); 1531 pending_second_half_open_.reset(); 1532 } 1533 ProcessPendingCalls(); 1534 } 1535 } 1536 1537 void IndexedDBDatabase::TransactionFinishedAndCompleteFired( 1538 IndexedDBTransaction* transaction) { 1539 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1540 DCHECK(pending_second_half_open_); 1541 if (pending_second_half_open_) { 1542 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); 1543 DCHECK(metadata_.id != kInvalidId); 1544 1545 // Connection was already minted for OnUpgradeNeeded callback. 1546 scoped_ptr<IndexedDBConnection> connection; 1547 1548 pending_second_half_open_->Callbacks()->OnSuccess( 1549 connection.Pass(), this->metadata()); 1550 pending_second_half_open_.reset(); 1551 } 1552 ProcessPendingCalls(); 1553 } 1554 } 1555 1556 size_t IndexedDBDatabase::ConnectionCount() const { 1557 // This does not include pending open calls, as those should not block version 1558 // changes and deletes. 1559 return connections_.size(); 1560 } 1561 1562 size_t IndexedDBDatabase::PendingOpenCount() const { 1563 return pending_open_calls_.size(); 1564 } 1565 1566 size_t IndexedDBDatabase::PendingUpgradeCount() const { 1567 return pending_run_version_change_transaction_call_ ? 1 : 0; 1568 } 1569 1570 size_t IndexedDBDatabase::RunningUpgradeCount() const { 1571 return pending_second_half_open_ ? 1 : 0; 1572 } 1573 1574 size_t IndexedDBDatabase::PendingDeleteCount() const { 1575 return pending_delete_calls_.size(); 1576 } 1577 1578 void IndexedDBDatabase::ProcessPendingCalls() { 1579 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) { 1580 DCHECK(pending_run_version_change_transaction_call_->Version() > 1581 metadata_.int_version); 1582 scoped_ptr<PendingUpgradeCall> pending_call = 1583 pending_run_version_change_transaction_call_.Pass(); 1584 RunVersionChangeTransactionFinal(pending_call->Callbacks(), 1585 pending_call->Connection(), 1586 pending_call->TransactionId(), 1587 pending_call->Version()); 1588 DCHECK_EQ(static_cast<size_t>(1), ConnectionCount()); 1589 // Fall through would be a no-op, since transaction must complete 1590 // asynchronously. 1591 DCHECK(IsDeleteDatabaseBlocked()); 1592 DCHECK(IsOpenConnectionBlocked()); 1593 return; 1594 } 1595 1596 if (!IsDeleteDatabaseBlocked()) { 1597 PendingDeleteCallList pending_delete_calls; 1598 pending_delete_calls_.swap(pending_delete_calls); 1599 while (!pending_delete_calls.empty()) { 1600 // Only the first delete call will delete the database, but each must fire 1601 // callbacks. 1602 scoped_ptr<PendingDeleteCall> pending_delete_call( 1603 pending_delete_calls.front()); 1604 pending_delete_calls.pop_front(); 1605 DeleteDatabaseFinal(pending_delete_call->Callbacks()); 1606 } 1607 // delete_database_final should never re-queue calls. 1608 DCHECK(pending_delete_calls_.empty()); 1609 // Fall through when complete, as pending opens may be unblocked. 1610 } 1611 1612 if (!IsOpenConnectionBlocked()) { 1613 PendingOpenCallList pending_open_calls; 1614 pending_open_calls_.swap(pending_open_calls); 1615 while (!pending_open_calls.empty()) { 1616 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front()); 1617 pending_open_calls.pop_front(); 1618 OpenConnection(pending_open_call->Callbacks(), 1619 pending_open_call->DatabaseCallbacks(), 1620 pending_open_call->TransactionId(), 1621 pending_open_call->Version()); 1622 } 1623 } 1624 } 1625 1626 void IndexedDBDatabase::CreateTransaction( 1627 int64 transaction_id, 1628 IndexedDBConnection* connection, 1629 const std::vector<int64>& object_store_ids, 1630 uint16 mode) { 1631 1632 DCHECK(connections_.has(connection)); 1633 1634 scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( 1635 transaction_id, 1636 connection->callbacks(), 1637 std::set<int64>(object_store_ids.begin(), object_store_ids.end()), 1638 static_cast<indexed_db::TransactionMode>(mode), 1639 this); 1640 DCHECK(transactions_.find(transaction_id) == transactions_.end()); 1641 transactions_[transaction_id] = transaction; 1642 } 1643 1644 bool IndexedDBDatabase::IsOpenConnectionBlocked() const { 1645 return !pending_delete_calls_.empty() || 1646 running_version_change_transaction_ || 1647 pending_run_version_change_transaction_call_; 1648 } 1649 1650 void IndexedDBDatabase::OpenConnection( 1651 scoped_refptr<IndexedDBCallbacks> callbacks, 1652 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, 1653 int64 transaction_id, 1654 int64 version) { 1655 const WebKit::WebIDBCallbacks::DataLoss kDataLoss = 1656 WebKit::WebIDBCallbacks::DataLossNone; 1657 OpenConnection( 1658 callbacks, database_callbacks, transaction_id, version, kDataLoss); 1659 } 1660 1661 void IndexedDBDatabase::OpenConnection( 1662 scoped_refptr<IndexedDBCallbacks> callbacks, 1663 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, 1664 int64 transaction_id, 1665 int64 version, 1666 WebKit::WebIDBCallbacks::DataLoss data_loss) { 1667 DCHECK(backing_store_); 1668 1669 // TODO(jsbell): Should have a priority queue so that higher version 1670 // requests are processed first. http://crbug.com/225850 1671 if (IsOpenConnectionBlocked()) { 1672 // The backing store only detects data loss when it is first opened. The 1673 // presence of existing connections means we didn't even check for data loss 1674 // so there'd better not be any. 1675 DCHECK_NE(WebKit::WebIDBCallbacks::DataLossTotal, data_loss); 1676 pending_open_calls_.push_back(new PendingOpenCall( 1677 callbacks, database_callbacks, transaction_id, version)); 1678 return; 1679 } 1680 1681 if (metadata_.id == kInvalidId) { 1682 // The database was deleted then immediately re-opened; OpenInternal() 1683 // recreates it in the backing store. 1684 if (OpenInternal()) { 1685 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION, 1686 metadata_.int_version); 1687 } else { 1688 string16 message; 1689 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) 1690 message = ASCIIToUTF16( 1691 "Internal error opening database with no version specified."); 1692 else 1693 message = 1694 ASCIIToUTF16("Internal error opening database with version ") + 1695 Int64ToString16(version); 1696 callbacks->OnError(IndexedDBDatabaseError( 1697 WebKit::WebIDBDatabaseExceptionUnknownError, message)); 1698 return; 1699 } 1700 } 1701 1702 // We infer that the database didn't exist from its lack of either type of 1703 // version. 1704 bool is_new_database = 1705 metadata_.version == kNoStringVersion && 1706 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION; 1707 1708 scoped_ptr<IndexedDBConnection> connection( 1709 new IndexedDBConnection(this, database_callbacks)); 1710 1711 if (version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) { 1712 // For unit tests only - skip upgrade steps. Calling from script with 1713 // DEFAULT_INT_VERSION throws exception. 1714 // TODO(jsbell): DCHECK that not in unit tests. 1715 DCHECK(is_new_database); 1716 connections_.insert(connection.get()); 1717 callbacks->OnSuccess(connection.Pass(), this->metadata()); 1718 return; 1719 } 1720 1721 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { 1722 if (!is_new_database) { 1723 connections_.insert(connection.get()); 1724 callbacks->OnSuccess(connection.Pass(), this->metadata()); 1725 return; 1726 } 1727 // Spec says: If no version is specified and no database exists, set 1728 // database version to 1. 1729 version = 1; 1730 } 1731 1732 if (version > metadata_.int_version) { 1733 connections_.insert(connection.get()); 1734 RunVersionChangeTransaction( 1735 callbacks, connection.Pass(), transaction_id, version, data_loss); 1736 return; 1737 } 1738 if (version < metadata_.int_version) { 1739 callbacks->OnError(IndexedDBDatabaseError( 1740 WebKit::WebIDBDatabaseExceptionVersionError, 1741 ASCIIToUTF16("The requested version (") + Int64ToString16(version) + 1742 ASCIIToUTF16(") is less than the existing version (") + 1743 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(")."))); 1744 return; 1745 } 1746 DCHECK_EQ(version, metadata_.int_version); 1747 connections_.insert(connection.get()); 1748 callbacks->OnSuccess(connection.Pass(), this->metadata()); 1749 } 1750 1751 void IndexedDBDatabase::RunVersionChangeTransaction( 1752 scoped_refptr<IndexedDBCallbacks> callbacks, 1753 scoped_ptr<IndexedDBConnection> connection, 1754 int64 transaction_id, 1755 int64 requested_version, 1756 WebKit::WebIDBCallbacks::DataLoss data_loss) { 1757 1758 DCHECK(callbacks); 1759 DCHECK(connections_.has(connection.get())); 1760 if (ConnectionCount() > 1) { 1761 DCHECK_NE(WebKit::WebIDBCallbacks::DataLossTotal, data_loss); 1762 // Front end ensures the event is not fired at connections that have 1763 // close_pending set. 1764 for (ConnectionSet::const_iterator it = connections_.begin(); 1765 it != connections_.end(); 1766 ++it) { 1767 if (*it != connection.get()) { 1768 (*it)->callbacks()->OnVersionChange( 1769 metadata_.int_version, requested_version); 1770 } 1771 } 1772 // TODO(jsbell): Remove the call to OnBlocked and instead wait 1773 // until the frontend tells us that all the "versionchange" events 1774 // have been delivered. http://crbug.com/100123 1775 callbacks->OnBlocked(metadata_.int_version); 1776 1777 DCHECK(!pending_run_version_change_transaction_call_); 1778 pending_run_version_change_transaction_call_.reset(new PendingUpgradeCall( 1779 callbacks, connection.Pass(), transaction_id, requested_version)); 1780 return; 1781 } 1782 RunVersionChangeTransactionFinal(callbacks, 1783 connection.Pass(), 1784 transaction_id, 1785 requested_version, 1786 data_loss); 1787 } 1788 1789 void IndexedDBDatabase::RunVersionChangeTransactionFinal( 1790 scoped_refptr<IndexedDBCallbacks> callbacks, 1791 scoped_ptr<IndexedDBConnection> connection, 1792 int64 transaction_id, 1793 int64 requested_version) { 1794 const WebKit::WebIDBCallbacks::DataLoss kDataLoss = 1795 WebKit::WebIDBCallbacks::DataLossNone; 1796 RunVersionChangeTransactionFinal(callbacks, 1797 connection.Pass(), 1798 transaction_id, 1799 requested_version, 1800 kDataLoss); 1801 } 1802 1803 void IndexedDBDatabase::RunVersionChangeTransactionFinal( 1804 scoped_refptr<IndexedDBCallbacks> callbacks, 1805 scoped_ptr<IndexedDBConnection> connection, 1806 int64 transaction_id, 1807 int64 requested_version, 1808 WebKit::WebIDBCallbacks::DataLoss data_loss) { 1809 1810 std::vector<int64> object_store_ids; 1811 CreateTransaction(transaction_id, 1812 connection.get(), 1813 object_store_ids, 1814 indexed_db::TRANSACTION_VERSION_CHANGE); 1815 scoped_refptr<IndexedDBTransaction> transaction = 1816 transactions_[transaction_id]; 1817 1818 transaction->ScheduleTask( 1819 new VersionChangeOperation(this, 1820 transaction_id, 1821 requested_version, 1822 callbacks, 1823 connection.Pass(), 1824 data_loss), 1825 new VersionChangeAbortOperation( 1826 this, metadata_.version, metadata_.int_version)); 1827 1828 DCHECK(!pending_second_half_open_); 1829 } 1830 1831 void IndexedDBDatabase::DeleteDatabase( 1832 scoped_refptr<IndexedDBCallbacks> callbacks) { 1833 1834 if (IsDeleteDatabaseBlocked()) { 1835 for (ConnectionSet::const_iterator it = connections_.begin(); 1836 it != connections_.end(); 1837 ++it) { 1838 // Front end ensures the event is not fired at connections that have 1839 // close_pending set. 1840 (*it)->callbacks()->OnVersionChange( 1841 metadata_.int_version, IndexedDBDatabaseMetadata::NO_INT_VERSION); 1842 } 1843 // TODO(jsbell): Only fire OnBlocked if there are open 1844 // connections after the VersionChangeEvents are received, not 1845 // just set up to fire. http://crbug.com/100123 1846 callbacks->OnBlocked(metadata_.int_version); 1847 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks)); 1848 return; 1849 } 1850 DeleteDatabaseFinal(callbacks); 1851 } 1852 1853 bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const { 1854 return !!ConnectionCount(); 1855 } 1856 1857 void IndexedDBDatabase::DeleteDatabaseFinal( 1858 scoped_refptr<IndexedDBCallbacks> callbacks) { 1859 DCHECK(!IsDeleteDatabaseBlocked()); 1860 DCHECK(backing_store_); 1861 if (!backing_store_->DeleteDatabase(metadata_.name)) { 1862 callbacks->OnError( 1863 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 1864 "Internal error deleting database.")); 1865 return; 1866 } 1867 metadata_.version = kNoStringVersion; 1868 metadata_.id = kInvalidId; 1869 metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; 1870 metadata_.object_stores.clear(); 1871 callbacks->OnSuccess(); 1872 } 1873 1874 void IndexedDBDatabase::Close(IndexedDBConnection* connection) { 1875 DCHECK(connections_.has(connection)); 1876 1877 // Close outstanding transactions from the closing connection. This 1878 // can not happen if the close is requested by the connection itself 1879 // as the front-end defers the close until all transactions are 1880 // complete, so something unusual has happened e.g. unexpected 1881 // process termination. 1882 { 1883 TransactionMap transactions(transactions_); 1884 for (TransactionMap::const_iterator it = transactions.begin(), 1885 end = transactions.end(); 1886 it != end; 1887 ++it) { 1888 if (it->second->connection() == connection->callbacks()) 1889 it->second->Abort( 1890 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError, 1891 "Connection is closing.")); 1892 } 1893 } 1894 1895 connections_.erase(connection); 1896 if (pending_second_half_open_ && 1897 pending_second_half_open_->Connection() == connection) { 1898 pending_second_half_open_->Callbacks()->OnError( 1899 IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionAbortError, 1900 "The connection was closed.")); 1901 pending_second_half_open_.reset(); 1902 } 1903 1904 // process_pending_calls allows the inspector to process a pending open call 1905 // and call close, reentering IndexedDBDatabase::close. Then the 1906 // backend would be removed both by the inspector closing its connection, and 1907 // by the connection that first called close. 1908 // To avoid that situation, don't proceed in case of reentrancy. 1909 if (closing_connection_) 1910 return; 1911 base::AutoReset<bool> ClosingConnection(&closing_connection_, true); 1912 ProcessPendingCalls(); 1913 1914 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. 1915 if (!ConnectionCount() && !pending_open_calls_.size() && 1916 !pending_delete_calls_.size()) { 1917 DCHECK(transactions_.empty()); 1918 1919 backing_store_ = NULL; 1920 1921 // factory_ should only be null in unit tests. 1922 // TODO(jsbell): DCHECK(factory_ || !in_unit_tests) - somehow. 1923 if (factory_) 1924 factory_->RemoveIDBDatabaseBackend(identifier_); 1925 } 1926 } 1927 1928 void CreateObjectStoreAbortOperation::Perform( 1929 IndexedDBTransaction* transaction) { 1930 IDB_TRACE("CreateObjectStoreAbortOperation"); 1931 DCHECK(!transaction); 1932 database_->RemoveObjectStore(object_store_id_); 1933 } 1934 1935 void DeleteObjectStoreAbortOperation::Perform( 1936 IndexedDBTransaction* transaction) { 1937 IDB_TRACE("DeleteObjectStoreAbortOperation"); 1938 DCHECK(!transaction); 1939 database_->AddObjectStore(object_store_metadata_, 1940 IndexedDBObjectStoreMetadata::kInvalidId); 1941 } 1942 1943 void IndexedDBDatabase::VersionChangeAbortOperation::Perform( 1944 IndexedDBTransaction* transaction) { 1945 IDB_TRACE("VersionChangeAbortOperation"); 1946 DCHECK(!transaction); 1947 database_->metadata_.version = previous_version_; 1948 database_->metadata_.int_version = previous_int_version_; 1949 } 1950 1951 } // namespace content 1952