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