Bug 1247644 - Don't do any I/O on doomed and unused HTTP cache entries, r=michal

This commit is contained in:
Honza Bambas 2016-02-12 14:45:00 +01:00
parent 48b434174d
commit 1c6a5ba1fc
10 changed files with 70 additions and 13 deletions

View File

@ -928,6 +928,13 @@ void CacheEntry::OnHandleClosed(CacheEntryHandle const* aHandle)
mozilla::MutexAutoLock lock(mLock);
if (IsDoomed() && mHandlesCount == 0 && NS_SUCCEEDED(mFileStatus)) {
// This entry is no longer referenced from outside and is doomed.
// Tell the file to kill the handle, i.e. bypass any I/O operations
// on it except removing the file.
mFile->Kill();
}
if (mWriter != aHandle) {
LOG((" not the writer"));
return;
@ -1117,8 +1124,10 @@ NS_IMETHODIMP CacheEntry::OpenInputStream(int64_t offset, nsIInputStream * *_ret
nsresult rv;
RefPtr<CacheEntryHandle> selfHandle = NewHandle();
nsCOMPtr<nsIInputStream> stream;
rv = mFile->OpenInputStream(getter_AddRefs(stream));
rv = mFile->OpenInputStream(selfHandle, getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISeekableStream> seekable =

View File

@ -194,6 +194,7 @@ CacheFile::CacheFile()
, mPreloadChunkCount(0)
, mStatus(NS_OK)
, mDataSize(-1)
, mKill(false)
, mOutput(nullptr)
{
LOG(("CacheFile::CacheFile() [this=%p]", this));
@ -204,7 +205,7 @@ CacheFile::~CacheFile()
LOG(("CacheFile::~CacheFile() [this=%p]", this));
MutexAutoLock lock(mLock);
if (!mMemoryOnly && mReady) {
if (!mMemoryOnly && mReady && !mKill) {
// mReady flag indicates we have metadata plus in a valid state.
WriteMetadataIfNeededLocked(true);
}
@ -703,8 +704,18 @@ CacheFile::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult)
return NS_ERROR_UNEXPECTED;
}
bool CacheFile::IsKilled()
{
bool killed = mKill;
if (killed) {
LOG(("CacheFile is killed, this=%p", this));
}
return killed;
}
nsresult
CacheFile::OpenInputStream(nsIInputStream **_retval)
CacheFile::OpenInputStream(nsICacheEntry *aEntryHandle, nsIInputStream **_retval)
{
CacheFileAutoLock lock(this);
@ -735,7 +746,7 @@ CacheFile::OpenInputStream(nsIInputStream **_retval)
// the last input stream is closed.
mPreloadWithoutInputStreams = false;
CacheFileInputStream *input = new CacheFileInputStream(this);
CacheFileInputStream *input = new CacheFileInputStream(this, aEntryHandle);
LOG(("CacheFile::OpenInputStream() - Creating new input stream %p [this=%p]",
input, this));
@ -907,6 +918,9 @@ nsresult
CacheFile::SetElement(const char *aKey, const char *aValue)
{
CacheFileAutoLock lock(this);
LOG(("CacheFile::SetElement() this=%p", this));
MOZ_ASSERT(mMetadata);
NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED);
@ -941,6 +955,10 @@ nsresult
CacheFile::SetExpirationTime(uint32_t aExpirationTime)
{
CacheFileAutoLock lock(this);
LOG(("CacheFile::SetExpirationTime() this=%p, expiration=%u",
this, aExpirationTime));
MOZ_ASSERT(mMetadata);
NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED);
@ -966,6 +984,10 @@ nsresult
CacheFile::SetFrecency(uint32_t aFrecency)
{
CacheFileAutoLock lock(this);
LOG(("CacheFile::SetFrecency() this=%p, frecency=%u",
this, aFrecency));
MOZ_ASSERT(mMetadata);
NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED);
@ -1021,6 +1043,9 @@ nsresult
CacheFile::OnFetched()
{
CacheFileAutoLock lock(this);
LOG(("CacheFile::OnFetched() this=%p", this));
MOZ_ASSERT(mMetadata);
NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED);

View File

@ -74,15 +74,17 @@ public:
NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) override;
NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) override;
NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) override;
virtual bool IsKilled() override;
NS_IMETHOD OnMetadataRead(nsresult aResult) override;
NS_IMETHOD OnMetadataWritten(nsresult aResult) override;
NS_IMETHOD OpenInputStream(nsIInputStream **_retval);
NS_IMETHOD OpenInputStream(nsICacheEntry *aCacheEntryHandle, nsIInputStream **_retval);
NS_IMETHOD OpenOutputStream(CacheOutputCloseListener *aCloseListener, nsIOutputStream **_retval);
NS_IMETHOD SetMemoryOnly();
NS_IMETHOD Doom(CacheFileListener *aCallback);
void Kill() { mKill = true; }
nsresult ThrowMemoryCachedData();
// metadata forwarders
@ -198,6 +200,7 @@ private:
RefPtr<CacheFileMetadata> mMetadata;
nsCOMPtr<CacheFileListener> mListener;
nsCOMPtr<CacheFileIOListener> mDoomAfterOpenListener;
Atomic<bool, Relaxed> mKill;
nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mChunks;
nsClassHashtable<nsUint32HashKey, ChunkListeners> mChunkListeners;

View File

@ -594,6 +594,12 @@ CacheFileChunk::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult)
return NS_ERROR_UNEXPECTED;
}
bool
CacheFileChunk::IsKilled()
{
return mFile->IsKilled();
}
bool
CacheFileChunk::IsReady() const
{

View File

@ -94,6 +94,7 @@ public:
NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) override;
NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) override;
NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) override;
virtual bool IsKilled() override;
bool IsReady() const;
bool IsDirty() const;

