Renaming nsDiskCacheEntry -> nsDiskCacheBindInfo, and reorganize files.

git-svn-id: svn://10.0.0.236/branches/DISKCACHE2_BRANCH@94555 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
gordon%netscape.com
2001-05-11 01:38:03 +00:00
parent cc6d193bae
commit 826ed51db3
11 changed files with 820 additions and 896 deletions

View File

@@ -26,15 +26,5 @@
#ifndef _nsDiskCache_h_
#define _nsDiskCache_h_
#include "prtypes.h"
#include "prnetdb.h"
#include "nsDebug.h"
/*
*/
#endif // _nsDiskCache_h_

View File

@@ -0,0 +1,221 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is nsDiskCacheBindData.cpp, released May 10, 2001.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Patrick C. Beard <beard@netscape.com>
* Gordon Sheridan <gordon@netscape.com>
*/
#include <limits.h>
#include "nsDiskCacheBindData.h"
/******************************************************************************
* nsDiskCacheBindData
*****************************************************************************/
NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheBindData);
PLDHashNumber
nsDiskCacheBindData::Hash(const char* key)
{
PLDHashNumber h = 0;
for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s)
h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ *s;
return (h == 0 ? ULONG_MAX : h);
}
/******************************************************************************
* nsDiskCacheHashTable
*****************************************************************************/
PLDHashTableOps nsDiskCacheHashTable::ops =
{
PL_DHashAllocTable,
PL_DHashFreeTable,
GetKey,
HashKey,
MatchEntry,
MoveEntry,
ClearEntry,
Finalize
};
nsDiskCacheHashTable::nsDiskCacheHashTable()
: initialized(PR_FALSE)
{
}
nsDiskCacheHashTable::~nsDiskCacheHashTable()
{
if (initialized)
PL_DHashTableFinish(&table);
}
nsresult
nsDiskCacheHashTable::Init()
{
nsresult rv = NS_OK;
initialized = PL_DHashTableInit(&table, &ops, nsnull,
sizeof(HashTableEntry), 512);
if (!initialized) rv = NS_ERROR_OUT_OF_MEMORY;
return rv;
}
nsDiskCacheBindData *
nsDiskCacheHashTable::GetEntry(const char * key)
{
return GetEntry(nsDiskCacheBindData::Hash(key));
}
nsDiskCacheBindData *
nsDiskCacheHashTable::GetEntry(PLDHashNumber key)
{
nsDiskCacheBindData * result = nsnull;
NS_ASSERTION(initialized, "nsDiskCacheHashTable not initialized");
HashTableEntry * hashEntry;
hashEntry = (HashTableEntry*) PL_DHashTableOperate(&table, (void*) key, PL_DHASH_LOOKUP);
if (PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
result = hashEntry->mDiskCacheBindData;
}
return result;
}
nsresult
nsDiskCacheHashTable::AddEntry(nsDiskCacheBindData * entry)
{
NS_ENSURE_ARG_POINTER(entry);
NS_ASSERTION(initialized, "nsDiskCacheHashTable not initialized");
HashTableEntry * hashEntry;
hashEntry = (HashTableEntry *) PL_DHashTableOperate(&table,
(void*) entry->getHashNumber(),
PL_DHASH_ADD);
if (!hashEntry) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(hashEntry->mDiskCacheBindData = entry);
return NS_OK;
}
void
nsDiskCacheHashTable::RemoveEntry(nsDiskCacheBindData * entry)
{
NS_ASSERTION(initialized, "nsDiskCacheHashTable not initialized");
NS_ASSERTION(entry, "### cacheEntry == nsnull");
(void) PL_DHashTableOperate(&table, (void*) entry->getHashNumber(), PL_DHASH_REMOVE);
}
void
nsDiskCacheHashTable::VisitEntries(Visitor *visitor)
{
PL_DHashTableEnumerate(&table, VisitEntry, visitor);
}
PLDHashOperator PR_CALLBACK
nsDiskCacheHashTable::VisitEntry(PLDHashTable * table,
PLDHashEntryHdr * header,
PRUint32 number,
void * arg)
{
HashTableEntry* hashEntry = (HashTableEntry *) header;
Visitor *visitor = (Visitor*) arg;
return (visitor->VisitEntry(hashEntry->mDiskCacheBindData) ? PL_DHASH_NEXT : PL_DHASH_STOP);
}
/**
* hash table operation callback functions
*/
const void * PR_CALLBACK
nsDiskCacheHashTable::GetKey(PLDHashTable * /*table*/, PLDHashEntryHdr * header)
{
HashTableEntry * hashEntry = (HashTableEntry *) header;
return (void*) hashEntry->mDiskCacheBindData->getHashNumber();
}
PLDHashNumber PR_CALLBACK
nsDiskCacheHashTable::HashKey( PLDHashTable *table, const void *key)
{
return (PLDHashNumber) key;
}
PRBool PR_CALLBACK
nsDiskCacheHashTable::MatchEntry(PLDHashTable * /* table */,
const PLDHashEntryHdr * header,
const void * key)
{
HashTableEntry * hashEntry = (HashTableEntry *) header;
return (hashEntry->mDiskCacheBindData->getHashNumber() == (PLDHashNumber) key);
}
void PR_CALLBACK
nsDiskCacheHashTable::MoveEntry(PLDHashTable * /* table */,
const PLDHashEntryHdr * fromHeader,
PLDHashEntryHdr * toHeader)
{
HashTableEntry * fromEntry = (HashTableEntry *) fromHeader;
HashTableEntry * toEntry = (HashTableEntry *) toHeader;
toEntry->keyHash = fromEntry->keyHash;
toEntry->mDiskCacheBindData = fromEntry->mDiskCacheBindData;
fromEntry->mDiskCacheBindData = nsnull;
}
void PR_CALLBACK
nsDiskCacheHashTable::ClearEntry(PLDHashTable * /* table */,
PLDHashEntryHdr * header)
{
HashTableEntry* hashEntry = (HashTableEntry *) header;
hashEntry->keyHash = 0;
NS_IF_RELEASE(hashEntry->mDiskCacheBindData);
}
void PR_CALLBACK
nsDiskCacheHashTable::Finalize(PLDHashTable * table)
{
(void) PL_DHashTableEnumerate(table, FreeCacheEntries, nsnull);
}
PLDHashOperator PR_CALLBACK
nsDiskCacheHashTable::FreeCacheEntries(PLDHashTable * /* table */,
PLDHashEntryHdr * header,
PRUint32 number,
void * arg)
{
HashTableEntry *entry = (HashTableEntry *) header;
NS_IF_RELEASE(entry->mDiskCacheBindData);
return PL_DHASH_NEXT;
}

View File

@@ -0,0 +1,188 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is nsDiskCacheBindData.h, released May 10, 2001.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Gordon Sheridan <gordon@netscape.com>
* Patrick C. Beard <beard@netscape.com>
*/
#ifndef _nsDiskCacheBindData_h_
#define _nsDiskCacheBindData_h_
#include "nspr.h"
#include "pldhash.h"
#include "nsISupports.h"
#include "nsCacheEntry.h"
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
#include "nsITransport.h"
#endif
/******************************************************************************
* nsDiskCacheBindData
*
* Created for disk cache specific data and stored in nsCacheEntry.mData as
* an nsISupports. Also stored in nsDiskCacheHashTable, with collisions
* linked by the PRCList.
*
*****************************************************************************/
class nsDiskCacheBindData : public nsISupports, public PRCList {
public:
NS_DECL_ISUPPORTS
nsDiskCacheBindData(nsCacheEntry* entry)
: mCacheEntry(entry),
mGeneration(0)
{
NS_INIT_ISUPPORTS();
PR_INIT_CLIST(this);
mHashNumber = Hash(entry->Key()->get());
}
virtual ~nsDiskCacheBindData()
{
PR_REMOVE_LINK(this);
}
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
/**
* Maps a cache access mode to a cached nsITransport for that access
* mode. We keep these cached to avoid repeated trips to the
* file transport service.
*/
nsCOMPtr<nsITransport>& getTransport(nsCacheAccessMode mode)
{
return mTransports[mode - 1];
}
#endif
nsCacheEntry* getCacheEntry()
{
return mCacheEntry;
}
PRUint32 getGeneration()
{
return mGeneration;
}
void setGeneration(PRUint32 generation)
{
mGeneration = generation;
}
PLDHashNumber getHashNumber()
{
return mHashNumber;
}
nsrefcnt getRefCount()
{
return mRefCnt;
}
static PLDHashNumber Hash(const char* key);
private:
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
nsCOMPtr<nsITransport> mTransports[3];
#endif
nsCacheEntry* mCacheEntry; // back pointer to parent nsCacheEntry
PRUint32 mGeneration; // XXX part of nsDiskCacheRecord
PLDHashNumber mHashNumber; // XXX part of nsDiskCacheRecord
// XXX nsDiskCacheRecord mMapRecord;
};
/******************************************************************************
* nsDiskCacheHashTable
*
* Used to keep track of nsDiskCacheEntries associated with active/bound (and
* possibly doomed) entries. Lookups on 4 byte disk hash to find collisions
* (which need to be doomed, instead of just evicted. Collisions are linked
* using a PRCList to keep track of current generation number.
*
*****************************************************************************/
class nsDiskCacheHashTable {
public:
nsDiskCacheHashTable();
~nsDiskCacheHashTable();
nsresult Init();
nsDiskCacheBindData * GetEntry(const char * key);
nsDiskCacheBindData * GetEntry(PLDHashNumber key);
nsresult AddEntry(nsDiskCacheBindData * entry);
void RemoveEntry(nsDiskCacheBindData * entry);
class Visitor {
public:
virtual PRBool VisitEntry(nsDiskCacheBindData * entry) = 0;
};
void VisitEntries(Visitor * visitor);
private:
struct HashTableEntry : PLDHashEntryHdr {
nsDiskCacheBindData * mDiskCacheBindData; // STRONG ref?
};
// PLDHashTable operation callbacks
static const void * PR_CALLBACK GetKey(PLDHashTable * table,
PLDHashEntryHdr * entry);
static PLDHashNumber PR_CALLBACK HashKey(PLDHashTable * table,
const void * key);
static PRBool PR_CALLBACK MatchEntry(PLDHashTable * table,
const PLDHashEntryHdr * entry,
const void * key);
static void PR_CALLBACK MoveEntry(PLDHashTable * table,
const PLDHashEntryHdr * from,
PLDHashEntryHdr * to);
static void PR_CALLBACK ClearEntry(PLDHashTable * table,
PLDHashEntryHdr * entry);
static void PR_CALLBACK Finalize(PLDHashTable *table);
static
PLDHashOperator PR_CALLBACK FreeCacheEntries(PLDHashTable * table,
PLDHashEntryHdr * hdr,
PRUint32 number,
void * arg);
static
PLDHashOperator PR_CALLBACK VisitEntry(PLDHashTable * table,
PLDHashEntryHdr * hdr,
PRUint32 number,
void * arg);
// member variables
static PLDHashTableOps ops;
PLDHashTable table;
PRBool initialized;
};
#endif /* _nsDiskCacheBindData_h_ */

