Bug 1320894 - Fixed serialization of cache index, r=valentin

This commit is contained in:
Michal Novotny 2016-12-02 16:21:35 +01:00
parent 8565d5695d
commit eeff8dadb0
2 changed files with 58 additions and 64 deletions

View File

@ -27,7 +27,7 @@
#define kMinUnwrittenChanges 300
#define kMinDumpInterval 20000 // in milliseconds
#define kMaxBufSize 16384
#define kIndexVersion 0x00000002
#define kIndexVersion 0x00000003
#define kUpdateIndexStartDelay 50000 // in milliseconds
#define INDEX_NAME "index"
@ -1649,13 +1649,18 @@ CacheIndex::WriteIndexToDisk()
AllocBuffer();
mRWHash = new CacheHash();
CacheIndexHeader *hdr = reinterpret_cast<CacheIndexHeader *>(mRWBuf);
NetworkEndian::writeUint32(&hdr->mVersion, kIndexVersion);
NetworkEndian::writeUint32(&hdr->mTimeStamp,
mRWBufPos = 0;
// index version
NetworkEndian::writeUint32(mRWBuf + mRWBufPos, kIndexVersion);
mRWBufPos += sizeof(uint32_t);
// timestamp
NetworkEndian::writeUint32(mRWBuf + mRWBufPos,
static_cast<uint32_t>(PR_Now() / PR_USEC_PER_SEC));
NetworkEndian::writeUint32(&hdr->mIsDirty, 1);
mRWBufPos += sizeof(uint32_t);
// dirty flag
NetworkEndian::writeUint32(mRWBuf + mRWBufPos, 1);
mRWBufPos += sizeof(uint32_t);
mRWBufPos = sizeof(CacheIndexHeader);
mSkipEntries = 0;
}
@ -2010,24 +2015,19 @@ CacheIndex::WriteLogToDisk()
rv = indexFile->OpenNSPRFileDesc(PR_RDWR, 0600, &fd);
NS_ENSURE_SUCCESS(rv, rv);
CacheIndexHeader header;
int32_t bytesRead = PR_Read(fd, &header, sizeof(CacheIndexHeader));
if (bytesRead != sizeof(CacheIndexHeader)) {
PR_Close(fd);
return NS_ERROR_FAILURE;
}
NetworkEndian::writeUint32(&header.mIsDirty, 0);
int64_t offset = PR_Seek64(fd, 0, PR_SEEK_SET);
// Seek to dirty flag in the index header and clear it.
static_assert(2 * sizeof(uint32_t) == offsetof(CacheIndexHeader, mIsDirty),
"Unexpected offset of CacheIndexHeader::mIsDirty");
int64_t offset = PR_Seek64(fd, 2 * sizeof(uint32_t), PR_SEEK_SET);
if (offset == -1) {
PR_Close(fd);
return NS_ERROR_FAILURE;
}
int32_t bytesWritten = PR_Write(fd, &header, sizeof(CacheIndexHeader));
uint32_t isDirty = 0;
int32_t bytesWritten = PR_Write(fd, &isDirty, sizeof(isDirty));
PR_Close(fd);
if (bytesWritten != sizeof(CacheIndexHeader)) {
if (bytesWritten != sizeof(isDirty)) {
return NS_ERROR_FAILURE;
}
@ -2140,41 +2140,37 @@ CacheIndex::ParseRecords()
uint32_t pos = 0;
if (!mSkipEntries) {
CacheIndexHeader *hdr = reinterpret_cast<CacheIndexHeader *>(
moz_xmalloc(sizeof(CacheIndexHeader)));
memcpy(hdr, mRWBuf, sizeof(CacheIndexHeader));
if (NetworkEndian::readUint32(&hdr->mVersion) != kIndexVersion) {
free(hdr);
if (NetworkEndian::readUint32(mRWBuf + pos) != kIndexVersion) {
FinishRead(false);
return;
}
pos += sizeof(uint32_t);
mIndexTimeStamp = NetworkEndian::readUint32(&hdr->mTimeStamp);
mIndexTimeStamp = NetworkEndian::readUint32(mRWBuf + pos);
pos += sizeof(uint32_t);
if (NetworkEndian::readUint32(&hdr->mIsDirty)) {
if (NetworkEndian::readUint32(mRWBuf + pos)) {
if (mJournalHandle) {
CacheFileIOManager::DoomFile(mJournalHandle, nullptr);
mJournalHandle = nullptr;
}
free(hdr);
} else {
NetworkEndian::writeUint32(&hdr->mIsDirty, 1);
uint32_t * isDirty = reinterpret_cast<uint32_t *>(
moz_xmalloc(sizeof(uint32_t)));
NetworkEndian::writeUint32(isDirty, 1);
// Mark index dirty. The buffer is freed by CacheFileIOManager when
// nullptr is passed as the listener and the call doesn't fail
// synchronously.
rv = CacheFileIOManager::Write(mIndexHandle, 0,
reinterpret_cast<char *>(hdr),
sizeof(CacheIndexHeader), true, false,
nullptr);
rv = CacheFileIOManager::Write(mIndexHandle, 2 * sizeof(uint32_t),
reinterpret_cast<char *>(isDirty),
sizeof(uint32_t), true, false, nullptr);
if (NS_FAILED(rv)) {
// This is not fatal, just free the memory
free(hdr);
free(isDirty);
}
}
pos += sizeof(CacheIndexHeader);
pos += sizeof(uint32_t);
}
uint32_t hashOffset = pos;
@ -2314,8 +2310,7 @@ CacheIndex::ParseJournal()
while (pos + sizeof(CacheIndexRecord) <= mRWBufPos &&
mSkipEntries != entryCnt) {
CacheIndexRecord *rec = reinterpret_cast<CacheIndexRecord *>(mRWBuf + pos);
CacheIndexEntry tmpEntry(&rec->mHash);
CacheIndexEntry tmpEntry(reinterpret_cast<SHA1Sum::Hash *>(mRWBuf + pos));
tmpEntry.ReadFromBuf(mRWBuf + pos);
CacheIndexEntry *entry = mTmpJournal.PutEntry(*tmpEntry.Hash());

View File

@ -56,11 +56,16 @@ typedef struct {
uint32_t mIsDirty;
} CacheIndexHeader;
static_assert(
sizeof(CacheIndexHeader::mVersion) + sizeof(CacheIndexHeader::mTimeStamp) +
sizeof(CacheIndexHeader::mIsDirty) == sizeof(CacheIndexHeader),
"Unexpected sizeof(CacheIndexHeader)!");
struct CacheIndexRecord {
SHA1Sum::Hash mHash;
uint32_t mFrecency;
uint32_t mExpirationTime;
OriginAttrsHash mOriginAttrsHash;
uint32_t mExpirationTime;
/*
* 1000 0000 0000 0000 0000 0000 0000 0000 : initialized
@ -72,16 +77,22 @@ struct CacheIndexRecord {
* 0000 0011 0000 0000 0000 0000 0000 0000 : reserved
* 0000 0000 1111 1111 1111 1111 1111 1111 : file size (in kB)
*/
uint32_t mFlags;
uint32_t mFlags;
CacheIndexRecord()
: mFrecency(0)
, mExpirationTime(nsICacheEntry::NO_EXPIRATION_TIME)
, mOriginAttrsHash(0)
, mExpirationTime(nsICacheEntry::NO_EXPIRATION_TIME)
, mFlags(0)
{}
};
static_assert(
sizeof(CacheIndexRecord::mHash) + sizeof(CacheIndexRecord::mFrecency) +
sizeof(CacheIndexRecord::mOriginAttrsHash) + sizeof(CacheIndexRecord::mExpirationTime) +
sizeof(CacheIndexRecord::mFlags) == sizeof(CacheIndexRecord),
"Unexpected sizeof(CacheIndexRecord)!");
class CacheIndexEntry : public PLDHashEntryHdr
{
public:
@ -221,36 +232,24 @@ public:
void WriteToBuf(void *aBuf)
{
CacheIndexRecord *dst = reinterpret_cast<CacheIndexRecord *>(aBuf);
// Copy the whole record to the buffer.
memcpy(aBuf, mRec, sizeof(CacheIndexRecord));
uint8_t* ptr = static_cast<uint8_t*>(aBuf);
memcpy(ptr, mRec->mHash, sizeof(SHA1Sum::Hash)); ptr += sizeof(SHA1Sum::Hash);
NetworkEndian::writeUint32(ptr, mRec->mFrecency); ptr += sizeof(uint32_t);
NetworkEndian::writeUint64(ptr, mRec->mOriginAttrsHash); ptr += sizeof(uint64_t);
NetworkEndian::writeUint32(ptr, mRec->mExpirationTime); ptr += sizeof(uint32_t);
// Dirty and fresh flags should never go to disk, since they make sense only
// during current session.
dst->mFlags &= ~kDirtyMask;
dst->mFlags &= ~kFreshMask;
#if defined(IS_LITTLE_ENDIAN)
// Data in the buffer are in machine byte order and we want them in network
// byte order.
NetworkEndian::writeUint32(&dst->mFrecency, dst->mFrecency);
NetworkEndian::writeUint32(&dst->mExpirationTime, dst->mExpirationTime);
NetworkEndian::writeUint64(&dst->mOriginAttrsHash, dst->mOriginAttrsHash);
NetworkEndian::writeUint32(&dst->mFlags, dst->mFlags);
#endif
NetworkEndian::writeUint32(ptr, mRec->mFlags & ~(kDirtyMask | kFreshMask));
}
void ReadFromBuf(void *aBuf)
{
CacheIndexRecord *src= reinterpret_cast<CacheIndexRecord *>(aBuf);
MOZ_ASSERT(memcmp(&mRec->mHash, &src->mHash,
sizeof(SHA1Sum::Hash)) == 0);
mRec->mFrecency = NetworkEndian::readUint32(&src->mFrecency);
mRec->mExpirationTime = NetworkEndian::readUint32(&src->mExpirationTime);
mRec->mOriginAttrsHash = NetworkEndian::readUint64(&src->mOriginAttrsHash);
mRec->mFlags = NetworkEndian::readUint32(&src->mFlags);
const uint8_t* ptr = static_cast<const uint8_t*>(aBuf);
MOZ_ASSERT(memcmp(&mRec->mHash, ptr, sizeof(SHA1Sum::Hash)) == 0); ptr += sizeof(SHA1Sum::Hash);
mRec->mFrecency = NetworkEndian::readUint32(ptr); ptr += sizeof(uint32_t);
mRec->mOriginAttrsHash = NetworkEndian::readUint64(ptr); ptr += sizeof(uint64_t);
mRec->mExpirationTime = NetworkEndian::readUint32(ptr); ptr += sizeof(uint32_t);
mRec->mFlags = NetworkEndian::readUint32(ptr);
}
void Log() const {