View File

@ -663,7 +663,7 @@ public:
{
nsresult rv;
if (mHandle->IsClosed()) {
if (mHandle->IsClosed() || (mCallback && mCallback->IsKilled())) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->ReadInternal(
@ -713,7 +713,7 @@ public:
{
nsresult rv;
if (mHandle->IsClosed()) {
if (mHandle->IsClosed() || (mCallback && mCallback->IsKilled())) {
// We usually get here only after the internal shutdown
// (i.e. mShuttingDown == true). Pretend write has succeeded
// to avoid any past-shutdown file dooming.
@ -886,7 +886,7 @@ public:
{
nsresult rv;
if (mHandle->IsClosed()) {
if (mHandle->IsClosed() || (mCallback && mCallback->IsKilled())) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->TruncateSeekSetEOFInternal(
@ -1919,7 +1919,7 @@ CacheFileIOManager::Write(CacheFileHandle *aHandle, int64_t aOffset,
nsresult rv;
RefPtr<CacheFileIOManager> ioMan = gInstance;
if (aHandle->IsClosed() || !ioMan) {
if (aHandle->IsClosed() || (aCallback && aCallback->IsKilled()) || !ioMan) {
if (!aCallback) {
// When no callback is provided, CacheFileIOManager is responsible for
// releasing the buffer. We must release it even in case of failure.
@ -2329,7 +2329,7 @@ CacheFileIOManager::TruncateSeekSetEOF(CacheFileHandle *aHandle,
nsresult rv;
RefPtr<CacheFileIOManager> ioMan = gInstance;
if (aHandle->IsClosed() || !ioMan) {
if (aHandle->IsClosed() || (aCallback && aCallback->IsKilled()) || !ioMan) {
return NS_ERROR_NOT_INITIALIZED;
}
@ -3791,6 +3791,8 @@ CacheFileIOManager::CreateCacheTree()
nsresult
CacheFileIOManager::OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate)
{
LOG(("CacheFileIOManager::OpenNSPRHandle BEGIN, handle=%p", aHandle));
MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased());
MOZ_ASSERT(!aHandle->mFD);
MOZ_ASSERT(mHandlesByLastUsed.IndexOf(aHandle) == mHandlesByLastUsed.NoIndex);
@ -3860,6 +3862,9 @@ CacheFileIOManager::OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate)
}
mHandlesByLastUsed.AppendElement(aHandle);
LOG(("CacheFileIOManager::OpenNSPRHandle END, handle=%p", aHandle));
return NS_OK;
}

View File

@ -234,6 +234,8 @@ public:
NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) = 0;
NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) = 0;
NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) = 0;
virtual bool IsKilled() { return false; }
};
NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileIOListener, CACHEFILEIOLISTENER_IID)

View File

@ -42,7 +42,7 @@ NS_INTERFACE_MAP_BEGIN(CacheFileInputStream)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END_THREADSAFE
CacheFileInputStream::CacheFileInputStream(CacheFile *aFile)
CacheFileInputStream::CacheFileInputStream(CacheFile *aFile, nsISupports *aEntry)
: mFile(aFile)
, mPos(0)
, mClosed(false)
@ -50,6 +50,7 @@ CacheFileInputStream::CacheFileInputStream(CacheFile *aFile)
, mWaitingForUpdate(false)
, mListeningForChunk(-1)
, mCallbackFlags(0)
, mCacheEntryHandle(aEntry)
{
LOG(("CacheFileInputStream::CacheFileInputStream() [this=%p]", this));
MOZ_COUNT_CTOR(CacheFileInputStream);
@ -240,6 +241,8 @@ CacheFileInputStream::CloseWithStatusLocked(nsresult aStatus)
MaybeNotifyListener();
mFile->ReleaseOutsideLock(mCacheEntryHandle.forget());
return NS_OK;
}

View File

@ -11,7 +11,6 @@
#include "nsAutoPtr.h"
#include "CacheFileChunk.h"
namespace mozilla {
namespace net {
@ -27,7 +26,7 @@ class CacheFileInputStream : public nsIAsyncInputStream
NS_DECL_NSISEEKABLESTREAM
public:
explicit CacheFileInputStream(CacheFile *aFile);
explicit CacheFileInputStream(CacheFile *aFile, nsISupports *aEntry);
NS_IMETHOD OnChunkRead(nsresult aResult, CacheFileChunk *aChunk) override;
NS_IMETHOD OnChunkWritten(nsresult aResult, CacheFileChunk *aChunk) override;
@ -64,6 +63,8 @@ private:
nsCOMPtr<nsIInputStreamCallback> mCallback;
uint32_t mCallbackFlags;
nsCOMPtr<nsIEventTarget> mCallbackTarget;
// Held purely for referencing purposes
RefPtr<nsISupports> mCacheEntryHandle;
};

View File

@ -116,6 +116,7 @@ public:
NS_IMETHOD OnMetadataRead(nsresult aResult) = 0;
NS_IMETHOD OnMetadataWritten(nsresult aResult) = 0;
virtual bool IsKilled() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileMetadataListener,
@ -183,6 +184,7 @@ public:
NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) override;
NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) override;
NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) override;
virtual bool IsKilled() override { return mListener && mListener->IsKilled(); }
// Memory reporting
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;