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"
%{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);
};
////////////////////////////////////////////////////////////////////////////////

View File

@ -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<nsZipHandle> 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<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
FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
{

View File

@ -95,6 +95,8 @@ class nsJAR : public nsIZipReader
mCache = cache;
}
nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
protected:
typedef nsClassHashtable<nsCStringHashKey, nsJARManifestItem> ManifestDataHashtable;
@ -195,6 +197,10 @@ public:
nsresult ReleaseZip(nsJAR* reader);
bool IsMustCacheFdEnabled() {
return mMustCacheFd;
}
typedef nsRefPtrHashtable<nsCStringHashKey, nsJAR> 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;

View File

@ -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<nsITabChild> 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;
}

View File

@ -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<nsZipHandle> 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;

View File

@ -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<nsZipItemPtr<uint8_t> > mBuf;
mozilla::ThreadSafeAutoRefCnt mRefCnt; /* ref count */
NS_DECL_OWNINGTHREAD

View File

@ -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)

View File

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