Bug 642551. Save status info we may want to use in a list so we don't have to walk the entire pending request hashtable looking for one of the rare ones with status info. r=neil
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 06 Sep 2011 22:57:46 -0400
changeset 76631 de06684dabc4f450a4e6e2984868e6820fcb6df1
parent 76630 9d0d13998ebb66a76d5f15d1889e8499b2d2b469
child 76632 64c328251a24e767893231306b311d81061cc12f
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersneil
bugs642551
milestone9.0a1
Bug 642551. Save status info we may want to use in a list so we don't have to walk the entire pending request hashtable looking for one of the rare ones with status info. r=neil
uriloader/base/nsDocLoader.cpp
uriloader/base/nsDocLoader.h
--- a/uriloader/base/nsDocLoader.cpp
+++ b/uriloader/base/nsDocLoader.cpp
@@ -89,36 +89,60 @@ void GetURIStringFromRequest(nsIRequest*
 {
     if (request)
         request->GetName(name);
     else
         name.AssignLiteral("???");
 }
 #endif /* DEBUG */
 
+struct nsStatusInfo : public PRCList
+{
+  nsString mStatusMessage;
+  nsresult mStatusCode;
+  // Weak mRequest is ok; we'll be told if it decides to go away.
+  nsIRequest * const mRequest;
+
+  nsStatusInfo(nsIRequest *aRequest) :
+    mRequest(aRequest)
+  {
+    MOZ_COUNT_CTOR(nsStatusInfo);
+    PR_INIT_CLIST(this);
+  }
+  ~nsStatusInfo()
+  {
+    MOZ_COUNT_DTOR(nsStatusInfo);
+    PR_REMOVE_LINK(this);
+  }
+};
+
 struct nsRequestInfo : public PLDHashEntryHdr
 {
   nsRequestInfo(const void *key)
     : mKey(key), mCurrentProgress(0), mMaxProgress(0), mUploading(PR_FALSE)
-   , mIsDone(PR_FALSE)
+    , mLastStatus(nsnull)
   {
+    MOZ_COUNT_CTOR(nsRequestInfo);
+  }
+
+  ~nsRequestInfo()
+  {
+    MOZ_COUNT_DTOR(nsRequestInfo);
   }
 
   nsIRequest* Request() {
     return static_cast<nsIRequest*>(const_cast<void*>(mKey));
   }
 
   const void* mKey; // Must be first for the pldhash stubs to work
   PRInt64 mCurrentProgress;
   PRInt64 mMaxProgress;
   PRBool mUploading;
 
-  PRBool mIsDone;
-  nsString mLastStatus;
-  nsresult mLastStatusCode;
+  nsAutoPtr<nsStatusInfo> mLastStatus;
 };
 
 
 static PRBool
 RequestInfoHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
                          const void *key)
 {
   // Initialize the entry with placement new
@@ -181,16 +205,18 @@ nsDocLoader::nsDocLoader()
 
   if (!PL_DHashTableInit(&mRequestInfoHash, &hash_table_ops, nsnull,
                          sizeof(nsRequestInfo), 16)) {
     mRequestInfoHash.ops = nsnull;
   }
 
   ClearInternalProgress();
 
+  PR_INIT_CLIST(&mStatusInfoList);
+
   PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
          ("DocLoader:%p: created.\n", this));
 }
 
 nsresult
 nsDocLoader::SetDocLoaderParent(nsDocLoader *aParent)
 {
   mParent = aParent;
@@ -596,17 +622,22 @@ nsDocLoader::OnStopRequest(nsIRequest *a
   //
   // Set the Maximum progress to the same value as the current progress.
   // Since the URI has finished loading, all the data is there.  Also,
   // this will allow a more accurate estimation of the max progress (in case
   // the old value was unknown ie. -1)
   //
   nsRequestInfo *info = GetRequestInfo(aRequest);
   if (info) {
-    info->mIsDone = PR_TRUE;
+    if (info->mLastStatus) {
+      // Null it out now so we don't find it when looking for status
+      // from now on.  This destroys the nsStatusInfo and hence
+      // removes it from our list.
+      info->mLastStatus = nsnull;
+    }
 
     PRInt64 oldMax = info->mMaxProgress;
 
     info->mMaxProgress = info->mCurrentProgress;
     
     //
     // If a request whose content-length was previously unknown has just
     // finished loading, then use this new data to try to calculate a
@@ -870,34 +901,16 @@ void nsDocLoader::doStartURLLoad(nsIRequ
 
   FireOnStateChange(this,
                     request,
                     nsIWebProgressListener::STATE_START |
                     nsIWebProgressListener::STATE_IS_REQUEST,
                     NS_OK);
 }
 
-// PLDHashTable enumeration callback that finds a RequestInfo that's not done
-// yet.
-static PLDHashOperator
-FindUnfinishedRequestCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
-                              PRUint32 number, void *arg)
-{
-  nsRequestInfo* info = static_cast<nsRequestInfo *>(hdr);
-  nsRequestInfo** retval = static_cast<nsRequestInfo**>(arg);
-
-  if (!info->mIsDone && !info->mLastStatus.IsEmpty()) {
-    *retval = info;
-    return PL_DHASH_STOP;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-
 void nsDocLoader::doStopURLLoad(nsIRequest *request, nsresult aStatus)
 {
 #if defined(DEBUG)
   nsCAutoString buffer;
 
   GetURIStringFromRequest(request, buffer);
     PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, 
           ("DocLoader:%p: ++ Firing OnStateChange for end url load (...)."
@@ -906,25 +919,24 @@ void nsDocLoader::doStopURLLoad(nsIReque
 #endif /* DEBUG */
 
   FireOnStateChange(this,
                     request,
                     nsIWebProgressListener::STATE_STOP |
                     nsIWebProgressListener::STATE_IS_REQUEST,
                     aStatus);
 
-  // Fire a status change message for a random unfinished request to make sure
-  // that the displayed status is not outdated.
-  nsRequestInfo* unfinishedRequest = nsnull;
-  PL_DHashTableEnumerate(&mRequestInfoHash, FindUnfinishedRequestCallback,
-                         &unfinishedRequest);
-  if (unfinishedRequest) {
-    FireOnStatusChange(this, unfinishedRequest->Request(),
-                       unfinishedRequest->mLastStatusCode,
-                       unfinishedRequest->mLastStatus.get());
+  // Fire a status change message for the most recent unfinished
+  // request to make sure that the displayed status is not outdated.
+  if (!PR_CLIST_IS_EMPTY(&mStatusInfoList)) {
+    nsStatusInfo* statusInfo =
+      static_cast<nsStatusInfo*>(PR_LIST_HEAD(&mStatusInfoList));
+    FireOnStatusChange(this, statusInfo->mRequest,
+                       statusInfo->mStatusCode,
+                       statusInfo->mStatusMessage.get());
   }
 }
 
 void nsDocLoader::doStopDocumentLoad(nsIRequest *request,
                                          nsresult aStatus)
 {
 #if defined(DEBUG)
   nsCAutoString buffer;
@@ -1184,18 +1196,27 @@ NS_IMETHODIMP nsDocLoader::OnStatus(nsIR
     if (NS_FAILED(rv))
       return rv;
 
     // Keep around the message. In case a request finishes, we need to make sure
     // to send the status message of another request to our user to that we
     // don't display, for example, "Transferring" messages for requests that are
     // already done.
     if (info) {
-      info->mLastStatus = msg;
-      info->mLastStatusCode = aStatus;
+      if (!info->mLastStatus) {
+        info->mLastStatus = new nsStatusInfo(aRequest);
+      } else {
+        // We're going to move it to the front of the list, so remove
+        // it from wherever it is now.
+        PR_REMOVE_LINK(info->mLastStatus);
+      }
+      info->mLastStatus->mStatusMessage = msg;
+      info->mLastStatus->mStatusCode = aStatus;
+      // Put the info at the front of the list
+      PR_INSERT_LINK(info->mLastStatus, &mStatusInfoList);
     }
     FireOnStatusChange(this, aRequest, aStatus, msg);
   }
   return NS_OK;
 }
 
 void nsDocLoader::ClearInternalProgress()
 {
--- a/uriloader/base/nsDocLoader.h
+++ b/uriloader/base/nsDocLoader.h
@@ -54,16 +54,17 @@
 #include "nsIProgressEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIChannelEventSink.h"
 #include "nsISecurityEventSink.h"
 #include "nsISupportsPriority.h"
 #include "nsCOMPtr.h"
 #include "pldhash.h"
+#include "prclist.h"
 
 struct nsRequestInfo;
 struct nsListenerInfo;
 
 /****************************************************************************
  * nsDocLoader implementation...
  ****************************************************************************/
 
@@ -229,16 +230,18 @@ protected:
     PRInt64 mMaxSelfProgress;
 
     PRInt64 mCurrentTotalProgress;
     PRInt64 mMaxTotalProgress;
 
     PLDHashTable mRequestInfoHash;
     PRInt64 mCompletedTotalProgress;
 
+    PRCList mStatusInfoList;
+
     /*
      * This flag indicates that the loader is loading a document.  It is set
      * from the call to LoadDocument(...) until the OnConnectionsComplete(...)
      * notification is fired...
      */
     PRPackedBool mIsLoadingDocument;
 
     /* Flag to indicate that we're in the process of restoring a document. */