зеркало из https://github.com/mozilla/gecko-dev.git
[not part of build]
Added rough cut of pref code for memory cache device to get cache size, and implemented simple eviction method. Restructured nsCacheEntryDescriptor to add SecurityInfo attribute. Created nsTransportWrapper as nested class (and member) that addrefs the descriptor instead of itself (like nsPipe). Also rename nsCacheOutputStream to nsOutputStreamWrapper and made it a nested class as well.
This commit is contained in:
Родитель
3bc7a8b81e
Коммит
acd18fda01
|
@ -76,6 +76,22 @@ nsCacheEntry::~nsCacheEntry()
|
|||
delete mMetaData;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheEntry::GetSecurityInfo( nsISupports ** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
NS_IF_ADDREF(*result = mSecurityInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsCacheEntry::SetSecurityInfo( nsISupports * info)
|
||||
{
|
||||
mSecurityInfo = info;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsCacheEntry::GetData(nsISupports **result)
|
||||
|
@ -197,6 +213,11 @@ nsCacheEntry::RequestAccess(nsCacheRequest * request, nsCacheAccessMode *accessG
|
|||
if (PR_CLIST_IS_EMPTY(&mDescriptorQ)) {
|
||||
// 1st descriptor for existing bound entry
|
||||
*accessGranted = request->AccessRequested();
|
||||
if (*accessGranted & nsICache::ACCESS_WRITE) {
|
||||
MarkInvalid();
|
||||
} else {
|
||||
MarkValid();
|
||||
}
|
||||
} else {
|
||||
// nth request for existing, bound entry
|
||||
*accessGranted = request->AccessRequested() & ~nsICache::ACCESS_WRITE;
|
||||
|
|
|
@ -80,6 +80,9 @@ public:
|
|||
nsCacheDevice * CacheDevice(void) { return mCacheDevice;}
|
||||
void SetCacheDevice( nsCacheDevice * device) { mCacheDevice = device;}
|
||||
|
||||
nsresult GetSecurityInfo( nsISupports ** result);
|
||||
nsresult SetSecurityInfo( nsISupports * info);
|
||||
|
||||
nsresult GetData( nsISupports ** result);
|
||||
nsresult SetData( nsISupports * data);
|
||||
|
||||
|
@ -169,10 +172,11 @@ private:
|
|||
PRUint32 mDataSize; // 4
|
||||
PRUint32 mMetaSize; // 4
|
||||
nsCacheDevice * mCacheDevice; // 4
|
||||
nsCOMPtr<nsISupports> mData; // 4
|
||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
nsCOMPtr<nsISupports> mData; //
|
||||
nsCacheMetaData * mMetaData; // 4
|
||||
PRCList mRequestQ; // 8 = 64
|
||||
PRCList mDescriptorQ; // 8 = 72
|
||||
PRCList mRequestQ; // 8
|
||||
PRCList mDescriptorQ; // 8
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -28,12 +28,13 @@
|
|||
#include "nsReadableUtils.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsCacheEntryDescriptor, nsICacheEntryDescriptor, nsITransport)
|
||||
NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor, nsICacheEntryDescriptor)
|
||||
|
||||
|
||||
nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry,
|
||||
nsCacheAccessMode accessGranted)
|
||||
: mCacheEntry(entry), mAccessGranted(accessGranted)
|
||||
: mCacheEntry(entry),
|
||||
mAccessGranted(accessGranted)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
PR_INIT_CLIST(this);
|
||||
|
@ -207,7 +208,7 @@ nsCacheEntryDescriptor::GetTransport(nsITransport ** result)
|
|||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM;
|
||||
|
||||
NS_ADDREF(*result = this);
|
||||
NS_ADDREF(*result = &mTransportWrapper);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -260,6 +261,7 @@ nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::GetFile(nsIFile ** result)
|
||||
{
|
||||
|
@ -269,6 +271,27 @@ nsCacheEntryDescriptor::GetFile(nsIFile ** result)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return mCacheEntry->GetSecurityInfo(result);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo)
|
||||
{
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
mCacheEntry->SetSecurityInfo(securityInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::Doom()
|
||||
{
|
||||
|
@ -353,195 +376,128 @@ nsCacheEntryDescriptor::GetMetaDataEnumerator(nsISimpleEnumerator ** result)
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
/******************************************************************************
|
||||
* nsCacheTransportWrapper
|
||||
******************************************************************************/
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
// XXX NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor::nsTransportWrapper, nsITransport);
|
||||
NS_IMPL_QUERY_INTERFACE1(nsCacheEntryDescriptor::nsTransportWrapper, nsITransport)
|
||||
|
||||
|
||||
// special AddRef and Release, because we are part of the descriptor
|
||||
#define GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(_this) \
|
||||
((nsCacheEntryDescriptor*)((char*)(_this) - \
|
||||
offsetof(nsCacheEntryDescriptor, mTransportWrapper)))
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt) nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::AddRef(void)
|
||||
{
|
||||
return GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this)->AddRef();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt) nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::Release(void)
|
||||
{
|
||||
return GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this)->Release();
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::GetNotificationCallbacks(nsIInterfaceRequestor **result)
|
||||
nsresult nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::EnsureTransportWithAccess(nsCacheAccessMode mode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
nsCacheEntryDescriptor * descriptor = GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this);
|
||||
if (!descriptor->mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!descriptor->mAccessGranted & mode) {
|
||||
rv = (mode == nsICache::ACCESS_READ) ?
|
||||
NS_ERROR_CACHE_READ_ACCESS_DENIED : NS_ERROR_CACHE_WRITE_ACCESS_DENIED;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::SetNotificationCallbacks(nsIInterfaceRequestor *requestor,
|
||||
PRBool isBackground)
|
||||
{
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::OpenInputStream(PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIInputStream ** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!(mAccessGranted & nsICache::ACCESS_READ))
|
||||
return NS_ERROR_CACHE_READ_ACCESS_DENIED;
|
||||
if (!mTransport) {
|
||||
nsresult rv;
|
||||
rv = nsCacheService::GlobalInstance()->
|
||||
GetTransportForEntry(mCacheEntry,
|
||||
mAccessGranted,
|
||||
GetTransportForEntry(descriptor->mCacheEntry,
|
||||
descriptor->mAccessGranted,
|
||||
getter_AddRefs(mTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return mTransport->OpenInputStream(offset, count, flags, result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* nsCacheOutputStream - a wrapper for nsIOutputstream to track the amount of data
|
||||
* written to a cache entry.
|
||||
*/
|
||||
class nsCacheOutputStream : public nsIOutputStream {
|
||||
nsCacheEntryDescriptor* mDescriptor;
|
||||
nsCOMPtr<nsIOutputStream> mOutput;
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsCacheOutputStream(nsCacheEntryDescriptor* descriptor, nsIOutputStream* output)
|
||||
: mDescriptor(nsnull), mOutput(output)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
NS_ADDREF(mDescriptor = descriptor);
|
||||
}
|
||||
|
||||
virtual ~nsCacheOutputStream()
|
||||
{
|
||||
NS_RELEASE(mDescriptor);
|
||||
}
|
||||
|
||||
nsresult Init();
|
||||
|
||||
NS_IMETHOD Close() { return mOutput->Close(); }
|
||||
NS_IMETHOD Flush() { return mOutput->Flush(); }
|
||||
NS_IMETHOD Write(const char *buf, PRUint32 count, PRUint32 *_retval);
|
||||
NS_IMETHOD WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval);
|
||||
NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval);
|
||||
NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking) { return mOutput->GetNonBlocking(aNonBlocking); }
|
||||
NS_IMETHOD SetNonBlocking(PRBool aNonBlocking) { return mOutput->SetNonBlocking(aNonBlocking); }
|
||||
NS_IMETHOD GetObserver(nsIOutputStreamObserver * *aObserver) { return mOutput->GetObserver(aObserver); }
|
||||
NS_IMETHOD SetObserver(nsIOutputStreamObserver * aObserver) { return mOutput->SetObserver(aObserver); }
|
||||
|
||||
private:
|
||||
nsresult OnWrite(PRUint32 count);
|
||||
};
|
||||
NS_IMPL_ISUPPORTS1(nsCacheOutputStream, nsIOutputStream);
|
||||
|
||||
nsresult
|
||||
nsCacheOutputStream::Init()
|
||||
{
|
||||
nsCacheAccessMode mode;
|
||||
nsresult rv = mDescriptor->GetAccessGranted(&mode);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (mode == nsICache::ACCESS_WRITE) {
|
||||
nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
|
||||
if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
nsCacheDevice* device = cacheEntry->CacheDevice();
|
||||
if (!device) return NS_ERROR_NOT_AVAILABLE;
|
||||
// the entry has been truncated to zero bytes, inform the device.
|
||||
PRInt32 delta = -cacheEntry->DataSize();
|
||||
rv = device->OnDataSizeChange(cacheEntry, delta);
|
||||
cacheEntry->SetDataSize(0);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *_retval)
|
||||
{
|
||||
nsresult rv = OnWrite(count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mOutput->Write(buf, count, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
|
||||
{
|
||||
nsresult rv = OnWrite(count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mOutput->WriteFrom(inStr, count, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
|
||||
{
|
||||
nsresult rv = OnWrite(count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mOutput->WriteSegments(reader, closure, count, _retval);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheOutputStream::OnWrite(PRUint32 count)
|
||||
{
|
||||
// XXX if count > 2^31 error_write_too_big
|
||||
return mDescriptor->RequestDataSizeChange((PRInt32)count);
|
||||
|
||||
#if 0
|
||||
nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
|
||||
if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
nsCacheDevice* device = cacheEntry->CacheDevice();
|
||||
if (!device) return NS_ERROR_NOT_AVAILABLE;
|
||||
nsresult rv = device->OnDataSizeChange(cacheEntry, count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
cacheEntry->SetDataSize(cacheEntry->DataSize() + count);
|
||||
return NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static nsresult NS_NewCacheOutputStream(nsIOutputStream ** result,
|
||||
nsCacheEntryDescriptor * descriptor,
|
||||
nsIOutputStream * output)
|
||||
static nsresult NS_NewOutputStreamWrapper(nsIOutputStream ** result,
|
||||
nsCacheEntryDescriptor * descriptor,
|
||||
nsIOutputStream * output)
|
||||
{
|
||||
nsCacheOutputStream* cacheOutput = new nsCacheOutputStream(descriptor, output);
|
||||
nsCacheEntryDescriptor::nsOutputStreamWrapper* cacheOutput =
|
||||
new nsCacheEntryDescriptor::nsOutputStreamWrapper(descriptor, output);
|
||||
if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsISupports> ref(cacheOutput);
|
||||
nsresult rv = cacheOutput->Init();
|
||||
nsresult rv = cacheOutput->Init();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_ADDREF(*result = cacheOutput);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::OpenOutputStream(PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIOutputStream ** result)
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::GetSecurityInfo(nsISupports ** securityInfo)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::GetNotificationCallbacks(nsIInterfaceRequestor **result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!(mAccessGranted & nsICache::ACCESS_WRITE))
|
||||
return NS_ERROR_CACHE_WRITE_ACCESS_DENIED;
|
||||
// if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsresult rv;
|
||||
if (!mTransport) {
|
||||
rv = nsCacheService::GlobalInstance()->
|
||||
GetTransportForEntry(mCacheEntry,
|
||||
mAccessGranted,
|
||||
getter_AddRefs(mTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// XXX allow more than one output stream at a time on a descriptor?
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::SetNotificationCallbacks(nsIInterfaceRequestor *requestor,
|
||||
PRBool isBackground)
|
||||
{
|
||||
// if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::OpenInputStream(PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIInputStream ** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
|
||||
nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_READ);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return mTransport->OpenInputStream(offset, count, flags, result);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::OpenOutputStream(PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIOutputStream ** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
|
||||
nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_WRITE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// XXX allow more than one output stream at a time on a descriptor? Why?
|
||||
|
||||
// Create the underlying output stream using the wrapped transport.
|
||||
nsCOMPtr<nsIOutputStream> output;
|
||||
|
@ -552,59 +508,119 @@ nsCacheEntryDescriptor::OpenOutputStream(PRUint32 offset,
|
|||
// to maintain the cache entry's size, and to inform the cache device. Eventually,
|
||||
// this mechanism will provide a way for the cache device to enforce space limits,
|
||||
// and to drive cache entry eviction.
|
||||
return NS_NewCacheOutputStream(result, this, output);
|
||||
nsCacheEntryDescriptor * descriptor = GET_DESCRIPTOR_FROM_TRANSPORT_WRAPPER(this);
|
||||
return NS_NewOutputStreamWrapper(result, descriptor, output);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::AsyncRead(nsIStreamListener * listener,
|
||||
nsISupports * ctxt,
|
||||
PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIRequest ** result)
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::AsyncRead(nsIStreamListener * listener,
|
||||
nsISupports * ctxt,
|
||||
PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIRequest ** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!(mAccessGranted & nsICache::ACCESS_READ))
|
||||
return NS_ERROR_CACHE_READ_ACCESS_DENIED;
|
||||
if (!mTransport) {
|
||||
nsresult rv;
|
||||
rv = nsCacheService::GlobalInstance()->
|
||||
GetTransportForEntry(mCacheEntry,
|
||||
mAccessGranted,
|
||||
getter_AddRefs(mTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_READ);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return mTransport->AsyncRead(listener, ctxt, offset, count, flags, result);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryDescriptor::AsyncWrite(nsIStreamProvider * provider,
|
||||
nsISupports * ctxt,
|
||||
PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIRequest ** result)
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsTransportWrapper::AsyncWrite(nsIStreamProvider * provider,
|
||||
nsISupports * ctxt,
|
||||
PRUint32 offset,
|
||||
PRUint32 count,
|
||||
PRUint32 flags,
|
||||
nsIRequest ** result)
|
||||
{
|
||||
// we're not planning on implementing this
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
#if 0
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!(mAccessGranted & nsICache::ACCESS_WRITE))
|
||||
return NS_ERROR_CACHE_WRITE_ACCESS_DENIED;
|
||||
if (!mTransport) {
|
||||
nsresult rv;
|
||||
rv = nsCacheService::GlobalInstance()->
|
||||
GetTransportForEntry(mCacheEntry,
|
||||
mAccessGranted,
|
||||
getter_AddRefs(mTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureTransportWithAccess(nsICache::ACCESS_WRITE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return mTransport->AsyncWrite(provider, ctxt, offset, count, flags, result);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsCacheOutputStream - a wrapper for nsIOutputstream to track the amount of
|
||||
* data written to a cache entry.
|
||||
******************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsCacheEntryDescriptor::nsOutputStreamWrapper, nsIOutputStream);
|
||||
|
||||
nsresult nsCacheEntryDescriptor::
|
||||
nsOutputStreamWrapper::Init()
|
||||
{
|
||||
nsCacheAccessMode mode;
|
||||
nsresult rv = mDescriptor->GetAccessGranted(&mode);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mode == nsICache::ACCESS_WRITE) {
|
||||
nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
|
||||
if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCacheDevice* device = cacheEntry->CacheDevice();
|
||||
if (!device) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// the entry has been truncated to zero bytes, inform the device.
|
||||
PRInt32 delta = -cacheEntry->DataSize();
|
||||
rv = device->OnDataSizeChange(cacheEntry, delta);
|
||||
cacheEntry->SetDataSize(0);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsOutputStreamWrapper::Write(const char * buf,
|
||||
PRUint32 count,
|
||||
PRUint32 * result)
|
||||
{
|
||||
nsresult rv = OnWrite(count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mOutput->Write(buf, count, result);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr,
|
||||
PRUint32 count,
|
||||
PRUint32 * result)
|
||||
{
|
||||
nsresult rv = OnWrite(count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mOutput->WriteFrom(inStr, count, result);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCacheEntryDescriptor::
|
||||
nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun reader,
|
||||
void * closure,
|
||||
PRUint32 count,
|
||||
PRUint32 * result)
|
||||
{
|
||||
nsresult rv = OnWrite(count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mOutput->WriteSegments(reader, closure, count, result);
|
||||
}
|
||||
|
||||
|
||||
nsresult nsCacheEntryDescriptor::
|
||||
nsOutputStreamWrapper::OnWrite(PRUint32 count)
|
||||
{
|
||||
// XXX if count > 2^31 error_write_too_big
|
||||
return mDescriptor->RequestDataSizeChange((PRInt32)count);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,15 +27,14 @@
|
|||
|
||||
#include "nsICacheEntryDescriptor.h"
|
||||
#include "nsCacheEntry.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
class nsCacheEntryDescriptor :
|
||||
public PRCList,
|
||||
public nsICacheEntryDescriptor,
|
||||
public nsITransport
|
||||
{
|
||||
public nsICacheEntryDescriptor
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITRANSPORT
|
||||
NS_DECL_NSICACHEENTRYDESCRIPTOR
|
||||
|
||||
nsCacheEntryDescriptor(nsCacheEntry * entry, nsCacheAccessMode mode);
|
||||
|
@ -55,11 +54,103 @@ public:
|
|||
*/
|
||||
nsCacheEntry * CacheEntry(void) { return mCacheEntry; }
|
||||
|
||||
protected:
|
||||
private:
|
||||
|
||||
/**
|
||||
* transport wrapper class -
|
||||
*
|
||||
* we want the transport wrapper to have the same lifetime as the descriptor,
|
||||
* but since they each need to reference the other, we have the descriptor
|
||||
* include the transport wrapper as a member, rather than just pointing to it,
|
||||
* which avoids circular AddRefs.
|
||||
*/
|
||||
class nsTransportWrapper : public nsITransport
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSITRANSPORT
|
||||
|
||||
nsTransportWrapper() : mTransport(nsnull) {}
|
||||
virtual ~nsTransportWrapper() {}
|
||||
|
||||
nsresult EnsureTransportWithAccess(nsCacheAccessMode mode);
|
||||
|
||||
nsCOMPtr<nsITransport> mTransport;
|
||||
}; // end of class nsTransportWrapper
|
||||
friend class nsTransportWrapper;
|
||||
|
||||
|
||||
/**
|
||||
* output stream wrapper class -
|
||||
*
|
||||
* The output stream wrapper references the descriptor, but the descriptor doesn't
|
||||
* need any references to the stream wrapper, so we don't need the same kind of
|
||||
* tricks that we're using for the transport wrapper.
|
||||
*/
|
||||
class nsOutputStreamWrapper : public nsIOutputStream {
|
||||
private:
|
||||
nsCacheEntryDescriptor * mDescriptor;
|
||||
nsCOMPtr<nsIOutputStream> mOutput;
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
// NS_DECL_NSIOUTPUTSTREAM
|
||||
NS_IMETHOD Close(void) { return mOutput->Close(); }
|
||||
NS_IMETHOD Flush(void) { return mOutput->Flush(); }
|
||||
|
||||
NS_IMETHOD Write(const char * buf,
|
||||
PRUint32 count,
|
||||
PRUint32 * result);
|
||||
|
||||
NS_IMETHOD WriteFrom(nsIInputStream * inStr,
|
||||
PRUint32 count,
|
||||
PRUint32 * result);
|
||||
|
||||
NS_IMETHOD WriteSegments(nsReadSegmentFun reader,
|
||||
void * closure,
|
||||
PRUint32 count,
|
||||
PRUint32 * result);
|
||||
|
||||
NS_IMETHOD GetNonBlocking(PRBool * nonBlocking)
|
||||
{ return mOutput->GetNonBlocking(nonBlocking); }
|
||||
|
||||
NS_IMETHOD SetNonBlocking(PRBool nonBlocking)
|
||||
{ return mOutput->SetNonBlocking(nonBlocking); }
|
||||
|
||||
NS_IMETHOD GetObserver(nsIOutputStreamObserver ** observer)
|
||||
{ return mOutput->GetObserver(observer); }
|
||||
|
||||
NS_IMETHOD SetObserver(nsIOutputStreamObserver * observer)
|
||||
{ return mOutput->SetObserver(observer); }
|
||||
|
||||
nsOutputStreamWrapper(nsCacheEntryDescriptor * descriptor,
|
||||
nsIOutputStream * output)
|
||||
: mDescriptor(nsnull), mOutput(output)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
NS_ADDREF(mDescriptor = descriptor);
|
||||
}
|
||||
|
||||
nsCacheEntry * mCacheEntry; // we are a child of the entry
|
||||
nsCacheAccessMode mAccessGranted;
|
||||
nsCOMPtr<nsITransport> mTransport;
|
||||
virtual ~nsOutputStreamWrapper()
|
||||
{
|
||||
NS_RELEASE(mDescriptor);
|
||||
}
|
||||
|
||||
nsresult Init();
|
||||
|
||||
|
||||
private:
|
||||
nsresult OnWrite(PRUint32 count);
|
||||
}; // end of class nsOutputStreamWrapper
|
||||
friend class nsOutputStreamWrapper;
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* nsCacheEntryDescriptor data members
|
||||
*/
|
||||
nsCacheEntry * mCacheEntry; // we are a child of the entry
|
||||
nsCacheAccessMode mAccessGranted;
|
||||
nsTransportWrapper mTransportWrapper;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -25,11 +25,21 @@
|
|||
#include "nsICacheService.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPref.h"
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kStorageTransportCID, NS_STORAGETRANSPORT_CID);
|
||||
|
||||
const char *gMemoryCacheSizePref = "browser.cache.memory_cache_size";
|
||||
|
||||
nsMemoryCacheDevice::nsMemoryCacheDevice()
|
||||
: mCurrentTotal(0)
|
||||
: mHardLimit(0),
|
||||
mSoftLimit(0),
|
||||
mTotalSize(0),
|
||||
mInactiveSize(0),
|
||||
mEntryCount(0),
|
||||
mMaxEntryCount(0)
|
||||
{
|
||||
PR_INIT_CLIST(&mEvictionList);
|
||||
}
|
||||
|
@ -37,6 +47,30 @@ nsMemoryCacheDevice::nsMemoryCacheDevice()
|
|||
nsMemoryCacheDevice::~nsMemoryCacheDevice()
|
||||
{
|
||||
// XXX dealloc all memory
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
prefs->UnregisterCallback(gMemoryCacheSizePref, MemoryCacheSizeChanged, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int PR_CALLBACK
|
||||
nsMemoryCacheDevice::MemoryCacheSizeChanged(const char * pref, void * closure)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 softLimit = 0;
|
||||
nsMemoryCacheDevice * device = (nsMemoryCacheDevice *)closure;
|
||||
|
||||
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = prefs->GetIntPref(gMemoryCacheSizePref, (PRInt32 *)&softLimit);
|
||||
|
||||
PRUint32 hardLimit = softLimit + 1024*1024*2; // XXX find better limit than +2Meg
|
||||
rv = device->AdjustMemoryLimits(softLimit, hardLimit);
|
||||
|
||||
return 0; // XXX what are we supposed to return?
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,6 +82,23 @@ nsMemoryCacheDevice::Init()
|
|||
rv = mMemCacheEntries.Init();
|
||||
|
||||
// XXX read user prefs for memory cache limits
|
||||
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = prefs->RegisterCallback(gMemoryCacheSizePref, MemoryCacheSizeChanged, this);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Initialize the pref
|
||||
MemoryCacheSizeChanged(gMemoryCacheSizePref, this);
|
||||
|
||||
// Register as a memory pressure observer
|
||||
NS_WITH_SERVICE(nsIObserverService,
|
||||
observerService,
|
||||
NS_OBSERVERSERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// XXX rv = observerServcie->AddObserver(this, NS_MEMORY_PRESSURE_TOPIC);
|
||||
}
|
||||
// Ignore failure of memory pressure registration
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -165,7 +216,56 @@ nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsMemoryCacheDevice::AdjustMemoryLimits(PRUint32 softLimit, PRUint32 hardLimit)
|
||||
{
|
||||
mSoftLimit = softLimit;
|
||||
mHardLimit = hardLimit;
|
||||
|
||||
if ((mTotalSize > mHardLimit) || (mInactiveSize > softLimit)) {
|
||||
// XXX rv = EvictEntries();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsMemoryCacheDevice::EvictEntries(void)
|
||||
{
|
||||
nsCacheEntry * entry;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList);
|
||||
while (entry != &mEvictionList) {
|
||||
if (entry->IsInUse()) {
|
||||
entry = (nsCacheEntry *)PR_NEXT_LINK(entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
// remove entry from our hashtable
|
||||
rv = mMemCacheEntries.RemoveEntry(entry);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "RemoveEntry() failed?");
|
||||
|
||||
// remove entry from the eviction list
|
||||
PR_REMOVE_AND_INIT_LINK(entry);
|
||||
|
||||
// update statistics
|
||||
PRUint32 memoryRecovered = entry->DataSize() + entry->MetaDataSize();
|
||||
mTotalSize -= memoryRecovered;
|
||||
mInactiveSize -= memoryRecovered;
|
||||
--mEntryCount;
|
||||
delete entry;
|
||||
|
||||
if ((mTotalSize < mHardLimit) && (mInactiveSize < mSoftLimit))
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// XXX need methods for enumerating entries
|
||||
|
||||
|
||||
// XXX check entry->IsInUse() before evicting.
|
||||
|
|
|
@ -49,16 +49,25 @@ public:
|
|||
nsITransport **transport );
|
||||
|
||||
virtual nsresult OnDataSizeChange( nsCacheEntry * entry, PRInt32 deltaSize );
|
||||
|
||||
static int PR_CALLBACK MemoryCacheSizeChanged(const char * pref, void * closure);
|
||||
|
||||
private:
|
||||
nsresult AdjustMemoryLimits(PRUint32 softLimit, PRUint32 hardLimit);
|
||||
nsresult EvictEntries(void);
|
||||
|
||||
nsCacheEntryHashTable mMemCacheEntries;
|
||||
PRCList mEvictionList;
|
||||
|
||||
PRUint32 mHardLimit;
|
||||
PRUint32 mSoftLimit;
|
||||
PRUint32 mCurrentTotal;
|
||||
|
||||
PRCList mEvictionList;
|
||||
PRUint32 mTotalSize;
|
||||
PRUint32 mInactiveSize;
|
||||
|
||||
PRUint32 mEntryCount;
|
||||
|
||||
PRUint32 mMaxEntryCount;
|
||||
// XXX what other stats do we want to keep?
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче