author | Junior Hsu <juhsu@mozilla.com> |
Mon, 06 Mar 2017 18:21:59 +0800 | |
changeset 348747 | 10514ae0b128eb7d1257821224ac6366cc3a0aae |
parent 348746 | 229705d51c0077f0dec34acc38161d4460bed51e |
child 348748 | 706d07027f02713274e0246df2eb4e472fc67efd |
push id | 88304 |
push user | ryanvm@gmail.com |
push date | Wed, 22 Mar 2017 01:53:57 +0000 |
treeherder | mozilla-inbound@706d07027f02 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | michal |
bugs | 1325091 |
milestone | 55.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/CacheFile.cpp +++ b/netwerk/cache2/CacheFile.cpp @@ -884,17 +884,17 @@ CacheFile::OpenOutputStream(CacheOutputC if (mAltDataOffset != -1) { // Remove alt-data rv = Truncate(mAltDataOffset); if (NS_FAILED(rv)) { LOG(("CacheFile::OpenOutputStream() - Truncating alt-data failed " "[rv=0x%08" PRIx32 "]", static_cast<uint32_t>(rv))); return rv; } - mMetadata->SetElement(CacheFileUtils::kAltDataKey, nullptr); + SetAltMetadata(nullptr); mAltDataOffset = -1; } // Once we open output stream we no longer allow preloading of chunks without // input stream. There is no reason to believe that some input stream will be // opened soon. Otherwise we would cache unused chunks of all newly created // entries until the CacheFile is destroyed. mPreloadWithoutInputStreams = false; @@ -913,18 +913,16 @@ nsresult CacheFile::OpenAlternativeOutputStream(CacheOutputCloseListener *aCloseListener, const char *aAltDataType, nsIOutputStream **_retval) { CacheFileAutoLock lock(this); MOZ_ASSERT(mHandle || mMemoryOnly || mOpeningFile); - nsresult rv; - if (!mReady) { LOG(("CacheFile::OpenAlternativeOutputStream() - CacheFile is not ready " "[this=%p]", this)); return NS_ERROR_NOT_AVAILABLE; } if (mOutput) { @@ -936,37 +934,37 @@ CacheFile::OpenAlternativeOutputStream(C // Fail if there is any input stream opened for alternative data for (uint32_t i = 0; i < mInputs.Length(); ++i) { if (mInputs[i]->IsAlternativeData()) { return NS_ERROR_NOT_AVAILABLE; } } + nsresult rv; + if (mAltDataOffset != -1) { // Truncate old alt-data rv = Truncate(mAltDataOffset); if (NS_FAILED(rv)) { LOG(("CacheFile::OpenAlternativeOutputStream() - Truncating old alt-data " "failed [rv=0x%08" PRIx32 "]", static_cast<uint32_t>(rv))); return rv; } } else { mAltDataOffset = mDataSize; } nsAutoCString altMetadata; CacheFileUtils::BuildAlternativeDataInfo(aAltDataType, mAltDataOffset, altMetadata); - rv = mMetadata->SetElement(CacheFileUtils::kAltDataKey, altMetadata.get()); + rv = SetAltMetadata(altMetadata.get()); if (NS_FAILED(rv)) { - // Removing element shouldn't fail because it doesn't allocate memory. - mMetadata->SetElement(CacheFileUtils::kAltDataKey, nullptr); - - mAltDataOffset = -1; + LOG(("CacheFile::OpenAlternativeOutputStream() - Set Metadata for alt-data" + "failed [rv=0x%08" PRIx32 "]", static_cast<uint32_t>(rv))); return rv; } // Once we open output stream we no longer allow preloading of chunks without // input stream. There is no reason to believe that some input stream will be // opened soon. Otherwise we would cache unused chunks of all newly created // entries until the CacheFile is destroyed. mPreloadWithoutInputStreams = false; @@ -1151,17 +1149,17 @@ CacheFile::SetExpirationTime(uint32_t aE this, aExpirationTime)); MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); PostWriteTimer(); if (mHandle && !mHandle->IsDoomed()) - CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, &aExpirationTime); + CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, &aExpirationTime, nullptr); return mMetadata->SetExpirationTime(aExpirationTime); } nsresult CacheFile::GetExpirationTime(uint32_t *_retval) { CacheFileAutoLock lock(this); @@ -1180,32 +1178,60 @@ CacheFile::SetFrecency(uint32_t aFrecenc this, aFrecency)); MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); PostWriteTimer(); if (mHandle && !mHandle->IsDoomed()) - CacheFileIOManager::UpdateIndexEntry(mHandle, &aFrecency, nullptr); + CacheFileIOManager::UpdateIndexEntry(mHandle, &aFrecency, nullptr, nullptr); return mMetadata->SetFrecency(aFrecency); } nsresult CacheFile::GetFrecency(uint32_t *_retval) { CacheFileAutoLock lock(this); MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); return mMetadata->GetFrecency(_retval); } nsresult +CacheFile::SetAltMetadata(const char* aAltMetadata) +{ + LOG(("CacheFile::SetAltMetadata() this=%p, aAltMetadata=%s", + this, aAltMetadata ? aAltMetadata : "")); + + MOZ_ASSERT(mMetadata); + NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); + + PostWriteTimer(); + + nsresult rv = mMetadata->SetElement(CacheFileUtils::kAltDataKey, aAltMetadata); + bool hasAltData = aAltMetadata ? true : false; + + if (NS_FAILED(rv)) { + // Removing element shouldn't fail because it doesn't allocate memory. + mMetadata->SetElement(CacheFileUtils::kAltDataKey, nullptr); + + mAltDataOffset = -1; + hasAltData = false; + } + + if (mHandle && !mHandle->IsDoomed()) { + CacheFileIOManager::UpdateIndexEntry(mHandle, nullptr, nullptr, &hasAltData); + } + return rv; +} + +nsresult CacheFile::GetLastModified(uint32_t *_retval) { CacheFileAutoLock lock(this); MOZ_ASSERT(mMetadata); NS_ENSURE_TRUE(mMetadata, NS_ERROR_UNEXPECTED); return mMetadata->GetLastModified(_retval); } @@ -2360,17 +2386,19 @@ CacheFile::InitIndexEntry() NS_ENSURE_SUCCESS(rv, rv); uint32_t expTime; mMetadata->GetExpirationTime(&expTime); uint32_t frecency; mMetadata->GetFrecency(&frecency); - rv = CacheFileIOManager::UpdateIndexEntry(mHandle, &frecency, &expTime); + bool hasAltData = mMetadata->GetElement(CacheFileUtils::kAltDataKey) ? true : false; + + rv = CacheFileIOManager::UpdateIndexEntry(mHandle, &frecency, &expTime, &hasAltData); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } size_t CacheFile::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
--- a/netwerk/cache2/CacheFile.h +++ b/netwerk/cache2/CacheFile.h @@ -181,16 +181,17 @@ private: void WriteMetadataIfNeededLocked(bool aFireAndForget = false); void PostWriteTimer(); void CleanUpCachedChunks(); nsresult PadChunkWithZeroes(uint32_t aChunkIdx); void SetError(nsresult aStatus); + nsresult SetAltMetadata(const char* aAltMetadata); nsresult InitIndexEntry(); mozilla::Mutex mLock; bool mOpeningFile; bool mReady; bool mMemoryOnly; bool mSkipSizeCheck;
--- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -973,44 +973,51 @@ public: CacheIndex::InitEntry(mHandle->Hash(), mOriginAttrsHash, mAnonymous, mPinning); // We cannot set the filesize before we init the entry. If we're opening // an existing entry file, frecency and expiration time will be set after // parsing the entry file, but we must set the filesize here since nobody is // going to set it if there is no write to the file. uint32_t sizeInK = mHandle->FileSizeInK(); - CacheIndex::UpdateEntry(mHandle->Hash(), nullptr, nullptr, &sizeInK); + CacheIndex::UpdateEntry(mHandle->Hash(), nullptr, nullptr, nullptr, &sizeInK); return NS_OK; } protected: RefPtr<CacheFileHandle> mHandle; OriginAttrsHash mOriginAttrsHash; bool mAnonymous; bool mPinning; }; class UpdateIndexEntryEvent : public Runnable { public: - UpdateIndexEntryEvent(CacheFileHandle *aHandle, const uint32_t *aFrecency, - const uint32_t *aExpirationTime) + UpdateIndexEntryEvent(CacheFileHandle *aHandle, + const uint32_t *aFrecency, + const uint32_t *aExpirationTime, + const bool *aHasAltData) : mHandle(aHandle) , mHasFrecency(false) , mHasExpirationTime(false) + , mHasHasAltData(false) { if (aFrecency) { mHasFrecency = true; mFrecency = *aFrecency; } if (aExpirationTime) { mHasExpirationTime = true; mExpirationTime = *aExpirationTime; } + if (aHasAltData) { + mHasHasAltData = true; + mHasAltData = *aHasAltData; + } } protected: ~UpdateIndexEntryEvent() { } public: @@ -1018,26 +1025,31 @@ public: { if (mHandle->IsClosed() || mHandle->IsDoomed()) { return NS_OK; } CacheIndex::UpdateEntry(mHandle->Hash(), mHasFrecency ? &mFrecency : nullptr, mHasExpirationTime ? &mExpirationTime : nullptr, + mHasHasAltData ? &mHasAltData : nullptr, nullptr); return NS_OK; } protected: - RefPtr<CacheFileHandle> mHandle; + RefPtr<CacheFileHandle> mHandle; + bool mHasFrecency; bool mHasExpirationTime; + bool mHasHasAltData; + uint32_t mFrecency; uint32_t mExpirationTime; + bool mHasAltData; }; class MetadataWriteScheduleEvent : public Runnable { public: enum EMode { SCHEDULE, UNSCHEDULE, @@ -2040,17 +2052,17 @@ CacheFileIOManager::WriteInternal(CacheF aHandle->mFileSize = writeEnd; } } uint32_t newSizeInK = aHandle->FileSizeInK(); if (oldSizeInK != newSizeInK && !aHandle->IsDoomed() && !aHandle->IsSpecialFile()) { - CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, &newSizeInK); + CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, nullptr, &newSizeInK); if (oldSizeInK < newSizeInK) { EvictIfOverLimitInternal(); } } } if (bytesWritten != aCount) { @@ -2569,17 +2581,17 @@ CacheFileIOManager::TruncateSeekSetEOFIn } uint32_t oldSizeInK = aHandle->FileSizeInK(); aHandle->mFileSize = aEOFPos; uint32_t newSizeInK = aHandle->FileSizeInK(); if (oldSizeInK != newSizeInK && !aHandle->IsDoomed() && !aHandle->IsSpecialFile()) { - CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, &newSizeInK); + CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, nullptr, &newSizeInK); if (oldSizeInK < newSizeInK) { EvictIfOverLimitInternal(); } } return NS_OK; } @@ -2874,17 +2886,17 @@ CacheFileIOManager::OverLimitEvictionInt // EnsureEntryExists(). rv = CacheIndex::EnsureEntryExists(&hash); NS_ENSURE_SUCCESS(rv, rv); // Move the entry at the end of both lists to make sure we won't end up // failing on one entry forever. uint32_t frecency = 0; uint32_t expTime = nsICacheEntry::NO_EXPIRATION_TIME; - rv = CacheIndex::UpdateEntry(&hash, &frecency, &expTime, nullptr); + rv = CacheIndex::UpdateEntry(&hash, &frecency, &expTime, nullptr, nullptr); NS_ENSURE_SUCCESS(rv, rv); consecutiveFailures++; if (consecutiveFailures >= cnt) { // This doesn't necessarily mean that we've tried to doom every entry // but we've reached a sane number of tries. It is likely that another // eviction will start soon. And as said earlier, this normally doesn't // happen at all. @@ -3538,36 +3550,38 @@ CacheFileIOManager::InitIndexEntry(Cache return NS_OK; } // static nsresult CacheFileIOManager::UpdateIndexEntry(CacheFileHandle *aHandle, const uint32_t *aFrecency, - const uint32_t *aExpirationTime) + const uint32_t *aExpirationTime, + const bool *aHasAltData) { LOG(("CacheFileIOManager::UpdateIndexEntry() [handle=%p, frecency=%s, " - "expirationTime=%s]", aHandle, + "expirationTime=%s hasAltData=%s]", aHandle, aFrecency ? nsPrintfCString("%u", *aFrecency).get() : "", - aExpirationTime ? nsPrintfCString("%u", *aExpirationTime).get() : "")); + aExpirationTime ? nsPrintfCString("%u", *aExpirationTime).get() : "", + aHasAltData ? (*aHasAltData ? "true" : "false") : "")); nsresult rv; RefPtr<CacheFileIOManager> ioMan = gInstance; if (aHandle->IsClosed() || !ioMan) { return NS_ERROR_NOT_INITIALIZED; } if (aHandle->IsSpecialFile()) { return NS_ERROR_UNEXPECTED; } RefPtr<UpdateIndexEntryEvent> ev = - new UpdateIndexEntryEvent(aHandle, aFrecency, aExpirationTime); + new UpdateIndexEntryEvent(aHandle, aFrecency, aExpirationTime, aHasAltData); rv = ioMan->mIOThread->Dispatch(ev, aHandle->mPriority ? CacheIOThread::WRITE_PRIORITY : CacheIOThread::WRITE); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
--- a/netwerk/cache2/CacheFileIOManager.h +++ b/netwerk/cache2/CacheFileIOManager.h @@ -331,17 +331,18 @@ public: bool aPinning); static nsresult InitIndexEntry(CacheFileHandle *aHandle, OriginAttrsHash aOriginAttrsHash, bool aAnonymous, bool aPinning); static nsresult UpdateIndexEntry(CacheFileHandle *aHandle, const uint32_t *aFrecency, - const uint32_t *aExpirationTime); + const uint32_t *aExpirationTime, + const bool *aHasAltData); static nsresult UpdateIndexEntry(); enum EEnumerateMode { ENTRIES, DOOMED };
--- a/netwerk/cache2/CacheFileUtils.cpp +++ b/netwerk/cache2/CacheFileUtils.cpp @@ -545,17 +545,20 @@ ParseAlternativeDataInfo(const char *aIn return NS_ERROR_NOT_AVAILABLE; } // The requested alt-data representation is not available if (altDataOffset < 0) { return NS_ERROR_NOT_AVAILABLE; } - *_offset = altDataOffset; + if (_offset) { + *_offset = altDataOffset; + } + if (_type) { mozilla::Unused << p.ReadUntil(Tokenizer::Token::EndOfFile(), *_type); } return NS_OK; } void
--- a/netwerk/cache2/CacheIndex.cpp +++ b/netwerk/cache2/CacheIndex.cpp @@ -22,17 +22,17 @@ #include <algorithm> #include "mozilla/Telemetry.h" #include "mozilla/Unused.h" #define kMinUnwrittenChanges 300 #define kMinDumpInterval 20000 // in milliseconds #define kMaxBufSize 16384 -#define kIndexVersion 0x00000003 +#define kIndexVersion 0x00000004 #define kUpdateIndexStartDelay 50000 // in milliseconds #define INDEX_NAME "index" #define TEMP_INDEX_NAME "index.tmp" #define JOURNAL_NAME "index.log" namespace mozilla { namespace net { @@ -912,22 +912,24 @@ CacheIndex::RemoveEntry(const SHA1Sum::H return NS_OK; } // static nsresult CacheIndex::UpdateEntry(const SHA1Sum::Hash *aHash, const uint32_t *aFrecency, const uint32_t *aExpirationTime, + const bool *aHasAltData, const uint32_t *aSize) { LOG(("CacheIndex::UpdateEntry() [hash=%08x%08x%08x%08x%08x, " - "frecency=%s, expirationTime=%s, size=%s]", LOGSHA1(aHash), + "frecency=%s, expirationTime=%s, hasAltData=%s, size=%s]", LOGSHA1(aHash), aFrecency ? nsPrintfCString("%u", *aFrecency).get() : "", aExpirationTime ? nsPrintfCString("%u", *aExpirationTime).get() : "", + aHasAltData ? (*aHasAltData ? "true" : "false") : "", aSize ? nsPrintfCString("%u", *aSize).get() : "")); MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); StaticMutexAutoLock lock(sLock); RefPtr<CacheIndex> index = gInstance; @@ -948,17 +950,17 @@ CacheIndex::UpdateEntry(const SHA1Sum::H entry = nullptr; } if (index->mState == READY || index->mState == UPDATING || index->mState == BUILDING) { MOZ_ASSERT(index->mPendingUpdates.Count() == 0); MOZ_ASSERT(entry); - if (!HasEntryChanged(entry, aFrecency, aExpirationTime, aSize)) { + if (!HasEntryChanged(entry, aFrecency, aExpirationTime, aHasAltData, aSize)) { return NS_OK; } MOZ_ASSERT(entry->IsFresh()); MOZ_ASSERT(entry->IsInitialized()); entry->MarkDirty(); if (aFrecency) { @@ -1506,26 +1508,31 @@ CacheIndex::IsCollision(CacheIndexEntry return false; } // static bool CacheIndex::HasEntryChanged(CacheIndexEntry *aEntry, const uint32_t *aFrecency, const uint32_t *aExpirationTime, + const bool *aHasAltData, const uint32_t *aSize) { if (aFrecency && *aFrecency != aEntry->GetFrecency()) { return true; } if (aExpirationTime && *aExpirationTime != aEntry->GetExpirationTime()) { return true; } + if (aHasAltData && *aHasAltData != aEntry->GetHasAltData()) { + return true; + } + if (aSize && (*aSize & CacheIndexEntry::kFileSizeMask) != aEntry->GetFileSize()) { return true; } return false; } @@ -2631,17 +2638,17 @@ CacheIndex::SetupDirectoryEnumerator() NS_ENSURE_SUCCESS(rv, rv); mDirEnumerator = do_QueryInterface(enumerator, &rv); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } -void +nsresult CacheIndex::InitEntryFromDiskData(CacheIndexEntry *aEntry, CacheFileMetadata *aMetaData, int64_t aFileSize) { aEntry->InitNew(); aEntry->MarkDirty(); aEntry->MarkFresh(); @@ -2652,19 +2659,28 @@ CacheIndex::InitEntryFromDiskData(CacheI uint32_t expirationTime; aMetaData->GetExpirationTime(&expirationTime); aEntry->SetExpirationTime(expirationTime); uint32_t frecency; aMetaData->GetFrecency(&frecency); aEntry->SetFrecency(frecency); + const char *altData = aMetaData->GetElement(CacheFileUtils::kAltDataKey); + bool hasAltData = altData ? true : false; + if (hasAltData && + NS_FAILED(CacheFileUtils::ParseAlternativeDataInfo(altData, nullptr, nullptr))) { + return NS_ERROR_FAILURE; + } + aEntry->SetHasAltData(hasAltData); + aEntry->SetFileSize(static_cast<uint32_t>( std::min(static_cast<int64_t>(PR_UINT32_MAX), (aFileSize + 0x3FF) >> 10))); + return NS_OK; } bool CacheIndex::IsUpdatePending() { sLock.AssertCurrentThreadOwns(); if (mUpdateTimer || mUpdateEventPending) { @@ -2797,20 +2813,25 @@ CacheIndex::BuildIndex() if (NS_FAILED(rv)) { LOG(("CacheIndex::BuildIndex() - CacheFileMetadata::SyncReadMetadata() " "failed, removing file. [name=%s]", leaf.get())); file->Remove(false); } else { CacheIndexEntryAutoManage entryMng(&hash, this); entry = mIndex.PutEntry(hash); - InitEntryFromDiskData(entry, meta, size); - LOG(("CacheIndex::BuildIndex() - Added entry to index. [hash=%s]", - leaf.get())); - entry->Log(); + if (NS_FAILED(InitEntryFromDiskData(entry, meta, size))) { + LOG(("CacheIndex::BuildIndex() - CacheFile::InitEntryFromDiskData() " + "failed, removing file. [name=%s]", leaf.get())); + file->Remove(false); + } else { + LOG(("CacheIndex::BuildIndex() - Added entry to index. [name=%s]", + leaf.get())); + entry->Log(); + } } } NS_NOTREACHED("We should never get here"); } bool CacheIndex::StartUpdatingIndexIfNeeded(bool aSwitchingToReadyState) @@ -3035,28 +3056,36 @@ CacheIndex::UpdateIndex() entry = mIndex.GetEntry(hash); MOZ_ASSERT(!entry || !entry->IsFresh()); CacheIndexEntryAutoManage entryMng(&hash, this); if (NS_FAILED(rv)) { LOG(("CacheIndex::UpdateIndex() - CacheFileMetadata::SyncReadMetadata() " "failed, removing file. [name=%s]", leaf.get())); + } else { + entry = mIndex.PutEntry(hash); + rv = InitEntryFromDiskData(entry, meta, size); + if (NS_FAILED(rv)) { + LOG(("CacheIndex::UpdateIndex() - CacheIndex::InitEntryFromDiskData " + "failed, removing file. [name=%s]", leaf.get())); + } + } + + if (NS_FAILED(rv)) { file->Remove(false); if (entry) { entry->MarkRemoved(); entry->MarkFresh(); entry->MarkDirty(); } } else { - entry = mIndex.PutEntry(hash); - InitEntryFromDiskData(entry, meta, size); - LOG(("CacheIndex::UpdateIndex() - Added/updated entry to/in index. " - "[hash=%s]", leaf.get())); - entry->Log(); + LOG(("CacheIndex::UpdateIndex() - Added/updated entry to/in index. " + "[name=%s]", leaf.get())); + entry->Log(); } } NS_NOTREACHED("We should never get here"); } void CacheIndex::FinishUpdate(bool aSucceeded)
--- a/netwerk/cache2/CacheIndex.h +++ b/netwerk/cache2/CacheIndex.h @@ -70,17 +70,18 @@ struct CacheIndexRecord { /* * 1000 0000 0000 0000 0000 0000 0000 0000 : initialized * 0100 0000 0000 0000 0000 0000 0000 0000 : anonymous * 0010 0000 0000 0000 0000 0000 0000 0000 : removed * 0001 0000 0000 0000 0000 0000 0000 0000 : dirty * 0000 1000 0000 0000 0000 0000 0000 0000 : fresh * 0000 0100 0000 0000 0000 0000 0000 0000 : pinned - * 0000 0011 0000 0000 0000 0000 0000 0000 : reserved + * 0000 0010 0000 0000 0000 0000 0000 0000 : has cached alt data + * 0000 0001 0000 0000 0000 0000 0000 0000 : reserved * 0000 0000 1111 1111 1111 1111 1111 1111 : file size (in kB) */ uint32_t mFlags; CacheIndexRecord() : mFrecency(0) , mOriginAttrsHash(0) , mExpirationTime(nsICacheEntry::NO_EXPIRATION_TIME) @@ -203,16 +204,23 @@ public: uint32_t GetFrecency() const { return mRec->mFrecency; } void SetExpirationTime(uint32_t aExpirationTime) { mRec->mExpirationTime = aExpirationTime; } uint32_t GetExpirationTime() const { return mRec->mExpirationTime; } + void SetHasAltData(bool aHasAltData) + { + aHasAltData ? mRec->mFlags |= kHasAltDataMask + : mRec->mFlags &= ~kHasAltDataMask; + } + bool GetHasAltData() const { return !!(mRec->mFlags & kHasAltDataMask); } + // Sets filesize in kilobytes. void SetFileSize(uint32_t aFileSize) { if (aFileSize > kFileSizeMask) { LOG(("CacheIndexEntry::SetFileSize() - FileSize is too large, " "truncating to %u", kFileSizeMask)); aFileSize = kFileSizeMask; } @@ -306,17 +314,19 @@ private: // This flag is set when the information about the entry is fresh, i.e. // we've created or opened this entry during this session, or we've seen // this entry during update or build process. static const uint32_t kFreshMask = 0x08000000; // Indicates a pinned entry. static const uint32_t kPinnedMask = 0x04000000; - static const uint32_t kReservedMask = 0x03000000; + // Indicates there is cached alternative data in the entry. + static const uint32_t kHasAltDataMask = 0x02000000; + static const uint32_t kReservedMask = 0x01000000; // FileSize in kilobytes static const uint32_t kFileSizeMask = 0x00FFFFFF; nsAutoPtr<CacheIndexRecord> mRec; }; class CacheIndexEntryUpdate : public CacheIndexEntry @@ -358,45 +368,60 @@ public: } void SetExpirationTime(uint32_t aExpirationTime) { mUpdateFlags |= kExpirationUpdatedMask; CacheIndexEntry::SetExpirationTime(aExpirationTime); } + void SetHasAltData(bool aHasAltData) + { + mUpdateFlags |= kHasAltDataUpdatedMask; + CacheIndexEntry::SetHasAltData(aHasAltData); + } + void SetFileSize(uint32_t aFileSize) { mUpdateFlags |= kFileSizeUpdatedMask; CacheIndexEntry::SetFileSize(aFileSize); } void ApplyUpdate(CacheIndexEntry *aDst) { MOZ_ASSERT(memcmp(&mRec->mHash, &aDst->mRec->mHash, sizeof(SHA1Sum::Hash)) == 0); if (mUpdateFlags & kFrecencyUpdatedMask) { aDst->mRec->mFrecency = mRec->mFrecency; } if (mUpdateFlags & kExpirationUpdatedMask) { aDst->mRec->mExpirationTime = mRec->mExpirationTime; } aDst->mRec->mOriginAttrsHash = mRec->mOriginAttrsHash; + + if (mUpdateFlags & kHasAltDataUpdatedMask && + ((aDst->mRec->mFlags ^ mRec->mFlags) & kHasAltDataMask)) { + // Toggle the bit if we need to. + aDst->mRec->mFlags ^= kHasAltDataMask; + } + if (mUpdateFlags & kFileSizeUpdatedMask) { - aDst->mRec->mFlags = mRec->mFlags; + // Copy all flags except |HasAltData|. + aDst->mRec->mFlags |= (mRec->mFlags & ~kHasAltDataMask); } else { - // Copy all flags except file size. + // Copy all flags except |HasAltData| and file size. aDst->mRec->mFlags &= kFileSizeMask; - aDst->mRec->mFlags |= (mRec->mFlags & ~kFileSizeMask); + aDst->mRec->mFlags |= (mRec->mFlags & ~kHasAltDataMask & ~kFileSizeMask); } } private: static const uint32_t kFrecencyUpdatedMask = 0x00000001; static const uint32_t kExpirationUpdatedMask = 0x00000002; static const uint32_t kFileSizeUpdatedMask = 0x00000004; + static const uint32_t kHasAltDataUpdatedMask = 0x00000008; uint32_t mUpdateFlags; }; class CacheIndexStats { public: CacheIndexStats() @@ -627,16 +652,17 @@ public: // Update some information in entry. The entry MUST be present in index and // MUST be initialized. Call to AddEntry() or EnsureEntryExists() and to // InitEntry() must precede the call to this method. // Pass nullptr if the value didn't change. static nsresult UpdateEntry(const SHA1Sum::Hash *aHash, const uint32_t *aFrecency, const uint32_t *aExpirationTime, + const bool *aHasAltData, const uint32_t *aSize); // Remove all entries from the index. Called when clearing the whole cache. static nsresult RemoveAll(); enum EntryStatus { EXISTS = 0, DOES_NOT_EXIST = 1, @@ -726,16 +752,17 @@ private: static bool IsCollision(CacheIndexEntry *aEntry, OriginAttrsHash aOriginAttrsHash, bool aAnonymous); // Checks whether any of the information about the entry has changed. static bool HasEntryChanged(CacheIndexEntry *aEntry, const uint32_t *aFrecency, const uint32_t *aExpirationTime, + const bool *aHasAltData, const uint32_t *aSize); // Merge all pending operations from mPendingUpdates into mIndex. void ProcessPendingOperations(); // Following methods perform writing of the index file. // // The index is written periodically, but not earlier than once in @@ -828,19 +855,19 @@ private: // Following methods perform updating and building of the index. // Timer callback that starts update or build process. static void DelayedUpdate(nsITimer *aTimer, void *aClosure); void DelayedUpdateLocked(); // Posts timer event that start update or build process. nsresult ScheduleUpdateTimer(uint32_t aDelay); nsresult SetupDirectoryEnumerator(); - void InitEntryFromDiskData(CacheIndexEntry *aEntry, - CacheFileMetadata *aMetaData, - int64_t aFileSize); + nsresult InitEntryFromDiskData(CacheIndexEntry *aEntry, + CacheFileMetadata *aMetaData, + int64_t aFileSize); // Returns true when either a timer is scheduled or event is posted. bool IsUpdatePending(); // Iterates through all files in entries directory that we didn't create/open // during this session, parses them and adds the entries to the index. void BuildIndex(); bool StartUpdatingIndexIfNeeded(bool aSwitchingToReadyState = false); // Starts update or build process or fires a timer when it is too early after