This commit is contained in:
dprice%netscape.com 2000-08-23 03:18:53 +00:00
Родитель 2e380b4e4b
Коммит 6ad5e8ece3
3 изменённых файлов: 126 добавлений и 99 удалений

Просмотреть файл

@ -110,9 +110,19 @@ interface nsIZipReader : nsISupports
[scriptable, uuid(52c45d86-0cc3-11d4-986e-00c04fa0cf4a)]
interface nsIZipReaderCache : nsISupports
{
/**
* Initializes a new zip reader cache.
* @param cacheSize - the number of released entries to maintain before
* beginning to throw some out (note that the number of outstanding
* entries can be much greater than this number -- this is the count
* for those otherwise unused entries)
*/
void init(in unsigned long cacheSize);
/**
* Returns a (possibly shared) nsIZipReader for an nsIFile.
*/
nsIZipReader getZip(in nsIFile zipFile);
void releaseZip(in nsIZipReader zip);
};
////////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -147,7 +147,8 @@ DeleteManifestEntry(nsHashKey* aKey, void* aData, void* closure)
// The following initialization makes a guess of 10 entries per jarfile.
nsJAR::nsJAR(): mManifestData(nsnull, nsnull, DeleteManifestEntry, nsnull, 10),
mParsedManifest(PR_FALSE), mGlobalStatus(nsIZipReader::NOT_SIGNED)
mParsedManifest(PR_FALSE), mGlobalStatus(nsIZipReader::NOT_SIGNED),
mReleaseTime(0), mCache(nsnull)
{
NS_INIT_REFCNT();
}
@ -157,7 +158,30 @@ nsJAR::~nsJAR()
Close();
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsJAR, nsIZipReader);
NS_IMPL_THREADSAFE_QUERY_INTERFACE1(nsJAR, nsIZipReader)
NS_IMPL_THREADSAFE_ADDREF(nsJAR)
// Custom Release method works with nsZipReaderCache...
nsrefcnt nsJAR::Release(void)
{
nsrefcnt count;
NS_PRECONDITION(0 != mRefCnt, "dup release");
count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
NS_LOG_RELEASE(this, count, "nsJAR");
if (0 == count) {
mRefCnt = 1; /* stabilize */
/* enable this to find non-threadsafe destructors: */
/* NS_ASSERT_OWNINGTHREAD(_class); */
NS_DELETEXPCOM(this);
return 0;
}
else if (1 == count && mCache) {
mReleaseTime = PR_IntervalNow();
nsresult rv = mCache->ReleaseZip(this);
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to release zip file");
}
return count;
}
//----------------------------------------------
// nsJAR public implementation
@ -1067,37 +1091,11 @@ nsJARItem::GetCRC32(PRUint32 *aCrc32)
////////////////////////////////////////////////////////////////////////////////
// nsIZipReaderCache
class nsZipCacheEntry
{
public:
nsZipCacheEntry(nsIZipReader* zip)
: mZip(zip), mUseCount(0), mNextOlder(nsnull) {}
~nsZipCacheEntry() {}
static void* PR_CALLBACK
Clone(nsHashKey *aKey, void *aData, void* closure) {
NS_NOTREACHED("nsZipCacheEntry::Clone"); // should never be called
return nsnull;
}
static PRBool PR_CALLBACK
Delete(nsHashKey *aKey, void *aData, void* closure) {
nsZipCacheEntry* entry = (nsZipCacheEntry*)aData;
delete entry;
return PR_TRUE;
}
nsCOMPtr<nsIZipReader> mZip;
nsrefcnt mUseCount;
nsZipCacheEntry* mNextOlder;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(nsZipReaderCache, nsIZipReaderCache)
nsZipReaderCache::nsZipReaderCache()
: mLock(nsnull),
mZips((nsHashtableCloneElementFunc)nsZipCacheEntry::Clone, nsnull, nsZipCacheEntry::Delete, nsnull),
mFreeList(nsnull),
mZips(16),
mFreeCount(0)
{
NS_INIT_REFCNT();
@ -1115,10 +1113,19 @@ nsZipReaderCache::Init(PRUint32 cacheSize)
return mLock ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
static PRBool
DropZipReaderCache(nsHashKey *aKey, void *aData, void* closure)
{
nsJAR* zip = (nsJAR*)aData;
zip->SetZipReaderCache(nsnull);
return PR_TRUE;
}
nsZipReaderCache::~nsZipReaderCache()
{
if (mLock)
PR_DestroyLock(mLock);
mZips.Enumerate(DropZipReaderCache, nsnull);
}
NS_METHOD
@ -1147,57 +1154,78 @@ nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
if (NS_FAILED(rv)) return rv;
nsCStringKey key(path);
nsZipCacheEntry* entry = (nsZipCacheEntry*)mZips.Get(&key);
if (entry) {
*result = entry->mZip;
NS_ADDREF(*result); // addref for the caller
if (entry->mUseCount++ == 0) {
// remove from free list
nsZipCacheEntry** entryPtr = &mFreeList;
NS_ASSERTION(*entryPtr, "null free list");
while (*entryPtr != nsnull) {
if (*entryPtr == entry) {
*entryPtr = entry->mNextOlder;
entry->mNextOlder = nsnull;
--mFreeCount;
return NS_OK;
}
entryPtr = &(*entryPtr)->mNextOlder;
}
NS_NOTREACHED("couldn't find entry in free list");
nsJAR* zip = (nsJAR*)mZips.Get(&key); // AddRefs
if (zip) {
if (zip->GetReleaseTime() != PR_INTERVAL_NO_TIMEOUT) {
// this was an otherwise-free entry, so decrement our free counter
NS_ASSERTION(mFreeCount > 0, "mFreeCount screwed up");
mFreeCount--;
}
return NS_OK;
}
else {
zip = new nsJAR();
if (zip == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(zip);
zip->SetZipReaderCache(this);
// not found -- create a new one and cache it
nsCOMPtr<nsIZipReader> zip;
rv = nsJAR::Create(nsnull, NS_GET_IID(nsIZipReader), getter_AddRefs(zip));
if (NS_FAILED(rv)) return rv;
rv = zip->Init(zipFile);
if (NS_FAILED(rv)) {
NS_RELEASE(zip);
return rv;
}
rv = zip->Open();
if (NS_FAILED(rv)) {
NS_RELEASE(zip);
return rv;
}
rv = zip->Init(zipFile);
if (NS_FAILED(rv)) return rv;
rv = zip->Open();
if (NS_FAILED(rv)) return rv;
entry = new nsZipCacheEntry(zip);
if (entry == nsnull) {
return NS_ERROR_OUT_OF_MEMORY;
PRBool collision = mZips.Put(&key, zip); // AddRefs to 2
NS_ASSERTION(!collision, "horked");
}
entry->mUseCount++;
(void)mZips.Put(&key, entry);
*result = zip;
NS_ADDREF(*result); // addref for the caller
return rv;
}
NS_IMETHODIMP
nsZipReaderCache::ReleaseZip(nsIZipReader* zip)
static PRBool
FindOldestZip(nsHashKey *aKey, void *aData, void* closure)
{
nsJAR** oldestPtr = (nsJAR**)closure;
nsJAR* oldest = *oldestPtr;
nsJAR* current = (nsJAR*)aData;
PRIntervalTime currentReleaseTime = current->GetReleaseTime();
if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
if (oldest == nsnull ||
currentReleaseTime < oldest->GetReleaseTime()) {
*oldestPtr = current;
}
}
return PR_TRUE;
}
nsresult
nsZipReaderCache::ReleaseZip(nsJAR* zip)
{
nsresult rv;
nsAutoLock lock(mLock);
mFreeCount++;
if (mZips.Count() <= mCacheSize)
return NS_OK;
nsJAR* oldest = nsnull;
if (mFreeCount == 1) {
// then this is our guy -- no need to search for the oldest
oldest = zip;
}
else {
mZips.Enumerate(FindOldestZip, &oldest);
}
NS_ASSERTION(oldest, "wacked");
// remove from hashtable
nsCOMPtr<nsIFile> zipFile;
rv = zip->GetFile(getter_AddRefs(zipFile));
rv = oldest->GetFile(getter_AddRefs(zipFile));
if (NS_FAILED(rv)) return rv;
nsXPIDLCString path;
@ -1205,36 +1233,9 @@ nsZipReaderCache::ReleaseZip(nsIZipReader* zip)
if (NS_FAILED(rv)) return rv;
nsCStringKey key(path);
nsZipCacheEntry* entry = (nsZipCacheEntry*)mZips.Get(&key);
if (entry == nsnull)
return NS_ERROR_FAILURE;
PRBool removed = mZips.Remove(&key); // Releases
NS_ASSERTION(removed, "botched");
if (--entry->mUseCount == 0) {
// The first step in releasing a zip is to throw it on the LRU free list.
// That way it can be quickly re-opened if necessary. But if the free
// list grows too long, some need to be thrown out.
entry->mNextOlder = mFreeList;
mFreeList = entry;
if (++mFreeCount > mCacheSize) {
// throw out the oldest one:
nsZipCacheEntry** oldestPtr = &mFreeList;
NS_ASSERTION(*oldestPtr, "null free list");
while ((*oldestPtr)->mNextOlder != nsnull) {
oldestPtr = &(*oldestPtr)->mNextOlder;
}
nsZipCacheEntry* oldest = *oldestPtr;
*oldestPtr = nsnull;
nsZipCacheEntry* elt = (nsZipCacheEntry*)mZips.Remove(&key);
NS_ASSERTION(elt == entry, "Remove failed");
--mFreeCount;
delete oldest; // release zip for good
}
}
// NS_RELEASE(zip); // release for the caller
return NS_OK;
}

Просмотреть файл

@ -35,6 +35,7 @@
#include "plstr.h"
#include "prlog.h"
#include "prtypes.h"
#include "prinrval.h"
#if 0
#include "xp_regexp.h"
#endif
@ -56,6 +57,7 @@
class nsIInputStream;
class nsJARManifestItem;
class nsZipReaderCache;
/*-------------------------------------------------------------------------
* Class nsJAR declaration.
@ -80,6 +82,17 @@ class nsJAR : public nsIZipReader
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
PRIntervalTime GetReleaseTime() {
if (mRefCnt == 1)
return mReleaseTime;
else
return PR_INTERVAL_NO_TIMEOUT;
}
void SetZipReaderCache(nsZipReaderCache* cache) {
mCache = cache;
}
protected:
//-- Private data members
@ -89,6 +102,8 @@ class nsJAR : public nsIZipReader
PRBool mParsedManifest; // True if manifest has been parsed
nsCOMPtr<nsIPrincipal> mPrincipal; // The entity which signed this file
PRInt16 mGlobalStatus; // Global signature verification status
PRIntervalTime mReleaseTime; // used by nsZipReaderCache for flushing entries
nsZipReaderCache* mCache; // if cached, this points to the cache it's contained in
//-- Private functions
nsresult ParseManifest(nsISignatureVerifier* verifier);
@ -170,11 +185,12 @@ public:
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
nsresult ReleaseZip(nsJAR* reader);
protected:
PRLock* mLock;
PRUint32 mCacheSize;
nsObjectHashtable mZips;
nsZipCacheEntry* mFreeList;
PRInt32 mCacheSize;
nsSupportsHashtable mZips;
PRUint32 mFreeCount;
};