Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Private Member Functions | Private Attributes
nsDiskCacheStreamIO Class Reference

#include <nsDiskCacheStreams.h>

Inheritance diagram for nsDiskCacheStreamIO:
Inheritance graph
[legend]
Collaboration diagram for nsDiskCacheStreamIO:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 nsDiskCacheStreamIO (nsDiskCacheBinding *binding)
virtual ~nsDiskCacheStreamIO ()
NS_DECL_ISUPPORTS nsresult GetInputStream (PRUint32 offset, nsIInputStream **inputStream)
nsresult GetOutputStream (PRUint32 offset, nsIOutputStream **outputStream)
nsresult CloseOutputStream (nsDiskCacheOutputStream *outputStream)
nsresult Write (const char *buffer, PRUint32 count, PRUint32 *bytesWritten)
nsresult Seek (PRInt32 whence, PRInt32 offset)
nsresult Tell (PRUint32 *position)
nsresult SetEOF ()
void ClearBinding ()
void IncrementInputStreamCount ()
void DecrementInputStreamCount ()
 nsDiskCacheStreamIO ()

Private Member Functions

void Close ()
nsresult OpenCacheFile (PRIntn flags, PRFileDesc **fd)
nsresult ReadCacheBlocks ()
nsresult FlushBufferToFile (PRBool clearBuffer)
PRUint32 WriteToBuffer (const char *buffer, PRUint32 count)
nsresult UpdateFileSize ()
void DeleteBuffer ()
nsresult Flush ()

Private Attributes

nsDiskCacheBindingmBinding
nsDiskCacheDevicemDevice
nsDiskCacheOutputStreammOutStream
PRInt32 mInStreamCount
nsCOMPtr< nsILocalFilemLocalFile
PRFileDescmFD
PRUint32 mStreamPos
PRUint32 mStreamEnd
PRUint32 mBufPos
PRUint32 mBufEnd
PRUint32 mBufSize
PRBool mBufDirty
char * mBuffer

Detailed Description

Definition at line 58 of file nsDiskCacheStreams.h.


Constructor & Destructor Documentation

Definition at line 306 of file nsDiskCacheStreams.cpp.

    : mBinding(binding)
    , mOutStream(nsnull)
    , mInStreamCount(0)
    , mFD(nsnull)
    , mStreamPos(0)
    , mStreamEnd(0)
    , mBufPos(0)
    , mBufEnd(0)
    , mBufSize(0)
    , mBufDirty(PR_FALSE)
    , mBuffer(nsnull)
{
    mDevice = (nsDiskCacheDevice *)mBinding->mCacheEntry->CacheDevice();

    // acquire "death grip" on cache service
    nsCacheService *service = nsCacheService::GlobalInstance();
    NS_ADDREF(service);
}

Here is the call graph for this function:

Definition at line 327 of file nsDiskCacheStreams.cpp.

{
    Close();

    // release "death grip" on cache service
    nsCacheService *service = nsCacheService::GlobalInstance();
    NS_RELEASE(service);
}

Here is the call graph for this function:

Definition at line 89 of file nsDiskCacheStreams.h.

{ NS_NOTREACHED("oops"); }

Member Function Documentation

Definition at line 436 of file nsDiskCacheStreams.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 338 of file nsDiskCacheStreams.cpp.

