Bug 988816 - Allow to keep file descriptor in JAR cache. r=aklotz, jduell

This commit is contained in:
Shian-Yow Wu 2014-07-18 10:46:24 +08:00
parent a968b880df
commit b601c06562
8 changed files with 205 additions and 13 deletions

View File

@ -6,6 +6,12 @@
#include "nsISupports.idl" #include "nsISupports.idl"
%{C++
struct PRFileDesc;
%}
[ptr] native PRFileDescStar(PRFileDesc);
interface nsIUTF8StringEnumerator; interface nsIUTF8StringEnumerator;
interface nsIInputStream; interface nsIInputStream;
interface nsIFile; interface nsIFile;
@ -192,7 +198,7 @@ interface nsIZipReader : nsISupports
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsIZipReaderCache // nsIZipReaderCache
[scriptable, uuid(748050ac-3ab6-4472-bc2a-cb1564ac6a81)] [scriptable, uuid(94ecd586-d405-4801-93d3-8ac7bef81bde)]
interface nsIZipReaderCache : nsISupports interface nsIZipReaderCache : nsISupports
{ {
/** /**
@ -228,6 +234,20 @@ interface nsIZipReaderCache : nsISupports
* See getZip * See getZip
*/ */
nsIZipReader getInnerZip(in nsIFile zipFile, in AUTF8String zipEntry); 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);
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -141,7 +141,7 @@ nsJAR::Open(nsIFile* zipFile)
mZip = zip; mZip = zip;
return NS_OK; return NS_OK;
} }
return mZip->OpenArchive(zipFile); return mZip->OpenArchive(zipFile, mCache ? mCache->IsMustCacheFdEnabled() : false);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -391,6 +391,26 @@ nsJAR::GetJarPath(nsACString& aResult)
return mZipFile->GetNativePath(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<nsZipHandle> handle = mZip->GetFD();
if (!handle) {
return NS_ERROR_FAILURE;
}
return handle->GetNSPRFileDesc(aNSPRFileDesc);
}
//---------------------------------------------- //----------------------------------------------
// nsJAR private implementation // nsJAR private implementation
//---------------------------------------------- //----------------------------------------------
@ -1009,6 +1029,7 @@ NS_IMPL_ISUPPORTS(nsZipReaderCache, nsIZipReaderCache, nsIObserver, nsISupportsW
nsZipReaderCache::nsZipReaderCache() nsZipReaderCache::nsZipReaderCache()
: mLock("nsZipReaderCache.mLock") : mLock("nsZipReaderCache.mLock")
, mZips(16) , mZips(16)
, mMustCacheFd(false)
#ifdef ZIP_CACHE_HIT_RATE #ifdef ZIP_CACHE_HIT_RATE
, ,
mZipCacheLookups(0), mZipCacheLookups(0),
@ -1104,7 +1125,6 @@ nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
} else { } else {
zip = new nsJAR(); zip = new nsJAR();
zip->SetZipReaderCache(this); zip->SetZipReaderCache(this);
rv = zip->Open(zipFile); rv = zip->Open(zipFile);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
@ -1162,6 +1182,87 @@ nsZipReaderCache::GetInnerZip(nsIFile* zipFile, const nsACString &entry,
return rv; 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<nsJAR> 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<nsJAR> 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<nsJAR> zipTemp = zip.forget();
return rv;
#endif /* XP_WIN */
}
static PLDHashOperator static PLDHashOperator
FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure) FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
{ {

View File

@ -95,6 +95,8 @@ class nsJAR : public nsIZipReader
mCache = cache; mCache = cache;
} }
nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
protected: protected:
typedef nsClassHashtable<nsCStringHashKey, nsJARManifestItem> ManifestDataHashtable; typedef nsClassHashtable<nsCStringHashKey, nsJARManifestItem> ManifestDataHashtable;
@ -195,6 +197,10 @@ public:
nsresult ReleaseZip(nsJAR* reader); nsresult ReleaseZip(nsJAR* reader);
bool IsMustCacheFdEnabled() {
return mMustCacheFd;
}
typedef nsRefPtrHashtable<nsCStringHashKey, nsJAR> ZipsHashtable; typedef nsRefPtrHashtable<nsCStringHashKey, nsJAR> ZipsHashtable;
protected: protected:
@ -204,6 +210,7 @@ protected:
mozilla::Mutex mLock; mozilla::Mutex mLock;
uint32_t mCacheSize; uint32_t mCacheSize;
ZipsHashtable mZips; ZipsHashtable mZips;
bool mMustCacheFd;
#ifdef ZIP_CACHE_HIT_RATE #ifdef ZIP_CACHE_HIT_RATE
uint32_t mZipCacheLookups; uint32_t mZipCacheLookups;

