mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 412796: Optimize fastload system (mmap fileIO) r=brendan
--HG-- extra : rebase_source : 425e1c4254b8e5c7c3b9fc98efb91c06805d1f02
This commit is contained in:
parent
005dd93cd6
commit
0192baad2a
@ -610,7 +610,7 @@ class nsXULFastLoadFileIO : public nsIFastLoadFileIO
|
||||
{
|
||||
public:
|
||||
nsXULFastLoadFileIO(nsIFile* aFile)
|
||||
: mFile(aFile) {
|
||||
: mFile(aFile), mTruncateOutputFile(true) {
|
||||
}
|
||||
|
||||
virtual ~nsXULFastLoadFileIO() {
|
||||
@ -622,6 +622,7 @@ class nsXULFastLoadFileIO : public nsIFastLoadFileIO
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
bool mTruncateOutputFile;
|
||||
};
|
||||
|
||||
|
||||
@ -653,7 +654,7 @@ nsXULFastLoadFileIO::GetOutputStream(nsIOutputStream** aResult)
|
||||
{
|
||||
if (! mOutputStream) {
|
||||
PRInt32 ioFlags = PR_WRONLY;
|
||||
if (! mInputStream)
|
||||
if (mTruncateOutputFile)
|
||||
ioFlags |= PR_CREATE_FILE | PR_TRUNCATE;
|
||||
|
||||
nsresult rv;
|
||||
@ -672,6 +673,13 @@ nsXULFastLoadFileIO::GetOutputStream(nsIOutputStream** aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULFastLoadFileIO::DisableTruncate()
|
||||
{
|
||||
mTruncateOutputFile = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
|
||||
{
|
||||
@ -766,13 +774,8 @@ nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
|
||||
// Try to read an existent FastLoad file.
|
||||
PRBool exists = PR_FALSE;
|
||||
if (NS_SUCCEEDED(file->Exists(&exists)) && exists) {
|
||||
nsCOMPtr<nsIInputStream> input;
|
||||
rv = io->GetInputStream(getter_AddRefs(input));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
rv = fastLoadService->NewInputStream(input, getter_AddRefs(objectInput));
|
||||
rv = fastLoadService->NewInputStream(file, getter_AddRefs(objectInput));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (gChecksumXULFastLoadFile) {
|
||||
@ -836,8 +839,6 @@ nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
|
||||
// that can't do open-unlink.
|
||||
if (objectInput)
|
||||
objectInput->Close();
|
||||
else
|
||||
input->Close();
|
||||
xio->mInputStream = nsnull;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -394,6 +394,7 @@ nsXPCFastLoadIO::GetInputStream(nsIInputStream **_retval)
|
||||
fileInput,
|
||||
XPC_DESERIALIZATION_BUFFER_SIZE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mTruncateOutputFile = false;
|
||||
}
|
||||
|
||||
NS_ADDREF(*_retval = mInputStream);
|
||||
@ -405,7 +406,7 @@ nsXPCFastLoadIO::GetOutputStream(nsIOutputStream **_retval)
|
||||
{
|
||||
if (! mOutputStream) {
|
||||
PRInt32 ioFlags = PR_WRONLY;
|
||||
if (! mInputStream) {
|
||||
if (mTruncateOutputFile) {
|
||||
ioFlags |= PR_CREATE_FILE | PR_TRUNCATE;
|
||||
}
|
||||
|
||||
@ -424,6 +425,13 @@ nsXPCFastLoadIO::GetOutputStream(nsIOutputStream **_retval)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCFastLoadIO::DisableTruncate()
|
||||
{
|
||||
mTruncateOutputFile = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReadScriptFromStream(JSContext *cx, nsIObjectInputStream *stream,
|
||||
JSScript **script)
|
||||
@ -945,11 +953,7 @@ mozJSComponentLoader::StartFastLoad(nsIFastLoadService *flSvc)
|
||||
if (exists) {
|
||||
LOG(("trying to use existing fastload file\n"));
|
||||
|
||||
nsCOMPtr<nsIInputStream> input;
|
||||
rv = mFastLoadIO->GetInputStream(getter_AddRefs(input));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = flSvc->NewInputStream(input, getter_AddRefs(mFastLoadInput));
|
||||
rv = flSvc->NewInputStream(mFastLoadFile, getter_AddRefs(mFastLoadInput));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG(("opened fastload file for reading\n"));
|
||||
|
||||
@ -987,9 +991,7 @@ mozJSComponentLoader::StartFastLoad(nsIFastLoadService *flSvc)
|
||||
if (mFastLoadInput) {
|
||||
mFastLoadInput->Close();
|
||||
mFastLoadInput = nsnull;
|
||||
} else {
|
||||
input->Close();
|
||||
}
|
||||
}
|
||||
mFastLoadIO->SetInputStream(nsnull);
|
||||
mFastLoadFile->Remove(PR_FALSE);
|
||||
exists = PR_FALSE;
|
||||
|
@ -74,7 +74,7 @@ class nsXPCFastLoadIO : public nsIFastLoadFileIO
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFASTLOADFILEIO
|
||||
|
||||
nsXPCFastLoadIO(nsIFile *file) : mFile(file) {}
|
||||
nsXPCFastLoadIO(nsIFile *file) : mFile(file), mTruncateOutputFile(true) {}
|
||||
|
||||
void SetInputStream(nsIInputStream *stream) { mInputStream = stream; }
|
||||
void SetOutputStream(nsIOutputStream *stream) { mOutputStream = stream; }
|
||||
@ -85,6 +85,7 @@ class nsXPCFastLoadIO : public nsIFastLoadFileIO
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
bool mTruncateOutputFile;
|
||||
};
|
||||
|
||||
|
||||
|
@ -57,6 +57,9 @@
|
||||
#include "nsBinaryStream.h"
|
||||
#include "nsFastLoadFile.h"
|
||||
#include "nsInt64.h"
|
||||
#ifdef XP_UNIX
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_brendan
|
||||
# define METERING
|
||||
@ -299,13 +302,6 @@ nsFastLoadFileReader::GetChecksum(PRUint32 *aChecksum)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::SetChecksum(PRUint32 aChecksum)
|
||||
{
|
||||
mHeader.mChecksum = aChecksum;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct nsStringMapEntry : public PLDHashEntryHdr {
|
||||
const char* mString; // key, must come first
|
||||
nsISupports* mURI; // for SelectMuxedDocument return value
|
||||
@ -530,17 +526,11 @@ nsFastLoadFileReader::EndMuxedDocument(nsISupports* aURI)
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry;
|
||||
if (entry) {
|
||||
// Don't call our Seek wrapper, as it clears mCurrentDocumentMapEntry.
|
||||
if (entry->mNeedToSeek) {
|
||||
rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
entry->mSaveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
SeekTo(entry->mSaveOffset);
|
||||
entry->mNeedToSeek = PR_FALSE;
|
||||
}
|
||||
|
||||
@ -555,15 +545,11 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
if (entry->mNextSegmentOffset == 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
entry->mNextSegmentOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
SeekTo(entry->mNextSegmentOffset);
|
||||
// Clear mCurrentDocumentMapEntry temporarily to avoid recursion.
|
||||
mCurrentDocumentMapEntry = nsnull;
|
||||
|
||||
rv = Read32(&entry->mNextSegmentOffset);
|
||||
nsresult rv = Read32(&entry->mNextSegmentOffset);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRUint32 bytesLeft = 0;
|
||||
rv = Read32(&bytesLeft);
|
||||
@ -578,10 +564,11 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
entry->mBytesLeft -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
rv = nsBinaryInputStream::Read(aBuffer, aCount, aBytesRead);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && entry) {
|
||||
PRUint32 count = PR_MIN(mFileLen - mFilePos, aCount);
|
||||
memcpy(aBuffer, mFileData+mFilePos, count);
|
||||
*aBytesRead = count;
|
||||
mFilePos += count;
|
||||
if (entry) {
|
||||
NS_ASSERTION(entry->mBytesLeft >= *aBytesRead, "demux Read underflow!");
|
||||
entry->mBytesLeft -= *aBytesRead;
|
||||
|
||||
@ -591,7 +578,7 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
||||
entry->mSaveOffset = 0;
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -603,9 +590,13 @@ nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
NS_ASSERTION(!entry || (!entry->mNeedToSeek && entry->mBytesLeft != 0),
|
||||
"ReadSegments called from above nsFastLoadFileReader layer?!");
|
||||
|
||||
nsresult rv = nsBinaryInputStream::ReadSegments(aWriter, aClosure, aCount,
|
||||
aResult);
|
||||
if (NS_SUCCEEDED(rv) && entry) {
|
||||
PRUint32 count = PR_MIN(mFileLen - mFilePos, aCount);
|
||||
|
||||
// Errors returned from the writer get ignored.
|
||||
aWriter(this, aClosure, (char*)(mFileData + mFilePos), 0,
|
||||
count, aResult);
|
||||
mFilePos += count;
|
||||
if (entry) {
|
||||
NS_ASSERTION(entry->mBytesLeft >= *aResult,
|
||||
"demux ReadSegments underflow!");
|
||||
entry->mBytesLeft -= *aResult;
|
||||
@ -616,90 +607,19 @@ nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
entry->mSaveOffset = 0;
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::SetInputStream(nsIInputStream *aInputStream)
|
||||
{
|
||||
nsresult rv = nsBinaryInputStream::SetInputStream(aInputStream);
|
||||
mSeekableInput = do_QueryInterface(aInputStream);
|
||||
NS_ASSERTION(!mInputStream || mSeekableInput,
|
||||
"FastLoad requires a seekable input stream");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME: bug #411579 (tune this macro!) Last updated: Jan 2008
|
||||
*/
|
||||
#define MFL_CHECKSUM_BUFSIZE (6 * 8192)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::ComputeChecksum(PRUint32 *aResult)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream = mInputStream;
|
||||
nsCOMPtr<nsISeekableStream> seekable = mSeekableInput;
|
||||
|
||||
PRInt64 saveOffset;
|
||||
nsresult rv = seekable->Tell(&saveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (mBufferAccess) {
|
||||
rv = mBufferAccess->GetUnbufferedStream(getter_AddRefs(stream));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
seekable = do_QueryInterface(stream);
|
||||
if (!seekable)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
char buf[MFL_CHECKSUM_BUFSIZE];
|
||||
PRUint32 len, rem;
|
||||
|
||||
rem = offsetof(nsFastLoadHeader, mChecksum);
|
||||
rv = stream->Read(buf, rem, &len);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (len != rem)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, 4);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
memset(buf + rem, 0, 4);
|
||||
rem += 4;
|
||||
|
||||
PRUint32 checksum = 0;
|
||||
while (NS_SUCCEEDED(rv = stream->Read(buf + rem, sizeof buf - rem, &len)) &&
|
||||
len) {
|
||||
len += rem;
|
||||
rem = NS_AccumulateFastLoadChecksum(&checksum,
|
||||
reinterpret_cast<PRUint8*>(buf),
|
||||
len,
|
||||
PR_FALSE);
|
||||
if (rem)
|
||||
memcpy(buf, buf + len - rem, rem);
|
||||
}
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (rem) {
|
||||
NS_AccumulateFastLoadChecksum(&checksum,
|
||||
reinterpret_cast<PRUint8*>(buf),
|
||||
rem,
|
||||
PR_TRUE);
|
||||
}
|
||||
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Skip first 2 fields.
|
||||
PRUint32 pos = offsetof(nsFastLoadHeader, mVersion);
|
||||
NS_AccumulateFastLoadChecksum(&checksum,
|
||||
mFileData + pos,
|
||||
mFileLen - pos,
|
||||
PR_TRUE);
|
||||
*aResult = checksum;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -938,49 +858,49 @@ nsresult
|
||||
nsFastLoadFileReader::Open()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(mFile, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &mFd);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Don't bother buffering the header, as we immediately seek to EOF.
|
||||
if (mBufferAccess)
|
||||
mBufferAccess->DisableBuffering();
|
||||
PRInt64 size = PR_Available64(mFd);
|
||||
if (size >= PR_INT32_MAX)
|
||||
return NS_ERROR_FILE_TOO_BIG;
|
||||
|
||||
mFileLen = (PRUint32) size;
|
||||
|
||||
PRFileMap *mFileMap = PR_CreateFileMap(mFd, mFileLen, PR_PROT_READONLY);
|
||||
if (!mFileMap)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mFileData = (PRUint8*) PR_MemMap(mFileMap, 0, mFileLen);
|
||||
|
||||
if (mFileLen < sizeof(nsFastLoadHeader))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
#ifdef XP_UNIX
|
||||
madvise(mFileData, mFileLen, MADV_WILLNEED);
|
||||
#endif
|
||||
|
||||
rv = ReadHeader(&mHeader);
|
||||
|
||||
if (mBufferAccess)
|
||||
mBufferAccess->EnableBuffering();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (mHeader.mVersion != MFL_FILE_VERSION)
|
||||
if (mHeader.mVersion != MFL_FILE_VERSION ||
|
||||
mHeader.mFooterOffset == 0 ||
|
||||
memcmp(mHeader.mMagic, magic, MFL_FILE_MAGIC_SIZE))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
if (mHeader.mFooterOffset == 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_END, 0);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRInt64 fileSize;
|
||||
rv = mSeekableInput->Tell(&fileSize);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsInt64 fileSize64 = fileSize;
|
||||
const nsInt64 maxUint32 = PR_UINT32_MAX;
|
||||
NS_ASSERTION(fileSize64 <= maxUint32, "fileSize must fit in 32 bits");
|
||||
if ((PRUint32) fileSize64 != mHeader.mFileSize)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
PRInt32(mHeader.mFooterOffset));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
SeekTo(mHeader.mFooterOffset);
|
||||
|
||||
rv = ReadFooter(&mFooter);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
return mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
sizeof(nsFastLoadHeader));
|
||||
SeekTo(sizeof(nsFastLoadHeader));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -995,13 +915,22 @@ nsFastLoadFileReader::Close()
|
||||
// a session not so much for reading objects as for its footer information,
|
||||
// which primes the updater's tables so that after the update completes, the
|
||||
// FastLoad file has a superset footer.
|
||||
|
||||
if (mFd) {
|
||||
if (mFileData)
|
||||
PR_MemUnmap(mFileData, mFileLen);
|
||||
mFileData = nsnull;
|
||||
if (mFileMap)
|
||||
PR_CloseFileMap(mFileMap);
|
||||
mFileMap = nsnull;
|
||||
PR_Close(mFd);
|
||||
mFd = nsnull;
|
||||
}
|
||||
for (PRUint32 i = 0, n = mFooter.mNumSharpObjects; i < n; i++) {
|
||||
nsObjectMapEntry* entry = &mFooter.mObjectMap[i];
|
||||
entry->mReadObject = nsnull;
|
||||
}
|
||||
|
||||
return mInputStream->Close();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1062,14 +991,9 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject)
|
||||
// Check whether we've already deserialized the object for this OID.
|
||||
object = entry->mReadObject;
|
||||
if (!object) {
|
||||
PRInt64 saveOffset;
|
||||
nsDocumentMapReadEntry* saveDocMapEntry = nsnull;
|
||||
|
||||
rv = mSeekableInput->Tell(&saveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRUint32 saveOffset32 = saveOffset;
|
||||
PRUint32 saveOffset32 = mFilePos;
|
||||
if (entry->mCIDOffset != saveOffset32) {
|
||||
// We skipped deserialization of this object from its position
|
||||
// earlier in the input stream, presumably due to the reference
|
||||
@ -1085,10 +1009,7 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject)
|
||||
// or more multiplexed documents in the FastLoad file.
|
||||
saveDocMapEntry = mCurrentDocumentMapEntry;
|
||||
mCurrentDocumentMapEntry = nsnull;
|
||||
rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
entry->mCIDOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
SeekTo(entry->mCIDOffset);
|
||||
}
|
||||
|
||||
rv = DeserializeObject(getter_AddRefs(object));
|
||||
@ -1098,17 +1019,11 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject)
|
||||
if (entry->mCIDOffset != saveOffset32) {
|
||||
// Save the "skip offset" in case we need to skip this object
|
||||
// definition when reading forward, later on.
|
||||
rv = mSeekableInput->Tell(&entry->mSkipOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
entry->mSkipOffset = mFilePos;
|
||||
// Restore stream offset and mCurrentDocumentMapEntry in case
|
||||
// we're still reading forward through a part of the multiplex
|
||||
// to get object definitions eagerly.
|
||||
rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
saveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
SeekTo(saveOffset32);
|
||||
mCurrentDocumentMapEntry = saveDocMapEntry;
|
||||
}
|
||||
|
||||
@ -1125,11 +1040,7 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject)
|
||||
// Since we are seeking within a muxed segment, we must adjust
|
||||
// mBytesLeft, so that Seek called from Read will be triggered
|
||||
// when mBytesLeft goes to zero.
|
||||
PRInt64 currentOffset;
|
||||
rv = mSeekableInput->Tell(¤tOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRUint32 currentOffset = mFilePos;
|
||||
NS_ASSERTION(entry->mSkipOffset > (PRUint32)currentOffset,
|
||||
"skipping backwards from object?!");
|
||||
NS_ASSERTION(mCurrentDocumentMapEntry->mBytesLeft >=
|
||||
@ -1139,10 +1050,7 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject)
|
||||
mCurrentDocumentMapEntry->mBytesLeft -=
|
||||
entry->mSkipOffset - (PRUint32)currentOffset;
|
||||
|
||||
rv = mSeekableInput->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
entry->mSkipOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
SeekTo(entry->mSkipOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1195,27 +1103,30 @@ nsFastLoadFileReader::ReadID(nsID *aResult)
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
||||
{
|
||||
NS_ASSERTION(aWhence == nsISeekableStream::NS_SEEK_SET, "Only NS_SEEK_SET seeks are supported");
|
||||
mCurrentDocumentMapEntry = nsnull;
|
||||
return mSeekableInput->Seek(aWhence, aOffset);
|
||||
SeekTo(aOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::Tell(PRInt64 *aResult)
|
||||
{
|
||||
return mSeekableInput->Tell(aResult);
|
||||
*aResult = mFilePos;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::SetEOF()
|
||||
{
|
||||
return mSeekableInput->SetEOF();
|
||||
NS_ERROR("Refusing to truncate a memory-mapped file");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult,
|
||||
nsIInputStream* aSrcStream)
|
||||
NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult, nsIFile *aFile)
|
||||
{
|
||||
nsFastLoadFileReader* reader = new nsFastLoadFileReader(aSrcStream);
|
||||
nsFastLoadFileReader* reader = new nsFastLoadFileReader(aFile);
|
||||
if (!reader)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
@ -1336,13 +1247,6 @@ nsFastLoadFileWriter::GetChecksum(PRUint32 *aChecksum)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileWriter::SetChecksum(PRUint32 aChecksum)
|
||||
{
|
||||
mHeader.mChecksum = aChecksum;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct nsDocumentMapWriteEntry : public nsDocumentMapEntry {
|
||||
PRUint32 mCurrentSegmentOffset; // last written segment's offset
|
||||
};
|
||||
@ -1925,6 +1829,8 @@ nsFastLoadFileWriter::Open()
|
||||
return Init();
|
||||
}
|
||||
|
||||
#define MFL_CHECKSUM_BUFSIZE (6 * 8192)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileWriter::Close()
|
||||
{
|
||||
@ -1996,20 +1902,11 @@ nsFastLoadFileWriter::Close()
|
||||
rv = mFileIO->GetInputStream(getter_AddRefs(input));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Get the unbuffered input stream, to avoid copying overhead and to
|
||||
// keep our view of the file coherent with the writer -- we don't want
|
||||
// to hit a stale buffer in the reader's underlying stream.
|
||||
nsCOMPtr<nsIStreamBufferAccess> bufferAccess =
|
||||
do_QueryInterface(input);
|
||||
rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(input));
|
||||
if (NS_FAILED(rv) || !input)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Seek the input stream to offset 0, in case it's a reader who has
|
||||
// already been used to consume some of the FastLoad file.
|
||||
|
||||
// Seek the input stream to right after checksum/magic.
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(input);
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
offsetof(nsFastLoadHeader, mVersion));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@ -2317,24 +2214,8 @@ NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult,
|
||||
|
||||
// -------------------------- nsFastLoadFileUpdater --------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsFastLoadFileUpdater,
|
||||
nsFastLoadFileWriter,
|
||||
nsIFastLoadFileIO)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileUpdater::GetInputStream(nsIInputStream** aResult)
|
||||
{
|
||||
*aResult = mInputStream;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileUpdater::GetOutputStream(nsIOutputStream** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsFastLoadFileUpdater,
|
||||
nsFastLoadFileWriter)
|
||||
|
||||
PLDHashOperator
|
||||
nsFastLoadFileUpdater::CopyReadDocumentMapEntryToUpdater(PLDHashTable *aTable,
|
||||
@ -2397,7 +2278,6 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader)
|
||||
// Prepare to save aReader state in case we need to seek back and read a
|
||||
// singleton object that might otherwise get written by this updater.
|
||||
nsDocumentMapReadEntry* saveDocMapEntry = nsnull;
|
||||
nsISeekableStream* inputSeekable = nsnull;
|
||||
PRInt64 saveOffset = 0;
|
||||
|
||||
for (i = 0, n = aReader->mFooter.mNumSharpObjects; i < n; i++) {
|
||||
@ -2415,8 +2295,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader)
|
||||
nsISupports* obj = readEntry->mReadObject;
|
||||
if (!obj && MFL_GET_SINGLETON_FLAG(readEntry)) {
|
||||
if (!saveDocMapEntry) {
|
||||
inputSeekable = aReader->mSeekableInput;
|
||||
rv = inputSeekable->Tell(&saveOffset);
|
||||
rv = aReader->Tell(&saveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@ -2424,7 +2303,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader)
|
||||
aReader->mCurrentDocumentMapEntry = nsnull;
|
||||
}
|
||||
|
||||
rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
rv = aReader->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
readEntry->mCIDOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
@ -2450,7 +2329,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader)
|
||||
// the system principal's serialized data, because the updater for
|
||||
// messenger.xul being opened here has already read it.
|
||||
|
||||
rv = inputSeekable->Tell(&readEntry->mSkipOffset);
|
||||
rv = aReader->Tell(&readEntry->mSkipOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
@ -2479,7 +2358,7 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader)
|
||||
|
||||
// If we had to read any singletons, restore aReader's saved state.
|
||||
if (saveDocMapEntry) {
|
||||
rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset);
|
||||
rv = aReader->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@ -2530,13 +2409,6 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader)
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Avoid creating yet another object by implementing nsIFastLoadFileIO on
|
||||
// this updater, and save aReader's input stream so it can be returned by
|
||||
// GetInputStream called from nsFastLoadFileWriter::Close. This requires
|
||||
// that we override Close to break the resulting zero-length cycle.
|
||||
mFileIO = this;
|
||||
mInputStream = aReader->mInputStream;
|
||||
mSeekableInput = aReader->mSeekableInput;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2553,7 +2425,7 @@ nsFastLoadFileUpdater::Close()
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult,
|
||||
nsIOutputStream* aOutputStream,
|
||||
nsIFastLoadFileIO *aFileIO,
|
||||
nsIObjectInputStream* aReaderAsStream)
|
||||
{
|
||||
// Make sure that aReaderAsStream is an nsFastLoadFileReader.
|
||||
@ -2561,15 +2433,19 @@ NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult,
|
||||
if (!reader)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsFastLoadFileUpdater* updater = new nsFastLoadFileUpdater(aOutputStream);
|
||||
nsCOMPtr<nsIOutputStream> output;
|
||||
nsresult rv = aFileIO->GetOutputStream(getter_AddRefs(output));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsFastLoadFileUpdater* updater = new nsFastLoadFileUpdater(output, aFileIO);
|
||||
if (!updater)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Stabilize updater's refcnt.
|
||||
nsCOMPtr<nsIObjectOutputStream> stream(updater);
|
||||
|
||||
nsresult rv = updater->Open(static_cast<nsFastLoadFileReader*>
|
||||
(aReaderAsStream));
|
||||
rv = updater->Open(static_cast<nsFastLoadFileReader*>(aReaderAsStream));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -262,9 +262,10 @@ class nsFastLoadFileReader
|
||||
public nsIFastLoadFileReader
|
||||
{
|
||||
public:
|
||||
nsFastLoadFileReader(nsIInputStream *aStream)
|
||||
: mCurrentDocumentMapEntry(nsnull) {
|
||||
SetInputStream(aStream);
|
||||
nsFastLoadFileReader(nsIFile *aFile)
|
||||
: mCurrentDocumentMapEntry(nsnull), mFile(aFile), mFd(nsnull),
|
||||
mFileLen(0), mFilePos(0), mFileMap(nsnull), mFileData(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsFastLoadFileReader);
|
||||
}
|
||||
|
||||
@ -280,6 +281,11 @@ class nsFastLoadFileReader
|
||||
NS_IMETHOD ReadObject(PRBool aIsStrongRef, nsISupports* *_retval);
|
||||
NS_IMETHOD ReadID(nsID *aResult);
|
||||
|
||||
void SeekTo(PRInt64 aOffset) {
|
||||
mFilePos = PR_MAX(0, PR_MIN(aOffset, mFileLen));
|
||||
NS_ASSERTION(aOffset == mFilePos, "Attempt to seek out of bounds");
|
||||
}
|
||||
|
||||
// nsIFastLoadFileControl methods
|
||||
NS_DECL_NSIFASTLOADFILECONTROL
|
||||
|
||||
@ -291,16 +297,6 @@ class nsFastLoadFileReader
|
||||
|
||||
// Override Read so we can demultiplex a document interleaved with others.
|
||||
NS_IMETHOD Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead);
|
||||
|
||||
// Override ReadSegments too, as nsBinaryInputStream::ReadSegments does
|
||||
// not call through our overridden Read method -- it calls directly into
|
||||
// the underlying input stream.
|
||||
NS_IMETHODIMP ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
PRUint32 aCount, PRUint32 *aResult);
|
||||
|
||||
// Override SetInputStream so we can update mSeekableInput
|
||||
NS_IMETHOD SetInputStream(nsIInputStream* aInputStream);
|
||||
|
||||
nsresult ReadHeader(nsFastLoadHeader *aHeader);
|
||||
|
||||
/**
|
||||
@ -313,6 +309,9 @@ class nsFastLoadFileReader
|
||||
PRUint16 mSaveWeakRefCnt; // after a Read
|
||||
};
|
||||
|
||||
NS_IMETHODIMP ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
PRUint32 aCount, PRUint32 *aResult);
|
||||
|
||||
/**
|
||||
* In-memory representation of the FastLoad file footer.
|
||||
*/
|
||||
@ -389,20 +388,23 @@ class nsFastLoadFileReader
|
||||
NS_IMETHOD Close();
|
||||
|
||||
protected:
|
||||
// Kept in sync with mInputStream to avoid repeated QI
|
||||
nsCOMPtr<nsISeekableStream> mSeekableInput;
|
||||
|
||||
nsFastLoadHeader mHeader;
|
||||
nsFastLoadFooter mFooter;
|
||||
|
||||
nsDocumentMapReadEntry* mCurrentDocumentMapEntry;
|
||||
|
||||
friend class nsFastLoadFileUpdater;
|
||||
nsIFile *mFile; // .mfasl file
|
||||
PRFileDesc *mFd; // OS file-descriptor
|
||||
PRUint32 mFileLen; // length of file
|
||||
PRUint32 mFilePos; // current position within file
|
||||
PRFileMap *mFileMap;// nspr datastructure for mmap
|
||||
PRUint8 *mFileData; // pointer to mmaped file
|
||||
};
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult NS_OUTPARAM,
|
||||
nsIInputStream* aSrcStream);
|
||||
nsIFile* aFile);
|
||||
|
||||
/**
|
||||
* Inherit from the concrete class nsBinaryInputStream, which inherits from
|
||||
@ -537,12 +539,11 @@ NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult NS_OUTPARAM,
|
||||
* that maps all data on Close.
|
||||
*/
|
||||
class nsFastLoadFileUpdater
|
||||
: public nsFastLoadFileWriter,
|
||||
private nsIFastLoadFileIO
|
||||
: public nsFastLoadFileWriter
|
||||
{
|
||||
public:
|
||||
nsFastLoadFileUpdater(nsIOutputStream* aOutputStream)
|
||||
: nsFastLoadFileWriter(aOutputStream, nsnull) {
|
||||
nsFastLoadFileUpdater(nsIOutputStream* aOutputStream, nsIFastLoadFileIO *aFileIO)
|
||||
: nsFastLoadFileWriter(aOutputStream, aFileIO) {
|
||||
MOZ_COUNT_CTOR(nsFastLoadFileUpdater);
|
||||
}
|
||||
|
||||
@ -554,9 +555,6 @@ class nsFastLoadFileUpdater
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIFastLoadFileIO methods
|
||||
NS_DECL_NSIFASTLOADFILEIO
|
||||
|
||||
nsresult Open(nsFastLoadFileReader* aReader);
|
||||
NS_IMETHOD Close();
|
||||
|
||||
@ -577,7 +575,7 @@ class nsFastLoadFileUpdater
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult NS_OUTPARAM,
|
||||
nsIOutputStream* aOutputStream,
|
||||
nsIFastLoadFileIO* aFileIO,
|
||||
nsIObjectInputStream* aReaderAsStream);
|
||||
|
||||
#endif // nsFastLoadFile_h___
|
||||
|
@ -163,16 +163,16 @@ nsFastLoadService::NewFastLoadFile(const char* aBaseName, nsIFile* *aResult)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadService::NewInputStream(nsIInputStream* aSrcStream,
|
||||
nsIObjectInputStream* *aResult)
|
||||
nsFastLoadService::NewInputStream(nsIFile *aFile, nsIObjectInputStream* *aResult)
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
nsCOMPtr<nsIObjectInputStream> stream;
|
||||
nsresult rv = NS_NewFastLoadFileReader(getter_AddRefs(stream), aSrcStream);
|
||||
nsresult rv = NS_NewFastLoadFileReader(getter_AddRefs(stream), aFile);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mFileIO->DisableTruncate();
|
||||
*aResult = stream;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
@ -285,15 +285,9 @@ nsFastLoadService::StartMuxedDocument(nsISupports* aURI, const char* aURISpec,
|
||||
// Ok, aURISpec is not in the existing mux. If we have no output
|
||||
// stream yet, wrap the reader with a FastLoad file updater.
|
||||
if (!mOutputStream && mFileIO) {
|
||||
nsCOMPtr<nsIOutputStream> output;
|
||||
rv = mFileIO->GetOutputStream(getter_AddRefs(output));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// NB: mInputStream must be an nsFastLoadFileReader!
|
||||
rv = NS_NewFastLoadFileUpdater(getter_AddRefs(mOutputStream),
|
||||
output,
|
||||
mInputStream);
|
||||
mFileIO, mInputStream);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
@ -54,13 +54,13 @@ interface nsISimpleEnumerator;
|
||||
* implementation may still be useful for object serialization, but it can't be
|
||||
* used to read or write a Mozilla FastLoad file.
|
||||
*/
|
||||
[scriptable, uuid(8a1e2c63-af50-4147-af7e-26289dc180dd)]
|
||||
[scriptable, uuid(e7c8c14f-c273-4e70-826f-b85864303dc6)]
|
||||
interface nsIFastLoadFileControl : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get and set the recorded checksum value from the FastLoad file header.
|
||||
* Get the recorded checksum value from the FastLoad file header.
|
||||
*/
|
||||
attribute PRUint32 checksum;
|
||||
readonly attribute PRUint32 checksum;
|
||||
|
||||
/**
|
||||
* Multiplexed document control methods. A FastLoad file may contain
|
||||
|
@ -46,19 +46,23 @@ interface nsIOutputStream;
|
||||
interface nsIObjectInputStream;
|
||||
interface nsIObjectOutputStream;
|
||||
|
||||
[scriptable, uuid(715577db-d9c5-464a-a32e-0a40c29b22d4)]
|
||||
[scriptable, uuid(61cd17e0-b07a-4158-9817-36a206b100e9)]
|
||||
interface nsIFastLoadFileIO : nsISupports
|
||||
{
|
||||
readonly attribute nsIInputStream inputStream;
|
||||
readonly attribute nsIOutputStream outputStream;
|
||||
/**
|
||||
* Causes outputStream to be created in non-truncating mode
|
||||
*/
|
||||
[noscript] void disableTruncate();
|
||||
};
|
||||
|
||||
[scriptable, uuid(759e475e-0c23-4dbf-b1b8-78c9369e3072)]
|
||||
[scriptable, uuid(c18df300-c2e4-4115-a61c-9110655f7dd8)]
|
||||
interface nsIFastLoadService : nsISupports
|
||||
{
|
||||
nsIFile newFastLoadFile(in string aBaseName);
|
||||
|
||||
nsIObjectInputStream newInputStream(in nsIInputStream aSrcStream);
|
||||
nsIObjectInputStream newInputStream(in nsIFile aFile);
|
||||
nsIObjectOutputStream newOutputStream(in nsIOutputStream aDestStream);
|
||||
|
||||
// Flag values for the direction attribute and the aDirectionFlags
|
||||
|
Loading…
Reference in New Issue
Block a user