Bug 364864: nsICategoryManager::deleteCategoryEntry does not persist outside of component registration; r=bsmedberg
☠☠ backed out by c79554eb3432 ☠ ☠
authorKarsten Düsterloh <mnyromyr@tprac.de>
Mon, 05 Oct 2009 21:05:24 +0200
changeset 33469 ecd2b45a42afaf5b6629d7fcb1f0875d8ded0e54
parent 33468 f511a5abb19d44b550b141a3ef4675f2e274cb3d
child 33470 8dfd3a7cab914a388c392bae978772d17dfb2a15
child 33477 c79554eb34323e03cd41a9e412adea373dd86ae5
push idunknown
push userunknown
push dateunknown
reviewersbsmedberg
bugs364864
milestone1.9.3a1pre
Bug 364864: nsICategoryManager::deleteCategoryEntry does not persist outside of component registration; r=bsmedberg
xpcom/components/nsCategoryManager.cpp
xpcom/components/nsCategoryManager.h
xpcom/components/nsComponentManager.cpp
--- 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
         }
     }