Bug 1376496 - Part 2 - Don't request FD from parent when JAR file is cached. r=mayhemer
authorHaik Aftandilian <haftandilian@mozilla.com>
Fri, 21 Jul 2017 15:19:09 -0700
changeset 419810 4a4f23c6fb22ddb6a288a6f245da985192ee4129
parent 419809 e4e70a229f5e71859aecd7299dbcfd30f03fc9ac
child 419811 20114f663be1e5cb2ec93bc72f841d5610b3be15
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1376496
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1376496 - Part 2 - Don't request FD from parent when JAR file is cached. r=mayhemer MozReview-Commit-ID: 6xooCVnBehj
modules/libjar/nsIJARChannel.idl
modules/libjar/nsIZipReader.idl
modules/libjar/nsJAR.cpp
modules/libjar/nsJAR.h
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
netwerk/protocol/res/ExtensionProtocolHandler.cpp
--- a/modules/libjar/nsIJARChannel.idl
+++ b/modules/libjar/nsIJARChannel.idl
@@ -27,9 +27,20 @@ interface nsIJARChannel : nsIChannel
      */
     attribute nsIFile jarFile;
 
     /**
      * Returns the zip entry if the file is synchronously accessible.
      * This will work even without opening the channel.
      */
     readonly attribute nsIZipEntry zipEntry;
+
+    /**
+     * If the JAR file is cached in the JAR cache, returns true and
+     * holds a reference to the cached zip reader to be used when
+     * the channel is read from, ensuring the cached reader will be used.
+     * For a successful read from the cached reader, close() should not
+     * be called on the reader--per nsIZipReader::getZip() documentation.
+     * Returns false if the JAR file is not cached. Calling this method
+     * after the channel has been opened is not permitted.
+     */
+    boolean ensureCached();
 };
