michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "DatabaseInfo.h" michael@0: michael@0: #include "nsDataHashtable.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: USING_INDEXEDDB_NAMESPACE michael@0: michael@0: namespace { michael@0: michael@0: typedef nsDataHashtable michael@0: DatabaseHash; michael@0: michael@0: DatabaseHash* gDatabaseHash = nullptr; michael@0: michael@0: PLDHashOperator michael@0: EnumerateObjectStoreNames(const nsAString& aKey, michael@0: ObjectStoreInfo* aData, michael@0: void* aUserArg) michael@0: { michael@0: nsTArray* array = static_cast*>(aUserArg); michael@0: if (!array->InsertElementSorted(aData->name)) { michael@0: NS_ERROR("Out of memory?"); michael@0: return PL_DHASH_STOP; michael@0: } michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: PLDHashOperator michael@0: CloneObjectStoreInfo(const nsAString& aKey, michael@0: ObjectStoreInfo* aData, michael@0: void* aUserArg) michael@0: { michael@0: ObjectStoreInfoHash* hash = static_cast(aUserArg); michael@0: michael@0: nsRefPtr newInfo(new ObjectStoreInfo(*aData)); michael@0: michael@0: hash->Put(aKey, newInfo); michael@0: michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: } michael@0: michael@0: DatabaseInfo::~DatabaseInfo() michael@0: { michael@0: // Clones are never in the hash. michael@0: if (!cloned) { michael@0: DatabaseInfo::Remove(id); michael@0: } michael@0: } michael@0: michael@0: ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther) michael@0: : nextAutoIncrementId(aOther.nextAutoIncrementId), michael@0: comittedAutoIncrementId(aOther.comittedAutoIncrementId) michael@0: { michael@0: *static_cast(this) = michael@0: static_cast(aOther); michael@0: michael@0: // Doesn't copy the refcount michael@0: MOZ_COUNT_CTOR(ObjectStoreInfo); michael@0: } michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: michael@0: IndexInfo::IndexInfo() michael@0: : id(INT64_MIN), michael@0: keyPath(0), michael@0: unique(false), michael@0: multiEntry(false) michael@0: { michael@0: MOZ_COUNT_CTOR(IndexInfo); michael@0: } michael@0: michael@0: IndexInfo::IndexInfo(const IndexInfo& aOther) michael@0: : name(aOther.name), michael@0: id(aOther.id), michael@0: keyPath(aOther.keyPath), michael@0: unique(aOther.unique), michael@0: multiEntry(aOther.multiEntry) michael@0: { michael@0: MOZ_COUNT_CTOR(IndexInfo); michael@0: } michael@0: michael@0: IndexInfo::~IndexInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(IndexInfo); michael@0: } michael@0: michael@0: ObjectStoreInfo::ObjectStoreInfo() michael@0: : nextAutoIncrementId(0), michael@0: comittedAutoIncrementId(0) michael@0: { michael@0: MOZ_COUNT_CTOR(ObjectStoreInfo); michael@0: } michael@0: michael@0: ObjectStoreInfo::~ObjectStoreInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(ObjectStoreInfo); michael@0: } michael@0: michael@0: IndexUpdateInfo::IndexUpdateInfo() michael@0: : indexId(0), michael@0: indexUnique(false) michael@0: { michael@0: MOZ_COUNT_CTOR(IndexUpdateInfo); michael@0: } michael@0: michael@0: IndexUpdateInfo::IndexUpdateInfo(const IndexUpdateInfo& aOther) michael@0: : indexId(aOther.indexId), michael@0: indexUnique(aOther.indexUnique), michael@0: value(aOther.value) michael@0: { michael@0: MOZ_COUNT_CTOR(IndexUpdateInfo); michael@0: } michael@0: michael@0: IndexUpdateInfo::~IndexUpdateInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(IndexUpdateInfo); michael@0: } michael@0: michael@0: #endif /* NS_BUILD_REFCNT_LOGGING */ michael@0: michael@0: // static michael@0: bool michael@0: DatabaseInfo::Get(const nsACString& aId, michael@0: DatabaseInfo** aInfo) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(!aId.IsEmpty(), "Bad id!"); michael@0: michael@0: if (gDatabaseHash && michael@0: gDatabaseHash->Get(aId, aInfo)) { michael@0: NS_IF_ADDREF(*aInfo); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: DatabaseInfo::Put(DatabaseInfo* aInfo) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(aInfo, "Null pointer!"); michael@0: michael@0: if (!gDatabaseHash) { michael@0: nsAutoPtr databaseHash(new DatabaseHash()); michael@0: gDatabaseHash = databaseHash.forget(); michael@0: } michael@0: michael@0: if (gDatabaseHash->Get(aInfo->id, nullptr)) { michael@0: NS_ERROR("Already know about this database!"); michael@0: return false; michael@0: } michael@0: michael@0: gDatabaseHash->Put(aInfo->id, aInfo); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // static michael@0: void michael@0: DatabaseInfo::Remove(const nsACString& aId) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: if (gDatabaseHash) { michael@0: gDatabaseHash->Remove(aId); michael@0: michael@0: if (!gDatabaseHash->Count()) { michael@0: delete gDatabaseHash; michael@0: gDatabaseHash = nullptr; michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool michael@0: DatabaseInfo::GetObjectStoreNames(nsTArray& aNames) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: aNames.Clear(); michael@0: if (objectStoreHash) { michael@0: objectStoreHash->EnumerateRead(EnumerateObjectStoreNames, &aNames); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DatabaseInfo::ContainsStoreName(const nsAString& aName) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return objectStoreHash && objectStoreHash->Get(aName, nullptr); michael@0: } michael@0: michael@0: ObjectStoreInfo* michael@0: DatabaseInfo::GetObjectStore(const nsAString& aName) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: if (objectStoreHash) { michael@0: return objectStoreHash->GetWeak(aName); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: bool michael@0: DatabaseInfo::PutObjectStore(ObjectStoreInfo* aInfo) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(aInfo, "Null pointer!"); michael@0: michael@0: if (!objectStoreHash) { michael@0: nsAutoPtr hash(new ObjectStoreInfoHash()); michael@0: objectStoreHash = hash.forget(); michael@0: } michael@0: michael@0: if (objectStoreHash->Get(aInfo->name, nullptr)) { michael@0: NS_ERROR("Already have an entry for this objectstore!"); michael@0: return false; michael@0: } michael@0: michael@0: objectStoreHash->Put(aInfo->name, aInfo); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: DatabaseInfo::RemoveObjectStore(const nsAString& aName) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(GetObjectStore(aName), "Don't know about this one!"); michael@0: michael@0: if (objectStoreHash) { michael@0: objectStoreHash->Remove(aName); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: DatabaseInfo::Clone() michael@0: { michael@0: nsRefPtr dbInfo(new DatabaseInfo()); michael@0: michael@0: dbInfo->cloned = true; michael@0: dbInfo->name = name; michael@0: dbInfo->group = group; michael@0: dbInfo->origin = origin; michael@0: dbInfo->version = version; michael@0: dbInfo->persistenceType = persistenceType; michael@0: dbInfo->id = id; michael@0: dbInfo->filePath = filePath; michael@0: dbInfo->nextObjectStoreId = nextObjectStoreId; michael@0: dbInfo->nextIndexId = nextIndexId; michael@0: michael@0: if (objectStoreHash) { michael@0: dbInfo->objectStoreHash = new ObjectStoreInfoHash(); michael@0: objectStoreHash->EnumerateRead(CloneObjectStoreInfo, michael@0: dbInfo->objectStoreHash); michael@0: } michael@0: michael@0: return dbInfo.forget(); michael@0: }