root-stringbundles
author Benjamin Smedberg <benjamin@smedbergs.us>
Sat, 26 Jul 2008 22:49:39 -0400
changeset 167 a4da40849f5436e629c5732f4368c6c48189637f
parent 113 f52b9eb1520af03948836535a37e522f93b2100c
permissions -rw-r--r--
State as of now

Root the stringbundle cache... also remove the silly LRU list.

diff --git a/intl/strres/src/nsStringBundle.cpp b/intl/strres/src/nsStringBundle.cpp
--- a/intl/strres/src/nsStringBundle.cpp
+++ b/intl/strres/src/nsStringBundle.cpp
@@ -112,20 +112,20 @@ nsStringBundle::LoadProperties()
   nsresult rv;
 
   // do it synchronously
-  nsCOMPtr<nsIURI> uri;
-  rv = NS_NewURI(getter_AddRefs(uri), mPropertiesURL);
+  nsIURI* uri = nsnull;
+  rv = NS_NewURI(&uri, mPropertiesURL);
   if (NS_FAILED(rv)) return rv;
 
   // We don't use NS_OpenURI because we want to tweak the channel
-  nsCOMPtr<nsIChannel> channel;
-  rv = NS_NewChannel(getter_AddRefs(channel), uri);
+  nsIChannel* channel = nsnull;
+  rv = NS_NewChannel(&channel, uri);
   if (NS_FAILED(rv)) return rv;
 
   // It's a string bundle.  We expect a text/plain type, so set that as hint
   channel->SetContentType(NS_LITERAL_CSTRING("text/plain"));
   
-  nsCOMPtr<nsIInputStream> in;
-  rv = channel->Open(getter_AddRefs(in));
+  nsIInputStream* in = nsnull;
+  rv = channel->Open(&in);
   if (NS_FAILED(rv)) return rv;
 
   NS_TIMELINE_MARK_FUNCTION("loading properties");
