Bug 1253883 - Do not release mRWBuf until pending read/write operation finishes, r=honzab

This commit is contained in:
Michal Novotny 2016-05-11 10:48:28 +02:00
Родитель d0b575b3af
Коммит 04256ec318
2 изменённых файлов: 62 добавлений и 27 удалений

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

@ -250,6 +250,7 @@ CacheIndex::CacheIndex()
, mRWBuf(nullptr)
, mRWBufSize(0)
, mRWBufPos(0)
, mRWPending(false)
, mJournalReadSuccessfully(false)
, mFrecencyArraySorted(false)
, mAsyncGetDiskConsumptionBlocked(false)
@ -262,6 +263,7 @@ CacheIndex::CacheIndex()
CacheIndex::~CacheIndex()
{
sLock.AssertCurrentThreadOwns();
LOG(("CacheIndex::~CacheIndex [this=%p]", this));
MOZ_COUNT_DTOR(CacheIndex);
@ -348,15 +350,12 @@ CacheIndex::PreShutdown()
nsCOMPtr<nsIRunnable> event;
event = NewRunnableMethod(index, &CacheIndex::PreShutdownInternal);
RefPtr<CacheIOThread> ioThread = CacheFileIOManager::IOThread();
MOZ_ASSERT(ioThread);
nsCOMPtr<nsIEventTarget> ioTarget = CacheFileIOManager::IOTarget();
MOZ_ASSERT(ioTarget);
// Executing PreShutdownInternal() on WRITE level ensures that read/write
// events holding pointer to mRWBuf will be executed before we release the
// buffer by calling FinishRead()/FinishWrite() in PreShutdownInternal(), but
// it will be executed before any queued event on INDEX level. That's OK since
// we don't want to wait until updating of the index finishes.
rv = ioThread->Dispatch(event, CacheIOThread::WRITE);
// PreShutdownInternal() will be executed before any queued event on INDEX
// level. That's OK since we don't want to wait for any operation in progess.
rv = ioTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
NS_WARNING("CacheIndex::PreShutdown() - Can't dispatch event");
LOG(("CacheIndex::PreShutdown() - Can't dispatch event" ));
@ -1567,7 +1566,7 @@ CacheIndex::ProcessPendingOperations()
bool
CacheIndex::WriteIndexToDiskIfNeeded()
{
if (mState != READY || mShuttingDown) {
if (mState != READY || mShuttingDown || mRWPending) {
return false;
}
@ -1597,6 +1596,7 @@ CacheIndex::WriteIndexToDisk()
MOZ_ASSERT(mState == READY);
MOZ_ASSERT(!mRWBuf);
MOZ_ASSERT(!mRWHash);
MOZ_ASSERT(!mRWPending);
ChangeState(WRITING);
@ -1637,6 +1637,7 @@ CacheIndex::WriteRecords()
sLock.AssertCurrentThreadOwns();
MOZ_ASSERT(mState == WRITING);
MOZ_ASSERT(!mRWPending);
int64_t fileOffset;
@ -1713,6 +1714,8 @@ CacheIndex::WriteRecords()
LOG(("CacheIndex::WriteRecords() - CacheFileIOManager::Write() failed "
"synchronously [rv=0x%08x]", rv));
FinishWrite(false);
} else {
mRWPending = true;
}
mRWBufPos = 0;
@ -1727,6 +1730,10 @@ CacheIndex::FinishWrite(bool aSucceeded)
sLock.AssertCurrentThreadOwns();
// If there is write operation pending we must be cancelling writing of the
// index when shutting down or removing the whole index.
MOZ_ASSERT(!mRWPending || (!aSucceeded && (mShuttingDown || mRemovingAll)));
mIndexHandle = nullptr;
mRWHash = nullptr;
ReleaseBuffer();
@ -2059,6 +2066,7 @@ CacheIndex::StartReadingIndex()
MOZ_ASSERT(!mDontMarkIndexClean);
MOZ_ASSERT(!mJournalReadSuccessfully);
MOZ_ASSERT(mIndexHandle->FileSize() >= 0);
MOZ_ASSERT(!mRWPending);
int64_t entriesSize = mIndexHandle->FileSize() - sizeof(CacheIndexHeader) -
sizeof(CacheHash::Hash32_t);
@ -2081,6 +2089,8 @@ CacheIndex::StartReadingIndex()
LOG(("CacheIndex::StartReadingIndex() - CacheFileIOManager::Read() failed "
"synchronously [rv=0x%08x]", rv));
FinishRead(false);
} else {
mRWPending = true;
}
}
@ -2093,6 +2103,8 @@ CacheIndex::ParseRecords()
sLock.AssertCurrentThreadOwns();
MOZ_ASSERT(!mRWPending);
uint32_t entryCnt = (mIndexHandle->FileSize() - sizeof(CacheIndexHeader) -
sizeof(CacheHash::Hash32_t)) / sizeof(CacheIndexRecord);
uint32_t pos = 0;
@ -2209,6 +2221,8 @@ CacheIndex::ParseRecords()
"synchronously [rv=0x%08x]", rv));
FinishRead(false);
return;
} else {
mRWPending = true;
}
}
@ -2225,6 +2239,7 @@ CacheIndex::StartReadingJournal()
MOZ_ASSERT(mIndexOnDiskIsValid);
MOZ_ASSERT(mTmpJournal.Count() == 0);
MOZ_ASSERT(mJournalHandle->FileSize() >= 0);
MOZ_ASSERT(!mRWPending);
int64_t entriesSize = mJournalHandle->FileSize() -
sizeof(CacheHash::Hash32_t);
@ -2246,6 +2261,8 @@ CacheIndex::StartReadingJournal()
LOG(("CacheIndex::StartReadingJournal() - CacheFileIOManager::Read() failed"
" synchronously [rv=0x%08x]", rv));
FinishRead(false);
} else {
mRWPending = true;
}
}
@ -2258,6 +2275,8 @@ CacheIndex::ParseJournal()
sLock.AssertCurrentThreadOwns();
MOZ_ASSERT(!mRWPending);
uint32_t entryCnt = (mJournalHandle->FileSize() -
sizeof(CacheHash::Hash32_t)) / sizeof(CacheIndexRecord);
@ -2323,6 +2342,8 @@ CacheIndex::ParseJournal()
"synchronously [rv=0x%08x]", rv));
FinishRead(false);
return;
} else {
mRWPending = true;
}
}
@ -2407,6 +2428,10 @@ CacheIndex::FinishRead(bool aSucceeded)
// -> ready
(aSucceeded && mIndexOnDiskIsValid && mJournalReadSuccessfully));
// If there is read operation pending we must be cancelling reading of the
// index when shutting down or removing the whole index.
MOZ_ASSERT(!mRWPending || (!aSucceeded && (mShuttingDown || mRemovingAll)));
if (mState == SHUTDOWN) {
RemoveFile(NS_LITERAL_CSTRING(TEMP_INDEX_NAME));
RemoveFile(NS_LITERAL_CSTRING(JOURNAL_NAME));
@ -3168,10 +3193,14 @@ CacheIndex::AllocBuffer()
void
CacheIndex::ReleaseBuffer()
{
if (!mRWBuf) {
sLock.AssertCurrentThreadOwns();
if (!mRWBuf || mRWPending) {
return;
}
LOG(("CacheIndex::ReleaseBuffer() releasing buffer"));
free(mRWBuf);
mRWBuf = nullptr;
mRWBufSize = 0;
@ -3279,13 +3308,13 @@ CacheIndex::OnFileOpenedInternal(FileOpenHelper *aOpener,
LOG(("CacheIndex::OnFileOpenedInternal() [opener=%p, handle=%p, "
"result=0x%08x]", aOpener, aHandle, aResult));
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
nsresult rv;
sLock.AssertCurrentThreadOwns();
if (!IsIndexUsable()) {
return NS_ERROR_NOT_AVAILABLE;
}
MOZ_RELEASE_ASSERT(IsIndexUsable());
if (mState == READY && mShuttingDown) {
return NS_OK;
@ -3389,13 +3418,15 @@ CacheIndex::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
LOG(("CacheIndex::OnDataWritten() [handle=%p, result=0x%08x]", aHandle,
aResult));
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
nsresult rv;
StaticMutexAutoLock lock(sLock);
if (!IsIndexUsable()) {
return NS_ERROR_NOT_AVAILABLE;
}
MOZ_RELEASE_ASSERT(IsIndexUsable());
MOZ_RELEASE_ASSERT(mRWPending);
mRWPending = false;
if (mState == READY && mShuttingDown) {
return NS_OK;
@ -3403,11 +3434,7 @@ CacheIndex::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
switch (mState) {
case WRITING:
if (mIndexHandle != aHandle) {
LOG(("CacheIndex::OnDataWritten() - ignoring notification since it "
"belongs to previously canceled operation [state=%d]", mState));
break;
}
MOZ_ASSERT(mIndexHandle == aHandle);
if (NS_FAILED(aResult)) {
FinishWrite(false);
@ -3430,6 +3457,7 @@ CacheIndex::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
// Writing was canceled.
LOG(("CacheIndex::OnDataWritten() - ignoring notification since the "
"operation was previously canceled [state=%d]", mState));
ReleaseBuffer();
}
return NS_OK;
@ -3441,11 +3469,13 @@ CacheIndex::OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult)
LOG(("CacheIndex::OnDataRead() [handle=%p, result=0x%08x]", aHandle,
aResult));
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
StaticMutexAutoLock lock(sLock);
if (!IsIndexUsable()) {
return NS_ERROR_NOT_AVAILABLE;
}
MOZ_RELEASE_ASSERT(IsIndexUsable());
MOZ_RELEASE_ASSERT(mRWPending);
mRWPending = false;
switch (mState) {
case READING:
@ -3465,6 +3495,7 @@ CacheIndex::OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult)
// Reading was canceled.
LOG(("CacheIndex::OnDataRead() - ignoring notification since the "
"operation was previously canceled [state=%d]", mState));
ReleaseBuffer();
}
return NS_OK;
@ -3490,11 +3521,11 @@ CacheIndex::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult)
LOG(("CacheIndex::OnFileRenamed() [handle=%p, result=0x%08x]", aHandle,
aResult));
MOZ_ASSERT(CacheFileIOManager::IsOnIOThread());
StaticMutexAutoLock lock(sLock);
if (!IsIndexUsable()) {
return NS_ERROR_NOT_AVAILABLE;
}
MOZ_RELEASE_ASSERT(IsIndexUsable());
if (mState == READY && mShuttingDown) {
return NS_OK;

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

@ -991,6 +991,10 @@ private:
uint32_t mRWBufPos;
RefPtr<CacheHash> mRWHash;
// True if read or write operation is pending. It is used to ensure that
// mRWBuf is not freed until OnDataRead or OnDataWritten is called.
bool mRWPending;
// Reading of journal succeeded if true.
bool mJournalReadSuccessfully;