mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Fix bug 79585 "need non-blocking OpenCacheEntry() for HTTP", r=pavlov, sr=darin.
This commit is contained in:
parent
50404b6290
commit
893e8e0225
@ -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
vendored
26
netwerk/cache/public/nsICache.idl
vendored
@ -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
vendored
5
netwerk/cache/public/nsICacheSession.idl
vendored
@ -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.
|
||||
|
3
netwerk/cache/src/nsCacheEntry.cpp
vendored
3
netwerk/cache/src/nsCacheEntry.cpp
vendored
@ -97,7 +97,8 @@ 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,
|
||||
|
9
netwerk/cache/src/nsCacheRequest.h
vendored
9
netwerk/cache/src/nsCacheRequest.h
vendored
@ -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
|
||||
};
|
||||
|
||||
@ -95,6 +98,10 @@ private:
|
||||
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)
|
||||
{
|
||||
NS_ASSERTION(policy <= 0xFF, "too many bits in nsCacheStoragePolicy");
|
||||
|
41
netwerk/cache/src/nsCacheService.cpp
vendored
41
netwerk/cache/src/nsCacheService.cpp
vendored
@ -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,
|
||||
@ -568,6 +557,7 @@ nsCacheService::NotifyListener(nsCacheRequest * request,
|
||||
|
||||
nsresult
|
||||
nsCacheService::ProcessRequest(nsCacheRequest * request,
|
||||
PRBool calledFromOpenCacheEntry,
|
||||
nsICacheEntryDescriptor ** result)
|
||||
{
|
||||
// !!! must be called with mCacheServiceLock held !!!
|
||||
@ -589,13 +579,14 @@ nsCacheService::ProcessRequest(nsCacheRequest * request,
|
||||
if (request->mListener) // async exits - validate, doom, or close will resume
|
||||
return rv;
|
||||
|
||||
// XXX allocate condvar for request if necessary
|
||||
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
|
||||
|
3
netwerk/cache/src/nsCacheService.h
vendored
3
netwerk/cache/src/nsCacheService.h
vendored
@ -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);
|
||||
|
||||
@ -137,6 +139,7 @@ private:
|
||||
void DeactivateEntry(nsCacheEntry * entry);
|
||||
|
||||
nsresult ProcessRequest(nsCacheRequest * request,
|
||||
PRBool calledFromOpenCacheEntry,
|
||||
nsICacheEntryDescriptor ** result);
|
||||
|
||||
nsresult ProcessPendingRequests(nsCacheEntry * entry);
|
||||
|
3
netwerk/cache/src/nsCacheSession.cpp
vendored
3
netwerk/cache/src/nsCacheSession.cpp
vendored
@ -68,12 +68,14 @@ NS_IMETHODIMP nsCacheSession::SetDoomEntriesIfExpired(PRBool doomEntriesIfExpire
|
||||
NS_IMETHODIMP
|
||||
nsCacheSession::OpenCacheEntry(const char * key,
|
||||
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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user