--- a/modules/libjar/nsIZipReader.idl
+++ b/modules/libjar/nsIZipReader.idl
@@ -229,16 +229,26 @@ interface nsIZipReaderCache : nsISupport
      * returned.
      *
      * @note If someone called close() on the shared nsIZipReader, this method 
      *       will return the closed zip reader.
      */
     nsIZipReader getZip(in nsIFile zipFile);
 
     /**
+     * Like getZip(), returns a (possibly shared) nsIZipReader for an nsIFile,
+     * but if a zip reader for the given file is not in the cache, returns
+     * error NS_ERROR_CACHE_KEY_NOT_FOUND rather than creating a new reader.
+     *
+     * @note If someone called close() on the shared nsIZipReader, this method
+     *       will return the closed zip reader.
+     */
+    nsIZipReader getZipIfCached(in nsIFile zipFile);
+
+    /**
      * returns true if this zipreader already has this file cached
      */
     bool isCached(in nsIFile zipFile);
 
     /**
      * Returns a (possibly shared) nsIZipReader for a zip inside another zip
      *
      * See getZip
--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -1115,18 +1115,19 @@ nsZipReaderCache::IsCached(nsIFile* zipF
     return rv;
 
   uri.Insert(NS_LITERAL_CSTRING("file:"), 0);
 
   *aResult = mZips.Contains(uri);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
+nsresult
+nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result,
+                         bool failOnMiss)
 {
   NS_ENSURE_ARG_POINTER(zipFile);
   nsresult rv;
   MutexAutoLock lock(mLock);
 
 #ifdef ZIP_CACHE_HIT_RATE
   mZipCacheLookups++;
 #endif
@@ -1140,31 +1141,47 @@ nsZipReaderCache::GetZip(nsIFile* zipFil
   RefPtr<nsJAR> zip;
   mZips.Get(uri, getter_AddRefs(zip));
   if (zip) {
 #ifdef ZIP_CACHE_HIT_RATE
     mZipCacheHits++;
 #endif
     zip->ClearReleaseTime();
   } else {
+    if (failOnMiss) {
+      return NS_ERROR_CACHE_KEY_NOT_FOUND;
+    }
+
     zip = new nsJAR();
     zip->SetZipReaderCache(this);
     rv = zip->Open(zipFile);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     MOZ_ASSERT(!mZips.Contains(uri));
     mZips.Put(uri, zip);
   }
   zip.forget(result);
   return rv;
 }
 
 NS_IMETHODIMP
+nsZipReaderCache::GetZipIfCached(nsIFile* zipFile, nsIZipReader* *result)
+{
+  return GetZip(zipFile, result, true);
+}
+
+NS_IMETHODIMP
+nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
+{
+  return GetZip(zipFile, result, false);
+}
+
+NS_IMETHODIMP
 nsZipReaderCache::GetInnerZip(nsIFile* zipFile, const nsACString &entry,
                               nsIZipReader* *result)
 {
   NS_ENSURE_ARG_POINTER(zipFile);
 
   nsCOMPtr<nsIZipReader> outerZipReader;
   nsresult rv = GetZip(zipFile, getter_AddRefs(outerZipReader));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/modules/libjar/nsJAR.h
+++ b/modules/libjar/nsJAR.h
@@ -209,13 +209,15 @@ protected:
 
 #ifdef ZIP_CACHE_HIT_RATE
   uint32_t              mZipCacheLookups;
   uint32_t              mZipCacheHits;
   uint32_t              mZipCacheFlushes;
   uint32_t              mZipSyncMisses;
 #endif
 
+private:
+  nsresult GetZip(nsIFile* zipFile, nsIZipReader* *result, bool failOnMiss);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 #endif /* nsJAR_h_ */
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -267,17 +267,19 @@ nsJARChannel::CreateJarInput(nsIZipReade
     nsresult rv = NS_OK;
     if (mJarFile) {
         rv = mJarFile->Clone(getter_AddRefs(clonedFile));
         if (NS_FAILED(rv))
             return rv;
     }
 
     nsCOMPtr<nsIZipReader> reader;
-    if (jarCache) {
+    if (mPreCachedJarReader) {
+      reader = mPreCachedJarReader;
+    } else if (jarCache) {
         MOZ_ASSERT(mJarFile);
         if (mInnerJarEntry.IsEmpty())
             rv = jarCache->GetZip(clonedFile, getter_AddRefs(reader));
         else
             rv = jarCache->GetInnerZip(clonedFile, mInnerJarEntry,
                                        getter_AddRefs(reader));
     } else {
         // create an uncached jar reader
@@ -896,16 +898,66 @@ nsJARChannel::SetJarFile(nsIFile *aFile)
 {
     if (mOpened) {
         return NS_ERROR_IN_PROGRESS;
     }
     mJarFileOverride = aFile;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsJARChannel::EnsureCached(bool *aIsCached)
+{
+    nsresult rv;
+    *aIsCached = false;
+
+    if (mOpened) {
+        return NS_ERROR_ALREADY_OPENED;
+    }
+
+    if (mPreCachedJarReader) {
+        // We've already been called and found the JAR is cached
+        *aIsCached = true;
+        return NS_OK;
+    }
+
+    nsCOMPtr<nsIURI> innerFileURI;
+    rv = mJarURI->GetJARFile(getter_AddRefs(innerFileURI));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFileURL> innerFileURL = do_QueryInterface(innerFileURI, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFile> jarFile;
+    rv = innerFileURL->GetFile(getter_AddRefs(jarFile));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIProtocolHandler> handler;
+    rv = ioService->GetProtocolHandler("jar", getter_AddRefs(handler));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIJARProtocolHandler> jarHandler = do_QueryInterface(handler);
+    MOZ_ASSERT(jarHandler);
+
+    nsCOMPtr<nsIZipReaderCache> jarCache;
+    rv = jarHandler->GetJARCache(getter_AddRefs(jarCache));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = jarCache->GetZipIfCached(jarFile, getter_AddRefs(mPreCachedJarReader));
+    if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) {
+        return NS_OK;
+    }
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    *aIsCached = true;
+    return NS_OK;
+}
 
 NS_IMETHODIMP
 nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry)
 {
     nsresult rv = LookupFile(false);
     if (NS_FAILED(rv))
         return rv;
 
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -96,16 +96,17 @@ private:
 
     mozilla::net::MemoryDownloader::Data mTempMem;
     nsCOMPtr<nsIInputStreamPump>    mPump;
     // mRequest is only non-null during OnStartRequest, so we'll have a pointer
     // to the request if we get called back via RetargetDeliveryTo.
     nsCOMPtr<nsIRequest>            mRequest;
     nsCOMPtr<nsIFile>               mJarFile;
     nsCOMPtr<nsIFile>               mJarFileOverride;
+    nsCOMPtr<nsIZipReader>          mPreCachedJarReader;
     nsCOMPtr<nsIURI>                mJarBaseURI;
     nsCString                       mJarEntry;
     nsCString                       mInnerJarEntry;
 
     // True if this channel should not download any remote files.
     bool                            mBlockRemoteFiles;
 };
 
--- a/netwerk/protocol/res/ExtensionProtocolHandler.cpp
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
@@ -773,16 +773,25 @@ Result<Ok, nsresult>
 ExtensionProtocolHandler::SubstituteRemoteJarChannel(nsIURI* aURI,
                                                      nsILoadInfo* aLoadinfo,
                                                      nsACString& aResolvedSpec,
                                                      nsIChannel** aRetVal)
 {
   MOZ_ASSERT(IsNeckoChild());
   nsresult rv;
 
+  nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(*aRetVal, &rv);
+  NS_TRY(rv);
+
+  bool isCached = false;
+  NS_TRY(jarChannel->EnsureCached(&isCached));
+  if (isCached) {
+    return Ok();
+  }
+
   // Build a JAR URI for this jar:file:// URI and use it to extract the
   // inner file URI.
   nsCOMPtr<nsIURI> uri;
   NS_TRY(NS_NewURI(getter_AddRefs(uri), aResolvedSpec));
 
   nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(uri, &rv);
   NS_TRY(rv);
 
@@ -790,19 +799,16 @@ ExtensionProtocolHandler::SubstituteRemo
   NS_TRY(jarURI->GetJARFile(getter_AddRefs(innerFileURI)));
 
   nsCOMPtr<nsIFileURL> innerFileURL = do_QueryInterface(innerFileURI, &rv);
   NS_TRY(rv);
 
   nsCOMPtr<nsIFile> jarFile;
   NS_TRY(innerFileURL->GetFile(getter_AddRefs(jarFile)));
 
-  nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(*aRetVal, &rv);
-  NS_TRY(rv);
-
   RefPtr<ExtensionStreamGetter> streamGetter =
     new ExtensionStreamGetter(aURI, aLoadinfo, jarChannel.forget(), jarFile);
 
   NewSimpleChannel(aURI, aLoadinfo, streamGetter, aRetVal);
   return Ok();
 }
 
 #undef NS_TRY