mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 699468: Part 5 - Clone the canonical DatabaseInfo when a Database is closed. r=bent
This commit is contained in:
parent
2ff0266dc0
commit
6ecd76ea59
@ -64,11 +64,32 @@ EnumerateObjectStoreNames(const nsAString& aKey,
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
CloneObjectStoreInfo(const nsAString& aKey,
|
||||
ObjectStoreInfo* aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
ObjectStoreInfoHash* hash = static_cast<ObjectStoreInfoHash*>(aUserArg);
|
||||
|
||||
nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo(*aData));
|
||||
|
||||
if (!hash->Put(aKey, newInfo)) {
|
||||
NS_WARNING("Out of memory?");
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
newInfo.forget();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DatabaseInfo::~DatabaseInfo()
|
||||
{
|
||||
DatabaseInfo::Remove(id);
|
||||
// Clones are never in the hash.
|
||||
if (!cloned) {
|
||||
DatabaseInfo::Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
@ -81,6 +102,16 @@ IndexInfo::IndexInfo()
|
||||
MOZ_COUNT_CTOR(IndexInfo);
|
||||
}
|
||||
|
||||
IndexInfo::IndexInfo(const IndexInfo& aOther)
|
||||
: id(aOther.id),
|
||||
name(aOther.name),
|
||||
keyPath(aOther.keyPath),
|
||||
unique(aOther.unique),
|
||||
autoIncrement(aOther.autoIncrement)
|
||||
{
|
||||
MOZ_COUNT_CTOR(IndexInfo);
|
||||
}
|
||||
|
||||
IndexInfo::~IndexInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(IndexInfo);
|
||||
@ -94,6 +125,17 @@ ObjectStoreInfo::ObjectStoreInfo()
|
||||
MOZ_COUNT_CTOR(ObjectStoreInfo);
|
||||
}
|
||||
|
||||
ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther)
|
||||
: name(aOther.name),
|
||||
id(aOther.id),
|
||||
keyPath(aOther.keyPath),
|
||||
autoIncrement(aOther.autoIncrement),
|
||||
databaseId(aOther.databaseId),
|
||||
indexes(aOther.indexes)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ObjectStoreInfo);
|
||||
}
|
||||
|
||||
ObjectStoreInfo::~ObjectStoreInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ObjectStoreInfo);
|
||||
@ -120,6 +162,7 @@ DatabaseInfo::Get(nsIAtom* aId,
|
||||
|
||||
if (gDatabaseHash &&
|
||||
gDatabaseHash->Get(aId, aInfo)) {
|
||||
NS_IF_ADDREF(*aInfo);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -180,20 +223,10 @@ bool
|
||||
DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(Get(id, nsnull), "Don't know anything about this one!");
|
||||
|
||||
if (!gDatabaseHash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DatabaseInfo* info;
|
||||
if (!gDatabaseHash->Get(id, &info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aNames.Clear();
|
||||
if (info->objectStoreHash) {
|
||||
info->objectStoreHash->EnumerateRead(EnumerateObjectStoreNames, &aNames);
|
||||
if (objectStoreHash) {
|
||||
objectStoreHash->EnumerateRead(EnumerateObjectStoreNames, &aNames);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -202,14 +235,8 @@ bool
|
||||
DatabaseInfo::ContainsStoreName(const nsAString& aName)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(Get(id, nsnull), "Don't know anything about this one!");
|
||||
|
||||
DatabaseInfo* dbInfo;
|
||||
|
||||
return gDatabaseHash &&
|
||||
gDatabaseHash->Get(id, &dbInfo) &&
|
||||
dbInfo->objectStoreHash &&
|
||||
dbInfo->objectStoreHash->Get(aName, nsnull);
|
||||
return objectStoreHash && objectStoreHash->Get(aName, nsnull);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -258,3 +285,31 @@ DatabaseInfo::RemoveObjectStore(const nsAString& aName)
|
||||
objectStoreHash->Remove(aName);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<DatabaseInfo>
|
||||
DatabaseInfo::Clone()
|
||||
{
|
||||
NS_ASSERTION(!cloned, "Should never clone a clone!");
|
||||
|
||||
nsRefPtr<DatabaseInfo> dbInfo(new DatabaseInfo());
|
||||
|
||||
dbInfo->cloned = true;
|
||||
dbInfo->name = name;
|
||||
dbInfo->version = version;
|
||||
dbInfo->id = id;
|
||||
dbInfo->filePath = filePath;
|
||||
dbInfo->nextObjectStoreId = nextObjectStoreId;
|
||||
dbInfo->nextIndexId = nextIndexId;
|
||||
|
||||
if (objectStoreHash) {
|
||||
dbInfo->objectStoreHash = new ObjectStoreInfoHash();
|
||||
if (!dbInfo->objectStoreHash->Init()) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
objectStoreHash->EnumerateRead(CloneObjectStoreInfo,
|
||||
dbInfo->objectStoreHash);
|
||||
}
|
||||
|
||||
return dbInfo.forget();
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ struct DatabaseInfo
|
||||
DatabaseInfo()
|
||||
: nextObjectStoreId(1),
|
||||
nextIndexId(1),
|
||||
runningVersionChange(false)
|
||||
cloned(false)
|
||||
{ }
|
||||
~DatabaseInfo();
|
||||
|
||||
@ -82,13 +82,15 @@ struct DatabaseInfo
|
||||
|
||||
void RemoveObjectStore(const nsAString& aName);
|
||||
|
||||
already_AddRefed<DatabaseInfo> Clone();
|
||||
|
||||
nsString name;
|
||||
PRUint64 version;
|
||||
nsIAtom* id;
|
||||
nsString filePath;
|
||||
PRInt64 nextObjectStoreId;
|
||||
PRInt64 nextIndexId;
|
||||
bool runningVersionChange;
|
||||
bool cloned;
|
||||
|
||||
nsAutoPtr<ObjectStoreInfoHash> objectStoreHash;
|
||||
|
||||
@ -99,6 +101,7 @@ struct IndexInfo
|
||||
{
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
IndexInfo();
|
||||
IndexInfo(const IndexInfo& aOther);
|
||||
~IndexInfo();
|
||||
#else
|
||||
IndexInfo()
|
||||
@ -116,6 +119,7 @@ struct ObjectStoreInfo
|
||||
{
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
ObjectStoreInfo();
|
||||
ObjectStoreInfo(ObjectStoreInfo& aOther);
|
||||
~ObjectStoreInfo();
|
||||
#else
|
||||
ObjectStoreInfo()
|
||||
|
@ -158,21 +158,24 @@ private:
|
||||
already_AddRefed<IDBDatabase>
|
||||
IDBDatabase::Create(nsIScriptContext* aScriptContext,
|
||||
nsPIDOMWindow* aOwner,
|
||||
DatabaseInfo* aDatabaseInfo,
|
||||
already_AddRefed<DatabaseInfo> aDatabaseInfo,
|
||||
const nsACString& aASCIIOrigin)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aDatabaseInfo, "Null pointer!");
|
||||
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
|
||||
|
||||
nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
|
||||
NS_ASSERTION(databaseInfo, "Null pointer!");
|
||||
|
||||
nsRefPtr<IDBDatabase> db(new IDBDatabase());
|
||||
|
||||
db->mScriptContext = aScriptContext;
|
||||
db->mOwner = aOwner;
|
||||
|
||||
db->mDatabaseId = aDatabaseInfo->id;
|
||||
db->mName = aDatabaseInfo->name;
|
||||
db->mFilePath = aDatabaseInfo->filePath;
|
||||
db->mDatabaseId = databaseInfo->id;
|
||||
db->mName = databaseInfo->name;
|
||||
db->mFilePath = databaseInfo->filePath;
|
||||
databaseInfo.swap(db->mDatabaseInfo);
|
||||
db->mASCIIOrigin = aASCIIOrigin;
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
@ -190,7 +193,8 @@ IDBDatabase::IDBDatabase()
|
||||
: mDatabaseId(0),
|
||||
mInvalidated(0),
|
||||
mRegistered(false),
|
||||
mClosed(false)
|
||||
mClosed(false),
|
||||
mRunningVersionChange(false)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
@ -205,7 +209,7 @@ IDBDatabase::~IDBDatabase()
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (mRegistered) {
|
||||
CloseInternal();
|
||||
CloseInternal(true);
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
if (mgr) {
|
||||
@ -213,11 +217,6 @@ IDBDatabase::~IDBDatabase()
|
||||
}
|
||||
}
|
||||
|
||||
if (mDatabaseId && !mInvalidated) {
|
||||
DatabaseInfo* info = Info();
|
||||
NS_RELEASE(info);
|
||||
}
|
||||
|
||||
if (mListenerManager) {
|
||||
mListenerManager->Disconnect();
|
||||
}
|
||||
@ -233,17 +232,6 @@ IDBDatabase::~IDBDatabase()
|
||||
}
|
||||
}
|
||||
|
||||
DatabaseInfo*
|
||||
IDBDatabase::Info() const
|
||||
{
|
||||
DatabaseInfo* dbInfo = nsnull;
|
||||
|
||||
DebugOnly<bool> got = DatabaseInfo::Get(Id(), &dbInfo);
|
||||
NS_ASSERTION(got && dbInfo, "This should never fail!");
|
||||
|
||||
return dbInfo;
|
||||
}
|
||||
|
||||
bool
|
||||
IDBDatabase::IsQuotaDisabled()
|
||||
{
|
||||
@ -313,10 +301,7 @@ IDBDatabase::Invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
if (!PR_ATOMIC_SET(&mInvalidated, 1)) {
|
||||
DatabaseInfo* info = Info();
|
||||
NS_RELEASE(info);
|
||||
}
|
||||
mInvalidated = true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -326,11 +311,23 @@ IDBDatabase::IsInvalidated()
|
||||
}
|
||||
|
||||
void
|
||||
IDBDatabase::CloseInternal()
|
||||
IDBDatabase::CloseInternal(bool aIsDead)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!mClosed) {
|
||||
// If we're getting called from Unlink, avoid cloning the DatabaseInfo.
|
||||
{
|
||||
nsRefPtr<DatabaseInfo> previousInfo;
|
||||
mDatabaseInfo.swap(previousInfo);
|
||||
|
||||
if (!aIsDead) {
|
||||
nsRefPtr<DatabaseInfo> clonedInfo = previousInfo->Clone();
|
||||
|
||||
clonedInfo.swap(mDatabaseInfo);
|
||||
}
|
||||
}
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
if (mgr) {
|
||||
mgr->OnDatabaseClosed(this);
|
||||
@ -349,19 +346,15 @@ IDBDatabase::IsClosed()
|
||||
void
|
||||
IDBDatabase::EnterSetVersionTransaction()
|
||||
{
|
||||
DatabaseInfo* dbInfo = Info();
|
||||
|
||||
NS_ASSERTION(!dbInfo->runningVersionChange, "How did that happen?");
|
||||
dbInfo->runningVersionChange = true;
|
||||
NS_ASSERTION(!mRunningVersionChange, "How did that happen?");
|
||||
mRunningVersionChange = true;
|
||||
}
|
||||
|
||||
void
|
||||
IDBDatabase::ExitSetVersionTransaction()
|
||||
{
|
||||
DatabaseInfo* dbInfo = Info();
|
||||
|
||||
NS_ASSERTION(dbInfo->runningVersionChange, "How did that happen?");
|
||||
dbInfo->runningVersionChange = false;
|
||||
NS_ASSERTION(mRunningVersionChange, "How did that happen?");
|
||||
mRunningVersionChange = false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -372,7 +365,7 @@ IDBDatabase::OnUnlink()
|
||||
|
||||
// We've been unlinked, at the very least we should be able to prevent further
|
||||
// transactions from starting and unblock any other SetVersion callers.
|
||||
Close();
|
||||
CloseInternal(true);
|
||||
|
||||
// No reason for the IndexedDatabaseManager to track us any longer.
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
@ -611,9 +604,7 @@ IDBDatabase::Transaction(const jsval& aStoreNames,
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
DatabaseInfo* info = Info();
|
||||
|
||||
if (info->runningVersionChange) {
|
||||
if (mRunningVersionChange) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
@ -719,6 +710,7 @@ IDBDatabase::Transaction(const jsval& aStoreNames,
|
||||
}
|
||||
|
||||
// Now check to make sure the object store names we collected actually exist.
|
||||
DatabaseInfo* info = Info();
|
||||
for (PRUint32 index = 0; index < storesToOpen.Length(); index++) {
|
||||
if (!info->ContainsStoreName(storesToOpen[index])) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
|
||||
@ -739,7 +731,7 @@ IDBDatabase::Close()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
CloseInternal();
|
||||
CloseInternal(false);
|
||||
|
||||
NS_ASSERTION(mClosed, "Should have set the closed flag!");
|
||||
return NS_OK;
|
||||
|
@ -77,7 +77,7 @@ public:
|
||||
static already_AddRefed<IDBDatabase>
|
||||
Create(nsIScriptContext* aScriptContext,
|
||||
nsPIDOMWindow* aOwner,
|
||||
DatabaseInfo* aDatabaseInfo,
|
||||
already_AddRefed<DatabaseInfo> aDatabaseInfo,
|
||||
const nsACString& aASCIIOrigin);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
@ -88,7 +88,10 @@ public:
|
||||
return mDatabaseId;
|
||||
}
|
||||
|
||||
DatabaseInfo* Info() const;
|
||||
DatabaseInfo* Info() const
|
||||
{
|
||||
return mDatabaseInfo;
|
||||
}
|
||||
|
||||
const nsString& Name()
|
||||
{
|
||||
@ -132,7 +135,7 @@ public:
|
||||
// transactions for this database will be allowed to run.
|
||||
bool IsInvalidated();
|
||||
|
||||
void CloseInternal();
|
||||
void CloseInternal(bool aIsDead);
|
||||
|
||||
// Whether or not the database has had Close called on it.
|
||||
bool IsClosed();
|
||||
@ -146,6 +149,7 @@ private:
|
||||
|
||||
void OnUnlink();
|
||||
|
||||
nsRefPtr<DatabaseInfo> mDatabaseInfo;
|
||||
nsCOMPtr<nsIAtom> mDatabaseId;
|
||||
nsString mName;
|
||||
nsString mFilePath;
|
||||
@ -154,6 +158,7 @@ private:
|
||||
PRInt32 mInvalidated;
|
||||
bool mRegistered;
|
||||
bool mClosed;
|
||||
bool mRunningVersionChange;
|
||||
|
||||
// Only touched on the main thread.
|
||||
nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
|
||||
|
@ -880,9 +880,8 @@ OpenDatabaseHelper::Run()
|
||||
nsresult
|
||||
OpenDatabaseHelper::EnsureSuccessResult()
|
||||
{
|
||||
DatabaseInfo* dbInfo;
|
||||
if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
|
||||
NS_ADDREF(dbInfo);
|
||||
nsRefPtr<DatabaseInfo> dbInfo;
|
||||
if (DatabaseInfo::Get(mDatabaseId, getter_AddRefs(dbInfo))) {
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
@ -944,7 +943,7 @@ OpenDatabaseHelper::EnsureSuccessResult()
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
newInfo.forget(&dbInfo);
|
||||
newInfo.swap(dbInfo);
|
||||
|
||||
nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mCurrentVersion,
|
||||
mObjectStores);
|
||||
@ -958,7 +957,9 @@ OpenDatabaseHelper::EnsureSuccessResult()
|
||||
|
||||
nsRefPtr<IDBDatabase> database =
|
||||
IDBDatabase::Create(mOpenDBRequest->ScriptContext(),
|
||||
mOpenDBRequest->Owner(), dbInfo, mASCIIOrigin);
|
||||
mOpenDBRequest->Owner(),
|
||||
dbInfo.forget(),
|
||||
mASCIIOrigin);
|
||||
if (!database) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
@ -142,9 +142,9 @@
|
||||
event = yield;
|
||||
ok(event.target.result instanceof IDBDatabase, "Expect a database here");
|
||||
is(event.target.result.version, 4, "Right version");
|
||||
todo_is(db3.version, 3, "After closing the version should not change!");
|
||||
todo_is(db2.version, 2, "After closing the version should not change!");
|
||||
todo_is(db1.version, 1, "After closing the version should not change!");
|
||||
is(db3.version, 3, "After closing the version should not change!");
|
||||
is(db2.version, 2, "After closing the version should not change!");
|
||||
is(db1.version, 1, "After closing the version should not change!");
|
||||
|
||||
is(versionChangeEventCount, 3, "Saw all expected events");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user