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