Fix bug 79585 "need non-blocking OpenCacheEntry() for HTTP", r=pavlov, sr=darin.

This commit is contained in:
gordon%netscape.com 2001-05-09 03:36:00 +00:00
Родитель 50404b6290
Коммит 893e8e0225
8 изменённых файлов: 72 добавлений и 44 удалений

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

@ -144,7 +144,7 @@ PRBool imgCache::Put(nsIURI *aKey, imgRequest *request, nsICacheEntryDescriptor
nsCOMPtr<nsICacheEntryDescriptor> entry;
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_WRITE, getter_AddRefs(entry));
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_WRITE, nsICache::BLOCKING, getter_AddRefs(entry));
if (NS_FAILED(rv) || !entry)
return PR_FALSE;
@ -175,7 +175,7 @@ PRBool imgCache::Get(nsIURI *aKey, imgRequest **aRequest, nsICacheEntryDescripto
nsCOMPtr<nsICacheEntryDescriptor> entry;
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_READ, getter_AddRefs(entry));
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_READ, nsICache::BLOCKING, getter_AddRefs(entry));
if (NS_FAILED(rv) || !entry)
return PR_FALSE;
@ -209,7 +209,7 @@ PRBool imgCache::Remove(nsIURI *aKey)
nsCOMPtr<nsICacheEntryDescriptor> entry;
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_READ, getter_AddRefs(entry));
rv = ses->OpenCacheEntry(spec, nsICache::ACCESS_READ, nsICache::BLOCKING, getter_AddRefs(entry));
if (NS_FAILED(rv) || !entry)
return PR_FALSE;

26
netwerk/cache/public/nsICache.idl поставляемый
Просмотреть файл

@ -139,6 +139,18 @@ interface nsICache
*/
const long NOT_STREAM_BASED = 0;
const long STREAM_BASED = 1;
/**
* The synchronous OpenCacheEntry() may be blocking or non-blocking. If a cache entry is
* waiting to be validated by another cache descriptor (so no new cache descriptors for that
* key can be created, OpenCacheEntry() will return NS_ERROR_CACHE_WAIT_FOR_VALIDATION in
* non-blocking mode. In blocking mode, it will wait until the cache entry for the key has
* been validated or doomed. If the cache entry is validated, then a descriptor for that
* entry will be created and returned. If the cache entry was doomed, then a descriptor
* will be created for a new cache entry for the key.
*/
const long NON_BLOCKING = 0;
const long BLOCKING = 1;
};
@ -147,12 +159,12 @@ interface nsICache
/**
* Cache specific nsresult error codes
*/
#define NS_ERROR_CACHE_KEY_NOT_FOUND NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 60)
#define NS_ERROR_CACHE_DATA_IS_STREAM NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 61)
#define NS_ERROR_CACHE_DATA_IS_NOT_STREAM NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 62)
#define NS_ERROR_CACHE_WAIT_FOR_VALIDATION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 63)
#define NS_ERROR_CACHE_ENTRY_DOOMED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 64)
#define NS_ERROR_CACHE_READ_ACCESS_DENIED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 65)
#define NS_ERROR_CACHE_WRITE_ACCESS_DENIED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 66)
#define NS_ERROR_CACHE_KEY_NOT_FOUND NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 61)
#define NS_ERROR_CACHE_DATA_IS_STREAM NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 62)
#define NS_ERROR_CACHE_DATA_IS_NOT_STREAM NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 63)
#define NS_ERROR_CACHE_WAIT_FOR_VALIDATION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 64)
#define NS_ERROR_CACHE_ENTRY_DOOMED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 65)
#define NS_ERROR_CACHE_READ_ACCESS_DENIED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 66)
#define NS_ERROR_CACHE_WRITE_ACCESS_DENIED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 67)
%}

5
netwerk/cache/public/nsICacheSession.idl поставляемый
Просмотреть файл

