nsresult CacheFileMetadata::OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) { LOG(("CacheFileMetadata::OnDataRead() [this=%p, handle=%p, result=0x%08x]", this, aHandle, aResult)); MOZ_ASSERT(mListener); nsresult rv, retval; nsCOMPtr<CacheFileMetadataListener> listener; if (NS_FAILED(aResult)) { LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() failed" ", creating empty metadata. [this=%p, rv=0x%08x]", this, aResult)); InitEmptyMetadata(); retval = NS_OK; mListener.swap(listener); listener->OnMetadataRead(retval); return NS_OK; } // check whether we have read all necessary data uint32_t realOffset = NetworkEndian::readUint32(mBuf + mBufSize - sizeof(uint32_t)); int64_t size = mHandle->FileSize(); MOZ_ASSERT(size != -1); if (realOffset >= size) { LOG(("CacheFileMetadata::OnDataRead() - Invalid realOffset, creating " "empty metadata. [this=%p, realOffset=%d, size=%lld]", this, realOffset, size)); InitEmptyMetadata(); retval = NS_OK; mListener.swap(listener); listener->OnMetadataRead(retval); return NS_OK; } uint32_t usedOffset = size - mBufSize; if (realOffset < usedOffset) { uint32_t missing = usedOffset - realOffset; // we need to read more data mBuf = static_cast<char *>(moz_xrealloc(mBuf, mBufSize + missing)); memmove(mBuf + missing, mBuf, mBufSize); mBufSize += missing; DoMemoryReport(MemoryUsage()); LOG(("CacheFileMetadata::OnDataRead() - We need to read %d more bytes to " "have full metadata. [this=%p]", missing, this)); rv = CacheFileIOManager::Read(mHandle, realOffset, mBuf, missing, true, this); if (NS_FAILED(rv)) { LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() " "failed synchronously, creating empty metadata. [this=%p, " "rv=0x%08x]", this, rv)); InitEmptyMetadata(); retval = NS_OK; mListener.swap(listener); listener->OnMetadataRead(retval); return NS_OK; } return NS_OK; } // We have all data according to offset information at the end of the entry. // Try to parse it. rv = ParseMetadata(realOffset, realOffset - usedOffset, true); if (NS_FAILED(rv)) { LOG(("CacheFileMetadata::OnDataRead() - Error parsing metadata, creating " "empty metadata. [this=%p]", this)); InitEmptyMetadata(); retval = NS_OK; } else { retval = NS_OK; } mListener.swap(listener); listener->OnMetadataRead(retval); return NS_OK; }
nsresult CacheFileMetadata::OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) { LOG(("CacheFileMetadata::OnDataRead() [this=%p, handle=%p, result=0x%08x]", this, aHandle, aResult)); MOZ_ASSERT(mListener); nsresult rv; nsCOMPtr<CacheFileMetadataListener> listener; if (NS_FAILED(aResult)) { LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() failed" ", creating empty metadata. [this=%p, rv=0x%08x]", this, aResult)); InitEmptyMetadata(); mListener.swap(listener); listener->OnMetadataRead(NS_OK); return NS_OK; } if (mFirstRead) { Telemetry::AccumulateTimeDelta( Telemetry::NETWORK_CACHE_METADATA_FIRST_READ_TIME_MS, mReadStart); Telemetry::Accumulate( Telemetry::NETWORK_CACHE_METADATA_FIRST_READ_SIZE, mBufSize); } else { Telemetry::AccumulateTimeDelta( Telemetry::NETWORK_CACHE_METADATA_SECOND_READ_TIME_MS, mReadStart); } // check whether we have read all necessary data uint32_t realOffset = NetworkEndian::readUint32(mBuf + mBufSize - sizeof(uint32_t)); int64_t size = mHandle->FileSize(); MOZ_ASSERT(size != -1); if (realOffset >= size) { LOG(("CacheFileMetadata::OnDataRead() - Invalid realOffset, creating " "empty metadata. [this=%p, realOffset=%u, size=%lld]", this, realOffset, size)); InitEmptyMetadata(); mListener.swap(listener); listener->OnMetadataRead(NS_OK); return NS_OK; } uint32_t maxHashCount = size / kChunkSize; uint32_t maxMetadataSize = CalcMetadataSize(kMaxElementsSize, maxHashCount); if (size - realOffset > maxMetadataSize) { LOG(("CacheFileMetadata::OnDataRead() - Invalid realOffset, metadata would " "be too big, creating empty metadata. [this=%p, realOffset=%u, " "maxMetadataSize=%u, size=%lld]", this, realOffset, maxMetadataSize, size)); InitEmptyMetadata(); mListener.swap(listener); listener->OnMetadataRead(NS_OK); return NS_OK; } uint32_t usedOffset = size - mBufSize; if (realOffset < usedOffset) { uint32_t missing = usedOffset - realOffset; // we need to read more data char *newBuf = static_cast<char *>(realloc(mBuf, mBufSize + missing)); if (!newBuf) { LOG(("CacheFileMetadata::OnDataRead() - Error allocating %d more bytes " "for the missing part of the metadata, creating empty metadata. " "[this=%p]", missing, this)); InitEmptyMetadata(); mListener.swap(listener); listener->OnMetadataRead(NS_OK); return NS_OK; } mBuf = newBuf; memmove(mBuf + missing, mBuf, mBufSize); mBufSize += missing; DoMemoryReport(MemoryUsage()); LOG(("CacheFileMetadata::OnDataRead() - We need to read %d more bytes to " "have full metadata. [this=%p]", missing, this)); mFirstRead = false; mReadStart = mozilla::TimeStamp::Now(); rv = CacheFileIOManager::Read(mHandle, realOffset, mBuf, missing, this); if (NS_FAILED(rv)) { LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() " "failed synchronously, creating empty metadata. [this=%p, " "rv=0x%08x]", this, rv)); InitEmptyMetadata(); mListener.swap(listener); listener->OnMetadataRead(NS_OK); return NS_OK; } return NS_OK; } Telemetry::Accumulate(Telemetry::NETWORK_CACHE_METADATA_SIZE, size - realOffset); // We have all data according to offset information at the end of the entry. // Try to parse it. rv = ParseMetadata(realOffset, realOffset - usedOffset, true); if (NS_FAILED(rv)) { LOG(("CacheFileMetadata::OnDataRead() - Error parsing metadata, creating " "empty metadata. [this=%p]", this)); InitEmptyMetadata(); } else { // Shrink elements buffer. mBuf = static_cast<char *>(moz_xrealloc(mBuf, mElementsSize)); mBufSize = mElementsSize; // There is usually no or just one call to SetMetadataElement() when the // metadata is parsed from disk. Avoid allocating power of two sized buffer // which we do in case of newly created metadata. mAllocExactSize = true; } mListener.swap(listener); listener->OnMetadataRead(NS_OK); return NS_OK; }
nsresult CacheFileMetadata::ReadMetadata(CacheFileMetadataListener *aListener) { LOG(("CacheFileMetadata::ReadMetadata() [this=%p, listener=%p]", this, aListener)); MOZ_ASSERT(!mListener); MOZ_ASSERT(!mHashArray); MOZ_ASSERT(!mBuf); MOZ_ASSERT(!mWriteBuf); nsresult rv; int64_t size = mHandle->FileSize(); MOZ_ASSERT(size != -1); if (size == 0) { // this is a new entry LOG(("CacheFileMetadata::ReadMetadata() - Filesize == 0, creating empty " "metadata. [this=%p]", this)); InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); return NS_OK; } if (size < int64_t(sizeof(CacheFileMetadataHeader) + 2*sizeof(uint32_t))) { // there must be at least checksum, header and offset LOG(("CacheFileMetadata::ReadMetadata() - File is corrupted, creating " "empty metadata. [this=%p, filesize=%lld]", this, size)); InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); return NS_OK; } // Set offset so that we read at least kMinMetadataRead if the file is big // enough. int64_t offset; if (size < kMinMetadataRead) { offset = 0; } else { offset = size - kMinMetadataRead; } // round offset to kAlignSize blocks offset = (offset / kAlignSize) * kAlignSize; mBufSize = size - offset; mBuf = static_cast<char *>(moz_xmalloc(mBufSize)); DoMemoryReport(MemoryUsage()); LOG(("CacheFileMetadata::ReadMetadata() - Reading metadata from disk, trying " "offset=%lld, filesize=%lld [this=%p]", offset, size, this)); mListener = aListener; rv = CacheFileIOManager::Read(mHandle, offset, mBuf, mBufSize, true, this); if (NS_FAILED(rv)) { LOG(("CacheFileMetadata::ReadMetadata() - CacheFileIOManager::Read() failed" " synchronously, creating empty metadata. [this=%p, rv=0x%08x]", this, rv)); mListener = nullptr; InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); return NS_OK; } return NS_OK; }
nsresult CacheFileMetadata::ReadMetadata(CacheFileMetadataListener *aListener) { LOG(("CacheFileMetadata::ReadMetadata() [this=%p, listener=%p]", this, aListener)); MOZ_ASSERT(!mListener); MOZ_ASSERT(!mHashArray); MOZ_ASSERT(!mBuf); MOZ_ASSERT(!mWriteBuf); nsresult rv; int64_t size = mHandle->FileSize(); MOZ_ASSERT(size != -1); if (size == 0) { if (mKeyIsHash) { LOG(("CacheFileMetadata::ReadMetadata() - Filesize == 0, cannot create " "empty metadata since key is a hash. [this=%p]", this)); CacheFileIOManager::DoomFile(mHandle, nullptr); return NS_ERROR_NOT_AVAILABLE; } // this is a new entry LOG(("CacheFileMetadata::ReadMetadata() - Filesize == 0, creating empty " "metadata. [this=%p]", this)); InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); return NS_OK; } if (size < int64_t(sizeof(CacheFileMetadataHeader) + 2*sizeof(uint32_t))) { if (mKeyIsHash) { LOG(("CacheFileMetadata::ReadMetadata() - File is corrupted, cannot " "create empty metadata since key is a hash. [this=%p, " "filesize=%lld]", this, size)); CacheFileIOManager::DoomFile(mHandle, nullptr); return NS_ERROR_FILE_CORRUPTED; } // there must be at least checksum, header and offset LOG(("CacheFileMetadata::ReadMetadata() - File is corrupted, creating " "empty metadata. [this=%p, filesize=%lld]", this, size)); InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); return NS_OK; } // round offset to 4k blocks int64_t offset = (size / kAlignSize) * kAlignSize; if (size - offset < kMinMetadataRead && offset > kAlignSize) offset -= kAlignSize; mBufSize = size - offset; mBuf = static_cast<char *>(moz_xmalloc(mBufSize)); DoMemoryReport(MemoryUsage()); LOG(("CacheFileMetadata::ReadMetadata() - Reading metadata from disk, trying " "offset=%lld, filesize=%lld [this=%p]", offset, size, this)); mListener = aListener; rv = CacheFileIOManager::Read(mHandle, offset, mBuf, mBufSize, this); if (NS_FAILED(rv)) { if (mKeyIsHash) { LOG(("CacheFileMetadata::ReadMetadata() - CacheFileIOManager::Read() " "failed synchronously, cannot create empty metadata since key is " "a hash. [this=%p, rv=0x%08x]", this, rv)); CacheFileIOManager::DoomFile(mHandle, nullptr); return rv; } LOG(("CacheFileMetadata::ReadMetadata() - CacheFileIOManager::Read() failed" " synchronously, creating empty metadata. [this=%p, rv=0x%08x]", this, rv)); mListener = nullptr; InitEmptyMetadata(); aListener->OnMetadataRead(NS_OK); return NS_OK; } return NS_OK; }