Bug 412796: Optimize fastload system (mmap fileIO) r=brendan

--HG--
extra : rebase_source : 425e1c4254b8e5c7c3b9fc98efb91c06805d1f02
This commit is contained in:
Taras Glek 2009-10-08 10:30:21 -07:00
parent 005dd93cd6
commit 0192baad2a
8 changed files with 164 additions and 288 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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(&currentOffset);
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;

View File

@ -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___

View File

@ -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;
}

View File

@ -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

View File

@ -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