@ -50,10 +50,11 @@ interface nsICacheSession : nsISupports
* Synchronous cache access. This returns a unique descriptor each
* time it is called, even if the same key is specified. When
* called by multiple threads for write access, only one writable
* descriptor will be granted.
* descriptor will be granted. If 'blocking' is set to false,
*/
nsICacheEntryDescriptor openCacheEntry(in string key,
in nsCacheAccessMode accessRequested);
in nsCacheAccessMode accessRequested,
in boolean blockingMode);
/**
* Asynchronous cache access. Does not block the calling thread.

5
netwerk/cache/src/nsCacheEntry.cpp поставляемый
Просмотреть файл

@ -97,8 +97,9 @@ nsCacheEntry::~nsCacheEntry()
}
nsISupports * data = mData;
NS_ADDREF(data);
NS_ADDREF(data); // this reference will be owned by the event
mData = nsnull; // release our reference before switching threads
PL_InitEvent(event,
data,
CacheElementReleaseEventHandler,

13
netwerk/cache/src/nsCacheRequest.h поставляемый
Просмотреть файл

@ -41,6 +41,7 @@ private:
nsCacheRequest( nsCString * key,
nsICacheListener * listener,
nsCacheAccessMode accessRequested,
PRBool blockingMode,
nsCacheSession * session)
: mKey(key),
mInfo(0),
@ -54,6 +55,7 @@ private:
SetStoragePolicy(session->StoragePolicy());
if (session->IsStreamBased()) MarkStreamBased();
if (session->WillDoomEntriesIfExpired()) MarkDoomEntriesIfExpired();
if (blockingMode == nsICache::BLOCKING) MarkBlockingMode();
MarkWaitingForValidation();
}
@ -72,7 +74,8 @@ private:
eStoragePolicyMask = 0x000000FF,
eStreamBasedMask = 0x00000100,
eDoomEntriesIfExpiredMask = 0x00001000,
eWaitingForValidationMask = 0x00010000,
eBlockingModeMask = 0x00010000,
eWaitingForValidationMask = 0x00100000,
eAccessRequestedMask = 0xFF000000
};
@ -92,8 +95,12 @@ private:
PRBool IsStreamBased() { return (mInfo & eStreamBasedMask) != 0; }
void MarkDoomEntriesIfExpired() { mInfo |= eDoomEntriesIfExpiredMask; }
PRBool WillDoomEntriesIfExpired() { return (mInfo & eDoomEntriesIfExpiredMask); }
void MarkDoomEntriesIfExpired() { mInfo |= eDoomEntriesIfExpiredMask; }
PRBool WillDoomEntriesIfExpired() { return (mInfo & eDoomEntriesIfExpiredMask); }
void MarkBlockingMode() { mInfo |= eBlockingModeMask; }
PRBool IsBlocking() { return (mInfo & eBlockingModeMask); }
PRBool IsNonBlocking() { return !(mInfo & eBlockingModeMask); }
void SetStoragePolicy(nsCacheStoragePolicy policy)
{

51
netwerk/cache/src/nsCacheService.cpp поставляемый
Просмотреть файл

@ -490,6 +490,7 @@ nsresult
nsCacheService::CreateRequest(nsCacheSession * session,
const char * clientKey,
nsCacheAccessMode accessRequested,
PRBool blockingMode,
nsICacheListener * listener,
nsCacheRequest ** request)
{
@ -504,7 +505,7 @@ nsCacheService::CreateRequest(nsCacheSession * session,
if (mMaxKeyLength < key->Length()) mMaxKeyLength = key->Length();
// create request
*request = new nsCacheRequest(key, listener, accessRequested, session);
*request = new nsCacheRequest(key, listener, accessRequested, blockingMode, session);
if (!*request) {
delete key;
return NS_ERROR_OUT_OF_MEMORY;
@ -514,19 +515,13 @@ nsCacheService::CreateRequest(nsCacheSession * session,
// get the nsIEventQueue for the request's thread
nsresult rv;
#if 0
// 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;
#endif
rv = mEventQService->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?
rv = NS_ERROR_NOT_AVAILABLE;
goto error;
}
@ -547,12 +542,6 @@ nsCacheService::NotifyListener(nsCacheRequest * request,
{
nsresult rv;
#if 0
// XXX can we hold onto the proxy object manager?
NS_WITH_SERVICE(nsIProxyObjectManager, proxyObjMgr, kProxyObjectManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
#endif
nsCOMPtr<nsICacheListener> listenerProxy;
NS_ASSERTION(request->mEventQ, "no event queue for async request!");
rv = mProxyObjectManager->GetProxyForObject(request->mEventQ,
@ -567,7 +556,8 @@ nsCacheService::NotifyListener(nsCacheRequest * request,
nsresult
nsCacheService::ProcessRequest(nsCacheRequest * request,
nsCacheService::ProcessRequest(nsCacheRequest * request,
PRBool calledFromOpenCacheEntry,
nsICacheEntryDescriptor ** result)
{
// !!! must be called with mCacheServiceLock held !!!
@ -587,15 +577,16 @@ nsCacheService::ProcessRequest(nsCacheRequest * request,
if (rv != NS_ERROR_CACHE_WAIT_FOR_VALIDATION) break;
if (request->mListener) // async exits - validate, doom, or close will resume
return rv;
return rv;
// XXX allocate condvar for request if necessary
PR_Unlock(mCacheServiceLock);
rv = request->WaitForValidation();
PR_Lock(mCacheServiceLock);
if (request->IsBlocking()) {
PR_Unlock(mCacheServiceLock);
rv = request->WaitForValidation();
PR_Lock(mCacheServiceLock);
}
PR_REMOVE_AND_INIT_LINK(request);
if (NS_FAILED(rv)) break;
if (NS_FAILED(rv)) break; // non-blocking mode returns WAIT_FOR_VALIDATION error
// okay, we're ready to process this request, request access again
}
if (rv != NS_ERROR_CACHE_ENTRY_DOOMED) break;
@ -613,6 +604,10 @@ nsCacheService::ProcessRequest(nsCacheRequest * request,
rv = entry->CreateDescriptor(request, accessGranted, getter_AddRefs(descriptor));
if (request->mListener) { // Asynchronous
if (NS_FAILED(rv) && calledFromOpenCacheEntry)
return rv; // skip notifying listener, just return rv to caller
// call listener to report error or descriptor
nsresult rv2 = NotifyListener(request, descriptor, accessGranted, rv);
if (NS_FAILED(rv2) && NS_SUCCEEDED(rv)) {
@ -629,6 +624,7 @@ nsresult
nsCacheService::OpenCacheEntry(nsCacheSession * session,
const char * key,
nsCacheAccessMode accessRequested,
PRBool blockingMode,
nsICacheListener * listener,
nsICacheEntryDescriptor ** result)
{
@ -638,11 +634,16 @@ nsCacheService::OpenCacheEntry(nsCacheSession * session,
nsCacheRequest * request = nsnull;
nsresult rv = CreateRequest(session, key, accessRequested, listener, &request);
nsAutoLock lock(mCacheServiceLock);
nsresult rv = CreateRequest(session,
key,
accessRequested,
blockingMode,
listener,
&request);
if (NS_FAILED(rv)) return rv;
nsAutoLock lock(mCacheServiceLock);
rv = ProcessRequest(request, result);
rv = ProcessRequest(request, PR_TRUE, result);
// delete requests that have completed
if (!(listener && (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)))
@ -1019,7 +1020,7 @@ nsCacheService::ProcessPendingRequests(nsCacheEntry * entry)
PR_REMOVE_AND_INIT_LINK(request);
if (entry->IsDoomed()) {
rv = ProcessRequest(request, nsnull);
rv = ProcessRequest(request, PR_FALSE, nsnull);
if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)
rv = NS_OK;
else

5
netwerk/cache/src/nsCacheService.h поставляемый
Просмотреть файл

@ -66,6 +66,7 @@ public:
nsresult OpenCacheEntry(nsCacheSession * session,
const char * key,
nsCacheAccessMode accessRequested,
PRBool blockingMode,
nsICacheListener * listener,
nsICacheEntryDescriptor ** result);
@ -120,6 +121,7 @@ private:
nsresult CreateRequest(nsCacheSession * session,
const char * clientKey,
nsCacheAccessMode accessRequested,
PRBool blockingMode,
nsICacheListener * listener,
nsCacheRequest ** request);
@ -136,7 +138,8 @@ private:
void DeactivateEntry(nsCacheEntry * entry);
nsresult ProcessRequest(nsCacheRequest * request,
nsresult ProcessRequest(nsCacheRequest * request,
PRBool calledFromOpenCacheEntry,
nsICacheEntryDescriptor ** result);
nsresult ProcessPendingRequests(nsCacheEntry * entry);

5
netwerk/cache/src/nsCacheSession.cpp поставляемый
Просмотреть файл

@ -67,13 +67,15 @@ NS_IMETHODIMP nsCacheSession::SetDoomEntriesIfExpired(PRBool doomEntriesIfExpire
NS_IMETHODIMP
nsCacheSession::OpenCacheEntry(const char * key,
nsCacheAccessMode accessRequested,
nsCacheAccessMode accessRequested,
PRBool blockingMode,
nsICacheEntryDescriptor ** result)
{
nsresult rv;
rv = nsCacheService::GlobalInstance()->OpenCacheEntry(this,
key,
accessRequested,
blockingMode,
nsnull, // no listener
result);
return rv;
@ -88,6 +90,7 @@ NS_IMETHODIMP nsCacheSession::AsyncOpenCacheEntry(const char *key,
rv = nsCacheService::GlobalInstance()->OpenCacheEntry(this,
key,
accessRequested,
nsICache::BLOCKING,
listener,
nsnull); // no result