/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=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 "DatabaseInfo.h" #include "nsDataHashtable.h" #include "nsThreadUtils.h" USING_INDEXEDDB_NAMESPACE namespace { typedef nsDataHashtable DatabaseHash; DatabaseHash* gDatabaseHash = nullptr; PLDHashOperator EnumerateObjectStoreNames(const nsAString& aKey, ObjectStoreInfo* aData, void* aUserArg) { nsTArray* array = static_cast*>(aUserArg); if (!array->InsertElementSorted(aData->name)) { NS_ERROR("Out of memory?"); return PL_DHASH_STOP; } return PL_DHASH_NEXT; } PLDHashOperator CloneObjectStoreInfo(const nsAString& aKey, ObjectStoreInfo* aData, void* aUserArg) { ObjectStoreInfoHash* hash = static_cast(aUserArg); nsRefPtr newInfo(new ObjectStoreInfo(*aData)); hash->Put(aKey, newInfo); return PL_DHASH_NEXT; } } DatabaseInfo::~DatabaseInfo() { // Clones are never in the hash. if (!cloned) { DatabaseInfo::Remove(id); } } ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther) : nextAutoIncrementId(aOther.nextAutoIncrementId), comittedAutoIncrementId(aOther.comittedAutoIncrementId) { *static_cast(this) = static_cast(aOther); // Doesn't copy the refcount MOZ_COUNT_CTOR(ObjectStoreInfo); } #ifdef NS_BUILD_REFCNT_LOGGING IndexInfo::IndexInfo() : id(INT64_MIN), keyPath(0), unique(false), multiEntry(false) { MOZ_COUNT_CTOR(IndexInfo); } IndexInfo::IndexInfo(const IndexInfo& aOther) : name(aOther.name), id(aOther.id), keyPath(aOther.keyPath), unique(aOther.unique), multiEntry(aOther.multiEntry) { MOZ_COUNT_CTOR(IndexInfo); } IndexInfo::~IndexInfo() { MOZ_COUNT_DTOR(IndexInfo); } ObjectStoreInfo::ObjectStoreInfo() : nextAutoIncrementId(0), comittedAutoIncrementId(0) { MOZ_COUNT_CTOR(ObjectStoreInfo); } ObjectStoreInfo::~ObjectStoreInfo() { MOZ_COUNT_DTOR(ObjectStoreInfo); } IndexUpdateInfo::IndexUpdateInfo() : indexId(0), indexUnique(false) { MOZ_COUNT_CTOR(IndexUpdateInfo); } IndexUpdateInfo::IndexUpdateInfo(const IndexUpdateInfo& aOther) : indexId(aOther.indexId), indexUnique(aOther.indexUnique), value(aOther.value) { MOZ_COUNT_CTOR(IndexUpdateInfo); } IndexUpdateInfo::~IndexUpdateInfo() { MOZ_COUNT_DTOR(IndexUpdateInfo); } #endif /* NS_BUILD_REFCNT_LOGGING */ // static bool DatabaseInfo::Get(nsIAtom* aId, DatabaseInfo** aInfo) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aId, "Bad id!"); if (gDatabaseHash && gDatabaseHash->Get(aId, aInfo)) { NS_IF_ADDREF(*aInfo); return true; } return false; } // static bool DatabaseInfo::Put(DatabaseInfo* aInfo) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aInfo, "Null pointer!"); if (!gDatabaseHash) { nsAutoPtr databaseHash(new DatabaseHash()); databaseHash->Init(); gDatabaseHash = databaseHash.forget(); } if (gDatabaseHash->Get(aInfo->id, nullptr)) { NS_ERROR("Already know about this database!"); return false; } gDatabaseHash->Put(aInfo->id, aInfo); return true; } // static void DatabaseInfo::Remove(nsIAtom* aId) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (gDatabaseHash) { gDatabaseHash->Remove(aId); if (!gDatabaseHash->Count()) { delete gDatabaseHash; gDatabaseHash = nullptr; } } } PLDHashOperator EnumerateDatabasesRemoveOrigin(nsISupports* aId, DatabaseInfo*& aDatabaseInfo, void* aUserArg) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); const nsACString* origin = static_cast(aUserArg); return aDatabaseInfo->origin.Equals(*origin) ? PL_DHASH_REMOVE : PL_DHASH_NEXT; } // static void DatabaseInfo::RemoveAllForOrigin(const nsACString& aOrigin) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (gDatabaseHash) { gDatabaseHash->Enumerate(EnumerateDatabasesRemoveOrigin, const_cast(&aOrigin)); } } bool DatabaseInfo::GetObjectStoreNames(nsTArray& aNames) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); aNames.Clear(); if (objectStoreHash) { objectStoreHash->EnumerateRead(EnumerateObjectStoreNames, &aNames); } return true; } bool DatabaseInfo::ContainsStoreName(const nsAString& aName) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); return objectStoreHash && objectStoreHash->Get(aName, nullptr); } ObjectStoreInfo* DatabaseInfo::GetObjectStore(const nsAString& aName) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (objectStoreHash) { return objectStoreHash->GetWeak(aName); } return nullptr; } bool DatabaseInfo::PutObjectStore(ObjectStoreInfo* aInfo) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aInfo, "Null pointer!"); if (!objectStoreHash) { nsAutoPtr hash(new ObjectStoreInfoHash()); hash->Init(); objectStoreHash = hash.forget(); } if (objectStoreHash->Get(aInfo->name, nullptr)) { NS_ERROR("Already have an entry for this objectstore!"); return false; } objectStoreHash->Put(aInfo->name, aInfo); return true; } void DatabaseInfo::RemoveObjectStore(const nsAString& aName) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(GetObjectStore(aName), "Don't know about this one!"); if (objectStoreHash) { objectStoreHash->Remove(aName); } } already_AddRefed DatabaseInfo::Clone() { nsRefPtr dbInfo(new DatabaseInfo()); dbInfo->cloned = true; dbInfo->name = name; dbInfo->origin = origin; dbInfo->version = version; dbInfo->id = id; dbInfo->filePath = filePath; dbInfo->nextObjectStoreId = nextObjectStoreId; dbInfo->nextIndexId = nextIndexId; if (objectStoreHash) { dbInfo->objectStoreHash = new ObjectStoreInfoHash(); dbInfo->objectStoreHash->Init(); objectStoreHash->EnumerateRead(CloneObjectStoreInfo, dbInfo->objectStoreHash); } return dbInfo.forget(); }