View File

@ -22,6 +22,7 @@
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/net/RemoteOpenFileChild.h" #include "mozilla/net/RemoteOpenFileChild.h"
#include "nsITabChild.h" #include "nsITabChild.h"
#include "private/pprio.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::net; using namespace mozilla::net;
@ -357,13 +358,34 @@ nsJARChannel::LookupFile()
mJarFile = remoteFile; mJarFile = remoteFile;
nsIZipReaderCache *jarCache = gJarHandler->JarCache(); nsIZipReaderCache *jarCache = gJarHandler->JarCache();
if (jarCache && !mEnsureChildFd) { if (jarCache) {
bool cached = false; bool cached = false;
rv = jarCache->IsCached(mJarFile, &cached); rv = jarCache->IsCached(mJarFile, &cached);
if (NS_SUCCEEDED(rv) && cached) { if (NS_SUCCEEDED(rv) && cached) {
// zipcache already has file mmapped: don't open on parent, // 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; 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; return NS_OK;
} }
if (mEnsureChildFd && jarCache) {
jarCache->SetMustCacheFd(remoteFile, true);
}
// Open file on parent: OnRemoteFileOpenComplete called when done // Open file on parent: OnRemoteFileOpenComplete called when done
nsCOMPtr<nsITabChild> tabChild; nsCOMPtr<nsITabChild> tabChild;
NS_QueryNotificationCallbacks(this, tabChild); NS_QueryNotificationCallbacks(this, tabChild);
@ -1044,7 +1070,11 @@ nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
mCallbacks = 0; mCallbacks = 0;
mProgressSink = 0; mProgressSink = 0;
if (mOpeningRemote) { if (mEnsureChildFd) {
nsIZipReaderCache *jarCache = gJarHandler->JarCache();
if (jarCache) {
jarCache->SetMustCacheFd(mJarFile, false);
}
// To deallocate file descriptor by RemoteOpenFileChild destructor. // To deallocate file descriptor by RemoteOpenFileChild destructor.
mJarFile = nullptr; mJarFile = nullptr;
} }

View File

@ -171,7 +171,8 @@ nsZipHandle::nsZipHandle()
NS_IMPL_ADDREF(nsZipHandle) NS_IMPL_ADDREF(nsZipHandle)
NS_IMPL_RELEASE(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; mozilla::AutoFDClose fd;
int32_t flags = PR_RDONLY; int32_t flags = PR_RDONLY;
@ -208,6 +209,10 @@ nsresult nsZipHandle::Init(nsIFile *file, nsZipHandle **ret, PRFileDesc **aFd)
if (aFd) { if (aFd) {
*aFd = fd.forget(); *aFd = fd.forget();
} }
#else
if (aMustCacheFd) {
handle->mNSPRFileDesc = fd.forget();
}
#endif #endif
handle->mMap = map; handle->mMap = map;
handle->mFile.Init(file); handle->mFile.Init(file);
@ -244,6 +249,16 @@ int64_t nsZipHandle::SizeOfMapping()
return mLen; return mLen;
} }
nsresult nsZipHandle::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc)
{
if (!aNSPRFileDesc) {
return NS_ERROR_ILLEGAL_VALUE;
}
*aNSPRFileDesc = mNSPRFileDesc;
return NS_OK;
}
nsZipHandle::~nsZipHandle() nsZipHandle::~nsZipHandle()
{ {
if (mMap) { if (mMap) {
@ -279,14 +294,15 @@ nsresult nsZipArchive::OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd)
return rv; return rv;
} }
nsresult nsZipArchive::OpenArchive(nsIFile *aFile) nsresult nsZipArchive::OpenArchive(nsIFile *aFile, bool aMustCacheFd)
{ {
nsRefPtr<nsZipHandle> handle; nsRefPtr<nsZipHandle> handle;
#if defined(XP_WIN) #if defined(XP_WIN)
mozilla::AutoFDClose fd; 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 #else
nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle)); nsresult rv = nsZipHandle::Init(aFile, aMustCacheFd, getter_AddRefs(handle));
#endif #endif
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;

View File

@ -120,10 +120,11 @@ public:
* *
* Convenience function that generates nsZipHandle * 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 * @return status code
*/ */
nsresult OpenArchive(nsIFile *aFile); nsresult OpenArchive(nsIFile *aFile, bool aMustCacheFd = false);
/** /**
* Test the integrity of items in this archive by running * Test the integrity of items in this archive by running
@ -380,7 +381,7 @@ class nsZipHandle {
friend class nsZipArchive; friend class nsZipArchive;
friend class mozilla::FileLocation; friend class mozilla::FileLocation;
public: public:
static nsresult Init(nsIFile *file, nsZipHandle **ret, static nsresult Init(nsIFile *file, bool aMustCacheFd, nsZipHandle **ret,
PRFileDesc **aFd = nullptr); PRFileDesc **aFd = nullptr);
static nsresult Init(nsZipArchive *zip, const char *entry, static nsresult Init(nsZipArchive *zip, const char *entry,
nsZipHandle **ret); nsZipHandle **ret);
@ -390,6 +391,8 @@ public:
int64_t SizeOfMapping(); int64_t SizeOfMapping();
nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
protected: protected:
const uint8_t * mFileData; /* pointer to mmaped file */ const uint8_t * mFileData; /* pointer to mmaped file */
uint32_t mLen; /* length of file and memory mapped area */ uint32_t mLen; /* length of file and memory mapped area */
@ -400,6 +403,7 @@ private:
~nsZipHandle(); ~nsZipHandle();
PRFileMap * mMap; /* nspr datastructure for mmap */ PRFileMap * mMap; /* nspr datastructure for mmap */
mozilla::AutoFDClose mNSPRFileDesc;
nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf; nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf;
mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */ mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */
NS_DECL_OWNINGTHREAD NS_DECL_OWNINGTHREAD

View File

@ -249,6 +249,18 @@ RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags,
#endif #endif
} }
nsresult
RemoteOpenFileChild::SetNSPRFileDesc(PRFileDesc* aNSPRFileDesc)
{
MOZ_ASSERT(!mNSPRFileDesc);
if (mNSPRFileDesc) {
return NS_ERROR_ALREADY_OPENED;
}
mNSPRFileDesc = aNSPRFileDesc;
return NS_OK;
}
void void
RemoteOpenFileChild::OnCachedFileDescriptor(const nsAString& aPath, RemoteOpenFileChild::OnCachedFileDescriptor(const nsAString& aPath,
const FileDescriptor& aFD) const FileDescriptor& aFD)

View File

@ -77,6 +77,8 @@ public:
nsITabChild* aTabChild, nsITabChild* aTabChild,
nsILoadContext *aLoadContext); nsILoadContext *aLoadContext);
nsresult SetNSPRFileDesc(PRFileDesc* aNSPRFileDesc);
void ReleaseIPDLReference() void ReleaseIPDLReference()
{ {
Release(); Release();