@@ -294,26 +294,26 @@ nsStringBundle::GetCombinedEnumeration(n
 nsStringBundle::GetCombinedEnumeration(nsIStringBundleOverride* aOverrideStrings,
                                        nsISimpleEnumerator** aResult)
 {
-  nsCOMPtr<nsISupports> supports;
-  nsCOMPtr<nsIPropertyElement> propElement;
+  nsISupports* supports = nsnull;
+  nsIPropertyElement* propElement = nsnull;
   
   nsresult rv;
 
-  nsCOMPtr<nsIMutableArray> resultArray =
+  nsIMutableArray* resultArray =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // first, append the override elements
-  nsCOMPtr<nsISimpleEnumerator> overrideEnumerator;
+  nsISimpleEnumerator* overrideEnumerator = nsnull;
   rv = aOverrideStrings->EnumerateKeysInBundle(mPropertiesURL,
-                                               getter_AddRefs(overrideEnumerator));
+                                               &overrideEnumerator);
   
   PRBool hasMore;
   rv = overrideEnumerator->HasMoreElements(&hasMore);
   NS_ENSURE_SUCCESS(rv, rv);
   while (hasMore) {
 
-    rv = overrideEnumerator->GetNext(getter_AddRefs(supports));
+    rv = overrideEnumerator->GetNext(&supports);
     if (NS_SUCCEEDED(rv))
       resultArray->AppendElement(supports, PR_FALSE);
 
@@ -322,8 +322,8 @@ nsStringBundle::GetCombinedEnumeration(n
   }
 
   // ok, now we have the override elements in resultArray
-  nsCOMPtr<nsISimpleEnumerator> propEnumerator;
-  rv = mProps->Enumerate(getter_AddRefs(propEnumerator));
+  nsISimpleEnumerator* propEnumerator = nsnull;
+  rv = mProps->Enumerate(&propEnumerator);
   if (NS_FAILED(rv)) {
     // no elements in mProps anyway, just return what we have
     return NS_NewArrayEnumerator(aResult, resultArray);
@@ -331,7 +331,7 @@ nsStringBundle::GetCombinedEnumeration(n
 
   // second, append all the elements that are in mProps
   do {
-    rv = propEnumerator->GetNext(getter_AddRefs(supports));
+    rv = propEnumerator->GetNext(&supports);
     if (NS_SUCCEEDED(rv) &&
         (propElement = do_QueryInterface(supports, &rv))) {
 
@@ -427,22 +427,22 @@ nsExtensibleStringBundle::Init(const cha
 {
 
   nsresult rv;
-  nsCOMPtr<nsICategoryManager> catman =
+  nsICategoryManager* catman =
     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
   if (NS_FAILED(rv)) return rv;
 
-  nsCOMPtr<nsISimpleEnumerator> enumerator;
-  rv = catman->EnumerateCategory(aCategory, getter_AddRefs(enumerator));
+  nsISimpleEnumerator* enumerator = nsnull;
+  rv = catman->EnumerateCategory(aCategory, &enumerator);
   if (NS_FAILED(rv)) return rv;
 
   PRBool hasMore;
   while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
-    nsCOMPtr<nsISupports> supports;
-    rv = enumerator->GetNext(getter_AddRefs(supports));
+    nsISupports* supports = nsnull;
+    rv = enumerator->GetNext(&supports);
     if (NS_FAILED(rv))
       continue;
 
-    nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports, &rv);
+    nsISupportsCString* supStr = do_QueryInterface(supports, &rv);
     if (NS_FAILED(rv))
       continue;
 
@@ -451,8 +451,8 @@ nsExtensibleStringBundle::Init(const cha
     if (NS_FAILED(rv))
       continue;
 
-    nsCOMPtr<nsIStringBundle> bundle;
-    rv = aBundleService->CreateBundle(name.get(), getter_AddRefs(bundle));
+    nsIStringBundle* bundle = nsnull;
+    rv = aBundleService->CreateBundle(name.get(), &bundle);
     if (NS_FAILED(rv))
       continue;
 
@@ -538,31 +538,16 @@ nsresult nsExtensibleStringBundle::GetSi
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
-#define MAX_CACHED_BUNDLES 16
-
-struct bundleCacheEntry_t {
-  PRCList list;
-  nsCStringKey *mHashKey;
-  // do not use a nsCOMPtr - this is a struct not a class!
-  nsIStringBundle* mBundle;
-};
-
-
-nsStringBundleService::nsStringBundleService() :
-  mBundleMap(MAX_CACHED_BUNDLES, PR_TRUE)
+nsStringBundleService::nsStringBundleService()
 {
 #ifdef DEBUG_tao_
   printf("\n++ nsStringBundleService::nsStringBundleService ++\n");
 #endif
 
-  PR_INIT_CLIST(&mBundleCache);
-  PL_InitArenaPool(&mCacheEntryPool, "srEntries",
-                   sizeof(bundleCacheEntry_t)*MAX_CACHED_BUNDLES,
-                   sizeof(bundleCacheEntry_t));
+  mBundleMap.Init(16);
 
   mErrorService = do_GetService(kErrorServiceCID);
   NS_ASSERTION(mErrorService, "Couldn't get error service");
-
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS3(nsStringBundleService,
@@ -572,14 +557,12 @@ NS_IMPL_THREADSAFE_ISUPPORTS3(nsStringBu
 
 nsStringBundleService::~nsStringBundleService()
 {
-  flushBundleCache();
-  PL_FinishArenaPool(&mCacheEntryPool);
 }
 
 nsresult
 nsStringBundleService::Init()
 {
-  nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
+  nsIObserverService* os = do_GetService("@mozilla.org/observer-service;1");
   if (os) {
     os->AddObserver(this, "memory-pressure", PR_TRUE);
     os->AddObserver(this, "profile-do-change", PR_TRUE);
@@ -619,20 +602,7 @@ nsStringBundleService::flushBundleCache(
 nsStringBundleService::flushBundleCache()
 {
   // release all bundles in the cache
-  mBundleMap.Reset();
-  
-  PRCList *current = PR_LIST_HEAD(&mBundleCache);
-  while (current != &mBundleCache) {
-    bundleCacheEntry_t *cacheEntry = (bundleCacheEntry_t*)current;
-
-    recycleEntry(cacheEntry);
-    PRCList *oldItem = current;
-    current = PR_NEXT_LINK(current);
-    
-    // will be freed in PL_FreeArenaPool
-    PR_REMOVE_LINK(oldItem);
-  }
-  PL_FreeArenaPool(&mCacheEntryPool);
+  mBundleMap.Clear();
 }
 
 NS_IMETHODIMP
@@ -646,94 +616,19 @@ nsStringBundleService::getStringBundle(c
 nsStringBundleService::getStringBundle(const char *aURLSpec,
                                        nsIStringBundle **aResult)
 {
-  nsCStringKey completeKey(aURLSpec);
+  nsDependentCString urlspec(aURLSpec);
 
-  bundleCacheEntry_t* cacheEntry =
-    (bundleCacheEntry_t*)mBundleMap.Get(&completeKey);
-  
-  if (cacheEntry) {
-    // cache hit!
-    // remove it from the list, it will later be reinserted
-    // at the head of the list
-    PR_REMOVE_LINK((PRCList*)cacheEntry);
-    
-  } else {
+  nsStringBundle *sb = nsnull;
+  mBundleMap.Get(urlspec, &sb);
 
+  if (!sb) {
     // hasn't been cached, so insert it into the hash table
-    nsStringBundle* bundle = new nsStringBundle(aURLSpec, mOverrideStrings);
-    if (!bundle) return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(bundle);
-    
-    cacheEntry = insertIntoCache(bundle, &completeKey);
-    NS_RELEASE(bundle);         // cache should now be holding a ref
-                                // in the cacheEntry
+    sb = new nsStringBundle(aURLSpec, mOverrideStrings);
+    mBundleMap.Put(urlspec, sb);
   }
 
-  // at this point the cacheEntry should exist in the hashtable,
-  // but is not in the LRU cache.
-  // put the cache entry at the front of the list
-  
-  PR_INSERT_LINK((PRCList *)cacheEntry, &mBundleCache);
-
-  // finally, return the value
-  *aResult = cacheEntry->mBundle;
-  NS_ADDREF(*aResult);
-
+  *aResult = sb;
   return NS_OK;
-}
-
-bundleCacheEntry_t *
-nsStringBundleService::insertIntoCache(nsIStringBundle* aBundle,
-                                       nsCStringKey* aHashKey)
-{
-  bundleCacheEntry_t *cacheEntry;
-  
-  if (mBundleMap.Count() < MAX_CACHED_BUNDLES) {
-    // cache not full - create a new entry
-    
-    void *cacheEntryArena;
-    PL_ARENA_ALLOCATE(cacheEntryArena, &mCacheEntryPool, sizeof(bundleCacheEntry_t));
-    cacheEntry = (bundleCacheEntry_t*)cacheEntryArena;
-      
-  } else {
-    // cache is full
-    // take the last entry in the list, and recycle it.
-    cacheEntry = (bundleCacheEntry_t*)PR_LIST_TAIL(&mBundleCache);
-      
-    // remove it from the hash table and linked list
-    NS_ASSERTION(mBundleMap.Exists(cacheEntry->mHashKey),
-                 "Element will not be removed!");
-#ifdef DEBUG_alecf
-    NS_WARNING(nsPrintfCString(300,
-                               "Booting %s to make room for %s\n",
-                               cacheEntry->mHashKey->GetString(),
-                               aHashKey->GetString()).get());
-#endif
-    mBundleMap.Remove(cacheEntry->mHashKey);
-    PR_REMOVE_LINK((PRCList*)cacheEntry);
-
-    // free up excess memory
-    recycleEntry(cacheEntry);
-  }
-    
-  // at this point we have a new cacheEntry that doesn't exist
-  // in the hashtable, so set up the cacheEntry
-  cacheEntry->mBundle = aBundle;
-  NS_ADDREF(cacheEntry->mBundle);
-
-  cacheEntry->mHashKey = (nsCStringKey*)aHashKey->Clone();
-  
-  // insert the entry into the cache and map, make it the MRU
-  mBundleMap.Put(cacheEntry->mHashKey, cacheEntry);
-
-  return cacheEntry;
-}
-
-void
-nsStringBundleService::recycleEntry(bundleCacheEntry_t *aEntry)
-{
-  delete aEntry->mHashKey;
-  NS_RELEASE(aEntry->mBundle);
 }
 
 NS_IMETHODIMP
@@ -817,7 +712,7 @@ nsStringBundleService::FormatStatusMessa
 {
   nsresult rv;
   PRUint32 i, argCount = 0;
-  nsCOMPtr<nsIStringBundle> bundle;
+  nsIStringBundle* bundle = nsnull;
   nsXPIDLCString stringBundleURL;
 
   // XXX hack for mailnews who has already formatted their messages:
@@ -862,13 +757,13 @@ nsStringBundleService::FormatStatusMessa
   rv = mErrorService->GetErrorStringBundle(NS_ERROR_GET_MODULE(aStatus), 
                                            getter_Copies(stringBundleURL));
   if (NS_SUCCEEDED(rv)) {
-    rv = getStringBundle(stringBundleURL, getter_AddRefs(bundle));
+    rv = getStringBundle(stringBundleURL, &bundle);
     if (NS_SUCCEEDED(rv)) {
       rv = FormatWithBundle(bundle, aStatus, argCount, argArray, result);
     }
   }
   if (NS_FAILED(rv)) {
-    rv = getStringBundle(GLOBAL_PROPERTIES, getter_AddRefs(bundle));
+    rv = getStringBundle(GLOBAL_PROPERTIES, &bundle);
     if (NS_SUCCEEDED(rv)) {
       rv = FormatWithBundle(bundle, aStatus, argCount, argArray, result);
     }
diff --git a/intl/strres/src/nsStringBundleService.h b/intl/strres/src/nsStringBundleService.h
--- a/intl/strres/src/nsStringBundleService.h
+++ b/intl/strres/src/nsStringBundleService.h
@@ -38,21 +38,18 @@
 #ifndef nsStringBundleService_h__
 #define nsStringBundleService_h__
 
-#include "prclist.h"
-#include "plarena.h"
-
 #include "nsCOMPtr.h"
-#include "nsHashtable.h"
+#include "nsInterfaceHashtable.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIStringBundle.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsIErrorService.h"
+#include "nsStringBundle.h"
 #include "nsIStringBundleOverride.h"
 
-struct bundleCacheEntry_t;
-
-class nsStringBundleService : public nsIStringBundleService,
+class nsStringBundleService : public XPCOMGCFinalizedObject,
+                              public nsIStringBundleService,
                               public nsIObserver,
                               public nsSupportsWeakReference
 {
@@ -74,14 +71,7 @@ private:
 
   void flushBundleCache();
   
-  bundleCacheEntry_t *insertIntoCache(nsIStringBundle *aBundle,
-                                      nsCStringKey *aHashKey);
-
-  static void recycleEntry(bundleCacheEntry_t*);
-  
-  nsHashtable mBundleMap;
-  PRCList mBundleCache;
-  PLArenaPool mCacheEntryPool;
+  nsInterfaceHashtable<nsCStringHashKey, nsStringBundle> mBundleMap;
 
   nsCOMPtr<nsIErrorService>     mErrorService;
   nsCOMPtr<nsIStringBundleOverride> mOverrideStrings;