View File

@@ -35,19 +35,12 @@
nsresult
nsDiskCacheBlockFile::Open( nsILocalFile * blockFile, PRUint32 blockSize)
{
// create the stream
PRStatus err = PR_SUCCESS;
mBlockSize = blockSize;
mStream = new nsANSIFileStream;
if (!mStream) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mStream);
// open the stream
nsresult rv = mStream->Open(blockFile);
if (NS_FAILED(rv)) {
NS_RELEASE(mStream);
mStream = nsnull;
return rv;
}
// open the file
nsresult rv = blockFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, 00666, &mFD);
if (NS_FAILED(rv)) return rv; // unable to open or create file
// allocate bit map buffer
mBitMap = new PRUint8[kBitMapBytes];
@@ -57,17 +50,18 @@ nsDiskCacheBlockFile::Open( nsILocalFile * blockFile, PRUint32 blockSize)
}
// check if we just creating the file
rv = mStream->Available(&mEndOfFile);
PRInt32 fileSize = PR_Available(mFD);
if (fileSize < 0) {
// XXX an error occurred. We could call PR_GetError(), but how would that help?
rv = NS_ERROR_UNEXPECTED;
goto error_exit;
}
mEndOfFile = fileSize;
if (mEndOfFile == 0) {
// initialize bit map and write it
nsCRT::zero(mBitMap, kBitMapBytes);
PRUint32 bytesWritten = 0;
rv = mStream->Write((char *)mBitMap, kBitMapBytes, &bytesWritten);
if (NS_FAILED(rv)) goto error_exit;
if (kBitMapBytes != bytesWritten) {
rv = NS_ERROR_UNEXPECTED;
goto error_exit;
}
PRInt32 bytesWritten = PR_Write(mFD, mBitMap, kBitMapBytes);
if (bytesWritten < kBitMapBytes) goto error_exit;
mEndOfFile = kBitMapBytes;
} else if (mEndOfFile < kBitMapBytes) {
@@ -76,10 +70,8 @@ nsDiskCacheBlockFile::Open( nsILocalFile * blockFile, PRUint32 blockSize)
} else {
// read the bit map
PRUint32 bytesRead = 0;
rv = mStream->Read((char *)mBitMap, kBitMapBytes, &bytesRead);
if (NS_FAILED(rv)) goto error_exit;
if (kBitMapBytes != bytesRead) {
PRInt32 bytesRead = PR_Read(mFD, mBitMap, kBitMapBytes);
if (bytesRead < kBitMapBytes) {
rv = NS_ERROR_UNEXPECTED;
goto error_exit;
}
@@ -92,10 +84,9 @@ nsDiskCacheBlockFile::Open( nsILocalFile * blockFile, PRUint32 blockSize)
return NS_OK;
error_exit:
if (mStream) {
(void) mStream->Close();
NS_RELEASE(mStream);
mStream = nsnull;
if (mFD) {
(void) PR_Close(mFD);
mFD = nsnull;
}
if (mBitMap) {
@@ -112,19 +103,21 @@ error_exit:
nsresult
nsDiskCacheBlockFile::Close()
{
if (!mStream) return NS_OK;
if (!mFD) return NS_OK;
nsresult rv = FlushBitMap();
nsresult rv2 = mStream->Close();
NS_RELEASE(mStream);
mStream = nsnull;
nsresult rv = FlushBitMap();
PRStatus err = PR_Close(mFD);
mFD = nsnull;
if (mBitMap) {
delete [] mBitMap;
mBitMap = nsnull;
}
return rv ? rv : rv2;
if (NS_SUCCEEDED(rv) && (err != PR_SUCCESS))
rv = NS_ERROR_UNEXPECTED;
return rv;
}
@@ -153,7 +146,7 @@ nsDiskCacheBlockFile::Trim()
PRInt32
nsDiskCacheBlockFile::AllocateBlocks(PRInt32 numBlocks)
{
if (!mStream) return -1; // NS_ERROR_NOT_AVAILABLE;
if (!mFD) return -1; // NS_ERROR_NOT_AVAILABLE;
// return -1 if unable to allocate blocks
// PRUint8 mask = (0x01 << numBlocks) - 1;
int i = 0;
@@ -233,7 +226,7 @@ nsDiskCacheBlockFile::AllocateBlocks(PRInt32 numBlocks)
nsresult
nsDiskCacheBlockFile::DeallocateBlocks( PRInt32 startBlock, PRInt32 numBlocks)
{
if (!mStream) return NS_ERROR_NOT_AVAILABLE;
if (!mFD) return NS_ERROR_NOT_AVAILABLE;
if ((startBlock < 0) || (startBlock > kBitMapBytes * 8 - 1) ||
(numBlocks < 1) || (numBlocks > 4))
return NS_ERROR_ILLEGAL_VALUE;
@@ -266,24 +259,22 @@ nsDiskCacheBlockFile::WriteBlocks( char * buffer,
PRInt32 numBlocks)
{
// presume buffer != nsnull
if (!mStream) return NS_ERROR_NOT_AVAILABLE;
if (!mFD) return NS_ERROR_NOT_AVAILABLE;
nsresult rv = VerifyAllocation(startBlock, numBlocks);
if (NS_FAILED(rv)) return rv;
// seek to block position
PRInt32 blockPos = kBitMapBytes + startBlock * mBlockSize;
rv = mStream->Seek(nsISeekableStream::NS_SEEK_SET, blockPos);
if (NS_FAILED(rv)) return rv;
PRInt32 filePos = PR_Seek(mFD, blockPos, PR_SEEK_SET);
if (filePos != blockPos) return NS_ERROR_UNEXPECTED;
if (mEndOfFile < (blockPos + numBlocks * mBlockSize))
mEndOfFile = (blockPos + numBlocks * mBlockSize);
// write the blocks
PRUint32 bytesToWrite = numBlocks * mBlockSize;
PRUint32 bytesWritten = 0;
rv = mStream->Write(buffer, bytesToWrite, &bytesWritten);
if (NS_FAILED(rv)) return rv;
if (bytesWritten != bytesToWrite) return NS_ERROR_UNEXPECTED;
PRInt32 bytesToWrite = numBlocks * mBlockSize;
PRInt32 bytesWritten = PR_Write(mFD, buffer, bytesToWrite);
if (bytesWritten < bytesToWrite) return NS_ERROR_UNEXPECTED;
// write the bit map and flush the file
rv = FlushBitMap();
@@ -300,21 +291,19 @@ nsDiskCacheBlockFile::ReadBlocks( char * buffer,
PRInt32 numBlocks)
{
// presume buffer != nsnull
if (!mStream) return NS_ERROR_NOT_AVAILABLE;
if (!mFD) return NS_ERROR_NOT_AVAILABLE;
nsresult rv = VerifyAllocation(startBlock, numBlocks);
if (NS_FAILED(rv)) return rv;
// seek to block position
PRInt32 blockPos = kBitMapBytes + startBlock * mBlockSize;
rv = mStream->Seek(nsISeekableStream::NS_SEEK_SET, blockPos);
if (NS_FAILED(rv)) return rv;
PRInt32 filePos = PR_Seek(mFD, blockPos, PR_SEEK_SET);
if (filePos != blockPos) return NS_ERROR_UNEXPECTED;
// read the blocks
PRUint32 bytesToRead = numBlocks * mBlockSize;
PRUint32 bytesRead = 0;
rv = mStream->Read(buffer, bytesToRead, &bytesRead);
if (NS_FAILED(rv)) return rv;
if (bytesRead != bytesToRead) return NS_ERROR_UNEXPECTED;
PRInt32 bytesToRead = numBlocks * mBlockSize;
PRInt32 bytesRead = PR_Read(mFD, buffer, bytesToRead);
if (bytesRead < bytesToRead) return NS_ERROR_UNEXPECTED;
return rv;
}
@@ -329,19 +318,15 @@ nsDiskCacheBlockFile::FlushBitMap()
if (!mBitMapDirty) return NS_OK;
// seek to bitmap
nsresult rv = mStream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
if (NS_FAILED(rv)) return rv;
PRInt32 filePos = PR_Seek(mFD, 0, PR_SEEK_SET);
if (filePos != 0) return NS_ERROR_UNEXPECTED;
// write bitmap
PRUint32 bytesWritten = 0;
rv = mStream->Write((char *)mBitMap, kBitMapBytes, &bytesWritten);
if (NS_FAILED(rv)) return rv;
if (kBitMapBytes != bytesWritten) {
return NS_ERROR_UNEXPECTED;
}
rv = mStream->Flush();
if (NS_FAILED(rv)) return rv;
PRInt32 bytesWritten = PR_Write(mFD, mBitMap, kBitMapBytes);
if (bytesWritten < kBitMapBytes) return NS_ERROR_UNEXPECTED;
PRStatus err = PR_Sync(mFD);
if (err != PR_SUCCESS) return NS_ERROR_UNEXPECTED;
mBitMapDirty = PR_FALSE;
return NS_OK;
@@ -357,20 +342,17 @@ nsDiskCacheBlockFile::FlushBitMap()
nsresult
nsDiskCacheBlockFile::ValidateFile()
{
PRUint32 estimatedSize = kBitMapBytes;
PRInt32 estimatedSize = kBitMapBytes;
PRInt32 lastBlock = LastBlock();
if (lastBlock >= 0)
estimatedSize += (lastBlock + 1) * mBlockSize;
PRUint32 fileSize = 0;
// seek to beginning
nsresult rv = mStream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
if (NS_FAILED(rv)) return rv;
rv = mStream->Available(&fileSize);
if (NS_FAILED(rv)) return rv;
PRInt32 filePos = PR_Seek(mFD, 0, PR_SEEK_SET);
if (filePos != 0) return NS_ERROR_UNEXPECTED;
PRInt32 fileSize = PR_Available(mFD);
if (estimatedSize > fileSize)
return NS_ERROR_UNEXPECTED;

View File

@@ -24,7 +24,8 @@
#ifndef _nsDiskCacheBlockFile_h_
#define _nsDiskCacheBlockFile_h_
#include "nsANSIFileStreams.h"
#include "nsILocalFile.h"
#include "nspr.h"
enum { kBitMapBytes = 4096 };
@@ -48,7 +49,7 @@ typedef struct BlockFile {
class nsDiskCacheBlockFile {
public:
nsDiskCacheBlockFile()
: mStream(nsnull)
: mFD(nsnull)
, mBlockSize(0)
, mEndOfFile(0)
, mBitMap(nsnull)
@@ -73,7 +74,7 @@ public:
/**
* Data members
*/
nsANSIFileStream * mStream;
PRFileDesc * mFD;
PRUint32 mBlockSize;
PRUint32 mEndOfFile;
PRUint8 * mBitMap; // XXX future: array of bit map blocks

View File

@@ -259,21 +259,20 @@ static nsresult removeObservers(nsDiskCacheDevice* device)
/******************************************************************************
* static utility functions
*****************************************************************************/
static nsDiskCacheEntry*
ensureDiskCacheEntry(nsCacheEntry * entry)
static nsDiskCacheBindData*
ensureDiskCacheBindData(nsCacheEntry * entry)
{
nsCOMPtr<nsISupports> data;
nsresult rv = entry->GetData(getter_AddRefs(data));
if (NS_SUCCEEDED(rv) && !data) {
nsDiskCacheEntry* diskEntry = new nsDiskCacheEntry(entry);
data = diskEntry;
nsDiskCacheBindData* bindData = new nsDiskCacheBindData(entry);
data = bindData;
if (NS_SUCCEEDED(rv) && data)
entry->SetData(data.get());
}
return (nsDiskCacheEntry*) (nsISupports*) data.get();
return (nsDiskCacheBindData*) (nsISupports*) data.get();
}
/******************************************************************************
* nsDiskCacheDeviceInfo
*****************************************************************************/
@@ -355,302 +354,9 @@ NS_IMETHODIMP nsDiskCacheDeviceInfo::GetMaximumSize(PRUint32 *aMaximumSize)
}
/******************************************************************************
* MetaData
*****************************************************************************/
struct MetaDataHeader {
PRUint32 mHeaderSize;
// PRUint32 mHashNumber; // XXX
// PRUint32 mMetaLocation; // XXX
PRInt32 mFetchCount;
PRUint32 mLastFetched;
PRUint32 mLastModified;
PRUint32 mExpirationTime;
PRUint32 mDataSize;
PRUint32 mKeySize;
PRUint32 mMetaDataSize;
// void * mKeyPtrSpace; // XXX don't need this
// void * mMetaDataPtrSpace; // XXX don't need this, we'll calculate it when necessary
// followed by null-terminated key and metadata string values.
MetaDataHeader()
: mHeaderSize(sizeof(MetaDataHeader)),
mFetchCount(0),
mLastFetched(0),
mLastModified(0),
mExpirationTime(0),
mDataSize(0),
mKeySize(0),
mMetaDataSize(0)
{
}
MetaDataHeader(nsCacheEntry* entry)
: mHeaderSize(sizeof(MetaDataHeader)),
mFetchCount(entry->FetchCount()),
mLastFetched(entry->LastFetched()),
mLastModified(entry->LastModified()),
mExpirationTime(entry->ExpirationTime()),
mDataSize(entry->DataSize()),
mKeySize(entry->Key()->Length() + 1),
mMetaDataSize(0)
{
}
void Swap()
{
#if defined(IS_LITTLE_ENDIAN)
mHeaderSize = ::PR_htonl(mHeaderSize);
mFetchCount = ::PR_htonl(mFetchCount);
mLastFetched = ::PR_htonl(mLastFetched);
mLastModified = ::PR_htonl(mLastModified);
mExpirationTime = ::PR_htonl(mExpirationTime);
mDataSize = ::PR_htonl(mDataSize);
mKeySize = ::PR_htonl(mKeySize);
mMetaDataSize = ::PR_htonl(mMetaDataSize);
#endif
}
void Unswap()
{
#if defined(IS_LITTLE_ENDIAN)
mHeaderSize = ::PR_ntohl(mHeaderSize);
mFetchCount = ::PR_ntohl(mFetchCount);
mLastFetched = ::PR_ntohl(mLastFetched);
mLastModified = ::PR_ntohl(mLastModified);
mExpirationTime = ::PR_ntohl(mExpirationTime);
mDataSize = ::PR_ntohl(mDataSize);
mKeySize = ::PR_ntohl(mKeySize);
mMetaDataSize = ::PR_ntohl(mMetaDataSize);
#endif
}
};
struct MetaDataFile : MetaDataHeader {
char* mKey;
char* mMetaData;
MetaDataFile()
: mKey(nsnull), mMetaData(nsnull)
{
}
MetaDataFile(nsCacheEntry* entry)
: MetaDataHeader(entry),
mKey(nsnull), mMetaData(nsnull)
{
}
~MetaDataFile()
{
delete[] mKey;
delete[] mMetaData;
}
nsresult Init(nsCacheEntry* entry)
{
PRUint32 size = 1 + entry->Key()->Length();
mKey = new char[size];
if (!mKey) return NS_ERROR_OUT_OF_MEMORY;
nsCRT::memcpy(mKey, entry->Key()->get(), size);
return entry->FlattenMetaData(&mMetaData, &mMetaDataSize);
}
nsresult Read(nsIInputStream* input);
nsresult Write(nsIOutputStream* output);
};
nsresult MetaDataFile::Read(nsIInputStream* input)
{
nsresult rv;
PRUint32 count;
// XXX Is it less expensive to read the file in multiple parts, or
// XXX get the size and read it in one chunk?
// read in the file header.
rv = input->Read((char*)&mHeaderSize, sizeof(MetaDataHeader), &count);
if (NS_FAILED(rv)) return rv;
Unswap();
// make sure it is self-consistent.
if (mHeaderSize != sizeof(MetaDataHeader)) {
NS_ERROR("### CACHE FORMAT CHANGED!!! PLEASE DELETE YOUR NewCache DIRECTORY!!! ###");
return NS_ERROR_ILLEGAL_VALUE;
}
// read in the key.
delete[] mKey;
mKey = new char[mKeySize];
if (!mKey) return NS_ERROR_OUT_OF_MEMORY;
rv = input->Read(mKey, mKeySize, &count);
if (NS_FAILED(rv)) return rv;
// read in the metadata.
delete mMetaData;
mMetaData = nsnull;
if (mMetaDataSize) {
mMetaData = new char[mMetaDataSize];
if (!mMetaData) return NS_ERROR_OUT_OF_MEMORY;
rv = input->Read(mMetaData, mMetaDataSize, &count);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
nsresult MetaDataFile::Write(nsIOutputStream* output)
{
nsresult rv;
PRUint32 count;
// write the header to the file.
Swap();
rv = output->Write((char*)&mHeaderSize, sizeof(MetaDataHeader), &count);
Unswap();
if (NS_FAILED(rv)) return rv;
// write the key to the file.
rv = output->Write(mKey, mKeySize, &count);
if (NS_FAILED(rv)) return rv;
// write the flattened metadata to the file.
if (mMetaDataSize) {
rv = output->Write(mMetaData, mMetaDataSize, &count);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
/******************************************************************************
* nsDiskCacheEntryInfo
*****************************************************************************/
class nsDiskCacheEntryInfo : public nsICacheEntryInfo {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICACHEENTRYINFO
nsDiskCacheEntryInfo()
{
NS_INIT_ISUPPORTS();
}
virtual ~nsDiskCacheEntryInfo() {}
nsresult Read(nsIInputStream * input)
{
return mMetaDataFile.Read(input);
}
const char* Key() { return mMetaDataFile.mKey; }
private:
MetaDataFile mMetaDataFile;
};
NS_IMPL_ISUPPORTS1(nsDiskCacheEntryInfo, nsICacheEntryInfo);
NS_IMETHODIMP nsDiskCacheEntryInfo::GetClientID(char ** clientID)
{
NS_ENSURE_ARG_POINTER(clientID);
return ClientIDFromCacheKey(nsLiteralCString(mMetaDataFile.mKey), clientID);
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetDeviceID(char ** deviceID)
{
NS_ENSURE_ARG_POINTER(deviceID);
*deviceID = nsCRT::strdup(DISK_CACHE_DEVICE_ID);
return *deviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetKey(char ** clientKey)
{
NS_ENSURE_ARG_POINTER(clientKey);
return ClientKeyFromCacheKey(nsLiteralCString(mMetaDataFile.mKey), clientKey);
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetFetchCount(PRInt32 *aFetchCount)
{
return *aFetchCount = mMetaDataFile.mFetchCount;
return NS_OK;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastFetched(PRUint32 *aLastFetched)
{
*aLastFetched = mMetaDataFile.mLastFetched;
return NS_OK;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastModified(PRUint32 *aLastModified)
{
*aLastModified = mMetaDataFile.mLastModified;
return NS_OK;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetExpirationTime(PRUint32 *aExpirationTime)
{
*aExpirationTime = mMetaDataFile.mExpirationTime;
return NS_OK;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::IsStreamBased(PRBool *aStreamBased)
{
*aStreamBased = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsDiskCacheEntryInfo::GetDataSize(PRUint32 *aDataSize)
{
*aDataSize = mMetaDataFile.mDataSize;
return NS_OK;
}
/******************************************************************************
* do_QueryElementAt
*****************************************************************************/
#if 0
/**
* Helper class for implementing do_QueryElementAt() pattern. Thanks scc!
* Eventually this should become part of nsICollection.idl.
*/
class do_QueryElementAt : public nsCOMPtr_helper {
public:
do_QueryElementAt(nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr = 0)
: mCollection(aCollection),
mIndex(aIndex),
mErrorPtr(aErrorPtr)
{
// nothing else to do here
}
virtual nsresult operator()( const nsIID& aIID, void** aResult) const
{
nsresult status;
if ( mCollection ) {
if ( !NS_SUCCEEDED(status = mCollection->QueryElementAt(mIndex, aIID, aResult)) )
*aResult = 0;
} else
status = NS_ERROR_NULL_POINTER;
if ( mErrorPtr )
*mErrorPtr = status;
return status;
}
private:
nsICollection* mCollection;
PRUint32 mIndex;
nsresult* mErrorPtr;
};
#endif
/******************************************************************************
* nsDiskCacheDevice
*****************************************************************************/
static nsCOMPtr<nsIFileTransportService> gFileTransportService;
nsDiskCacheDevice::nsDiskCacheDevice()
@@ -701,7 +407,7 @@ nsDiskCacheDevice::Init()
// no cache directory has ever existed before.
rv = readCacheMap();
if (NS_FAILED(rv) || mCacheMap->IsDirty()) {
rv = clobberDiskCache(); // XXX initializeCacheDirectory()
rv = InitializeCacheDirectory(); // XXX initializeCacheDirectory()
if (NS_FAILED(rv)) return rv;
}
@@ -766,23 +472,23 @@ nsDiskCacheDevice::FindEntry(nsCString * key)
// XXX look in entry hashtable first, if not found, then look on
// disk, to see if we have a disk cache entry that maches.
nsCacheEntry * entry = nsnull;
nsDiskCacheEntry * diskEntry = nsnull;
nsDiskCacheBindData * bindData = nsnull;
// XXX checking the bound hash table should only be a debug check
// XXX - the cache service shouldn't bother calling the device
// XXX - if the entry is already active (bound or not).
// XXX change to #if DEBUG, because we shouldn't be called for active entries
diskEntry = mBoundEntries.GetEntry(key->get());
NS_ASSERTION(!diskEntry, "### FindEntry() called for a bound entry.");
bindData = mBoundEntries.GetEntry(key->get());
NS_ASSERTION(!bindData, "### FindEntry() called for a bound entry.");
// XXX #endif
if (!diskEntry) {
PLDHashNumber hashNumber = nsDiskCacheEntry::Hash(key->get());
if (!bindData) {
PLDHashNumber hashNumber = nsDiskCacheBindData::Hash(key->get());
nsDiskCacheRecord* record = mCacheMap->GetRecord(hashNumber);
if (record->HashNumber() == hashNumber) {
nsresult rv = readDiskCacheEntry(key->get(), &diskEntry);
nsresult rv = readDiskCacheEntry(key->get(), &bindData);
if (NS_FAILED(rv)) return nsnull;
entry = diskEntry->getCacheEntry();
rv = mBoundEntries.AddEntry(diskEntry);
entry = bindData->getCacheEntry();
rv = mBoundEntries.AddEntry(bindData);
if (NS_FAILED(rv)) {
delete entry;
return nsnull;
@@ -791,7 +497,7 @@ nsDiskCacheDevice::FindEntry(nsCString * key)
} else {
// XXX need to make sure this is an exact match, not just
// a hash code match.
entry = diskEntry->getCacheEntry();
entry = bindData->getCacheEntry();
if (nsCRT::strcmp(entry->Key()->get(), key->get()) != 0)
return nsnull;
}
@@ -803,24 +509,24 @@ nsresult
nsDiskCacheDevice::DeactivateEntry(nsCacheEntry * entry)
{
// XXX if entry->mData is null, it's an error.
nsDiskCacheEntry* diskEntry = ensureDiskCacheEntry(entry);
if (mBoundEntries.GetEntry(diskEntry->getHashNumber()) == diskEntry) {
nsDiskCacheBindData* bindData = ensureDiskCacheBindData(entry);
if (mBoundEntries.GetEntry(bindData->getHashNumber()) == bindData) {
// XXX eventually, as a performance enhancement, keep entries around for a while before deleting them.
// XXX right now, to prove correctness, destroy the entries eagerly.
mBoundEntries.RemoveEntry(diskEntry);
mBoundEntries.RemoveEntry(bindData);
}
if (!entry->IsDoomed()) {
// commit any changes about this entry to disk.
updateDiskCacheEntry(diskEntry);
updateDiskCacheEntry(bindData);
// XXX if this entry collided with other concurrently bound entries, then its
// generation count will be non-zero. The other entries that came before it
// will be linked to it and doomed. deletion of the entry can only be done
// when all of the other doomed entries are deactivated, so that the final live entry
// can have its generation number reset to zero.
if (diskEntry->getGeneration() != 0)
scavengeDiskCacheEntries(diskEntry);
if (bindData->getGeneration() != 0)
scavengeDiskCacheEntries(bindData);
else
delete entry;
} else {
@@ -828,13 +534,13 @@ nsDiskCacheDevice::DeactivateEntry(nsCacheEntry * entry)
mCacheMap->DataSize() -= entry->DataSize();
// obliterate all knowledge of this entry on disk.
deleteDiskCacheEntry(diskEntry);
deleteDiskCacheEntry(bindData);
// XXX if this entry resides on a list, then there must have been a collision
// during the entry's lifetime. use this deactivation as a trigger to scavenge
// generation numbers, and reset the live entry's generation to zero.
if (!PR_CLIST_IS_EMPTY(diskEntry)) {
scavengeDiskCacheEntries(diskEntry);
if (!PR_CLIST_IS_EMPTY(bindData)) {
scavengeDiskCacheEntries(bindData);
}
// delete entry from memory.
@@ -850,42 +556,42 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * newEntry)
{
nsresult rv;
// Make sure this entry has its associated nsDiskCacheEntry data attached.
nsDiskCacheEntry* newDiskEntry = ensureDiskCacheEntry(newEntry);
NS_ASSERTION(newDiskEntry, "nsDiskCacheDevice::BindEntry");
if (!newDiskEntry) return NS_ERROR_OUT_OF_MEMORY;
// Make sure this entry has its associated nsDiskCacheBindData attached.
nsDiskCacheBindData* newBindData = ensureDiskCacheBindData(newEntry);
NS_ASSERTION(newBindData, "nsDiskCacheDevice::BindEntry");
if (!newBindData) return NS_ERROR_OUT_OF_MEMORY;
// XXX check for cache collision. if an entry exists on disk that has the same
// hash code as this newly bound entry, AND there is already a bound entry for
// that key, we need to ask the cache service to doom that entry, since two
// simultaneous entries that have the same hash code aren't allowed until
// some sort of chaining mechanism is implemented.
nsDiskCacheEntry* oldDiskEntry = mBoundEntries.GetEntry(newEntry->Key()->get());
if (oldDiskEntry) {
nsDiskCacheBindData* oldBindData = mBoundEntries.GetEntry(newEntry->Key()->get());
if (oldBindData) {
// XXX Hacky liveness test, remove when we've figured this all out.
if (oldDiskEntry->getRefCount() > 1) {
if (oldBindData->getRefCount() > 1) {
// set the generation count on the newly bound entry,
// so that files created will be unique and won't conflict
// with the doomed entries that are still active.
newDiskEntry->setGeneration(oldDiskEntry->getGeneration() + 1);
PR_APPEND_LINK(newDiskEntry, oldDiskEntry);
newBindData->setGeneration(oldBindData->getGeneration() + 1);
PR_APPEND_LINK(newBindData, oldBindData);
// XXX Whom do we tell about this impending doom?
nsCacheEntry* oldEntry = oldDiskEntry->getCacheEntry();
nsCacheEntry* oldEntry = oldBindData->getCacheEntry();
// XXX Yes Virginia, a doomed entry can be bound.
// NS_ASSERTION(!oldEntry->IsDoomed(), "a bound entry is doomed!");
if (!oldEntry->IsDoomed())
nsCacheService::GlobalInstance()->DoomEntry_Locked(oldEntry);
else
mBoundEntries.RemoveEntry(oldDiskEntry);
mBoundEntries.RemoveEntry(oldBindData);
} else {
// XXX somehow we didn't hear about the entry going away. Ask gordon.
NS_NOTREACHED("bound disk cache entry with no corresponding cache entry.");
mBoundEntries.RemoveEntry(oldDiskEntry);
mBoundEntries.RemoveEntry(oldBindData);
}
}
rv = mBoundEntries.AddEntry(newDiskEntry);
rv = mBoundEntries.AddEntry(newBindData);
if (NS_FAILED(rv))
return rv;
@@ -897,7 +603,7 @@ nsDiskCacheDevice::BindEntry(nsCacheEntry * newEntry)
// this probably isn't needed while the entry is bound,
// only when the entry is deactivated. this could be
// the reason disk cache performance suffers.
return updateDiskCacheEntry(newDiskEntry);
return updateDiskCacheEntry(newBindData);
}
@@ -906,8 +612,8 @@ nsDiskCacheDevice::DoomEntry(nsCacheEntry * entry)
{
// so it can't be seen by FindEntry() ever again.
// XXX if entry->mData is null, it's an error
nsDiskCacheEntry* diskEntry = ensureDiskCacheEntry(entry);
mBoundEntries.RemoveEntry(diskEntry);
nsDiskCacheBindData* bindData = ensureDiskCacheBindData(entry);
mBoundEntries.RemoveEntry(bindData);
// XXX clear this entry out of the cache map.
// this is done in deleteDiskCacheEntry().
@@ -922,11 +628,11 @@ nsDiskCacheDevice::GetTransportForEntry(nsCacheEntry * entry,
NS_ENSURE_ARG_POINTER(entry);
NS_ENSURE_ARG_POINTER(result);
nsDiskCacheEntry* diskEntry = ensureDiskCacheEntry(entry);
if (!diskEntry) return NS_ERROR_OUT_OF_MEMORY;
nsDiskCacheBindData* bindData = ensureDiskCacheBindData(entry);
if (!bindData) return NS_ERROR_OUT_OF_MEMORY;
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
nsCOMPtr<nsITransport>& transport = diskEntry->getTransport(mode);
nsCOMPtr<nsITransport>& transport = bindData->getTransport(mode);
if (transport) {
NS_ADDREF(*result = transport);
return NS_OK;
@@ -938,7 +644,7 @@ nsDiskCacheDevice::GetTransportForEntry(nsCacheEntry * entry,
// XXX generate the name of the cache entry from the hash code of its key,
// modulo the number of files we're willing to keep cached.
nsCOMPtr<nsIFile> dataFile;
nsresult rv = getFileForDiskCacheEntry(diskEntry, PR_FALSE,
nsresult rv = getFileForDiskCacheEntry(bindData, PR_FALSE,
getter_AddRefs(dataFile));
if (NS_SUCCEEDED(rv)) {
rv = getTransportForFile(dataFile, mode, getter_AddRefs(transport));
@@ -953,9 +659,9 @@ nsresult
nsDiskCacheDevice::GetFileForEntry(nsCacheEntry * entry,
nsIFile ** result)
{
nsDiskCacheEntry* diskEntry = ensureDiskCacheEntry(entry);
if (!diskEntry) return NS_ERROR_OUT_OF_MEMORY;
return getFileForDiskCacheEntry(diskEntry, PR_FALSE, result);
nsDiskCacheBindData* bindData = ensureDiskCacheBindData(entry);
if (!bindData) return NS_ERROR_OUT_OF_MEMORY;
return getFileForDiskCacheEntry(bindData, PR_FALSE, result);
}
/**
@@ -990,6 +696,7 @@ nsDiskCacheDevice::Visit(nsICacheVisitor * visitor)
return NS_OK;
}
nsresult
nsDiskCacheDevice::EvictEntries(const char * clientID)
{
@@ -1019,9 +726,9 @@ nsDiskCacheDevice::EvictEntries(const char * clientID)
nsDiskCacheRecord* record = &records[j];
// if the entry is currently in use, then doom it rather than evicting right here.
nsDiskCacheEntry* diskEntry = mBoundEntries.GetEntry(record->HashNumber());
if (diskEntry) {
nsCacheService::GlobalInstance()->DoomEntry_Locked(diskEntry->getCacheEntry());
nsDiskCacheBindData* bindData = mBoundEntries.GetEntry(record->HashNumber());
if (bindData) {
nsCacheService::GlobalInstance()->DoomEntry_Locked(bindData->getCacheEntry());
continue;
}
@@ -1159,14 +866,14 @@ nsresult nsDiskCacheDevice::getFileForHashNumber(PLDHashNumber hashNumber, PRBoo
nsresult nsDiskCacheDevice::getFileForKey(const char* key, PRBool meta,
PRUint32 generation, nsIFile ** result)
{
PLDHashNumber hash = nsDiskCacheEntry::Hash(key);
PLDHashNumber hash = nsDiskCacheBindData::Hash(key);
return getFileForHashNumber(hash, meta, generation, result);
}
nsresult nsDiskCacheDevice::getFileForDiskCacheEntry(nsDiskCacheEntry * diskEntry, PRBool meta,
nsresult nsDiskCacheDevice::getFileForDiskCacheEntry(nsDiskCacheBindData * bindData, PRBool meta,
nsIFile ** result)
{
return getFileForHashNumber(diskEntry->getHashNumber(), meta, diskEntry->getGeneration(), result);
return getFileForHashNumber(bindData->getHashNumber(), meta, bindData->getGeneration(), result);
}
nsresult nsDiskCacheDevice::getTransportForFile(nsIFile* file, nsCacheAccessMode mode, nsITransport ** result)
@@ -1239,7 +946,7 @@ nsresult nsDiskCacheDevice::visitEntries(nsICacheVisitor * visitor)
rv = updateDiskCacheEntries();
if (NS_FAILED(rv)) return rv;
nsDiskCacheEntryInfo* entryInfo = new nsDiskCacheEntryInfo();
nsDiskCacheEntryInfo* entryInfo = new nsDiskCacheEntryInfo(DISK_CACHE_DEVICE_ID);
if (!entryInfo) return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsICacheEntryInfo> ref(entryInfo);
@@ -1278,14 +985,14 @@ nsresult nsDiskCacheDevice::visitEntries(nsICacheVisitor * visitor)
return NS_OK;
}
class UpdateEntryVisitor : public nsDiskCacheEntryHashTable::Visitor {
class UpdateEntryVisitor : public nsDiskCacheHashTable::Visitor {
nsDiskCacheDevice* mDevice;
public:
UpdateEntryVisitor(nsDiskCacheDevice * device) : mDevice(device) {}
virtual PRBool VisitEntry(nsDiskCacheEntry * diskEntry)
virtual PRBool VisitEntry(nsDiskCacheBindData * bindData)
{
mDevice->updateDiskCacheEntry(diskEntry);
mDevice->updateDiskCacheEntry(bindData);
return PR_TRUE;
}
};
@@ -1297,17 +1004,17 @@ nsresult nsDiskCacheDevice::updateDiskCacheEntries()
return NS_OK;
}
nsresult nsDiskCacheDevice::updateDiskCacheEntry(nsDiskCacheEntry* diskEntry)
nsresult nsDiskCacheDevice::updateDiskCacheEntry(nsDiskCacheBindData* bindData)
{
nsresult rv;
nsCacheEntry* entry = diskEntry->getCacheEntry();
nsCacheEntry* entry = bindData->getCacheEntry();
if (entry->IsMetaDataDirty() || entry->IsEntryDirty() || entry->IsDataDirty()) {
// make sure this disk entry is known to the cache map.
rv = updateCacheMap(diskEntry);
rv = updateCacheMap(bindData);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIFile> file;
rv = getFileForDiskCacheEntry(diskEntry, PR_TRUE,
rv = getFileForDiskCacheEntry(bindData, PR_TRUE,
getter_AddRefs(file));
if (NS_FAILED(rv)) return rv;
@@ -1332,7 +1039,7 @@ nsresult nsDiskCacheDevice::updateDiskCacheEntry(nsDiskCacheEntry* diskEntry)
}
nsresult nsDiskCacheDevice::readDiskCacheEntry(const char * key, nsDiskCacheEntry ** result)
nsresult nsDiskCacheDevice::readDiskCacheEntry(const char * key, nsDiskCacheBindData ** result)
{
// result should be nsull on cache miss.
*result = nsnull;
@@ -1377,7 +1084,7 @@ nsresult nsDiskCacheDevice::readDiskCacheEntry(const char * key, nsDiskCacheEntr
}
// celebrate!
*result = ensureDiskCacheEntry(entry);
*result = ensureDiskCacheBindData(entry);
if (!*result) goto error;
return NS_OK;
@@ -1387,13 +1094,13 @@ error:
return NS_ERROR_NOT_AVAILABLE;
}
nsresult nsDiskCacheDevice::deleteDiskCacheEntry(nsDiskCacheEntry * diskEntry)
nsresult nsDiskCacheDevice::deleteDiskCacheEntry(nsDiskCacheBindData * bindData)
{
nsresult rv;
// delete the metadata file.
nsCOMPtr<nsIFile> metaFile;
rv = getFileForDiskCacheEntry(diskEntry, PR_TRUE,
rv = getFileForDiskCacheEntry(bindData, PR_TRUE,
getter_AddRefs(metaFile));
if (NS_SUCCEEDED(rv)) {
rv = metaFile->Delete(PR_FALSE);
@@ -1402,7 +1109,7 @@ nsresult nsDiskCacheDevice::deleteDiskCacheEntry(nsDiskCacheEntry * diskEntry)
// delete the data file
nsCOMPtr<nsIFile> dataFile;
rv = getFileForDiskCacheEntry(diskEntry, PR_FALSE,
rv = getFileForDiskCacheEntry(bindData, PR_FALSE,
getter_AddRefs(dataFile));
if (NS_SUCCEEDED(rv)) {
rv = dataFile->Delete(PR_FALSE);
@@ -1410,14 +1117,14 @@ nsresult nsDiskCacheDevice::deleteDiskCacheEntry(nsDiskCacheEntry * diskEntry)
}
// remove from cache map.
nsDiskCacheRecord* record = mCacheMap->GetRecord(diskEntry->getHashNumber());
if (record->HashNumber() == diskEntry->getHashNumber() && record->FileGeneration() == diskEntry->getGeneration())
nsDiskCacheRecord* record = mCacheMap->GetRecord(bindData->getHashNumber());
if (record->HashNumber() == bindData->getHashNumber() && record->FileGeneration() == bindData->getGeneration())
mCacheMap->DeleteRecord(record);
return NS_OK;
}
nsresult nsDiskCacheDevice::scavengeDiskCacheEntries(nsDiskCacheEntry * diskEntry)
nsresult nsDiskCacheDevice::scavengeDiskCacheEntries(nsDiskCacheBindData * bindData)
{
nsresult rv;
@@ -1426,22 +1133,22 @@ nsresult nsDiskCacheDevice::scavengeDiskCacheEntries(nsDiskCacheEntry * diskEntr
// the liveEntry, if inactive, can have its generation reset
// to zero.
PRUint32 doomedEntryCount = 0;
nsDiskCacheEntry * youngestDiskEntry = diskEntry;
nsCacheEntry * youngestEntry = diskEntry->getCacheEntry();
nsDiskCacheEntry * nextDiskEntry = NS_STATIC_CAST(nsDiskCacheEntry*, PR_NEXT_LINK(diskEntry));
while (nextDiskEntry != diskEntry) {
nsCacheEntry* nextEntry = nextDiskEntry->getCacheEntry();
nsDiskCacheBindData * youngestBindData = bindData;
nsCacheEntry * youngestEntry = bindData->getCacheEntry();
nsDiskCacheBindData * nextBindData = NS_STATIC_CAST(nsDiskCacheBindData*, PR_NEXT_LINK(bindData));
while (nextBindData != bindData) {
nsCacheEntry* nextEntry = nextBindData->getCacheEntry();
if (nextEntry->IsDoomed()) {
++doomedEntryCount;
} else if (nextDiskEntry->getGeneration() > youngestDiskEntry->getGeneration()) {
} else if (nextBindData->getGeneration() > youngestBindData->getGeneration()) {
youngestEntry = nextEntry;
youngestDiskEntry = nextDiskEntry;
youngestBindData = nextBindData;
}
nextDiskEntry = NS_STATIC_CAST(nsDiskCacheEntry*, PR_NEXT_LINK(nextDiskEntry));
nextBindData = NS_STATIC_CAST(nsDiskCacheBindData*, PR_NEXT_LINK(nextBindData));
}
if (doomedEntryCount == 0 && !youngestEntry->IsDoomed() && !youngestEntry->IsActive()) {
PRUint32 generation = youngestDiskEntry->getGeneration();
PRUint32 generation = youngestBindData->getGeneration();
// XXX reset generation number.
const char* key = youngestEntry->Key()->get();
nsCOMPtr<nsIFile> oldFile, newFile;
@@ -1472,107 +1179,8 @@ nsresult nsDiskCacheDevice::scavengeDiskCacheEntries(nsDiskCacheEntry * diskEntr
return NS_OK;
}
nsresult nsDiskCacheDevice::scanDiskCacheEntries(nsISupportsArray ** result)
{
#if 0
nsresult rv;
// XXX make sure meta data is up to date.
rv = updateDiskCacheEntries();
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> files;
rv = mCacheDirectory->GetDirectoryEntries(getter_AddRefs(files));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISupportsArray> entries = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
PRUint32 newCacheSize = 0;
for (PRBool more; NS_SUCCEEDED(files->HasMoreElements(&more)) && more;) {
nsCOMPtr<nsISupports> next;
rv = files->GetNext(getter_AddRefs(next));
if (NS_FAILED(rv)) break;
nsCOMPtr<nsIFile> file(do_QueryInterface(next, &rv));
if (NS_FAILED(rv)) break;
nsXPIDLCString name;
rv = file->GetLeafName(getter_Copies(name));
if (isMetaDataFile(name)) {
// this must be a metadata file.
nsCOMPtr<nsIInputStream> input;
rv = openInputStream(file, getter_AddRefs(input));
if (NS_FAILED(rv)) continue;
nsDiskCacheEntryInfo* entryInfo = new nsDiskCacheEntryInfo();
if (!entryInfo) return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsISupports> ref(entryInfo);
rv = entryInfo->Read(input);
input->Close();
if (NS_FAILED(rv)) return rv;
// update the cache size.
PRUint32 dataSize;
entryInfo->GetDataSize(&dataSize);
newCacheSize += dataSize;
// update the cache map.
PLDHashNumber hashNumber = nsDiskCacheEntry::Hash(entryInfo->Key());
nsDiskCacheRecord* record = mCacheMap->GetRecord(hashNumber);
record->SetHashNumber(hashNumber);
record->SetEvictionRank(0);
record->SetFileGeneration(0);
// sort entries by modification time.
PRUint32 count;
entries->Count(&count);
if (count == 0) {
rv = entries->AppendElement(entryInfo);
if (NS_FAILED(rv)) return rv;
continue;
}
PRUint32 modTime;
entryInfo->GetLastModified(&modTime);
PRInt32 low = 0, high = count - 1;
for (;;) {
PRInt32 middle = (low + high) / 2;
nsCOMPtr<nsICacheEntryInfo> info = do_QueryElementAt(entries, middle, &rv);
if (NS_FAILED(rv)) return rv;
PRUint32 modTime1;
info->GetLastModified(&modTime1);
if (low >= high) {
if (modTime <= modTime1)
rv = entries->InsertElementAt(entryInfo, middle);
else
rv = entries->InsertElementAt(entryInfo, middle + 1);
if (NS_FAILED(rv)) return rv;
break;
} else {
if (modTime < modTime1) {
high = middle - 1;
} else if (modTime > modTime1) {
low = middle + 1;
} else {
rv = entries->InsertElementAt(entryInfo, middle);
if (NS_FAILED(rv)) return rv;
break;
}
}
}
}
}
NS_ADDREF(*result = entries);
// we've successfully totaled the cache size.
mCacheMap->DataSize() = newCacheSize;
entries->Count(&mCacheMap->EntryCount());
#endif
return NS_OK;
}
nsresult nsDiskCacheDevice::clobberDiskCache()
nsresult nsDiskCacheDevice::InitializeCacheDirectory()
{
nsresult rv;
@@ -1677,8 +1285,8 @@ nsresult nsDiskCacheDevice::evictDiskCacheEntries()
// XXX if this entry is currently active, then leave it alone,
// as it is likely to be modified very soon.
nsDiskCacheEntry* diskEntry = mBoundEntries.GetEntry(record->HashNumber());
if (diskEntry) continue;
nsDiskCacheBindData* bindData = mBoundEntries.GetEntry(record->HashNumber());
if (bindData) continue;
// delete the metadata file.
nsCOMPtr<nsIFile> metaFile;
@@ -1715,6 +1323,10 @@ nsresult nsDiskCacheDevice::evictDiskCacheEntries()
return NS_OK;
}
/**
* openCacheMap : called by InitializeCacheDirectory, readCacheMap, writeCacheMap, updateCacheMap
*/
nsresult nsDiskCacheDevice::openCacheMap()
{
nsresult rv;
@@ -1738,7 +1350,7 @@ nsresult nsDiskCacheDevice::openCacheMap()
return NS_OK;
}
nsresult nsDiskCacheDevice::readCacheMap()
nsresult nsDiskCacheDevice::readCacheMap() // only called by Init()
{
nsresult rv;
if (!mCacheStream) {
@@ -1749,7 +1361,7 @@ nsresult nsDiskCacheDevice::readCacheMap()
return rv;
}
nsresult nsDiskCacheDevice::writeCacheMap()
nsresult nsDiskCacheDevice::writeCacheMap() // only called by Shutdown()
{
nsresult rv;
if (!mCacheStream) {
@@ -1760,14 +1372,18 @@ nsresult nsDiskCacheDevice::writeCacheMap()
return rv;
}
nsresult nsDiskCacheDevice::updateCacheMap(nsDiskCacheEntry * diskEntry)
/**
* updateCacheMap : called by updateDiskCacheEntry
*/
nsresult nsDiskCacheDevice::updateCacheMap(nsDiskCacheBindData * bindData)
{
nsresult rv;
// get a record from the cache map, and use the fetch time for eviction ranking.
PRBool commitBucket = PR_TRUE;
nsDiskCacheRecord* record = mCacheMap->GetRecord(diskEntry->getHashNumber());
if (record->HashNumber() != diskEntry->getHashNumber()) {
nsDiskCacheRecord* record = mCacheMap->GetRecord(bindData->getHashNumber());
if (record->HashNumber() != bindData->getHashNumber()) {
if (record->HashNumber() != 0) {
// eviction of eldest entry in this bucket.
evictDiskCacheRecord(record);
@@ -1775,14 +1391,14 @@ nsresult nsDiskCacheDevice::updateCacheMap(nsDiskCacheEntry * diskEntry)
mCacheMap->EntryCount() += 1;
}
// newly bound record. fill in the blanks.
record->SetHashNumber(diskEntry->getHashNumber());
record->SetHashNumber(bindData->getHashNumber());
record->SetEvictionRank(0);
record->SetFileGeneration(diskEntry->getGeneration());
} else if (record->FileGeneration() != diskEntry->getGeneration()) {
record->SetFileGeneration(bindData->getGeneration());
} else if (record->FileGeneration() != bindData->getGeneration()) {
// a collision has occurred
record->SetHashNumber(diskEntry->getHashNumber());
record->SetHashNumber(bindData->getHashNumber());
record->SetEvictionRank(0);
record->SetFileGeneration(diskEntry->getGeneration());
record->SetFileGeneration(bindData->getGeneration());
} else {
commitBucket = PR_FALSE;
record->SetEvictionRank(record->EvictionRank() + 1);
@@ -1816,9 +1432,9 @@ nsresult nsDiskCacheDevice::evictDiskCacheRecord(nsDiskCacheRecord * record)
nsresult rv;
// if the entry is currently in use, then doom it rather than evicting right here.
nsDiskCacheEntry* diskEntry = mBoundEntries.GetEntry(record->HashNumber());
if (diskEntry)
return nsCacheService::GlobalInstance()->DoomEntry_Locked(diskEntry->getCacheEntry());
nsDiskCacheBindData* bindData = mBoundEntries.GetEntry(record->HashNumber());
if (bindData)
return nsCacheService::GlobalInstance()->DoomEntry_Locked(bindData->getCacheEntry());
// delete the metadata file.
nsCOMPtr<nsIFile> metaFile;

View File

@@ -26,12 +26,13 @@
#define _nsDiskCacheDevice_h_
#include "nsCacheDevice.h"
#include "nsDiskCacheBindData.h"
#include "nsDiskCacheEntry.h"
#include "nsILocalFile.h"
#include "nsIObserver.h"
class nsDiskCacheEntry;
class nsDiskCacheBindData;
class nsDiskCacheMap;
class nsDiskCacheRecord;
@@ -81,42 +82,41 @@ public:
nsresult getFileForHashNumber(PLDHashNumber hashNumber, PRBool meta, PRUint32 generation, nsIFile ** result);
nsresult getFileForKey(const char* key, PRBool meta, PRUint32 generation, nsIFile ** result);
nsresult getFileForDiskCacheEntry(nsDiskCacheEntry * diskEntry, PRBool meta, nsIFile ** result);
nsresult getFileForDiskCacheEntry(nsDiskCacheBindData * bindData, PRBool meta, nsIFile ** result);
static nsresult getTransportForFile(nsIFile* file, nsCacheAccessMode mode, nsITransport ** result);
static nsresult openInputStream(nsIFile* file, nsIInputStream ** result);
static nsresult openOutputStream(nsIFile* file, nsIOutputStream ** result);
nsresult visitEntries(nsICacheVisitor * visitory);
nsresult visitEntries(nsICacheVisitor * visitor);
nsresult readDiskCacheEntry(const char * key, nsDiskCacheEntry ** diskEntry);
nsresult readDiskCacheEntry(const char * key, nsDiskCacheBindData ** bindData);
nsresult updateDiskCacheEntries();
nsresult updateDiskCacheEntry(nsDiskCacheEntry * diskEntry);
nsresult deleteDiskCacheEntry(nsDiskCacheEntry * diskEntry);
nsresult updateDiskCacheEntry(nsDiskCacheBindData * bindData);
nsresult deleteDiskCacheEntry(nsDiskCacheBindData * bindData);
nsresult scavengeDiskCacheEntries(nsDiskCacheEntry * diskEntry);
nsresult scavengeDiskCacheEntries(nsDiskCacheBindData * bindData);
nsresult scanDiskCacheEntries(nsISupportsArray ** result);
nsresult evictDiskCacheEntries();
nsresult clobberDiskCache();
nsresult InitializeCacheDirectory();
nsresult openCacheMap();
nsresult readCacheMap();
nsresult writeCacheMap();
nsresult updateCacheMap(nsDiskCacheEntry * diskEntry);
nsresult updateCacheMap(nsDiskCacheBindData * bindData);
nsresult evictDiskCacheRecord(nsDiskCacheRecord * record);
private:
PRBool mInitialized;
nsCOMPtr<nsIObserver> mPrefsObserver; // XXX ?
nsCOMPtr<nsILocalFile> mCacheDirectory;
nsDiskCacheEntryHashTable mBoundEntries; // XXX rename to refer to active entries
PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal
nsDiskCacheMap* mCacheMap;
nsANSIFileStream* mCacheStream; // XXX should be owned by cache map
PRBool mInitialized;
nsCOMPtr<nsIObserver> mPrefsObserver; // XXX ?
nsCOMPtr<nsILocalFile> mCacheDirectory;
nsDiskCacheHashTable mBoundEntries; // XXX rename to refer to active entries
PRUint32 mCacheCapacity; // XXX need soft/hard limits, currentTotal
nsDiskCacheMap* mCacheMap;
nsANSIFileStream* mCacheStream; // XXX should be owned by cache map
// XXX need array of cache block files
};

View File

@@ -10,7 +10,7 @@
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is nsMemoryCacheDevice.cpp, released February 22, 2001.
* The Original Code is nsDiskCacheEntry.cpp, released May 10, 2001.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
@@ -18,196 +18,132 @@
* Rights Reserved.
*
* Contributor(s):
* Gordon Sheridan <gordon@netscape.com>
* Patrick C. Beard <beard@netscape.com>
*/
#include <limits.h>
#include "nsDiskCacheEntry.h"
#include "nsCache.h"
NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheEntry);
PLDHashNumber
nsDiskCacheEntry::Hash(const char* key)
nsresult MetaDataFile::Read(nsIInputStream* input)
{
PLDHashNumber h = 0;
for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s)
h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ *s;
return (h == 0 ? ULONG_MAX : h);
}
/******************************************************************************
* nsCacheEntryHashTable
*****************************************************************************/
PLDHashTableOps nsDiskCacheEntryHashTable::ops =
{
PL_DHashAllocTable,
PL_DHashFreeTable,
GetKey,
HashKey,
MatchEntry,
MoveEntry,
ClearEntry,
Finalize
};
nsDiskCacheEntryHashTable::nsDiskCacheEntryHashTable()
: initialized(PR_FALSE)
{
}
nsDiskCacheEntryHashTable::~nsDiskCacheEntryHashTable()
{
if (initialized)
PL_DHashTableFinish(&table);
}
nsresult
nsDiskCacheEntryHashTable::Init()
{
nsresult rv = NS_OK;
initialized = PL_DHashTableInit(&table, &ops, nsnull,
sizeof(HashTableEntry), 512);
if (!initialized) rv = NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
PRUint32 count;
return rv;
}
nsDiskCacheEntry *
nsDiskCacheEntryHashTable::GetEntry(const char * key)
{
return GetEntry(nsDiskCacheEntry::Hash(key));
}
nsDiskCacheEntry *
nsDiskCacheEntryHashTable::GetEntry(PLDHashNumber key)
{
nsDiskCacheEntry * result = nsnull;
NS_ASSERTION(initialized, "nsDiskCacheEntryHashTable not initialized");
HashTableEntry * hashEntry;
hashEntry = (HashTableEntry*) PL_DHashTableOperate(&table, (void*) key, PL_DHASH_LOOKUP);
if (PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
result = hashEntry->mDiskCacheEntry;
// XXX Is it less expensive to read the file in multiple parts, or
// XXX get the size and read it in one chunk?
// read in the file header.
rv = input->Read((char*)&mHeaderSize, sizeof(MetaDataHeader), &count);
if (NS_FAILED(rv)) return rv;
Unswap();
// make sure it is self-consistent.
if (mHeaderSize != sizeof(MetaDataHeader)) {
NS_ERROR("### CACHE FORMAT CHANGED!!! PLEASE DELETE YOUR NewCache DIRECTORY!!! ###");
return NS_ERROR_ILLEGAL_VALUE;
}
return result;
// read in the key.
delete[] mKey;
mKey = new char[mKeySize];
if (!mKey) return NS_ERROR_OUT_OF_MEMORY;
rv = input->Read(mKey, mKeySize, &count);
if (NS_FAILED(rv)) return rv;
// read in the metadata.
delete mMetaData;
mMetaData = nsnull;
if (mMetaDataSize) {
mMetaData = new char[mMetaDataSize];
if (!mMetaData) return NS_ERROR_OUT_OF_MEMORY;
rv = input->Read(mMetaData, mMetaDataSize, &count);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
nsresult
nsDiskCacheEntryHashTable::AddEntry(nsDiskCacheEntry * entry)
nsresult MetaDataFile::Write(nsIOutputStream* output)
{
NS_ENSURE_ARG_POINTER(entry);
NS_ASSERTION(initialized, "nsDiskCacheEntryHashTable not initialized");
HashTableEntry * hashEntry;
hashEntry = (HashTableEntry *) PL_DHashTableOperate(&table,
(void*) entry->getHashNumber(),
PL_DHASH_ADD);
if (!hashEntry) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
PRUint32 count;
// write the header to the file.
Swap();
rv = output->Write((char*)&mHeaderSize, sizeof(MetaDataHeader), &count);
Unswap();
if (NS_FAILED(rv)) return rv;
// write the key to the file.
rv = output->Write(mKey, mKeySize, &count);
if (NS_FAILED(rv)) return rv;
// write the flattened metadata to the file.
if (mMetaDataSize) {
rv = output->Write(mMetaData, mMetaDataSize, &count);
if (NS_FAILED(rv)) return rv;
}
NS_ADDREF(hashEntry->mDiskCacheEntry = entry);
return NS_OK;
}
void
nsDiskCacheEntryHashTable::RemoveEntry(nsDiskCacheEntry * entry)
{
NS_ASSERTION(initialized, "nsDiskCacheEntryHashTable not initialized");
NS_ASSERTION(entry, "### cacheEntry == nsnull");
NS_IMPL_ISUPPORTS1(nsDiskCacheEntryInfo, nsICacheEntryInfo);
(void) PL_DHashTableOperate(&table, (void*) entry->getHashNumber(), PL_DHASH_REMOVE);
NS_IMETHODIMP nsDiskCacheEntryInfo::GetClientID(char ** clientID)
{
NS_ENSURE_ARG_POINTER(clientID);
return ClientIDFromCacheKey(nsLiteralCString(mMetaDataFile.mKey), clientID);
}
extern const char DISK_CACHE_DEVICE_ID[];
NS_IMETHODIMP nsDiskCacheEntryInfo::GetDeviceID(char ** deviceID)
{
NS_ENSURE_ARG_POINTER(deviceID);
*deviceID = nsCRT::strdup(mDeviceID);
return *deviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
void
nsDiskCacheEntryHashTable::VisitEntries(Visitor *visitor)
NS_IMETHODIMP nsDiskCacheEntryInfo::GetKey(char ** clientKey)
{
PL_DHashTableEnumerate(&table, VisitEntry, visitor);
NS_ENSURE_ARG_POINTER(clientKey);
return ClientKeyFromCacheKey(nsLiteralCString(mMetaDataFile.mKey), clientKey);
}
PLDHashOperator PR_CALLBACK
nsDiskCacheEntryHashTable::VisitEntry(PLDHashTable * table,
PLDHashEntryHdr * header,
PRUint32 number,
void * arg)
NS_IMETHODIMP nsDiskCacheEntryInfo::GetFetchCount(PRInt32 *aFetchCount)
{
HashTableEntry* hashEntry = (HashTableEntry *) header;
Visitor *visitor = (Visitor*) arg;
return (visitor->VisitEntry(hashEntry->mDiskCacheEntry) ? PL_DHASH_NEXT : PL_DHASH_STOP);
return *aFetchCount = mMetaDataFile.mFetchCount;
return NS_OK;
}
/**
* hash table operation callback functions
*/
const void * PR_CALLBACK
nsDiskCacheEntryHashTable::GetKey(PLDHashTable * /*table*/, PLDHashEntryHdr * header)
NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastFetched(PRUint32 *aLastFetched)
{
HashTableEntry * hashEntry = (HashTableEntry *) header;
return (void*) hashEntry->mDiskCacheEntry->getHashNumber();
*aLastFetched = mMetaDataFile.mLastFetched;
return NS_OK;
}
PLDHashNumber PR_CALLBACK
nsDiskCacheEntryHashTable::HashKey( PLDHashTable *table, const void *key)
NS_IMETHODIMP nsDiskCacheEntryInfo::GetLastModified(PRUint32 *aLastModified)
{
return (PLDHashNumber) key;
*aLastModified = mMetaDataFile.mLastModified;
return NS_OK;
}
PRBool PR_CALLBACK
nsDiskCacheEntryHashTable::MatchEntry(PLDHashTable * /* table */,
const PLDHashEntryHdr * header,
const void * key)
NS_IMETHODIMP nsDiskCacheEntryInfo::GetExpirationTime(PRUint32 *aExpirationTime)
{
HashTableEntry * hashEntry = (HashTableEntry *) header;
return (hashEntry->mDiskCacheEntry->getHashNumber() == (PLDHashNumber) key);
*aExpirationTime = mMetaDataFile.mExpirationTime;
return NS_OK;
}
void PR_CALLBACK
nsDiskCacheEntryHashTable::MoveEntry(PLDHashTable * /* table */,
const PLDHashEntryHdr * fromHeader,
PLDHashEntryHdr * toHeader)
NS_IMETHODIMP nsDiskCacheEntryInfo::IsStreamBased(PRBool *aStreamBased)
{
HashTableEntry * fromEntry = (HashTableEntry *) fromHeader;
HashTableEntry * toEntry = (HashTableEntry *) toHeader;
toEntry->keyHash = fromEntry->keyHash;
toEntry->mDiskCacheEntry = fromEntry->mDiskCacheEntry;
fromEntry->mDiskCacheEntry = nsnull;
*aStreamBased = PR_TRUE;
return NS_OK;
}
void PR_CALLBACK
nsDiskCacheEntryHashTable::ClearEntry(PLDHashTable * /* table */,
PLDHashEntryHdr * header)
NS_IMETHODIMP nsDiskCacheEntryInfo::GetDataSize(PRUint32 *aDataSize)
{
HashTableEntry* hashEntry = (HashTableEntry *) header;
hashEntry->keyHash = 0;
NS_IF_RELEASE(hashEntry->mDiskCacheEntry);
}
void PR_CALLBACK
nsDiskCacheEntryHashTable::Finalize(PLDHashTable * table)
{
(void) PL_DHashTableEnumerate(table, FreeCacheEntries, nsnull);
}
PLDHashOperator PR_CALLBACK
nsDiskCacheEntryHashTable::FreeCacheEntries(PLDHashTable * /* table */,
PLDHashEntryHdr * header,
PRUint32 number,
void * arg)
{
HashTableEntry *entry = (HashTableEntry *) header;
NS_IF_RELEASE(entry->mDiskCacheEntry);
return PL_DHASH_NEXT;
*aDataSize = mMetaDataFile.mDataSize;
return NS_OK;
}

View File

@@ -17,7 +17,8 @@
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s):
* Gordon Sheridan <gordon@netscape.com>
* Patrick C. Beard <beard@netscape.com>
*/
@@ -25,162 +26,149 @@
#define _nsDiskCacheEntry_h_
#include "nspr.h"
#include "pldhash.h"
#include "nscore.h"
#include "nsError.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsICacheVisitor.h"
#include "nsISupports.h"
#include "nsCacheEntry.h"
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
#include "nsITransport.h"
/******************************************************************************
* MetaData
*****************************************************************************/
struct MetaDataHeader {
PRUint32 mHeaderSize;
// PRUint32 mHashNumber; // XXX
// PRUint32 mMetaLocation; // XXX
PRInt32 mFetchCount;
PRUint32 mLastFetched;
PRUint32 mLastModified;
PRUint32 mExpirationTime;
PRUint32 mDataSize;
PRUint32 mKeySize;
PRUint32 mMetaDataSize;
// void * mKeyPtrSpace; // XXX don't need this
// void * mMetaDataPtrSpace; // XXX don't need this, we'll calculate it when necessary
// followed by null-terminated key and metadata string values.
MetaDataHeader()
: mHeaderSize(sizeof(MetaDataHeader)),
mFetchCount(0),
mLastFetched(0),
mLastModified(0),
mExpirationTime(0),
mDataSize(0),
mKeySize(0),
mMetaDataSize(0)
{
}
MetaDataHeader(nsCacheEntry* entry)
: mHeaderSize(sizeof(MetaDataHeader)),
mFetchCount(entry->FetchCount()),
mLastFetched(entry->LastFetched()),
mLastModified(entry->LastModified()),
mExpirationTime(entry->ExpirationTime()),
mDataSize(entry->DataSize()),
mKeySize(entry->Key()->Length() + 1),
mMetaDataSize(0)
{
}
void Swap()
{
#if defined(IS_LITTLE_ENDIAN)
mHeaderSize = ::PR_htonl(mHeaderSize);
mFetchCount = ::PR_htonl(mFetchCount);
mLastFetched = ::PR_htonl(mLastFetched);
mLastModified = ::PR_htonl(mLastModified);
mExpirationTime = ::PR_htonl(mExpirationTime);
mDataSize = ::PR_htonl(mDataSize);
mKeySize = ::PR_htonl(mKeySize);
mMetaDataSize = ::PR_htonl(mMetaDataSize);
#endif
}
void Unswap()
{
#if defined(IS_LITTLE_ENDIAN)
mHeaderSize = ::PR_ntohl(mHeaderSize);
mFetchCount = ::PR_ntohl(mFetchCount);
mLastFetched = ::PR_ntohl(mLastFetched);
mLastModified = ::PR_ntohl(mLastModified);
mExpirationTime = ::PR_ntohl(mExpirationTime);
mDataSize = ::PR_ntohl(mDataSize);
mKeySize = ::PR_ntohl(mKeySize);
mMetaDataSize = ::PR_ntohl(mMetaDataSize);
#endif
}
};
struct MetaDataFile : MetaDataHeader {
char* mKey;
char* mMetaData;
MetaDataFile()
: mKey(nsnull), mMetaData(nsnull)
{
}
MetaDataFile(nsCacheEntry* entry)
: MetaDataHeader(entry),
mKey(nsnull), mMetaData(nsnull)
{
}
~MetaDataFile()
{
delete[] mKey;
delete[] mMetaData;
}
nsresult Init(nsCacheEntry* entry)
{
PRUint32 size = 1 + entry->Key()->Length();
mKey = new char[size];
if (!mKey) return NS_ERROR_OUT_OF_MEMORY;
nsCRT::memcpy(mKey, entry->Key()->get(), size);
return entry->FlattenMetaData(&mMetaData, &mMetaDataSize);
}
nsresult Read(nsIInputStream* input);
nsresult Write(nsIOutputStream* output);
};
/******************************************************************************
* nsDiskCacheEntry
*
* Created for disk cache specific data and stored in nsCacheEntry.mData as
* an nsISupports. Also stored in nsDiscCacheEntryHashTable, with collisions
* linked by the PRCList.
*
* nsDiskCacheEntryInfo
*****************************************************************************/
class nsDiskCacheEntry : public nsISupports, public PRCList {
class nsDiskCacheEntryInfo : public nsICacheEntryInfo {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICACHEENTRYINFO
nsDiskCacheEntry(nsCacheEntry* entry)
: mCacheEntry(entry),
mGeneration(0)
nsDiskCacheEntryInfo(const char * deviceID)
: mDeviceID(deviceID)
{
NS_INIT_ISUPPORTS();
PR_INIT_CLIST(this);
mHashNumber = Hash(entry->Key()->get());
}
virtual ~nsDiskCacheEntry()
{
PR_REMOVE_LINK(this);
}
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
/**
* Maps a cache access mode to a cached nsITransport for that access
* mode. We keep these cached to avoid repeated trips to the
* file transport service.
*/
nsCOMPtr<nsITransport>& getTransport(nsCacheAccessMode mode)
{
return mTransports[mode - 1];
}
#endif
virtual ~nsDiskCacheEntryInfo() {}
nsCacheEntry* getCacheEntry()
nsresult Read(nsIInputStream * input)
{
return mCacheEntry;
return mMetaDataFile.Read(input);
}
PRUint32 getGeneration()
{
return mGeneration;
}
void setGeneration(PRUint32 generation)
{
mGeneration = generation;
}
PLDHashNumber getHashNumber()
{
return mHashNumber;
}
nsrefcnt getRefCount()
{
return mRefCnt;
}
static PLDHashNumber Hash(const char* key);
const char* Key() { return mMetaDataFile.mKey; }
private:
#ifdef MOZ_NEW_CACHE_REUSE_TRANSPORTS
nsCOMPtr<nsITransport> mTransports[3];
#endif
nsCacheEntry* mCacheEntry; // back pointer to parent nsCacheEntry
PRUint32 mGeneration; // XXX part of nsDiskCacheRecord
PLDHashNumber mHashNumber; // XXX part of nsDiskCacheRecord
// XXX nsDiskCacheRecord mMapRecord;
const char * mDeviceID;
MetaDataFile mMetaDataFile;
};
/******************************************************************************
* nsDiskCacheEntryHashTable
*
* Used to keep track of nsDiskCacheEntries associated with active/bound (and
* possibly doomed) entries. Lookups on 4 byte disk hash to find collisions
* (which need to be doomed, instead of just evicted. Collisions are linked
* using a PRCList to keep track of current generation number.
*
*****************************************************************************/
class nsDiskCacheEntryHashTable {
public:
nsDiskCacheEntryHashTable();
~nsDiskCacheEntryHashTable();
nsresult Init();
nsDiskCacheEntry * GetEntry(const char * key);
nsDiskCacheEntry * GetEntry(PLDHashNumber key);
nsresult AddEntry(nsDiskCacheEntry * entry);
void RemoveEntry(nsDiskCacheEntry * entry);
class Visitor {
public:
virtual PRBool VisitEntry(nsDiskCacheEntry * entry) = 0;
};
void VisitEntries(Visitor * visitor);
private:
struct HashTableEntry : PLDHashEntryHdr {
nsDiskCacheEntry * mDiskCacheEntry; // STRONG ref?
};
// PLDHashTable operation callbacks
static const void * PR_CALLBACK GetKey(PLDHashTable * table,
PLDHashEntryHdr * entry);
static PLDHashNumber PR_CALLBACK HashKey(PLDHashTable * table,
const void * key);
static PRBool PR_CALLBACK MatchEntry(PLDHashTable * table,
const PLDHashEntryHdr * entry,
const void * key);
static void PR_CALLBACK MoveEntry(PLDHashTable * table,
const PLDHashEntryHdr * from,
PLDHashEntryHdr * to);
static void PR_CALLBACK ClearEntry(PLDHashTable * table,
PLDHashEntryHdr * entry);
static void PR_CALLBACK Finalize(PLDHashTable *table);
static
PLDHashOperator PR_CALLBACK FreeCacheEntries(PLDHashTable * table,
PLDHashEntryHdr * hdr,
PRUint32 number,
void * arg);
static
PLDHashOperator PR_CALLBACK VisitEntry(PLDHashTable * table,
PLDHashEntryHdr * hdr,
PRUint32 number,
void * arg);
// member variables
static PLDHashTableOps ops;
PLDHashTable table;
PRBool initialized;
};
#endif /* _nsDiskCacheEntry_h_ */

View File

@@ -130,7 +130,7 @@ nsDiskCacheMap::Close()
// XXX dealloc cache map memory?
// XXX return rv ? rv : rv2;
// return rv ? rv : rv2;
return rv2;
}
@@ -139,14 +139,14 @@ nsresult
nsDiskCacheMap::AddRecord( nsDiskCacheRecord * mapRecord,
nsDiskCacheRecord * oldRecord)
{
return NS_OK;
}
nsresult
nsDiskCacheMap::UpdateRecord( nsDiskCacheRecord * mapRecord)
{
return NS_OK;
}
@@ -159,7 +159,7 @@ nsDiskCacheMap::FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * mapRecord
for (int i = 0; i < kRecordsPerBucket; ++i) {
if (bucket->mRecords[i].HashNumber() == 0) break;
if (bucket->mRecords[i].HashNumber() == hashNumber) {
if (bucket->mRecords[i].HashNumber() == mapRecord->HashNumber()) {
*mapRecord = bucket->mRecords[i]; // copy the record
return NS_OK;
}
@@ -212,8 +212,8 @@ void nsDiskCacheMap::Reset()
mHeader.mIsDirty = PR_TRUE;
for (PRUint32 b = 0; b < kBucketsPerTable; ++b) {
nsDiskCacheBucket& bucket = mBuckets[b];
::memset(&bucket, 0, sizeof(nsDiskCacheBucket));
nsDiskCacheBucket * bucket = &mBuckets[b];
::memset(bucket, 0, sizeof(nsDiskCacheBucket));
}
}

View File

@@ -25,13 +25,12 @@
#ifndef _nsDiskCacheMap_h_
#define _nsDiskCacheMap_h_
#include "nsANSIFileStreams.h"
#include "prtypes.h"
#include "prnetdb.h"
#include "nsDebug.h"
#include "nsError.h"
#include "nsILocalFile.h"
#include "nsANSIFileStreams.h"
class nsIInputStream;
class nsIOutputStream;
@@ -193,10 +192,9 @@ class nsDiskCacheRecordVisitor {
/******************************************************************************
* nsDiskCacheBucket
*****************************************************************************/
enum {
kRecordsPerBucket = 256,
kBucketsPerTable = (1 << 5) // must be a power of 2!
};
enum {
kRecordsPerBucket = 256
};
struct nsDiskCacheBucket {
nsDiskCacheRecord mRecords[kRecordsPerBucket];
@@ -206,10 +204,9 @@ struct nsDiskCacheBucket {
/******************************************************************************
* nsDiskCacheHeader
*****************************************************************************/
enum { kCurrentVersion = 0x00010002 };
enum { kCurrentVersion = 0x00010002 };
struct nsDiskCacheHeader {
PRUint32 mVersion; // cache version.
PRUint32 mDataSize; // size of cache in bytes.
PRUint32 mEntryCount; // number of entries stored in cache.
@@ -247,15 +244,20 @@ struct nsDiskCacheHeader {
}
};
enum { kCacheMapSize = sizeof(nsDiskCacheHeader) +
kBucketsPerTable * sizeof(nsDiskCacheBucket)
};
/******************************************************************************
* nsDiskCacheMap
*
* // XXX initial capacity, enough for 8192 distinct entries.
*****************************************************************************/
enum {
kBucketsPerTable = (1 << 5), // must be a power of 2!
kCacheMapSize = sizeof(nsDiskCacheHeader) +
kBucketsPerTable * sizeof(nsDiskCacheBucket)
};
class nsDiskCacheMap {
public:
nsDiskCacheMap();
@@ -281,11 +283,11 @@ public:
nsresult AddRecord( nsDiskCacheRecord * mapRecord, nsDiskCacheRecord * oldRecord);
nsresult UpdateRecord( nsDiskCacheRecord * mapRecord);
nsresult FindRecord( PRUint32 hashNumber, nsDiskCacheRecord * mapRecord);
nsresult GetRecord2( nsDiskCacheRecord * mapRecord);
nsresult DeleteRecord2( nsDiskCacheRecord * mapRecord);
nsresult EvictRecords( nsDiskCacheRecordVisitor * visitor);
//private:
void Reset();