IDBIndex.cpp (19937B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "IDBIndex.h" 8 9 #include "IDBCursorType.h" 10 #include "IDBDatabase.h" 11 #include "IDBEvents.h" 12 #include "IDBKeyRange.h" 13 #include "IDBObjectStore.h" 14 #include "IDBRequest.h" 15 #include "IDBTransaction.h" 16 #include "IndexedDatabase.h" 17 #include "IndexedDatabaseInlines.h" 18 #include "ProfilerHelpers.h" 19 #include "ReportInternalError.h" 20 #include "mozilla/ErrorResult.h" 21 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h" 22 23 // Include this last to avoid path problems on Windows. 24 #include "ActorsChild.h" 25 26 namespace mozilla::dom { 27 28 using namespace mozilla::dom::indexedDB; 29 30 namespace { 31 32 MovingNotNull<RefPtr<IDBRequest>> GenerateRequest(JSContext* aCx, 33 IDBIndex* aIndex) { 34 MOZ_ASSERT(aIndex); 35 aIndex->AssertIsOnOwningThread(); 36 37 auto transaction = aIndex->ObjectStore()->AcquireTransaction(); 38 auto* const database = transaction->Database(); 39 40 return IDBRequest::Create(aCx, aIndex, database, std::move(transaction)); 41 } 42 43 } // namespace 44 45 IDBIndex::IDBIndex(IDBObjectStore* aObjectStore, const IndexMetadata* aMetadata) 46 : mObjectStore(aObjectStore), 47 mCachedKeyPath(JS::UndefinedValue()), 48 mMetadata(aMetadata), 49 mId(aMetadata->id()), 50 mRooted(false) { 51 MOZ_ASSERT(aObjectStore); 52 aObjectStore->AssertIsOnOwningThread(); 53 MOZ_ASSERT(aMetadata); 54 } 55 56 IDBIndex::~IDBIndex() { 57 AssertIsOnOwningThread(); 58 59 if (mRooted) { 60 mozilla::DropJSObjects(this); 61 } 62 } 63 64 RefPtr<IDBIndex> IDBIndex::Create(IDBObjectStore* aObjectStore, 65 const IndexMetadata& aMetadata) { 66 MOZ_ASSERT(aObjectStore); 67 aObjectStore->AssertIsOnOwningThread(); 68 69 return new IDBIndex(aObjectStore, &aMetadata); 70 } 71 72 #ifdef DEBUG 73 74 void IDBIndex::AssertIsOnOwningThread() const { 75 MOZ_ASSERT(mObjectStore); 76 mObjectStore->AssertIsOnOwningThread(); 77 } 78 79 #endif // DEBUG 80 81 RefPtr<IDBRequest> IDBIndex::OpenCursor(JSContext* aCx, 82 JS::Handle<JS::Value> aRange, 83 IDBCursorDirection aDirection, 84 ErrorResult& aRv) { 85 AssertIsOnOwningThread(); 86 87 return OpenCursorInternal(/* aKeysOnly */ false, aCx, aRange, aDirection, 88 aRv); 89 } 90 91 RefPtr<IDBRequest> IDBIndex::OpenKeyCursor(JSContext* aCx, 92 JS::Handle<JS::Value> aRange, 93 IDBCursorDirection aDirection, 94 ErrorResult& aRv) { 95 AssertIsOnOwningThread(); 96 97 return OpenCursorInternal(/* aKeysOnly */ true, aCx, aRange, aDirection, aRv); 98 } 99 100 RefPtr<IDBRequest> IDBIndex::Get(JSContext* aCx, JS::Handle<JS::Value> aKey, 101 ErrorResult& aRv) { 102 AssertIsOnOwningThread(); 103 104 return GetInternal(/* aKeyOnly */ false, aCx, aKey, aRv); 105 } 106 107 RefPtr<IDBRequest> IDBIndex::GetKey(JSContext* aCx, JS::Handle<JS::Value> aKey, 108 ErrorResult& aRv) { 109 AssertIsOnOwningThread(); 110 111 return GetInternal(/* aKeyOnly */ true, aCx, aKey, aRv); 112 } 113 114 RefPtr<IDBRequest> IDBIndex::GetAll(JSContext* aCx, JS::Handle<JS::Value> aKey, 115 const Optional<uint32_t>& aLimit, 116 ErrorResult& aRv) { 117 AssertIsOnOwningThread(); 118 119 return GetAllInternal(/* aKeysOnly */ false, aCx, aKey, aLimit, aRv); 120 } 121 122 RefPtr<IDBRequest> IDBIndex::GetAllKeys(JSContext* aCx, 123 JS::Handle<JS::Value> aKey, 124 const Optional<uint32_t>& aLimit, 125 ErrorResult& aRv) { 126 AssertIsOnOwningThread(); 127 128 return GetAllInternal(/* aKeysOnly */ true, aCx, aKey, aLimit, aRv); 129 } 130 131 void IDBIndex::RefreshMetadata(bool aMayDelete) { 132 AssertIsOnOwningThread(); 133 MOZ_ASSERT_IF(mDeletedMetadata, mMetadata == mDeletedMetadata.get()); 134 135 const auto& indexes = mObjectStore->Spec().indexes(); 136 const auto foundIt = std::find_if( 137 indexes.cbegin(), indexes.cend(), 138 [id = Id()](const auto& metadata) { return metadata.id() == id; }); 139 const bool found = foundIt != indexes.cend(); 140 141 MOZ_ASSERT_IF(!aMayDelete && !mDeletedMetadata, found); 142 143 if (found) { 144 mMetadata = &*foundIt; 145 MOZ_ASSERT(mMetadata != mDeletedMetadata.get()); 146 mDeletedMetadata = nullptr; 147 } else { 148 NoteDeletion(); 149 } 150 } 151 152 void IDBIndex::NoteDeletion() { 153 AssertIsOnOwningThread(); 154 MOZ_ASSERT(mMetadata); 155 MOZ_ASSERT(Id() == mMetadata->id()); 156 157 if (mDeletedMetadata) { 158 MOZ_ASSERT(mMetadata == mDeletedMetadata.get()); 159 return; 160 } 161 162 mDeletedMetadata = MakeUnique<IndexMetadata>(*mMetadata); 163 164 mMetadata = mDeletedMetadata.get(); 165 } 166 167 const nsString& IDBIndex::Name() const { 168 AssertIsOnOwningThread(); 169 MOZ_ASSERT(mMetadata); 170 171 return mMetadata->name(); 172 } 173 174 void IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv) { 175 AssertIsOnOwningThread(); 176 177 const auto& transaction = mObjectStore->TransactionRef(); 178 179 if (transaction.GetMode() != IDBTransaction::Mode::VersionChange || 180 mDeletedMetadata) { 181 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 182 return; 183 } 184 185 if (!transaction.IsActive()) { 186 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 187 return; 188 } 189 190 if (aName == mMetadata->name()) { 191 return; 192 } 193 194 // Cache logging string of this index before renaming. 195 const LoggingString loggingOldIndex(this); 196 197 const int64_t indexId = Id(); 198 199 nsresult rv = 200 transaction.Database()->RenameIndex(mObjectStore->Id(), indexId, aName); 201 202 if (NS_FAILED(rv)) { 203 aRv.Throw(rv); 204 return; 205 } 206 207 // Don't do this in the macro because we always need to increment the serial 208 // number to keep in sync with the parent. 209 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); 210 211 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 212 "database(%s).transaction(%s).objectStore(%s).index(%s)." 213 "rename(%s)", 214 "IDBIndex.rename(%.0s%.0s%.0s%.0s%.0s)", 215 transaction.LoggingSerialNumber(), requestSerialNumber, 216 IDB_LOG_STRINGIFY(transaction.Database()), IDB_LOG_STRINGIFY(transaction), 217 IDB_LOG_STRINGIFY(mObjectStore), loggingOldIndex.get(), 218 IDB_LOG_STRINGIFY(this)); 219 220 mObjectStore->MutableTransactionRef().RenameIndex(mObjectStore, indexId, 221 aName); 222 } 223 224 bool IDBIndex::Unique() const { 225 AssertIsOnOwningThread(); 226 MOZ_ASSERT(mMetadata); 227 228 return mMetadata->unique(); 229 } 230 231 bool IDBIndex::MultiEntry() const { 232 AssertIsOnOwningThread(); 233 MOZ_ASSERT(mMetadata); 234 235 return mMetadata->multiEntry(); 236 } 237 238 bool IDBIndex::LocaleAware() const { 239 AssertIsOnOwningThread(); 240 MOZ_ASSERT(mMetadata); 241 242 return mMetadata->locale().IsEmpty(); 243 } 244 245 const indexedDB::KeyPath& IDBIndex::GetKeyPath() const { 246 AssertIsOnOwningThread(); 247 MOZ_ASSERT(mMetadata); 248 249 return mMetadata->keyPath(); 250 } 251 252 void IDBIndex::GetLocale(nsString& aLocale) const { 253 AssertIsOnOwningThread(); 254 MOZ_ASSERT(mMetadata); 255 256 if (mMetadata->locale().IsEmpty()) { 257 SetDOMStringToNull(aLocale); 258 } else { 259 CopyASCIItoUTF16(mMetadata->locale(), aLocale); 260 } 261 } 262 263 const nsCString& IDBIndex::Locale() const { 264 AssertIsOnOwningThread(); 265 MOZ_ASSERT(mMetadata); 266 267 return mMetadata->locale(); 268 } 269 270 bool IDBIndex::IsAutoLocale() const { 271 AssertIsOnOwningThread(); 272 MOZ_ASSERT(mMetadata); 273 274 return mMetadata->autoLocale(); 275 } 276 277 nsIGlobalObject* IDBIndex::GetParentObject() const { 278 AssertIsOnOwningThread(); 279 280 return mObjectStore->GetParentObject(); 281 } 282 283 void IDBIndex::GetKeyPath(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 284 ErrorResult& aRv) { 285 AssertIsOnOwningThread(); 286 287 if (!mCachedKeyPath.isUndefined()) { 288 MOZ_ASSERT(mRooted); 289 aResult.set(mCachedKeyPath); 290 return; 291 } 292 293 MOZ_ASSERT(!mRooted); 294 295 aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath); 296 if (NS_WARN_IF(aRv.Failed())) { 297 return; 298 } 299 300 if (mCachedKeyPath.isGCThing()) { 301 mozilla::HoldJSObjects(this); 302 mRooted = true; 303 } 304 305 aResult.set(mCachedKeyPath); 306 } 307 308 RefPtr<IDBRequest> IDBIndex::GetInternal(bool aKeyOnly, JSContext* aCx, 309 JS::Handle<JS::Value> aKey, 310 ErrorResult& aRv) { 311 AssertIsOnOwningThread(); 312 313 if (mDeletedMetadata) { 314 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 315 return nullptr; 316 } 317 318 const auto& transaction = mObjectStore->TransactionRef(); 319 if (!transaction.IsActive()) { 320 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 321 return nullptr; 322 } 323 324 RefPtr<IDBKeyRange> keyRange; 325 IDBKeyRange::FromJSVal(aCx, aKey, &keyRange, aRv); 326 if (NS_WARN_IF(aRv.Failed())) { 327 return nullptr; 328 } 329 330 if (!keyRange) { 331 // Must specify a key or keyRange for get() and getKey(). 332 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_KEY_ERR); 333 return nullptr; 334 } 335 336 const int64_t objectStoreId = mObjectStore->Id(); 337 const int64_t indexId = Id(); 338 339 SerializedKeyRange serializedKeyRange; 340 keyRange->ToSerialized(serializedKeyRange); 341 342 RequestParams params; 343 344 if (aKeyOnly) { 345 params = IndexGetKeyParams(objectStoreId, indexId, serializedKeyRange); 346 } else { 347 params = IndexGetParams(objectStoreId, indexId, serializedKeyRange); 348 } 349 350 auto request = GenerateRequest(aCx, this).unwrap(); 351 352 if (aKeyOnly) { 353 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 354 "database(%s).transaction(%s).objectStore(%s).index(%s)." 355 "getKey(%s)", 356 "IDBIndex.getKey(%.0s%.0s%.0s%.0s%.0s)", 357 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(), 358 IDB_LOG_STRINGIFY(transaction.Database()), 359 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), 360 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange)); 361 } else { 362 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 363 "database(%s).transaction(%s).objectStore(%s).index(%s)." 364 "get(%s)", 365 "IDBIndex.get(%.0s%.0s%.0s%.0s%.0s)", transaction.LoggingSerialNumber(), 366 request->LoggingSerialNumber(), 367 IDB_LOG_STRINGIFY(transaction.Database()), 368 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), 369 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange)); 370 } 371 372 auto& mutableTransaction = mObjectStore->MutableTransactionRef(); 373 374 // TODO: This is necessary to preserve request ordering only. Proper 375 // sequencing of requests should be done in a more sophisticated manner that 376 // doesn't require invalidating cursor caches (Bug 1580499). 377 mutableTransaction.InvalidateCursorCaches(); 378 379 mutableTransaction.StartRequest(request, params); 380 381 return request; 382 } 383 384 RefPtr<IDBRequest> IDBIndex::GetAllInternal(bool aKeysOnly, JSContext* aCx, 385 JS::Handle<JS::Value> aKey, 386 const Optional<uint32_t>& aLimit, 387 ErrorResult& aRv) { 388 AssertIsOnOwningThread(); 389 390 if (mDeletedMetadata) { 391 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 392 return nullptr; 393 } 394 395 const auto& transaction = mObjectStore->TransactionRef(); 396 if (!transaction.IsActive()) { 397 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 398 return nullptr; 399 } 400 401 RefPtr<IDBKeyRange> keyRange; 402 IDBKeyRange::FromJSVal(aCx, aKey, &keyRange, aRv); 403 if (NS_WARN_IF(aRv.Failed())) { 404 return nullptr; 405 } 406 407 const int64_t objectStoreId = mObjectStore->Id(); 408 const int64_t indexId = Id(); 409 410 Maybe<SerializedKeyRange> optionalKeyRange; 411 if (keyRange) { 412 SerializedKeyRange serializedKeyRange; 413 keyRange->ToSerialized(serializedKeyRange); 414 optionalKeyRange.emplace(serializedKeyRange); 415 } 416 417 const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0; 418 419 const auto& params = 420 aKeysOnly ? RequestParams{IndexGetAllKeysParams(objectStoreId, indexId, 421 optionalKeyRange, limit)} 422 : RequestParams{IndexGetAllParams(objectStoreId, indexId, 423 optionalKeyRange, limit)}; 424 425 auto request = GenerateRequest(aCx, this).unwrap(); 426 427 if (aKeysOnly) { 428 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 429 "database(%s).transaction(%s).objectStore(%s).index(%s)." 430 "getAllKeys(%s, %s)", 431 "IDBIndex.getAllKeys(%.0s%.0s%.0s%.0s%.0s%.0s)", 432 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(), 433 IDB_LOG_STRINGIFY(transaction.Database()), 434 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), 435 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), 436 IDB_LOG_STRINGIFY(aLimit)); 437 } else { 438 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 439 "database(%s).transaction(%s).objectStore(%s).index(%s)." 440 "getAll(%s, %s)", 441 "IDBIndex.getAll(%.0s%.0s%.0s%.0s%.0s%.0s)", 442 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(), 443 IDB_LOG_STRINGIFY(transaction.Database()), 444 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), 445 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), 446 IDB_LOG_STRINGIFY(aLimit)); 447 } 448 449 auto& mutableTransaction = mObjectStore->MutableTransactionRef(); 450 451 // TODO: This is necessary to preserve request ordering only. Proper 452 // sequencing of requests should be done in a more sophisticated manner that 453 // doesn't require invalidating cursor caches (Bug 1580499). 454 mutableTransaction.InvalidateCursorCaches(); 455 456 mutableTransaction.StartRequest(request, params); 457 458 return request; 459 } 460 461 RefPtr<IDBRequest> IDBIndex::OpenCursorInternal(bool aKeysOnly, JSContext* aCx, 462 JS::Handle<JS::Value> aRange, 463 IDBCursorDirection aDirection, 464 ErrorResult& aRv) { 465 AssertIsOnOwningThread(); 466 467 if (mDeletedMetadata) { 468 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 469 return nullptr; 470 } 471 472 const auto& transaction = mObjectStore->TransactionRef(); 473 if (!transaction.IsActive()) { 474 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 475 return nullptr; 476 } 477 478 RefPtr<IDBKeyRange> keyRange; 479 IDBKeyRange::FromJSVal(aCx, aRange, &keyRange, aRv); 480 if (NS_WARN_IF(aRv.Failed())) { 481 return nullptr; 482 } 483 484 const int64_t objectStoreId = mObjectStore->Id(); 485 const int64_t indexId = Id(); 486 487 Maybe<SerializedKeyRange> optionalKeyRange; 488 489 if (keyRange) { 490 SerializedKeyRange serializedKeyRange; 491 keyRange->ToSerialized(serializedKeyRange); 492 493 optionalKeyRange.emplace(std::move(serializedKeyRange)); 494 } 495 496 const CommonIndexOpenCursorParams commonIndexParams = { 497 {objectStoreId, std::move(optionalKeyRange), aDirection}, indexId}; 498 499 const auto params = 500 aKeysOnly ? OpenCursorParams{IndexOpenKeyCursorParams{commonIndexParams}} 501 : OpenCursorParams{IndexOpenCursorParams{commonIndexParams}}; 502 503 auto request = GenerateRequest(aCx, this).unwrap(); 504 505 if (aKeysOnly) { 506 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 507 "database(%s).transaction(%s).objectStore(%s).index(%s)." 508 "openKeyCursor(%s, %s)", 509 "IDBIndex.openKeyCursor(%.0s%.0s%.0s%.0s%.0s%.0s)", 510 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(), 511 IDB_LOG_STRINGIFY(transaction.Database()), 512 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), 513 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), 514 IDB_LOG_STRINGIFY(aDirection)); 515 } else { 516 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 517 "database(%s).transaction(%s).objectStore(%s).index(%s)." 518 "openCursor(%s, %s)", 519 "IDBIndex.openCursor(%.0s%.0s%.0s%.0s%.0s%.0s)", 520 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(), 521 IDB_LOG_STRINGIFY(transaction.Database()), 522 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), 523 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), 524 IDB_LOG_STRINGIFY(aDirection)); 525 } 526 527 const auto actor = 528 aKeysOnly 529 ? static_cast<SafeRefPtr<BackgroundCursorChildBase>>( 530 MakeSafeRefPtr<BackgroundCursorChild<IDBCursorType::IndexKey>>( 531 request, this, aDirection)) 532 : MakeSafeRefPtr<BackgroundCursorChild<IDBCursorType::Index>>( 533 request, this, aDirection); 534 535 auto& mutableTransaction = mObjectStore->MutableTransactionRef(); 536 537 // TODO: This is necessary to preserve request ordering only. Proper 538 // sequencing of requests should be done in a more sophisticated manner that 539 // doesn't require invalidating cursor caches (Bug 1580499). 540 mutableTransaction.InvalidateCursorCaches(); 541 542 mutableTransaction.OpenCursor(*actor, params); 543 544 return request; 545 } 546 547 RefPtr<IDBRequest> IDBIndex::Count(JSContext* aCx, JS::Handle<JS::Value> aKey, 548 ErrorResult& aRv) { 549 AssertIsOnOwningThread(); 550 551 if (mDeletedMetadata) { 552 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 553 return nullptr; 554 } 555 556 const auto& transaction = mObjectStore->TransactionRef(); 557 if (!transaction.IsActive()) { 558 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 559 return nullptr; 560 } 561 562 RefPtr<IDBKeyRange> keyRange; 563 IDBKeyRange::FromJSVal(aCx, aKey, &keyRange, aRv); 564 if (aRv.Failed()) { 565 return nullptr; 566 } 567 568 IndexCountParams params; 569 params.objectStoreId() = mObjectStore->Id(); 570 params.indexId() = Id(); 571 572 if (keyRange) { 573 SerializedKeyRange serializedKeyRange; 574 keyRange->ToSerialized(serializedKeyRange); 575 params.optionalKeyRange().emplace(serializedKeyRange); 576 } 577 578 auto request = GenerateRequest(aCx, this).unwrap(); 579 580 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 581 "database(%s).transaction(%s).objectStore(%s).index(%s)." 582 "count(%s)", 583 "IDBIndex.count(%.0s%.0s%.0s%.0s%.0s)", transaction.LoggingSerialNumber(), 584 request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction.Database()), 585 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), 586 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange)); 587 588 auto& mutableTransaction = mObjectStore->MutableTransactionRef(); 589 590 // TODO: This is necessary to preserve request ordering only. Proper 591 // sequencing of requests should be done in a more sophisticated manner that 592 // doesn't require invalidating cursor caches (Bug 1580499). 593 mutableTransaction.InvalidateCursorCaches(); 594 595 mutableTransaction.StartRequest(request, params); 596 597 return request; 598 } 599 600 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex) 601 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex) 602 603 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex) 604 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 605 NS_INTERFACE_MAP_ENTRY(nsISupports) 606 NS_INTERFACE_MAP_END 607 608 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex) 609 610 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex) 611 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 612 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath) 613 NS_IMPL_CYCLE_COLLECTION_TRACE_END 614 615 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex) 616 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore) 617 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 618 619 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex) 620 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 621 622 // Don't unlink mObjectStore! 623 624 tmp->mCachedKeyPath.setUndefined(); 625 626 if (tmp->mRooted) { 627 mozilla::DropJSObjects(tmp); 628 tmp->mRooted = false; 629 } 630 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 631 632 JSObject* IDBIndex::WrapObject(JSContext* aCx, 633 JS::Handle<JSObject*> aGivenProto) { 634 return IDBIndex_Binding::Wrap(aCx, this, aGivenProto); 635 } 636 637 } // namespace mozilla::dom