author | Honza Bambas <honzab.moz@firemni.cz> |
Fri, 12 Feb 2016 14:45:00 +0100 | |
changeset 285392 | 74c396a8252c15c22b71d6e9f12614c8e44f49a3 |
parent 285391 | f72ada9941bbfe936e1d4704e28b950200884352 |
child 285393 | 4ca40a403e9d239733d4ac0890bb475760337732 |
push id | 30030 |
push user | cbook@mozilla.com |
push date | Thu, 25 Feb 2016 10:58:04 +0000 |
treeherder | mozilla-central@c1e0d1890cfe [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | michal |
bugs | 1247644 |
milestone | 47.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -923,16 +923,23 @@ CacheEntryHandle* CacheEntry::NewWriteHa } void CacheEntry::OnHandleClosed(CacheEntryHandle const* aHandle) { LOG(("CacheEntry::OnHandleClosed [this=%p, state=%s, handle=%p]", this, StateString(mState), 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; } if (mOutputStream) { LOG((" abandoning phantom output stream")); // No one took our internal output stream, so there are no data @@ -1112,18 +1119,20 @@ NS_IMETHODIMP CacheEntry::SetExpirationT NS_IMETHODIMP CacheEntry::OpenInputStream(int64_t offset, nsIInputStream * *_retval) { LOG(("CacheEntry::OpenInputStream [this=%p]", this)); NS_ENSURE_SUCCESS(mFileStatus, NS_ERROR_NOT_AVAILABLE); 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 = do_QueryInterface(stream, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, offset); NS_ENSURE_SUCCESS(rv, rv);
--- a/netwerk/cache2/CacheFile.cpp +++ b/netwerk/cache2/CacheFile.cpp @@ -189,27 +189,28 @@ CacheFile::CacheFile() , mPriority(false) , mDataAccessed(false) , mDataIsDirty(false) , mWritingMetadata(false) , mPreloadWithoutInputStreams(true) , mPreloadChunkCount(0) , mStatus(NS_OK) , mDataSize(-1) + , mKill(false) , mOutput(nullptr) { LOG(("CacheFile::CacheFile() [this=%p]", this)); } 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); } } nsresult CacheFile::Init(const nsACString &aKey, bool aCreateNew, @@ -698,18 +699,28 @@ CacheFile::OnEOFSet(CacheFileHandle *aHa nsresult CacheFile::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) { MOZ_CRASH("CacheFile::OnFileRenamed should not be called!"); 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); MOZ_ASSERT(mHandle || mMemoryOnly || mOpeningFile); if (!mReady) { LOG(("CacheFile::OpenInputStream() - CacheFile is not ready [this=%p]", this)); @@ -730,17 +741,17 @@ CacheFile::OpenInputStream(nsIInputStrea return mStatus; } // Once we open input stream we no longer allow preloading of chunks without // input stream, i.e. we will no longer keep first few chunks preloaded when // 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)); mInputs.AppendElement(input); NS_ADDREF(input); mDataAccessed = true; @@ -902,16 +913,19 @@ CacheFile::GetElement(const char *aKey, *_retval = NS_strdup(value); return NS_OK; } 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); PostWriteTimer(); return mMetadata->SetElement(aKey, aValue); } nsresult @@ -936,16 +950,20 @@ CacheFile::ElementsSize(uint32_t *_retva *_retval = mMetadata->ElementsSize(); return NS_OK; } 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); PostWriteTimer(); if (mHandle && !mHandle->IsDoomed()) CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, &aExpirationTime); @@ -961,16 +979,20 @@ CacheFile::GetExpirationTime(uint32_t *_ return mMetadata->GetExpirationTime(_retval); } 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); PostWriteTimer(); if (mHandle && !mHandle->IsDoomed()) CacheFileIOManager::UpdateIndexEntry(mHandle, &aFrecency, nullptr); @@ -1016,16 +1038,19 @@ CacheFile::GetFetchCount(uint32_t *_retv return mMetadata->GetFetchCount(_retval); } nsresult CacheFile::OnFetched() { CacheFileAutoLock lock(this); + + LOG(("CacheFile::OnFetched() this=%p", this)); + MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); PostWriteTimer(); return mMetadata->OnFetched(); }
--- a/netwerk/cache2/CacheFile.h +++ b/netwerk/cache2/CacheFile.h @@ -69,25 +69,27 @@ public: NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult) override; NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf, nsresult aResult) override; NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) override; 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 nsresult GetElement(const char *aKey, char **_retval); nsresult SetElement(const char *aKey, const char *aValue); nsresult VisitMetaData(nsICacheEntryMetaDataVisitor *aVisitor); nsresult ElementsSize(uint32_t *_retval); nsresult SetExpirationTime(uint32_t aExpirationTime); @@ -193,16 +195,17 @@ private: nsresult mStatus; int64_t mDataSize; nsCString mKey; RefPtr<CacheFileHandle> mHandle; RefPtr<CacheFileMetadata> mMetadata; nsCOMPtr<CacheFileListener> mListener; nsCOMPtr<CacheFileIOListener> mDoomAfterOpenListener; + Atomic<bool, Relaxed> mKill; nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mChunks; nsClassHashtable<nsUint32HashKey, ChunkListeners> mChunkListeners; nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mCachedChunks; nsTArray<CacheFileInputStream*> mInputs; CacheFileOutputStream *mOutput;
--- a/netwerk/cache2/CacheFileChunk.cpp +++ b/netwerk/cache2/CacheFileChunk.cpp @@ -590,16 +590,22 @@ CacheFileChunk::OnEOFSet(CacheFileHandle nsresult CacheFileChunk::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) { MOZ_CRASH("CacheFileChunk::OnFileRenamed should not be called!"); return NS_ERROR_UNEXPECTED; } bool +CacheFileChunk::IsKilled() +{ + return mFile->IsKilled(); +} + +bool CacheFileChunk::IsReady() const { mFile->AssertOwnsLock(); return (NS_SUCCEEDED(mStatus) && (mState == READY || mState == WRITING)); } bool
--- a/netwerk/cache2/CacheFileChunk.h +++ b/netwerk/cache2/CacheFileChunk.h @@ -89,16 +89,17 @@ public: NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult) override; NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf, nsresult aResult) override; NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) override; 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; nsresult GetStatus(); void SetError(nsresult aStatus); char * BufForWriting() const;
--- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -658,17 +658,17 @@ protected: MOZ_COUNT_DTOR(ReadEvent); } public: NS_IMETHOD Run() { nsresult rv; - if (mHandle->IsClosed()) { + if (mHandle->IsClosed() || (mCallback && mCallback->IsKilled())) { rv = NS_ERROR_NOT_INITIALIZED; } else { rv = CacheFileIOManager::gInstance->ReadInternal( mHandle, mOffset, mBuf, mCount); } mCallback->OnDataRead(mHandle, mBuf, rv); return NS_OK; @@ -708,17 +708,17 @@ protected: } } public: NS_IMETHOD Run() { 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. rv = (CacheFileIOManager::gInstance->IsPastShutdownIOLag() || CacheFileIOManager::gInstance->mShuttingDown) ? NS_OK : NS_ERROR_NOT_INITIALIZED; } else { @@ -881,17 +881,17 @@ protected: MOZ_COUNT_DTOR(TruncateSeekSetEOFEvent); } public: NS_IMETHOD Run() { nsresult rv; - if (mHandle->IsClosed()) { + if (mHandle->IsClosed() || (mCallback && mCallback->IsKilled())) { rv = NS_ERROR_NOT_INITIALIZED; } else { rv = CacheFileIOManager::gInstance->TruncateSeekSetEOFInternal( mHandle, mTruncatePos, mEOFPos); } if (mCallback) { mCallback->OnEOFSet(mHandle, rv); @@ -1914,17 +1914,17 @@ CacheFileIOManager::Write(CacheFileHandl { LOG(("CacheFileIOManager::Write() [handle=%p, offset=%lld, count=%d, " "validate=%d, truncate=%d, listener=%p]", aHandle, aOffset, aCount, aValidate, aTruncate, aCallback)); 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. free(const_cast<char *>(aBuf)); } return NS_ERROR_NOT_INITIALIZED; } @@ -2324,17 +2324,17 @@ CacheFileIOManager::TruncateSeekSetEOF(C CacheFileIOListener *aCallback) { LOG(("CacheFileIOManager::TruncateSeekSetEOF() [handle=%p, truncatePos=%lld, " "EOFPos=%lld, listener=%p]", aHandle, aTruncatePos, aEOFPos, aCallback)); nsresult rv; RefPtr<CacheFileIOManager> ioMan = gInstance; - if (aHandle->IsClosed() || !ioMan) { + if (aHandle->IsClosed() || (aCallback && aCallback->IsKilled()) || !ioMan) { return NS_ERROR_NOT_INITIALIZED; } RefPtr<TruncateSeekSetEOFEvent> ev = new TruncateSeekSetEOFEvent( aHandle, aTruncatePos, aEOFPos, aCallback); rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::WRITE); NS_ENSURE_SUCCESS(rv, rv); @@ -3786,16 +3786,18 @@ CacheFileIOManager::CreateCacheTree() } return NS_OK; } 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); MOZ_ASSERT(mHandlesByLastUsed.Length() <= kOpenHandlesLimit); MOZ_ASSERT((aCreate && !aHandle->mFileExists) || (!aCreate && aHandle->mFileExists)); nsresult rv; @@ -3855,16 +3857,19 @@ CacheFileIOManager::OpenNSPRHandle(Cache LOG((" file doesn't exists")); aHandle->mFileExists = false; return DoomFileInternal(aHandle); } NS_ENSURE_SUCCESS(rv, rv); } mHandlesByLastUsed.AppendElement(aHandle); + + LOG(("CacheFileIOManager::OpenNSPRHandle END, handle=%p", aHandle)); + return NS_OK; } void CacheFileIOManager::NSPRHandleUsed(CacheFileHandle *aHandle) { MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); MOZ_ASSERT(aHandle->mFD);
--- a/netwerk/cache2/CacheFileIOManager.h +++ b/netwerk/cache2/CacheFileIOManager.h @@ -229,16 +229,18 @@ public: NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult) = 0; NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf, nsresult aResult) = 0; NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) = 0; 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) class CacheFileIOManager : public nsITimerCallback { public:
--- a/netwerk/cache2/CacheFileInputStream.cpp +++ b/netwerk/cache2/CacheFileInputStream.cpp @@ -37,24 +37,25 @@ CacheFileInputStream::Release() NS_INTERFACE_MAP_BEGIN(CacheFileInputStream) NS_INTERFACE_MAP_ENTRY(nsIInputStream) NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream) NS_INTERFACE_MAP_ENTRY(nsISeekableStream) NS_INTERFACE_MAP_ENTRY(mozilla::net::CacheFileChunkListener) 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) , mStatus(NS_OK) , mWaitingForUpdate(false) , mListeningForChunk(-1) , mCallbackFlags(0) + , mCacheEntryHandle(aEntry) { LOG(("CacheFileInputStream::CacheFileInputStream() [this=%p]", this)); MOZ_COUNT_CTOR(CacheFileInputStream); } CacheFileInputStream::~CacheFileInputStream() { LOG(("CacheFileInputStream::~CacheFileInputStream() [this=%p]", this)); @@ -235,16 +236,18 @@ CacheFileInputStream::CloseWithStatusLoc if (mChunk) { ReleaseChunk(); } // TODO propagate error from input stream to other streams ??? MaybeNotifyListener(); + mFile->ReleaseOutsideLock(mCacheEntryHandle.forget()); + return NS_OK; } NS_IMETHODIMP CacheFileInputStream::AsyncWait(nsIInputStreamCallback *aCallback, uint32_t aFlags, uint32_t aRequestedCount, nsIEventTarget *aEventTarget)
--- a/netwerk/cache2/CacheFileInputStream.h +++ b/netwerk/cache2/CacheFileInputStream.h @@ -6,33 +6,32 @@ #define CacheFileInputStream__h__ #include "nsIAsyncInputStream.h" #include "nsISeekableStream.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "CacheFileChunk.h" - namespace mozilla { namespace net { class CacheFile; class CacheFileInputStream : public nsIAsyncInputStream , public nsISeekableStream , public CacheFileChunkListener { NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIINPUTSTREAM NS_DECL_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; NS_IMETHOD OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx, CacheFileChunk *aChunk) override; NS_IMETHOD OnChunkUpdated(CacheFileChunk *aChunk) override; // Memory reporting @@ -59,15 +58,17 @@ private: bool mClosed; nsresult mStatus; bool mWaitingForUpdate; int64_t mListeningForChunk; nsCOMPtr<nsIInputStreamCallback> mCallback; uint32_t mCallbackFlags; nsCOMPtr<nsIEventTarget> mCallbackTarget; + // Held purely for referencing purposes + RefPtr<nsISupports> mCacheEntryHandle; }; } // namespace net } // namespace mozilla #endif
--- a/netwerk/cache2/CacheFileMetadata.h +++ b/netwerk/cache2/CacheFileMetadata.h @@ -111,16 +111,17 @@ public: class CacheFileMetadataListener : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(CACHEFILEMETADATALISTENER_IID) NS_IMETHOD OnMetadataRead(nsresult aResult) = 0; NS_IMETHOD OnMetadataWritten(nsresult aResult) = 0; + virtual bool IsKilled() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileMetadataListener, CACHEFILEMETADATALISTENER_IID) class CacheFileMetadata : public CacheFileIOListener , public CacheMemoryConsumer @@ -178,16 +179,17 @@ public: NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult) override; NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf, nsresult aResult) override; NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) override; 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; size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; private: virtual ~CacheFileMetadata();