[not part of build]

Restructured open cache entry code in preparation for async implementation, to better share code with synchronous version.

Changed nsCacheRequest, nsCacheEntry, nsCacheEntryDescriptor to inherit from PRCList rather than include mListLink member, and removed extraneous GetListNode/GetInstance methods.

Consolidated mAccessRequested, mStreamBased, and mStoragePolicy into a single PRUint32 in nsCacheRequest.  Added PRLock, PRCondVar, and a 'wait for validation' flag, used for synchronously opening cache entries.  Added accessor functions for these "attributes".

Record current event queue for asychronous requests to be used with GetProxyForObject().  Removed mRequestThread.


git-svn-id: svn://10.0.0.236/trunk@88535 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
gordon%netscape.com
2001-03-05 07:17:58 +00:00
parent b2477d93b9
commit 0ea21fde31
9 changed files with 266 additions and 80 deletions

View File

@@ -40,7 +40,7 @@ nsCacheEntry::nsCacheEntry(nsCString * key,
PRBool streamBased,
nsCacheStoragePolicy storagePolicy)
: mKey(key),
mFetchCount(0),
mFetchCount(1),
mLastValidated(0),
mExpirationTime(0),
mFlags(0),
@@ -50,7 +50,7 @@ nsCacheEntry::nsCacheEntry(nsCString * key,
mData(nsnull),
mMetaData(nsnull)
{
PR_INIT_CLIST(&mListLink);
PR_INIT_CLIST(this);
PR_INIT_CLIST(&mRequestQ);
PR_INIT_CLIST(&mDescriptorQ);
@@ -170,47 +170,72 @@ nsCacheEntry::UnflattenMetaData(char * data, PRUint32 size)
*/
nsresult
nsCacheEntry::CommonOpen(nsCacheRequest * request, nsCacheAccessMode *accessGranted)
nsCacheEntry::RequestAccess(nsCacheRequest * request, nsCacheAccessMode *accessGranted)
{
nsresult rv = NS_OK;
if (!IsInitialized()) {
// brand new, unbound entry
request->mKey = nsnull; // steal ownership of the key string
*accessGranted = request->mAccessRequested & nsICache::ACCESS_WRITE;
NS_ASSERTION(*accessGranted, "new cache entry for READ-ONLY request");
if (request->mStreamBased) MarkStreamBased();
mFetchCount = 1;
if (request->IsStreamBased()) MarkStreamBased();
MarkInitialized();
*accessGranted = request->AccessRequested() & nsICache::ACCESS_WRITE;
NS_ASSERTION(*accessGranted, "new cache entry for READ-ONLY request");
PR_APPEND_LINK(request, &mRequestQ);
return rv;
}
if (IsStreamData() != request->mStreamBased) {
if (IsStreamData() != request->IsStreamBased()) {
*accessGranted = nsICache::ACCESS_NONE;
return request->mStreamBased ?
return request->IsStreamBased() ?
NS_ERROR_CACHE_DATA_IS_NOT_STREAM : NS_ERROR_CACHE_DATA_IS_STREAM;
}
if (PR_CLIST_IS_EMPTY(&mDescriptorQ)) {
// 1st descriptor for existing, bound entry
*accessGranted = request->mAccessRequested;
// 1st descriptor for existing bound entry
*accessGranted = request->AccessRequested();
} else {
// nth request for existing, bound entry
*accessGranted = request->mAccessRequested & ~nsICache::ACCESS_WRITE;
*accessGranted = request->AccessRequested() & ~nsICache::ACCESS_WRITE;
if (!IsValid())
rv = NS_ERROR_CACHE_WAIT_FOR_VALIDATION;
}
PR_APPEND_LINK(request,&mRequestQ);
return rv;
}
nsresult
nsCacheEntry::CreateDescriptor(nsCacheRequest * request,
nsCacheAccessMode accessGranted,
nsICacheEntryDescriptor ** result)
{
NS_ENSURE_ARG_POINTER(request && result);
nsCacheEntryDescriptor * descriptor =
new nsCacheEntryDescriptor(this, accessGranted);
if (descriptor == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
// XXX check request is on q
PR_REMOVE_AND_INIT_LINK(request);
PR_APPEND_LINK(descriptor, &mDescriptorQ);
NS_ADDREF(*result = descriptor);
return NS_OK;
}
nsresult
nsCacheEntry::Open(nsCacheRequest * request, nsICacheEntryDescriptor ** result)
{
if (!request) return NS_ERROR_NULL_POINTER;
nsCacheAccessMode accessGranted;
nsresult rv = CommonOpen(request, &accessGranted);
nsresult rv = RequestAccess(request, &accessGranted);
if (NS_SUCCEEDED(rv)) {
// rv = nsCacheEntryDescriptor::Create(this, accessGranted, result);
@@ -224,12 +249,12 @@ nsCacheEntry::Open(nsCacheRequest * request, nsICacheEntryDescriptor ** result)
if (NS_SUCCEEDED(rv)) {
// queue the descriptor
PR_APPEND_LINK((descriptor)->GetListNode(), &mDescriptorQ);
PR_APPEND_LINK(descriptor, &mDescriptorQ);
}
} else if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
// queue request
PR_APPEND_LINK(request->GetListNode(), &mRequestQ);
PR_APPEND_LINK(request, &mRequestQ);
// XXX allocate PRCondVar for request, if none
// XXX release service lock
// XXX wait until valid or doomed
@@ -244,7 +269,7 @@ nsCacheEntry::AsyncOpen(nsCacheRequest * request)
if (!request) return NS_ERROR_NULL_POINTER;
nsCacheAccessMode accessGranted;
nsresult rv = CommonOpen(request, &accessGranted);
nsresult rv = RequestAccess(request, &accessGranted);
if (NS_SUCCEEDED(rv)) {
nsICacheEntryDescriptor * descriptor;
rv = nsCacheEntryDescriptor::Create(this, accessGranted, &descriptor);
@@ -263,7 +288,7 @@ PRBool
nsCacheEntry::RemoveRequest(nsCacheRequest * request)
{
// XXX if debug: verify this request belongs to this entry
PR_REMOVE_AND_INIT_LINK(request->GetListNode());
PR_REMOVE_AND_INIT_LINK(request);
// return true if this entry should stay active
return !((PR_CLIST_IS_EMPTY(&mRequestQ)) &&
@@ -275,7 +300,7 @@ PRBool
nsCacheEntry::RemoveDescriptor(nsCacheEntryDescriptor * descriptor)
{
// XXX if debug: verify this descriptor belongs to this entry
PR_REMOVE_AND_INIT_LINK(descriptor->GetListNode());
PR_REMOVE_AND_INIT_LINK(descriptor);
if (!PR_CLIST_IS_EMPTY(&mDescriptorQ))
return PR_TRUE; // stay active if we still have open descriptors

View File

@@ -42,7 +42,7 @@ class nsCacheRequest;
class nsCacheEntryDescriptor;
class nsCacheEntry
class nsCacheEntry : public PRCList
{
public:
@@ -137,16 +137,15 @@ public:
PR_CLIST_IS_EMPTY(&mDescriptorQ)); }
// methods for nsCacheService
nsresult RequestAccess( nsCacheRequest * request, nsCacheAccessMode *accessGranted);
nsresult CreateDescriptor( nsCacheRequest * request,
nsCacheAccessMode accessGranted,
nsICacheEntryDescriptor ** result);
nsresult Open(nsCacheRequest *request, nsICacheEntryDescriptor ** result);
nsresult AsyncOpen(nsCacheRequest *request);
PRBool RemoveRequest( nsCacheRequest * request);
PRBool RemoveDescriptor( nsCacheEntryDescriptor * descriptor);
PRCList* GetListNode(void) { return &mListLink; }
static nsCacheEntry* GetInstance(PRCList* qp) {
return (nsCacheEntry*) ((char*)qp - offsetof(nsCacheEntry, mListLink));
}
private:
friend class nsCacheEntryHashTable;
@@ -160,7 +159,6 @@ private:
void MarkActive() { mFlags |= eActiveMask; }
void MarkInactive() { mFlags &= ~eActiveMask; }
PRCList mListLink; // 8 for holding entry on various lists
nsCString * mKey; // 4 // XXX ask scc about const'ness
PRUint32 mFetchCount; // 4
PRUint32 mLastFetched; // 8
@@ -196,6 +194,7 @@ public:
nsresult RemoveEntry( nsCacheEntry *entry);
// XXX enumerate entries?
// XXX
private:
// PLDHashTable operation callbacks

View File

@@ -36,7 +36,7 @@ nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry,
: mCacheEntry(entry), mAccessGranted(accessGranted)
{
NS_INIT_ISUPPORTS();
PR_INIT_CLIST(&mListLink);
PR_INIT_CLIST(this);
}

View File

@@ -29,6 +29,7 @@
#include "nsCacheEntry.h"
class nsCacheEntryDescriptor :
public PRCList,
public nsICacheEntryDescriptor,
public nsITransport
{
@@ -43,14 +44,6 @@ public:
static nsresult Create(nsCacheEntry * entry, nsCacheAccessMode accessGranted,
nsICacheEntryDescriptor ** result);
/**
* routines for manipulating descriptors in PRCLists
*/
PRCList* GetListNode(void) { return &mListLink; }
static nsCacheEntryDescriptor* GetInstance(PRCList* qp) {
return (nsCacheEntryDescriptor*)
((char*)qp - offsetof(nsCacheEntryDescriptor, mListLink));
}
/**
* utility method to attempt changing data size of associated entry
@@ -64,7 +57,6 @@ public:
protected:
PRCList mListLink;
nsCacheEntry * mCacheEntry; // we are a child of the entry
nsCacheAccessMode mAccessGranted;
nsCOMPtr<nsITransport> mTransport;

View File

@@ -28,9 +28,10 @@
#include "nsCOMPtr.h"
#include "nsICache.h"
#include "nsICacheListener.h"
#include "nsIEventQueue.h"
class nsCacheRequest
class nsCacheRequest : public PRCList
{
private:
friend class nsCacheService;
@@ -43,37 +44,106 @@ private:
nsCacheStoragePolicy storagePolicy)
: mKey(key),
mInfo(0),
mListener(listener),
mAccessRequested(accessRequested),
mStreamBased(streamBased),
mStoragePolicy(storagePolicy)
mEventQ(nsnull),
mLock(nsnull),
mCondVar(nsnull)
{
mRequestThread = PR_GetCurrentThread();
PR_INIT_CLIST(&mListLink);
PR_INIT_CLIST(this);
SetAccessRequested(accessRequested);
if (streamBased) MarkStreamBased();
SetStoragePolicy(storagePolicy);
}
~nsCacheRequest()
{
delete mKey;
NS_ASSERTION(PR_CLIST_IS_EMPTY(&mListLink), "request still on a list");
NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "request still on a list");
}
/**
* Simple Accessors
*/
enum CacheRequestInfo {
eAccessRequestedMask = 0xFF000000,
eStoragePolicyMask = 0x00FF0000,
eStreamBasedMask = 0x00000010,
eWaitingForValidationMask = 0x00000001
};
PRCList* GetListNode(void) { return &mListLink; }
static nsCacheRequest* GetInstance(PRCList* qp) {
return (nsCacheRequest*)
((char*)qp - offsetof(nsCacheRequest, mListLink));
void SetAccessRequested(nsCacheAccessMode mode)
{
NS_ASSERTION(mode <= 0xFF, "too many bits in nsCacheAccessMode");
mInfo &= ~eAccessRequestedMask;
mInfo |= mode << 24;
}
nsCacheAccessMode AccessRequested()
{
return (nsCacheAccessMode)((mInfo >> 24) & 0xFF);
}
void MarkStreamBased() { mInfo |= eStreamBasedMask; }
PRBool IsStreamBased() { return (mInfo & eStreamBasedMask) != 0; }
void SetStoragePolicy(nsCacheStoragePolicy policy)
{
NS_ASSERTION(policy <= 0xFF, "too many bits in nsCacheStoragePolicy");
mInfo &= ~eStoragePolicyMask; // clear storage policy bits
mInfo |= policy << 16; // or in new bits
}
nsCacheStoragePolicy StoragePolicy()
{
return (nsCacheStoragePolicy)((mInfo >> 16) & 0xFF);
}
void MarkWaitingForValidation() { mInfo |= eWaitingForValidationMask; }
void DoneWaitingForValidation() { mInfo &= ~eWaitingForValidationMask; }
PRBool WaitingForValidation()
{
return (mInfo & eWaitingForValidationMask) != 0;
}
nsresult
WaitForValidation(void)
{
if (!mLock) {
mLock = PR_NewLock();
if (!mLock) return NS_ERROR_OUT_OF_MEMORY;
NS_ASSERTION(!mCondVar,"we have mCondVar, but didn't have mLock?");
mCondVar = PR_NewCondVar(mLock);
if (!mCondVar) {
PR_DestroyLock(mLock);
return NS_ERROR_OUT_OF_MEMORY;
}
}
PRStatus status;
PR_Lock(mLock);
while (WaitingForValidation() && (status == PR_SUCCESS) ) {
status = PR_WaitCondVar(mCondVar, PR_INTERVAL_NO_TIMEOUT);
}
PR_Unlock(mLock);
NS_ASSERTION(status == PR_SUCCESS, "PR_WaitCondVar() returned PR_FAILURE?");
if (status == PR_FAILURE)
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
/**
* Data members
*/
nsCString * mKey;
PRUint32 mInfo;
nsCOMPtr<nsICacheListener> mListener;
nsCacheAccessMode mAccessRequested;
PRBool mStreamBased;
nsCacheStoragePolicy mStoragePolicy;
PRThread * mRequestThread;
PRCList mListLink;
nsCOMPtr<nsIEventQueue> mEventQ;
PRLock * mLock;
PRCondVar * mCondVar;
};
#endif // _nsCacheRequest_h_

View File

@@ -31,6 +31,10 @@
#include "nsDiskCacheDevice.h"
#include "nsAutoLock.h"
#include "nsVoidArray.h"
#include "nsIEventQueueService.h"
#include "nsIEventQueue.h"
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
nsCacheService * nsCacheService::gService = nsnull;
@@ -201,10 +205,87 @@ nsCacheService::CreateRequest(nsCacheSession * session,
return NS_ERROR_OUT_OF_MEMORY;
}
if (!listener) return NS_OK; // we're sync, we're done.
// get the nsIEventQueue for the request's thread
nsresult rv;
// XXX can we just keep a reference so we don't have to do this everytime?
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
if (NS_FAILED(rv)) goto error;
rv = eventQService->ResolveEventQueue(NS_CURRENT_EVENTQ,
getter_AddRefs((*request)->mEventQ));
if (NS_FAILED(rv)) goto error;
if (!(*request)->mEventQ) {
rv = NS_ERROR_UNEXPECTED; // XXX what is the right error?
goto error;
}
return NS_OK;
}
error:
delete *request;
*request = nsnull;
return rv;
}
nsresult
nsCacheService::OpenCacheEntry(nsCacheSession * session,
const char * key,
nsCacheAccessMode accessRequested,
nsICacheListener * listener,
nsICacheEntryDescriptor ** result)
{
if (*result)
*result = nsnull;
nsCacheRequest * request = nsnull;
nsCacheEntry * entry = nsnull;
nsCacheAccessMode accessGranted = nsICache::ACCESS_NONE;
nsresult rv = CreateRequest(session, key, accessRequested, listener, &request);
if (NS_FAILED(rv)) return rv;
nsAutoLock cacheService(mCacheServiceLock);
while(1) { // Activate entry loop
rv = ActivateEntry(request, &entry); // get the entry for this request
if (NS_FAILED(rv)) break;
while(1) { // Request Access loop
NS_ASSERTION(entry, "no entry in Request Access loop!");
rv = entry->RequestAccess(request, &accessGranted);
if (rv != NS_ERROR_CACHE_WAIT_FOR_VALIDATION) break;
if (listener) // async exits - validate, doom, or close will resume
return rv;
cacheService.unlock();
rv = request->WaitForValidation();
cacheService.lock();
if (NS_FAILED(rv)) break;
// okay, we're ready to process this request, request access again
}
if (rv != NS_ERROR_CACHE_ENTRY_DOOMED) break;
}
nsICacheEntryDescriptor * descriptor;
rv = entry->CreateDescriptor(request, accessGranted, &descriptor);
if (listener) {
// XXX call listener to report error or descriptor
} else {
*result = descriptor;
}
delete request;
return rv;
}
#if 0
nsresult
nsCacheService::OpenCacheEntry(nsCacheSession * session,
const char * key,
@@ -244,7 +325,7 @@ nsCacheService::AsyncOpenCacheEntry(nsCacheSession * session,
{
if (!mCacheServiceLock) return NS_ERROR_NOT_INITIALIZED;
if (!listener) return NS_ERROR_NULL_POINTER;
nsCacheRequest * request = nsnull;
nsCacheEntry * entry = nsnull;
@@ -258,7 +339,7 @@ nsCacheService::AsyncOpenCacheEntry(nsCacheSession * session,
return rv;
}
#endif
nsresult
nsCacheService::ActivateEntry(nsCacheRequest * request,
@@ -276,18 +357,18 @@ nsCacheService::ActivateEntry(nsCacheRequest * request,
if (!entry) {
// search cache devices for entry
entry = SearchCacheDevices(request->mKey, request->mStoragePolicy);
entry = SearchCacheDevices(request->mKey, request->StoragePolicy());
if (entry) entry->MarkInitialized();
}
if (!entry && !(request->mAccessRequested & nsICache::ACCESS_WRITE)) {
if (!entry && !(request->AccessRequested() & nsICache::ACCESS_WRITE)) {
// this is a READ-ONLY request
rv = NS_ERROR_CACHE_KEY_NOT_FOUND;
goto error;
}
if (entry &&
((request->mAccessRequested == nsICache::ACCESS_WRITE) ||
((request->AccessRequested() == nsICache::ACCESS_WRITE) ||
(entry->mExpirationTime &&
entry->mExpirationTime < ConvertPRTimeToSeconds(PR_Now()))))
// XXX beginning to look a lot like lisp
@@ -306,8 +387,8 @@ nsCacheService::ActivateEntry(nsCacheRequest * request,
if (!entry) {
entry = new nsCacheEntry(request->mKey,
request->mStreamBased,
request->mStoragePolicy);
request->IsStreamBased(),
request->StoragePolicy());
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
@@ -411,10 +492,12 @@ nsCacheService::DoomEntry_Internal(nsCacheEntry * entry)
}
}
// put on doom list to wait for descriptors to close
NS_ASSERTION(PR_CLIST_IS_EMPTY(entry->GetListNode()),
NS_ASSERTION(PR_CLIST_IS_EMPTY(entry),
"doomed entry still on device list");
PR_APPEND_LINK(entry->GetListNode(), &mDoomedEntries);
PR_APPEND_LINK(entry, &mDoomedEntries);
// XXX reprocess pending requests
return rv;
}
@@ -464,7 +547,9 @@ nsCacheService::CloseDescriptor(nsCacheEntryDescriptor * descriptor)
// ask entry to remove descriptor
nsCacheEntry * entry = descriptor->CacheEntry();
PRBool stillActive = entry->RemoveDescriptor(descriptor);
// XXX if (!entry->IsValid()) process pending requests
if (!stillActive) {
DeactivateEntry(entry);
}
@@ -479,7 +564,7 @@ nsCacheService::DeactivateEntry(nsCacheEntry * entry)
if (entry->IsDoomed()) {
// remove from Doomed list
PR_REMOVE_AND_INIT_LINK(entry->GetListNode());
PR_REMOVE_AND_INIT_LINK(entry);
} else {
if (entry->IsActive()) {
// remove from active entries

View File

@@ -57,6 +57,13 @@ public:
/**
* Methods called by nsCacheSession
*/
nsresult OpenCacheEntry(nsCacheSession * session,
const char * key,
nsCacheAccessMode accessRequested,
nsICacheListener * listener,
nsICacheEntryDescriptor ** result);
#if 0
nsresult OpenCacheEntry(nsCacheSession * session,
const char * clientKey,
nsCacheAccessMode accessRequested,
@@ -66,7 +73,7 @@ public:
const char * key,
nsCacheAccessMode accessRequested,
nsICacheListener * listener);
#endif
/**
* Methods called by nsCacheEntryDescriptor
*/

View File

@@ -52,10 +52,13 @@ nsCacheSession::OpenCacheEntry(const char * key,
nsCacheAccessMode accessRequested,
nsICacheEntryDescriptor ** result)
{
return nsCacheService::GlobalInstance()->OpenCacheEntry(this,
key,
accessRequested,
result);
nsresult rv;
rv = nsCacheService::GlobalInstance()->OpenCacheEntry(this,
key,
accessRequested,
nsnull, // no listener
result);
return rv;
}
@@ -63,8 +66,13 @@ NS_IMETHODIMP nsCacheSession::AsyncOpenCacheEntry(const char *key,
nsCacheAccessMode accessRequested,
nsICacheListener *listener)
{
return nsCacheService::GlobalInstance()->AsyncOpenCacheEntry(this,
key,
accessRequested,
listener);
nsresult rv;
rv = nsCacheService::GlobalInstance()->OpenCacheEntry(this,
key,
accessRequested,
listener,
nsnull); // no result
if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) rv = NS_OK;
return rv;
}

View File

@@ -67,8 +67,8 @@ nsMemoryCacheDevice::FindEntry(nsCString * key)
if (!entry) return nsnull;
// move entry to the tail of the eviction list
PR_REMOVE_AND_INIT_LINK(entry->GetListNode());
PR_APPEND_LINK(entry->GetListNode(), &mEvictionList);
PR_REMOVE_AND_INIT_LINK(entry);
PR_APPEND_LINK(entry, &mEvictionList);
return entry;;
}
@@ -98,15 +98,15 @@ nsMemoryCacheDevice::DeactivateEntry(nsCacheEntry * entry)
nsresult
nsMemoryCacheDevice::BindEntry(nsCacheEntry * entry)
{
NS_ASSERTION(PR_CLIST_IS_EMPTY(entry->GetListNode()),"entry is already on a list!");
NS_ASSERTION(PR_CLIST_IS_EMPTY(entry),"entry is already on a list!");
// append entry to the eviction list
PR_APPEND_LINK(entry->GetListNode(), &mEvictionList);
PR_APPEND_LINK(entry, &mEvictionList);
// add entry to hashtable of mem cache entries
nsresult rv = mMemCacheEntries.AddEntry(entry);
if (NS_FAILED(rv)) {
PR_REMOVE_AND_INIT_LINK(entry->GetListNode());
PR_REMOVE_AND_INIT_LINK(entry);
return rv;
}
@@ -123,7 +123,7 @@ nsMemoryCacheDevice::DoomEntry(nsCacheEntry * entry)
if (NS_FAILED(rv)) return rv;
// remove entry from our eviction list
PR_REMOVE_AND_INIT_LINK(entry->GetListNode());
PR_REMOVE_AND_INIT_LINK(entry);
return NS_OK;
}