{
    // this should only be called from our destructor
    // no one is interested in us anymore, so we don't need to grab any locks
    
    // assert streams closed
    NS_ASSERTION(!mOutStream, "output stream still open");
    NS_ASSERTION(mInStreamCount == 0, "input stream still open");
    NS_ASSERTION(!mFD, "file descriptor not closed");

    DeleteBuffer();
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 444 of file nsDiskCacheStreams.cpp.

{
    nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock
    nsresult   rv;

    if (outputStream != mOutStream) {
        NS_WARNING("mismatched output streams");
        return NS_ERROR_UNEXPECTED;
    }
    
    // output stream is closing
    if (!mBinding) {    // if we're severed, just clear member variables
        NS_ASSERTION(!mBufDirty, "oops");
        mOutStream = nsnull;
        outputStream->ReleaseStreamIO();
        return NS_ERROR_NOT_AVAILABLE;
    }

    rv = Flush();
    NS_ASSERTION(NS_SUCCEEDED(rv), "Flush() failed");

    mOutStream = nsnull;
    return rv;
}

Here is the call graph for this function:

Definition at line 81 of file nsDiskCacheStreams.h.

                {
                    PR_AtomicDecrement(&mInStreamCount);
                    NS_ASSERTION(mInStreamCount >= 0, "mInStreamCount has gone negative");
                }

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 754 of file nsDiskCacheStreams.cpp.

{
    if (mBuffer) {
        NS_ASSERTION(mBufDirty == PR_FALSE, "deleting dirty buffer");
        free(mBuffer);
        mBuffer = nsnull;
        mBufPos = 0;
        mBufEnd = 0;
        mBufSize = 0;
    }
}

Here is the caller graph for this function:

Definition at line 470 of file nsDiskCacheStreams.cpp.

{
    NS_ASSERTION(mBinding, "oops");

    if (!mBufDirty)
        return NS_OK;

    // write data to cache blocks, or flush mBuffer to file
    nsDiskCacheMap *cacheMap = mDevice->CacheMap();  // get map reference
    nsresult rv;
    
    if ((mStreamEnd > kMaxBufferSize) ||
        (mBinding->mCacheEntry->StoragePolicy() == nsICache::STORE_ON_DISK_AS_FILE)) {
        // make sure we save as separate file
        rv = FlushBufferToFile(PR_TRUE);       // will initialize DataFileLocation() if necessary

        if (mFD) {
          // close file descriptor
          (void) PR_Close(mFD);
          mFD = nsnull;
        }
        else
          NS_WARNING("no file descriptor");

        // close mFD first if possible before returning if FlushBufferToFile
        // failed
        NS_ENSURE_SUCCESS(rv, rv);

        // since the data location is on disk as a single file, the only value
        // in keeping mBuffer around is to avoid an extra malloc the next time
        // we need to write to this file.  reading will use a file descriptor.
        // therefore, it's probably not worth optimizing for the subsequent
        // write, so we unconditionally delete mBuffer here.
        DeleteBuffer();

    } else {
        // store data (if any) in cache block files
        
        // delete existing storage
        nsDiskCacheRecord * record = &mBinding->mRecord;
        if (record->DataLocationInitialized()) {
            rv = cacheMap->DeleteStorage(record, nsDiskCache::kData);
            if (NS_FAILED(rv)) {
                NS_WARNING("cacheMap->DeleteStorage() failed.");
                cacheMap->DoomRecord(record);
                return  rv;
            }
        }
    
        // flush buffer to block files
        if (mStreamEnd > 0) {
            rv = cacheMap->WriteDataCacheBlocks(mBinding, mBuffer, mBufEnd);
            if (NS_FAILED(rv)) {
                NS_WARNING("WriteDataCacheBlocks() failed.");
                return rv;   // XXX doom cache entry?
                
            }
        }

        mBufDirty = PR_FALSE;
    }
    
    // XXX do we need this here?  WriteDataCacheBlocks() calls UpdateRecord()
    // update cache map if entry isn't doomed
    if (!mBinding->mDoomed) {
        rv = cacheMap->UpdateRecord(&mBinding->mRecord);
        if (NS_FAILED(rv)) {
            NS_WARNING("cacheMap->UpdateRecord() failed.");
            return rv;   // XXX doom cache entry
        }
    }
    
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 676 of file nsDiskCacheStreams.cpp.

{
    nsresult  rv;
    nsDiskCacheRecord * record = &mBinding->mRecord;
    
    if (!mFD) {
        if (record->DataLocationInitialized() && (record->DataFile() > 0)) {
            // remove cache block storage
            nsDiskCacheMap * cacheMap = mDevice->CacheMap();
            rv = cacheMap->DeleteStorage(record, nsDiskCache::kData);
            if (NS_FAILED(rv))  return rv;
        }
        record->SetDataFileGeneration(mBinding->mGeneration);
        
        // allocate file
        rv = OpenCacheFile(PR_RDWR | PR_CREATE_FILE, &mFD);
        if (NS_FAILED(rv))  return rv;
    }
    
    // write buffer
    PRInt32 bytesWritten = PR_Write(mFD, mBuffer, mBufEnd);
    if (PRUint32(bytesWritten) != mBufEnd) {
        NS_WARNING("failed to flush all data");
        return NS_ERROR_UNEXPECTED;     // NS_ErrorAccordingToNSPR()
    }
    mBufDirty = PR_FALSE;
    
    if (clearBuffer) {
        // reset buffer
        mBufPos = 0;
        mBufEnd = 0;
    }
    
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 354 of file nsDiskCacheStreams.cpp.

{
    NS_ENSURE_ARG_POINTER(inputStream);
    NS_ENSURE_TRUE(offset == 0, NS_ERROR_NOT_IMPLEMENTED);

    *inputStream = nsnull;
    
    if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;

    if (mOutStream) {
        NS_WARNING("already have an output stream open");
        return NS_ERROR_NOT_AVAILABLE;
    }

    nsresult            rv;
    PRFileDesc *        fd = nsnull;

    mStreamEnd = mBinding->mCacheEntry->DataSize();
    if (mStreamEnd == 0) {
        // there's no data to read
        NS_ASSERTION(!mBinding->mRecord.DataLocationInitialized(), "storage allocated for zero data size");
    } else if (mBinding->mRecord.DataFile() == 0) {
        // open file desc for data
        rv = OpenCacheFile(PR_RDONLY, &fd);
        if (NS_FAILED(rv))  return rv;  // unable to open file        
        NS_ASSERTION(fd, "cache stream lacking open file.");
            
    } else if (!mBuffer) {
        // read block file for data
        rv = ReadCacheBlocks();
        if (NS_FAILED(rv))  return rv;
    }
    // else, mBuffer already contains all of the data (left over from a
    // previous block-file read or write).

    NS_ASSERTION(!(fd && mBuffer), "ambiguous data sources for input stream");

    // create a new input stream
    nsDiskCacheInputStream * inStream = new nsDiskCacheInputStream(this, fd, mBuffer, mStreamEnd);
    if (!inStream)  return NS_ERROR_OUT_OF_MEMORY;
    
    NS_ADDREF(*inputStream = inStream);
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 402 of file nsDiskCacheStreams.cpp.

{
    NS_ENSURE_ARG_POINTER(outputStream);
    *outputStream = nsnull;

    if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;
        
    NS_ASSERTION(!mOutStream, "already have an output stream open");
    NS_ASSERTION(mInStreamCount == 0, "we already have input streams open");
    if (mOutStream || mInStreamCount)  return NS_ERROR_NOT_AVAILABLE;
    
    // mBuffer lazily allocated, but might exist if a previous stream already
    // created one.
    mBufPos    = 0;
    mStreamPos = 0;
    mStreamEnd = mBinding->mCacheEntry->DataSize();

    nsresult rv;
    if (offset) {
        rv = Seek(PR_SEEK_SET, offset);
        if (NS_FAILED(rv)) return rv;
    }
    rv = SetEOF();
    if (NS_FAILED(rv)) return rv;

    // create a new output stream
    mOutStream = new nsDiskCacheOutputStream(this);
    if (!mOutStream)  return NS_ERROR_OUT_OF_MEMORY;
    
    NS_ADDREF(*outputStream = mOutStream);
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 80 of file nsDiskCacheStreams.h.

Here is the call graph for this function:

nsresult nsDiskCacheStreamIO::OpenCacheFile ( PRIntn  flags,
PRFileDesc **  fd 
) [private]

Definition at line 618 of file nsDiskCacheStreams.cpp.

{
    NS_ENSURE_ARG_POINTER(fd);
    
    nsresult         rv;
    nsDiskCacheMap * cacheMap = mDevice->CacheMap();
    
    rv = cacheMap->GetLocalFileForDiskCacheRecord(&mBinding->mRecord,
                                                  nsDiskCache::kData,
                                                  getter_AddRefs(mLocalFile));
    if (NS_FAILED(rv))  return rv;
    
    // create PRFileDesc for input stream - the 00600 is just for consistency
    rv = mLocalFile->OpenNSPRFileDesc(flags, 00600, fd);
    if (NS_FAILED(rv))  return rv;  // unable to open file

    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 639 of file nsDiskCacheStreams.cpp.

{
    NS_ASSERTION(mStreamEnd == mBinding->mCacheEntry->DataSize(), "bad stream");
    NS_ASSERTION(mStreamEnd <= kMaxBufferSize, "data too large for buffer");

    nsDiskCacheRecord * record = &mBinding->mRecord;
    if (!record->DataLocationInitialized()) return NS_OK;

    NS_ASSERTION(record->DataFile() != kSeparateFile, "attempt to read cache blocks on separate file");

    PRUint32 bufSize = record->DataBlockCount() * record->DataBlockSize();
    
    if (!mBuffer) {
        // allocate buffer
        mBufSize  = bufSize;
        mBuffer   = (char *) malloc(mBufSize);
        if (!mBuffer) {
            mBufSize = 0;
            return NS_ERROR_OUT_OF_MEMORY;
        }
    }
    NS_ASSERTION(bufSize <= mBufSize, "allocated buffer is too small");
    
    // read data stored in cache block files            
    nsDiskCacheMap *map = mDevice->CacheMap();  // get map reference
    nsresult rv = map->ReadDataCacheBlocks(mBinding, mBuffer, mBufSize);
    if (NS_FAILED(rv)) return rv;

    // update streamIO variables
    mBufPos = 0;
    mBufEnd = mStreamEnd;
    
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 769 of file nsDiskCacheStreams.cpp.

{
    PRInt32  newPos;
    if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;

    if (PRUint32(offset) > mStreamEnd)  return NS_ERROR_FAILURE;
 
    if (mBinding->mRecord.DataLocationInitialized()) {
        if (mBinding->mRecord.DataFile() == 0) {
            if (!mFD) {
                // we need an mFD, we better open it now
                nsresult rv = OpenCacheFile(PR_RDWR | PR_CREATE_FILE, &mFD);
                if (NS_FAILED(rv))  return rv;
            }
        }
    }

    if (mFD) {
        // do we have data in the buffer that needs to be flushed?
        if (mBufDirty) {
            // XXX optimization: are we just moving within the current buffer?
            nsresult rv = FlushBufferToFile(PR_TRUE);
            if (NS_FAILED(rv))  return rv;
        }
    
        newPos = PR_Seek(mFD, offset, (PRSeekWhence)whence);
        if (newPos == -1)
            return NS_ErrorAccordingToNSPR();
        
        mStreamPos = (PRUint32) newPos;
        mBufPos = 0;
        mBufEnd = 0;
        return NS_OK;
    }
    
    // else, seek in mBuffer
    
    switch(whence) {
        case PR_SEEK_SET:
            newPos = offset;
            break;
        
        case PR_SEEK_CUR:   // relative from current posistion
            newPos = offset + (PRUint32)mStreamPos;
            break;
            
        case PR_SEEK_END:   // relative from end
            newPos = offset + (PRUint32)mBufEnd;
            break;
        
        default:
            return NS_ERROR_INVALID_ARG;
    }

    // read data into mBuffer if not read yet.
    if (mStreamEnd && !mBufEnd) {
        if (newPos > 0) {
            nsresult rv = ReadCacheBlocks();
            if (NS_FAILED(rv))  return rv;
        }
    }

    // stream buffer sanity checks
    NS_ASSERTION(mBufEnd <= (16 * 1024), "bad stream");
    NS_ASSERTION(mBufPos <= mBufEnd,     "bad stream");
    NS_ASSERTION(mStreamPos == mBufPos,  "bad stream");
    NS_ASSERTION(mStreamEnd == mBufEnd,  "bad stream");
    
    if ((newPos < 0) || (PRUint32(newPos) > mBufEnd)) {
        NS_WARNING("seek offset out of range");
        return NS_ERROR_INVALID_ARG;
    }

    mStreamPos = newPos;
    mBufPos    = newPos;
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 860 of file nsDiskCacheStreams.cpp.

{
    nsresult    rv;
    PRBool      needToCloseFD = PR_FALSE;

    NS_ASSERTION(mStreamPos <= mStreamEnd, "bad stream");
    if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;
    
    if (mBinding->mRecord.DataLocationInitialized()) {
        if (mBinding->mRecord.DataFile() == 0) {
            if (!mFD) {
                // we need an mFD, we better open it now
                rv = OpenCacheFile(PR_RDWR | PR_CREATE_FILE, &mFD);
                if (NS_FAILED(rv))  return rv;
                needToCloseFD = PR_TRUE;
            }
        } else {
            // data in cache block files
            if ((mStreamPos != 0) && (mStreamPos != mBufPos)) {
                // only read data if there will be some left after truncation
                rv = ReadCacheBlocks();
                if (NS_FAILED(rv))  return rv;
            }
        }
    }
    
    if (mFD) {
        rv = nsDiskCache::Truncate(mFD, mStreamPos);
#ifdef DEBUG
        PRUint32 oldSizeK = (mStreamEnd + 0x03FF) >> 10;
        NS_ASSERTION(mBinding->mRecord.DataFileSize() == oldSizeK, "bad disk cache entry size");
    } else {
        // data stored in buffer.
        NS_ASSERTION(mStreamEnd < (16 * 1024), "buffer truncation inadequate");
        NS_ASSERTION(mBufPos == mStreamPos, "bad stream");
        NS_ASSERTION(mBuffer ? mBufEnd == mStreamEnd : PR_TRUE, "bad stream");
#endif
    }

    NS_ASSERTION(mStreamEnd == mBinding->mCacheEntry->DataSize(), "cache entry not updated");
    // we expect nsCacheEntryDescriptor::TransportWrapper::OpenOutputStream()
    // to eventually update the cache entry    

    mStreamEnd  = mStreamPos;
    mBufEnd     = mBufPos;
    
    if (mFD) {
        UpdateFileSize();
        if (needToCloseFD) {
            (void) PR_Close(mFD);
            mFD = nsnull;
        } 
    }

    return  NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 850 of file nsDiskCacheStreams.cpp.

Definition at line 587 of file nsDiskCacheStreams.cpp.

{
    NS_ASSERTION(mFD, "nsDiskCacheStreamIO::UpdateFileSize should not have been called");
    if (!mFD)  return NS_ERROR_UNEXPECTED;
    
    nsDiskCacheRecord * record = &mBinding->mRecord;
    PRUint32            oldSizeK  = record->DataFileSize();
    PRUint32            newSizeK  = (mStreamEnd + 0x03FF) >> 10;
    
    if (newSizeK == oldSizeK)  return NS_OK;
    
    record->SetDataFileSize(newSizeK);

    // update cache size totals
    nsDiskCacheMap * cacheMap = mDevice->CacheMap();
    cacheMap->DecrementTotalSize(oldSizeK * 1024);       // decrement old size
    cacheMap->IncrementTotalSize(newSizeK * 1024);       // increment new size
    
    if (!mBinding->mDoomed) {
        nsresult rv = cacheMap->UpdateRecord(&mBinding->mRecord);
        if (NS_FAILED(rv)) {
            NS_WARNING("cacheMap->UpdateRecord() failed.");
            // XXX doom cache entry?
            return rv;
        }
    }
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsDiskCacheStreamIO::Write ( const char *  buffer,
PRUint32  count,
PRUint32 bytesWritten 
)

Definition at line 552 of file nsDiskCacheStreams.cpp.

{
    nsresult    rv = NS_OK;
    nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock
    if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;

    if (mInStreamCount) {
        // we have open input streams already
        // this is an error until we support overlapped I/O
        NS_WARNING("Attempting to write to cache entry with open input streams.\n");
        return NS_ERROR_NOT_AVAILABLE;
    }

    *bytesWritten = WriteToBuffer(buffer, count);
    if (*bytesWritten != count)  return NS_ERROR_FAILURE;

    // update mStreamPos, mStreamEnd
    mStreamPos += count;
    if (mStreamEnd < mStreamPos) {
        mStreamEnd = mStreamPos;
        NS_ASSERTION(mBinding->mCacheEntry->DataSize() == mStreamEnd, "bad stream");

        // if we have a separate file, we need to adjust the disk cache size totals here
        if (mFD) {
            rv = UpdateFileSize();
        }
    }
    
    return rv;
}

Here is the call graph for this function:

PRUint32 nsDiskCacheStreamIO::WriteToBuffer ( const char *  buffer,
PRUint32  count 
) [private]

Definition at line 714 of file nsDiskCacheStreams.cpp.

{
    NS_ASSERTION(count, "WriteToBuffer called with count of zero");
    NS_ASSERTION(mBufPos <= mBufEnd, "streamIO buffer corrupted");

    PRUint32 bytesLeft = count;
    
    while (bytesLeft) {
        if (mBufPos == mBufSize) {
            if (mBufSize < kMaxBufferSize) {
                mBufSize = kMaxBufferSize;
                mBuffer  = (char *) realloc(mBuffer, mBufSize);
                if (!mBuffer)  {
                    mBufSize = 0;
                    return 0;
                }
            } else {
                nsresult rv = FlushBufferToFile(PR_TRUE);
                if (NS_FAILED(rv))  return 0;
            }
        }
        
        PRUint32 chunkSize = bytesLeft;
        if (chunkSize > (mBufSize - mBufPos))
            chunkSize =  mBufSize - mBufPos;
        
        memcpy(mBuffer + mBufPos, buffer, chunkSize);
        mBufDirty = PR_TRUE;
        mBufPos += chunkSize;
        bytesLeft -= chunkSize;
        buffer += chunkSize;
        
        if (mBufEnd < mBufPos)
            mBufEnd = mBufPos;
    }
    
    return count;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 103 of file nsDiskCacheStreams.h.

Definition at line 115 of file nsDiskCacheStreams.h.

Definition at line 113 of file nsDiskCacheStreams.h.

Definition at line 116 of file nsDiskCacheStreams.h.

Definition at line 112 of file nsDiskCacheStreams.h.

Definition at line 114 of file nsDiskCacheStreams.h.

Definition at line 104 of file nsDiskCacheStreams.h.

Definition at line 108 of file nsDiskCacheStreams.h.

Definition at line 106 of file nsDiskCacheStreams.h.

Definition at line 107 of file nsDiskCacheStreams.h.

Definition at line 105 of file nsDiskCacheStreams.h.

Definition at line 111 of file nsDiskCacheStreams.h.

Definition at line 110 of file nsDiskCacheStreams.h.


The documentation for this class was generated from the following files: