diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/indexedDB/IDBIndex.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/indexedDB/IDBIndex.cpp')
-rw-r--r-- | dom/indexedDB/IDBIndex.cpp | 679 |
1 files changed, 679 insertions, 0 deletions
diff --git a/dom/indexedDB/IDBIndex.cpp b/dom/indexedDB/IDBIndex.cpp new file mode 100644 index 000000000..657e744c9 --- /dev/null +++ b/dom/indexedDB/IDBIndex.cpp @@ -0,0 +1,679 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "IDBIndex.h" + +#include "FileInfo.h" +#include "IDBCursor.h" +#include "IDBEvents.h" +#include "IDBKeyRange.h" +#include "IDBObjectStore.h" +#include "IDBRequest.h" +#include "IDBTransaction.h" +#include "IndexedDatabase.h" +#include "IndexedDatabaseInlines.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h" +#include "ProfilerHelpers.h" +#include "ReportInternalError.h" + +// Include this last to avoid path problems on Windows. +#include "ActorsChild.h" + +namespace mozilla { +namespace dom { + +namespace { + +already_AddRefed<IDBRequest> +GenerateRequest(JSContext* aCx, IDBIndex* aIndex) +{ + MOZ_ASSERT(aIndex); + aIndex->AssertIsOnOwningThread(); + + IDBTransaction* transaction = aIndex->ObjectStore()->Transaction(); + + RefPtr<IDBRequest> request = + IDBRequest::Create(aCx, aIndex, transaction->Database(), transaction); + MOZ_ASSERT(request); + + return request.forget(); +} + +} // namespace + +IDBIndex::IDBIndex(IDBObjectStore* aObjectStore, const IndexMetadata* aMetadata) + : mObjectStore(aObjectStore) + , mCachedKeyPath(JS::UndefinedValue()) + , mMetadata(aMetadata) + , mId(aMetadata->id()) + , mRooted(false) +{ + MOZ_ASSERT(aObjectStore); + aObjectStore->AssertIsOnOwningThread(); + MOZ_ASSERT(aMetadata); +} + +IDBIndex::~IDBIndex() +{ + AssertIsOnOwningThread(); + + if (mRooted) { + mCachedKeyPath.setUndefined(); + mozilla::DropJSObjects(this); + } +} + +already_AddRefed<IDBIndex> +IDBIndex::Create(IDBObjectStore* aObjectStore, + const IndexMetadata& aMetadata) +{ + MOZ_ASSERT(aObjectStore); + aObjectStore->AssertIsOnOwningThread(); + + RefPtr<IDBIndex> index = new IDBIndex(aObjectStore, &aMetadata); + + return index.forget(); +} + +#ifdef DEBUG + +void +IDBIndex::AssertIsOnOwningThread() const +{ + MOZ_ASSERT(mObjectStore); + mObjectStore->AssertIsOnOwningThread(); +} + +#endif // DEBUG + +void +IDBIndex::RefreshMetadata(bool aMayDelete) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT_IF(mDeletedMetadata, mMetadata == mDeletedMetadata); + + const nsTArray<IndexMetadata>& indexes = mObjectStore->Spec().indexes(); + + bool found = false; + + for (uint32_t count = indexes.Length(), index = 0; + index < count; + index++) { + const IndexMetadata& metadata = indexes[index]; + + if (metadata.id() == Id()) { + mMetadata = &metadata; + + found = true; + break; + } + } + + MOZ_ASSERT_IF(!aMayDelete && !mDeletedMetadata, found); + + if (found) { + MOZ_ASSERT(mMetadata != mDeletedMetadata); + mDeletedMetadata = nullptr; + } else { + NoteDeletion(); + } +} + +void +IDBIndex::NoteDeletion() +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + MOZ_ASSERT(Id() == mMetadata->id()); + + if (mDeletedMetadata) { + MOZ_ASSERT(mMetadata == mDeletedMetadata); + return; + } + + mDeletedMetadata = new IndexMetadata(*mMetadata); + + mMetadata = mDeletedMetadata; +} + +const nsString& +IDBIndex::Name() const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + return mMetadata->name(); +} + +void +IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv) +{ + AssertIsOnOwningThread(); + + IDBTransaction* transaction = mObjectStore->Transaction(); + + if (transaction->GetMode() != IDBTransaction::VERSION_CHANGE || + mDeletedMetadata) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + + if (!transaction->IsOpen()) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); + return; + } + + if (aName == mMetadata->name()) { + return; + } + + // Cache logging string of this index before renaming. + const LoggingString loggingOldIndex(this); + + const int64_t indexId = Id(); + + nsresult rv = + transaction->Database()->RenameIndex(mObjectStore->Id(), + indexId, + aName); + + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return; + } + + // Don't do this in the macro because we always need to increment the serial + // number to keep in sync with the parent. + const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); + + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "rename(%s)", + "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.rename()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + requestSerialNumber, + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + loggingOldIndex.get(), + IDB_LOG_STRINGIFY(this)); + + transaction->RenameIndex(mObjectStore, indexId, aName); +} + +bool +IDBIndex::Unique() const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + return mMetadata->unique(); +} + +bool +IDBIndex::MultiEntry() const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + return mMetadata->multiEntry(); +} + +bool +IDBIndex::LocaleAware() const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + return mMetadata->locale().IsEmpty(); +} + +const indexedDB::KeyPath& +IDBIndex::GetKeyPath() const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + return mMetadata->keyPath(); +} + +void +IDBIndex::GetLocale(nsString& aLocale) const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + if (mMetadata->locale().IsEmpty()) { + SetDOMStringToNull(aLocale); + } else { + aLocale.AssignWithConversion(mMetadata->locale()); + } +} + +const nsCString& +IDBIndex::Locale() const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + return mMetadata->locale(); +} + +bool +IDBIndex::IsAutoLocale() const +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mMetadata); + + return mMetadata->autoLocale(); +} + +nsPIDOMWindowInner* +IDBIndex::GetParentObject() const +{ + AssertIsOnOwningThread(); + + return mObjectStore->GetParentObject(); +} + +void +IDBIndex::GetKeyPath(JSContext* aCx, + JS::MutableHandle<JS::Value> aResult, + ErrorResult& aRv) +{ + AssertIsOnOwningThread(); + + if (!mCachedKeyPath.isUndefined()) { + MOZ_ASSERT(mRooted); + aResult.set(mCachedKeyPath); + return; + } + + MOZ_ASSERT(!mRooted); + + aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + if (mCachedKeyPath.isGCThing()) { + mozilla::HoldJSObjects(this); + mRooted = true; + } + + aResult.set(mCachedKeyPath); +} + +already_AddRefed<IDBRequest> +IDBIndex::GetInternal(bool aKeyOnly, + JSContext* aCx, + JS::Handle<JS::Value> aKey, + ErrorResult& aRv) +{ + AssertIsOnOwningThread(); + + if (mDeletedMetadata) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); + return nullptr; + } + + IDBTransaction* transaction = mObjectStore->Transaction(); + if (!transaction->IsOpen()) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); + return nullptr; + } + + RefPtr<IDBKeyRange> keyRange; + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + if (!keyRange) { + // Must specify a key or keyRange for get() and getKey(). + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); + return nullptr; + } + + const int64_t objectStoreId = mObjectStore->Id(); + const int64_t indexId = Id(); + + SerializedKeyRange serializedKeyRange; + keyRange->ToSerialized(serializedKeyRange); + + RequestParams params; + + if (aKeyOnly) { + params = IndexGetKeyParams(objectStoreId, indexId, serializedKeyRange); + } else { + params = IndexGetParams(objectStoreId, indexId, serializedKeyRange); + } + + RefPtr<IDBRequest> request = GenerateRequest(aCx, this); + MOZ_ASSERT(request); + + if (aKeyOnly) { + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "getKey(%s)", + "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getKey()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + request->LoggingSerialNumber(), + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + IDB_LOG_STRINGIFY(this), + IDB_LOG_STRINGIFY(keyRange)); + } else { + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "get(%s)", + "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.get()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + request->LoggingSerialNumber(), + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + IDB_LOG_STRINGIFY(this), + IDB_LOG_STRINGIFY(keyRange)); + } + + transaction->StartRequest(request, params); + + return request.forget(); +} + +already_AddRefed<IDBRequest> +IDBIndex::GetAllInternal(bool aKeysOnly, + JSContext* aCx, + JS::Handle<JS::Value> aKey, + const Optional<uint32_t>& aLimit, + ErrorResult& aRv) +{ + AssertIsOnOwningThread(); + + if (mDeletedMetadata) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); + return nullptr; + } + + IDBTransaction* transaction = mObjectStore->Transaction(); + if (!transaction->IsOpen()) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); + return nullptr; + } + + RefPtr<IDBKeyRange> keyRange; + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + const int64_t objectStoreId = mObjectStore->Id(); + const int64_t indexId = Id(); + + OptionalKeyRange optionalKeyRange; + if (keyRange) { + SerializedKeyRange serializedKeyRange; + keyRange->ToSerialized(serializedKeyRange); + optionalKeyRange = serializedKeyRange; + } else { + optionalKeyRange = void_t(); + } + + const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0; + + RequestParams params; + if (aKeysOnly) { + params = IndexGetAllKeysParams(objectStoreId, indexId, optionalKeyRange, + limit); + } else { + params = IndexGetAllParams(objectStoreId, indexId, optionalKeyRange, limit); + } + + RefPtr<IDBRequest> request = GenerateRequest(aCx, this); + MOZ_ASSERT(request); + + if (aKeysOnly) { + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "getAllKeys(%s, %s)", + "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAllKeys()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + request->LoggingSerialNumber(), + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + IDB_LOG_STRINGIFY(this), + IDB_LOG_STRINGIFY(keyRange), + IDB_LOG_STRINGIFY(aLimit)); + } else { + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "getAll(%s, %s)", + "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAll()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + request->LoggingSerialNumber(), + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + IDB_LOG_STRINGIFY(this), + IDB_LOG_STRINGIFY(keyRange), + IDB_LOG_STRINGIFY(aLimit)); + } + + transaction->StartRequest(request, params); + + return request.forget(); +} + +already_AddRefed<IDBRequest> +IDBIndex::OpenCursorInternal(bool aKeysOnly, + JSContext* aCx, + JS::Handle<JS::Value> aRange, + IDBCursorDirection aDirection, + ErrorResult& aRv) +{ + AssertIsOnOwningThread(); + + if (mDeletedMetadata) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); + return nullptr; + } + + IDBTransaction* transaction = mObjectStore->Transaction(); + if (!transaction->IsOpen()) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); + return nullptr; + } + + RefPtr<IDBKeyRange> keyRange; + aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange)); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + int64_t objectStoreId = mObjectStore->Id(); + int64_t indexId = Id(); + + OptionalKeyRange optionalKeyRange; + + if (keyRange) { + SerializedKeyRange serializedKeyRange; + keyRange->ToSerialized(serializedKeyRange); + + optionalKeyRange = Move(serializedKeyRange); + } else { + optionalKeyRange = void_t(); + } + + IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection); + + OpenCursorParams params; + if (aKeysOnly) { + IndexOpenKeyCursorParams openParams; + openParams.objectStoreId() = objectStoreId; + openParams.indexId() = indexId; + openParams.optionalKeyRange() = Move(optionalKeyRange); + openParams.direction() = direction; + + params = Move(openParams); + } else { + IndexOpenCursorParams openParams; + openParams.objectStoreId() = objectStoreId; + openParams.indexId() = indexId; + openParams.optionalKeyRange() = Move(optionalKeyRange); + openParams.direction() = direction; + + params = Move(openParams); + } + + RefPtr<IDBRequest> request = GenerateRequest(aCx, this); + MOZ_ASSERT(request); + + if (aKeysOnly) { + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "openKeyCursor(%s, %s)", + "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.openKeyCursor()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + request->LoggingSerialNumber(), + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + IDB_LOG_STRINGIFY(this), + IDB_LOG_STRINGIFY(keyRange), + IDB_LOG_STRINGIFY(direction)); + } else { + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "openCursor(%s, %s)", + "IndexedDB %s: C T[%lld] R[%llu]: " + "IDBObjectStore.openKeyCursor()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + request->LoggingSerialNumber(), + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + IDB_LOG_STRINGIFY(this), + IDB_LOG_STRINGIFY(keyRange), + IDB_LOG_STRINGIFY(direction)); + } + + BackgroundCursorChild* actor = + new BackgroundCursorChild(request, this, direction); + + mObjectStore->Transaction()->OpenCursor(actor, params); + + return request.forget(); +} + +already_AddRefed<IDBRequest> +IDBIndex::Count(JSContext* aCx, + JS::Handle<JS::Value> aKey, + ErrorResult& aRv) +{ + AssertIsOnOwningThread(); + + if (mDeletedMetadata) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); + return nullptr; + } + + IDBTransaction* transaction = mObjectStore->Transaction(); + if (!transaction->IsOpen()) { + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); + return nullptr; + } + + RefPtr<IDBKeyRange> keyRange; + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); + if (aRv.Failed()) { + return nullptr; + } + + IndexCountParams params; + params.objectStoreId() = mObjectStore->Id(); + params.indexId() = Id(); + + if (keyRange) { + SerializedKeyRange serializedKeyRange; + keyRange->ToSerialized(serializedKeyRange); + params.optionalKeyRange() = serializedKeyRange; + } else { + params.optionalKeyRange() = void_t(); + } + + RefPtr<IDBRequest> request = GenerateRequest(aCx, this); + MOZ_ASSERT(request); + + IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " + "database(%s).transaction(%s).objectStore(%s).index(%s)." + "count(%s)", + "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()", + IDB_LOG_ID_STRING(), + transaction->LoggingSerialNumber(), + request->LoggingSerialNumber(), + IDB_LOG_STRINGIFY(transaction->Database()), + IDB_LOG_STRINGIFY(transaction), + IDB_LOG_STRINGIFY(mObjectStore), + IDB_LOG_STRINGIFY(this), + IDB_LOG_STRINGIFY(keyRange)); + + transaction->StartRequest(request, params); + + return request.forget(); +} + +NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex) +NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex) + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER + + // Don't unlink mObjectStore! + + tmp->mCachedKeyPath.setUndefined(); + + if (tmp->mRooted) { + mozilla::DropJSObjects(tmp); + tmp->mRooted = false; + } +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +JSObject* +IDBIndex::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return IDBIndexBinding::Wrap(aCx, this, aGivenProto); +} + +} // namespace dom +} // namespace mozilla |