Bug 364864: nsICategoryManager::deleteCategoryEntry does not persist outside of component registration; r=bsmedberg
--- a/xpcom/components/nsCategoryManager.cpp
+++ b/xpcom/components/nsCategoryManager.cpp
@@ -278,18 +278,20 @@ CategoryNode::GetLeaf(const char* aEntry
}
NS_METHOD
CategoryNode::AddLeaf(const char* aEntryName,
const char* aValue,
PRBool aPersist,
PRBool aReplace,
char** _retval,
- PLArenaPool* aArena)
+ PLArenaPool* aArena,
+ PRBool* aDirty)
{
+ NS_ABORT_IF_FALSE(aDirty, "CategoryNode::AddLeaf: aDirty is null");
MutexAutoLock lock(mLock);
CategoryLeaf* leaf =
mTable.GetEntry(aEntryName);
nsresult rv = NS_OK;
if (leaf) {
//if the entry was found, aReplace must be specified
if (!aReplace && (leaf->nonpValue || (aPersist && leaf->pValue )))
@@ -318,35 +320,39 @@ CategoryNode::AddLeaf(const char* aEntry
return NS_ERROR_OUT_OF_MEMORY;
}
else {
*_retval = nsnull;
}
}
leaf->nonpValue = arenaValue;
- if (aPersist)
+ if (aPersist) {
leaf->pValue = arenaValue;
+ *aDirty = PR_TRUE;
+ }
}
}
-
return rv;
}
NS_METHOD
CategoryNode::DeleteLeaf(const char* aEntryName,
- PRBool aDontPersist)
+ PRBool aDontPersistAnymore,
+ PRBool* aDirty)
{
+ NS_ABORT_IF_FALSE(aDirty, "CategoryNode::DeleteLeaf: aDirty is null");
// we don't throw any errors, because it normally doesn't matter
// and it makes JS a lot cleaner
MutexAutoLock lock(mLock);
- if (aDontPersist) {
+ if (aDontPersistAnymore) {
// we can just remove the entire hash entry without introspection
mTable.RemoveEntry(aEntryName);
+ *aDirty = PR_TRUE;
} else {
// if we are keeping the persistent value, we need to look at
// the contents of the current entry
CategoryLeaf* leaf = mTable.GetEntry(aEntryName);
if (leaf) {
if (leaf->pValue) {
leaf->nonpValue = nsnull;
} else {
@@ -592,34 +598,33 @@ nsCategoryManager::AddCategoryEntry( con
CategoryNode* category;
{
MutexAutoLock lock(mLock);
category = get_category(aCategoryName);
if (!category) {
// That category doesn't exist yet; let's make it.
category = CategoryNode::Create(&mArena);
-
char* categoryName = ArenaStrdup(aCategoryName, &mArena);
mTable.Put(categoryName, category);
}
}
if (!category)
return NS_ERROR_OUT_OF_MEMORY;
// We will need the return value of AddLeaf even if the called doesn't want it
char *oldEntry = nsnull;
-
nsresult rv = category->AddLeaf(aEntryName,
aValue,
aPersist,
aReplace,
&oldEntry,
- &mArena);
+ &mArena,
+ &mDirty);
if (NS_SUCCEEDED(rv)) {
if (oldEntry) {
NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID,
aCategoryName, oldEntry);
}
NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID,
aCategoryName, aEntryName);
@@ -631,17 +636,17 @@ nsCategoryManager::AddCategoryEntry( con
}
return rv;
}
NS_IMETHODIMP
nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName,
const char *aEntryName,
- PRBool aDontPersist)
+ PRBool aDontPersistAnymore)
{
NS_ENSURE_ARG_POINTER(aCategoryName);
NS_ENSURE_ARG_POINTER(aEntryName);
/*
Note: no errors are reported since failure to delete
probably won't hurt you, and returning errors seriously
inconveniences JS clients
@@ -652,17 +657,18 @@ nsCategoryManager::DeleteCategoryEntry(
MutexAutoLock lock(mLock);
category = get_category(aCategoryName);
}
if (!category)
return NS_OK;
nsresult rv = category->DeleteLeaf(aEntryName,
- aDontPersist);
+ aDontPersistAnymore,
+ &mDirty);
if (NS_SUCCEEDED(rv)) {
NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID,
aCategoryName, aEntryName);
}
return rv;
}
@@ -757,16 +763,17 @@ nsCategoryManager::WriteCategoryManagerT
MutexAutoLock lock(mLock);
mTable.EnumerateRead(enumfunc_categories, &args);
if (!args.success) {
return NS_ERROR_UNEXPECTED;
}
+ mDirty = PR_FALSE;
return NS_OK;
}
NS_METHOD
nsCategoryManager::SuppressNotifications(PRBool aSuppress)
{
mSuppressNotifications = aSuppress;
return NS_OK;
--- a/xpcom/components/nsCategoryManager.h
+++ b/xpcom/components/nsCategoryManager.h
@@ -83,20 +83,22 @@ public:
NS_METHOD GetLeaf(const char* aEntryName,
char** _retval);
NS_METHOD AddLeaf(const char* aEntryName,
const char* aValue,
PRBool aPersist,
PRBool aReplace,
char** _retval,
- PLArenaPool* aArena);
+ PLArenaPool* aArena,
+ PRBool* aDirty);
NS_METHOD DeleteLeaf(const char* aEntryName,
- PRBool aDontPersist);
+ PRBool aDontPersist,
+ PRBool* aDirty);
void Clear() {
mozilla::MutexAutoLock lock(mLock);
mTable.Clear();
}
PRUint32 Count() {
mozilla::MutexAutoLock lock(mLock);
@@ -145,19 +147,26 @@ public:
/**
* Suppress or unsuppress notifications of category changes to the
* observer service. This is to be used by nsComponentManagerImpl
* on startup while reading the stored category list.
*/
NS_METHOD SuppressNotifications(PRBool aSuppress);
+ /**
+ * Do we have persistable category changes?
+ * This is to be used by nsComponentManagerImpl::Shutdown ONLY.
+ */
+ inline PRBool IsDirty() { return mDirty; }
+
nsCategoryManager()
: mLock("nsCategoryManager")
, mSuppressNotifications(PR_FALSE)
+ , mDirty(PR_FALSE)
{ }
private:
friend class nsCategoryManagerFactory;
static nsCategoryManager* Create();
~nsCategoryManager();
@@ -165,11 +174,12 @@ private:
void NotifyObservers(const char* aTopic,
const char* aCategoryName,
const char* aEntryName);
PLArenaPool mArena;
nsClassHashtable<nsDepCharHashKey, CategoryNode> mTable;
mozilla::Mutex mLock;
PRBool mSuppressNotifications;
+ PRBool mDirty;
};
#endif
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -710,18 +710,18 @@ nsresult nsComponentManagerImpl::Shutdow
if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED)
return NS_ERROR_FAILURE;
mShuttingDown = NS_SHUTDOWN_INPROGRESS;
// Shutdown the component manager
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
- // Write out our component data file.
- if (mRegistryDirty) {
+ // Write out our component data file, if dirty.
+ if (mRegistryDirty || mCategoryManager->IsDirty()) {
nsresult rv = WritePersistentRegistry();
if (NS_FAILED(rv)) {
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Could not write out persistent registry."));
#ifdef DEBUG
printf("Could not write out persistent registry!\n");
#endif
}
}