From b601c065621c32d92bfe94e4fe7746974823c061 Mon Sep 17 00:00:00 2001 From: Shian-Yow Wu Date: Fri, 18 Jul 2014 10:46:24 +0800 Subject: [PATCH] Bug 988816 - Allow to keep file descriptor in JAR cache. r=aklotz, jduell --- modules/libjar/nsIZipReader.idl | 22 +++++- modules/libjar/nsJAR.cpp | 105 +++++++++++++++++++++++++++- modules/libjar/nsJAR.h | 7 ++ modules/libjar/nsJARChannel.cpp | 36 +++++++++- modules/libjar/nsZipArchive.cpp | 24 +++++-- modules/libjar/nsZipArchive.h | 10 ++- netwerk/ipc/RemoteOpenFileChild.cpp | 12 ++++ netwerk/ipc/RemoteOpenFileChild.h | 2 + 8 files changed, 205 insertions(+), 13 deletions(-) diff --git a/modules/libjar/nsIZipReader.idl b/modules/libjar/nsIZipReader.idl index 7966e564d2d..10ae7768aa1 100644 --- a/modules/libjar/nsIZipReader.idl +++ b/modules/libjar/nsIZipReader.idl @@ -6,6 +6,12 @@ #include "nsISupports.idl" +%{C++ +struct PRFileDesc; +%} + +[ptr] native PRFileDescStar(PRFileDesc); + interface nsIUTF8StringEnumerator; interface nsIInputStream; interface nsIFile; @@ -192,7 +198,7 @@ interface nsIZipReader : nsISupports //////////////////////////////////////////////////////////////////////////////// // nsIZipReaderCache -[scriptable, uuid(748050ac-3ab6-4472-bc2a-cb1564ac6a81)] +[scriptable, uuid(94ecd586-d405-4801-93d3-8ac7bef81bde)] interface nsIZipReaderCache : nsISupports { /** @@ -228,6 +234,20 @@ interface nsIZipReaderCache : nsISupports * See getZip */ nsIZipReader getInnerZip(in nsIFile zipFile, in AUTF8String zipEntry); + + /** + * Whether to keep NSPR file descriptor for newly opened files in the cache. + * When aMustCacheFd is enabled and a file is given, the file will be flushed + * from the cache if its file descriptor was not cached. + * Note: currently not supported on Windows platform. + */ + void setMustCacheFd(in nsIFile zipFile, in bool aMustCacheFd); + + /** + * Returns the cached NSPR file descriptor of the file. + * Note: currently not supported on Windows platform. + */ + PRFileDescStar getFd(in nsIFile zipFile); }; //////////////////////////////////////////////////////////////////////////////// diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index 01aec919455..1c57e8dd20b 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -141,7 +141,7 @@ nsJAR::Open(nsIFile* zipFile) mZip = zip; return NS_OK; } - return mZip->OpenArchive(zipFile); + return mZip->OpenArchive(zipFile, mCache ? mCache->IsMustCacheFdEnabled() : false); } NS_IMETHODIMP @@ -391,6 +391,26 @@ nsJAR::GetJarPath(nsACString& aResult) return mZipFile->GetNativePath(aResult); } +nsresult +nsJAR::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc) +{ + if (!aNSPRFileDesc) { + return NS_ERROR_ILLEGAL_VALUE; + } + *aNSPRFileDesc = nullptr; + + if (!mZip) { + return NS_ERROR_FAILURE; + } + + nsRefPtr handle = mZip->GetFD(); + if (!handle) { + return NS_ERROR_FAILURE; + } + + return handle->GetNSPRFileDesc(aNSPRFileDesc); +} + //---------------------------------------------- // nsJAR private implementation //---------------------------------------------- @@ -1009,6 +1029,7 @@ NS_IMPL_ISUPPORTS(nsZipReaderCache, nsIZipReaderCache, nsIObserver, nsISupportsW nsZipReaderCache::nsZipReaderCache() : mLock("nsZipReaderCache.mLock") , mZips(16) + , mMustCacheFd(false) #ifdef ZIP_CACHE_HIT_RATE , mZipCacheLookups(0), @@ -1104,7 +1125,6 @@ nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result) } else { zip = new nsJAR(); zip->SetZipReaderCache(this); - rv = zip->Open(zipFile); if (NS_FAILED(rv)) { return rv; @@ -1162,6 +1182,87 @@ nsZipReaderCache::GetInnerZip(nsIFile* zipFile, const nsACString &entry, return rv; } +NS_IMETHODIMP +nsZipReaderCache::SetMustCacheFd(nsIFile* zipFile, bool aMustCacheFd) +{ +#if defined(XP_WIN) + MOZ_CRASH("Not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else + mMustCacheFd = aMustCacheFd; + + if (!aMustCacheFd) { + return NS_OK; + } + + if (!zipFile) { + return NS_ERROR_FAILURE; + } + + nsresult rv; + nsAutoCString uri; + rv = zipFile->GetNativePath(uri); + if (NS_FAILED(rv)) { + return rv; + } + uri.Insert(NS_LITERAL_CSTRING("file:"), 0); + + MutexAutoLock lock(mLock); + nsRefPtr zip; + mZips.Get(uri, getter_AddRefs(zip)); + if (!zip) { + return NS_ERROR_FAILURE; + } + + // Flush the file from the cache if its file descriptor was not cached. + PRFileDesc* fd = nullptr; + zip->GetNSPRFileDesc(&fd); + if (!fd) { +#ifdef ZIP_CACHE_HIT_RATE + mZipCacheFlushes++; +#endif + zip->SetZipReaderCache(nullptr); + mZips.Remove(uri); + } + return NS_OK; +#endif /* XP_WIN */ +} + +NS_IMETHODIMP +nsZipReaderCache::GetFd(nsIFile* zipFile, PRFileDesc** aRetVal) +{ +#if defined(XP_WIN) + MOZ_CRASH("Not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +#else + if (!zipFile) { + return NS_ERROR_FAILURE; + } + + nsresult rv; + nsAutoCString uri; + rv = zipFile->GetNativePath(uri); + if (NS_FAILED(rv)) { + return rv; + } + uri.Insert(NS_LITERAL_CSTRING("file:"), 0); + + MutexAutoLock lock(mLock); + nsRefPtr zip; + mZips.Get(uri, getter_AddRefs(zip)); + if (!zip) { + return NS_ERROR_FAILURE; + } + + zip->ClearReleaseTime(); + rv = zip->GetNSPRFileDesc(aRetVal); + // Do this to avoid possible deadlock on mLock with ReleaseZip(). + MutexAutoUnlock unlock(mLock); + nsRefPtr zipTemp = zip.forget(); + return rv; +#endif /* XP_WIN */ +} + static PLDHashOperator FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure) { diff --git a/modules/libjar/nsJAR.h b/modules/libjar/nsJAR.h index 496899cf036..9943e880359 100644 --- a/modules/libjar/nsJAR.h +++ b/modules/libjar/nsJAR.h @@ -95,6 +95,8 @@ class nsJAR : public nsIZipReader mCache = cache; } + nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc); + protected: typedef nsClassHashtable ManifestDataHashtable; @@ -195,6 +197,10 @@ public: nsresult ReleaseZip(nsJAR* reader); + bool IsMustCacheFdEnabled() { + return mMustCacheFd; + } + typedef nsRefPtrHashtable ZipsHashtable; protected: @@ -204,6 +210,7 @@ protected: mozilla::Mutex mLock; uint32_t mCacheSize; ZipsHashtable mZips; + bool mMustCacheFd; #ifdef ZIP_CACHE_HIT_RATE uint32_t mZipCacheLookups; diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index e7c283c8e04..6ad41f3304d 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -22,6 +22,7 @@ #include "mozilla/Preferences.h" #include "mozilla/net/RemoteOpenFileChild.h" #include "nsITabChild.h" +#include "private/pprio.h" using namespace mozilla; using namespace mozilla::net; @@ -357,13 +358,34 @@ nsJARChannel::LookupFile() mJarFile = remoteFile; nsIZipReaderCache *jarCache = gJarHandler->JarCache(); - if (jarCache && !mEnsureChildFd) { + if (jarCache) { bool cached = false; rv = jarCache->IsCached(mJarFile, &cached); if (NS_SUCCEEDED(rv) && cached) { // zipcache already has file mmapped: don't open on parent, - // just return and proceed to cache hit in CreateJarInput() + // just return and proceed to cache hit in CreateJarInput(). + // When the file descriptor is needed, get it from JAR cache + // if available, otherwise do the remote open to get a new + // one. + #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) + // Windows/OSX desktop builds skip remoting, we don't need + // file descriptor here. return NS_OK; + #else + if (!mEnsureChildFd) { + return NS_OK; + } + PRFileDesc *fd = nullptr; + jarCache->GetFd(mJarFile, &fd); + if (fd) { + PROsfd osfd = dup(PR_FileDesc2NativeHandle(fd)); + if (osfd == -1) { + return NS_ERROR_FAILURE; + } + remoteFile->SetNSPRFileDesc(PR_ImportFile(osfd)); + return NS_OK; + } + #endif } } @@ -377,6 +399,10 @@ nsJARChannel::LookupFile() return NS_OK; } + if (mEnsureChildFd && jarCache) { + jarCache->SetMustCacheFd(remoteFile, true); + } + // Open file on parent: OnRemoteFileOpenComplete called when done nsCOMPtr tabChild; NS_QueryNotificationCallbacks(this, tabChild); @@ -1044,7 +1070,11 @@ nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status) mCallbacks = 0; mProgressSink = 0; - if (mOpeningRemote) { + if (mEnsureChildFd) { + nsIZipReaderCache *jarCache = gJarHandler->JarCache(); + if (jarCache) { + jarCache->SetMustCacheFd(mJarFile, false); + } // To deallocate file descriptor by RemoteOpenFileChild destructor. mJarFile = nullptr; } diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 901d07bc3c6..28f8d8f2f2f 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -171,7 +171,8 @@ nsZipHandle::nsZipHandle() NS_IMPL_ADDREF(nsZipHandle) NS_IMPL_RELEASE(nsZipHandle) -nsresult nsZipHandle::Init(nsIFile *file, nsZipHandle **ret, PRFileDesc **aFd) +nsresult nsZipHandle::Init(nsIFile *file, bool aMustCacheFd, nsZipHandle **ret, + PRFileDesc **aFd) { mozilla::AutoFDClose fd; int32_t flags = PR_RDONLY; @@ -208,6 +209,10 @@ nsresult nsZipHandle::Init(nsIFile *file, nsZipHandle **ret, PRFileDesc **aFd) if (aFd) { *aFd = fd.forget(); } +#else + if (aMustCacheFd) { + handle->mNSPRFileDesc = fd.forget(); + } #endif handle->mMap = map; handle->mFile.Init(file); @@ -244,6 +249,16 @@ int64_t nsZipHandle::SizeOfMapping() return mLen; } +nsresult nsZipHandle::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc) +{ + if (!aNSPRFileDesc) { + return NS_ERROR_ILLEGAL_VALUE; + } + + *aNSPRFileDesc = mNSPRFileDesc; + return NS_OK; +} + nsZipHandle::~nsZipHandle() { if (mMap) { @@ -279,14 +294,15 @@ nsresult nsZipArchive::OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd) return rv; } -nsresult nsZipArchive::OpenArchive(nsIFile *aFile) +nsresult nsZipArchive::OpenArchive(nsIFile *aFile, bool aMustCacheFd) { nsRefPtr handle; #if defined(XP_WIN) mozilla::AutoFDClose fd; - nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle), &fd.rwget()); + nsresult rv = nsZipHandle::Init(aFile, aMustCacheFd, getter_AddRefs(handle), + &fd.rwget()); #else - nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle)); + nsresult rv = nsZipHandle::Init(aFile, aMustCacheFd, getter_AddRefs(handle)); #endif if (NS_FAILED(rv)) return rv; diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index 3e2a829b68a..da74e80d536 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -120,10 +120,11 @@ public: * * Convenience function that generates nsZipHandle * - * @param aFile The file used to access the zip + * @param aFile The file used to access the zip + * @param aMustCacheFd Optional flag to keep the PRFileDesc in nsZipHandle * @return status code */ - nsresult OpenArchive(nsIFile *aFile); + nsresult OpenArchive(nsIFile *aFile, bool aMustCacheFd = false); /** * Test the integrity of items in this archive by running @@ -380,7 +381,7 @@ class nsZipHandle { friend class nsZipArchive; friend class mozilla::FileLocation; public: - static nsresult Init(nsIFile *file, nsZipHandle **ret, + static nsresult Init(nsIFile *file, bool aMustCacheFd, nsZipHandle **ret, PRFileDesc **aFd = nullptr); static nsresult Init(nsZipArchive *zip, const char *entry, nsZipHandle **ret); @@ -390,6 +391,8 @@ public: int64_t SizeOfMapping(); + nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc); + protected: const uint8_t * mFileData; /* pointer to mmaped file */ uint32_t mLen; /* length of file and memory mapped area */ @@ -400,6 +403,7 @@ private: ~nsZipHandle(); PRFileMap * mMap; /* nspr datastructure for mmap */ + mozilla::AutoFDClose mNSPRFileDesc; nsAutoPtr > mBuf; mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */ NS_DECL_OWNINGTHREAD diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp index ec445a12d67..aba8a21e046 100644 --- a/netwerk/ipc/RemoteOpenFileChild.cpp +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -249,6 +249,18 @@ RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags, #endif } +nsresult +RemoteOpenFileChild::SetNSPRFileDesc(PRFileDesc* aNSPRFileDesc) +{ + MOZ_ASSERT(!mNSPRFileDesc); + if (mNSPRFileDesc) { + return NS_ERROR_ALREADY_OPENED; + } + + mNSPRFileDesc = aNSPRFileDesc; + return NS_OK; +} + void RemoteOpenFileChild::OnCachedFileDescriptor(const nsAString& aPath, const FileDescriptor& aFD) diff --git a/netwerk/ipc/RemoteOpenFileChild.h b/netwerk/ipc/RemoteOpenFileChild.h index b60e65d2c13..808e1c73c30 100644 --- a/netwerk/ipc/RemoteOpenFileChild.h +++ b/netwerk/ipc/RemoteOpenFileChild.h @@ -77,6 +77,8 @@ public: nsITabChild* aTabChild, nsILoadContext *aLoadContext); + nsresult SetNSPRFileDesc(PRFileDesc* aNSPRFileDesc); + void ReleaseIPDLReference() { Release();