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