ole32: Cache data and block locations in BigBlockStream objects.
This commit is contained in:
parent
101de22a1a
commit
89646084ba
|
@ -2857,7 +2857,10 @@ end:
|
|||
*result = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
StorageImpl_Flush((StorageBaseImpl*)This);
|
||||
*result = This;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -2896,8 +2899,26 @@ static void StorageImpl_Destroy(StorageBaseImpl* iface)
|
|||
static HRESULT StorageImpl_Flush(StorageBaseImpl* iface)
|
||||
{
|
||||
StorageImpl *This = (StorageImpl*) iface;
|
||||
int i;
|
||||
HRESULT hr;
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
return ILockBytes_Flush(This->lockBytes);
|
||||
hr = BlockChainStream_Flush(This->smallBlockRootChain);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = BlockChainStream_Flush(This->rootBlockChain);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = BlockChainStream_Flush(This->smallBlockDepotChain);
|
||||
|
||||
for (i=0; SUCCEEDED(hr) && i<BLOCKCHAIN_CACHE_SIZE; i++)
|
||||
if (This->blockChainCache[i])
|
||||
hr = BlockChainStream_Flush(This->blockChainCache[i]);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = ILockBytes_Flush(This->lockBytes);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -5820,6 +5841,53 @@ ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset)
|
|||
return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset;
|
||||
}
|
||||
|
||||
HRESULT BlockChainStream_GetBlockAtOffset(BlockChainStream *This,
|
||||
ULONG index, BlockChainBlock **block, ULONG *sector, BOOL create)
|
||||
{
|
||||
BlockChainBlock *result=NULL;
|
||||
int i;
|
||||
|
||||
for (i=0; i<2; i++)
|
||||
if (This->cachedBlocks[i].index == index)
|
||||
{
|
||||
*sector = This->cachedBlocks[i].sector;
|
||||
*block = &This->cachedBlocks[i];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*sector = BlockChainStream_GetSectorOfOffset(This, index);
|
||||
if (*sector == BLOCK_END_OF_CHAIN)
|
||||
return STG_E_DOCFILECORRUPT;
|
||||
|
||||
if (create)
|
||||
{
|
||||
if (This->cachedBlocks[0].index == 0xffffffff)
|
||||
result = &This->cachedBlocks[0];
|
||||
else if (This->cachedBlocks[1].index == 0xffffffff)
|
||||
result = &This->cachedBlocks[1];
|
||||
else
|
||||
{
|
||||
result = &This->cachedBlocks[This->blockToEvict++];
|
||||
if (This->blockToEvict == 2)
|
||||
This->blockToEvict = 0;
|
||||
}
|
||||
|
||||
if (result->dirty)
|
||||
{
|
||||
if (!StorageImpl_WriteBigBlock(This->parentStorage, result->sector, result->data))
|
||||
return STG_E_WRITEFAULT;
|
||||
result->dirty = 0;
|
||||
}
|
||||
|
||||
result->read = 0;
|
||||
result->index = index;
|
||||
result->sector = *sector;
|
||||
}
|
||||
|
||||
*block = result;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BlockChainStream* BlockChainStream_Construct(
|
||||
StorageImpl* parentStorage,
|
||||
ULONG* headOfStreamPlaceHolder,
|
||||
|
@ -5835,6 +5903,11 @@ BlockChainStream* BlockChainStream_Construct(
|
|||
newStream->indexCache = NULL;
|
||||
newStream->indexCacheLen = 0;
|
||||
newStream->indexCacheSize = 0;
|
||||
newStream->cachedBlocks[0].index = 0xffffffff;
|
||||
newStream->cachedBlocks[0].dirty = 0;
|
||||
newStream->cachedBlocks[1].index = 0xffffffff;
|
||||
newStream->cachedBlocks[1].dirty = 0;
|
||||
newStream->blockToEvict = 0;
|
||||
|
||||
if (FAILED(BlockChainStream_UpdateIndexCache(newStream)))
|
||||
{
|
||||
|
@ -5846,10 +5919,30 @@ BlockChainStream* BlockChainStream_Construct(
|
|||
return newStream;
|
||||
}
|
||||
|
||||
HRESULT BlockChainStream_Flush(BlockChainStream* This)
|
||||
{
|
||||
int i;
|
||||
if (!This) return S_OK;
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
if (This->cachedBlocks[i].dirty)
|
||||
{
|
||||
if (StorageImpl_WriteBigBlock(This->parentStorage, This->cachedBlocks[i].sector, This->cachedBlocks[i].data))
|
||||
This->cachedBlocks[i].dirty = 0;
|
||||
else
|
||||
return STG_E_WRITEFAULT;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void BlockChainStream_Destroy(BlockChainStream* This)
|
||||
{
|
||||
if (This)
|
||||
{
|
||||
BlockChainStream_Flush(This);
|
||||
HeapFree(GetProcessHeap(), 0, This->indexCache);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
|
@ -5915,6 +6008,8 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
|
|||
ULONG blockIndex;
|
||||
BYTE* bufferWalker;
|
||||
ULARGE_INTEGER stream_size;
|
||||
HRESULT hr;
|
||||
BlockChainBlock *cachedBlock;
|
||||
|
||||
TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
|
||||
|
||||
|
@ -5936,17 +6031,25 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
|
|||
*/
|
||||
bufferWalker = buffer;
|
||||
|
||||
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
|
||||
while (size > 0)
|
||||
{
|
||||
ULARGE_INTEGER ulOffset;
|
||||
DWORD bytesReadAt;
|
||||
|
||||
/*
|
||||
* Calculate how many bytes we can copy from this big block.
|
||||
*/
|
||||
bytesToReadInBuffer =
|
||||
min(This->parentStorage->bigBlockSize - offsetInBlock, size);
|
||||
|
||||
TRACE("block %i\n",blockIndex);
|
||||
hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToReadInBuffer);
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (!cachedBlock)
|
||||
{
|
||||
/* Not in cache, and we're going to read past the end of the block. */
|
||||
ulOffset.u.HighPart = 0;
|
||||
ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
|
||||
offsetInBlock;
|
||||
|
@ -5956,12 +6059,22 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
|
|||
bufferWalker,
|
||||
bytesToReadInBuffer,
|
||||
&bytesReadAt);
|
||||
/*
|
||||
* Step to the next big block.
|
||||
*/
|
||||
if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
|
||||
return STG_E_DOCFILECORRUPT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cachedBlock->read)
|
||||
{
|
||||
if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
|
||||
return STG_E_READFAULT;
|
||||
|
||||
cachedBlock->read = 1;
|
||||
}
|
||||
|
||||
memcpy(bufferWalker, cachedBlock->data+offsetInBlock, bytesToReadInBuffer);
|
||||
bytesReadAt = bytesToReadInBuffer;
|
||||
}
|
||||
|
||||
blockNoInSequence++;
|
||||
bufferWalker += bytesReadAt;
|
||||
size -= bytesReadAt;
|
||||
*bytesRead += bytesReadAt;
|
||||
|
@ -5991,34 +6104,36 @@ HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
|
|||
ULONG bytesToWrite;
|
||||
ULONG blockIndex;
|
||||
const BYTE* bufferWalker;
|
||||
|
||||
/*
|
||||
* Find the first block in the stream that contains part of the buffer.
|
||||
*/
|
||||
blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
|
||||
|
||||
/* BlockChainStream_SetSize should have already been called to ensure we have
|
||||
* enough blocks in the chain to write into */
|
||||
if (blockIndex == BLOCK_END_OF_CHAIN)
|
||||
{
|
||||
ERR("not enough blocks in chain to write data\n");
|
||||
return STG_E_DOCFILECORRUPT;
|
||||
}
|
||||
HRESULT hr;
|
||||
BlockChainBlock *cachedBlock;
|
||||
|
||||
*bytesWritten = 0;
|
||||
bufferWalker = buffer;
|
||||
|
||||
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
|
||||
while (size > 0)
|
||||
{
|
||||
ULARGE_INTEGER ulOffset;
|
||||
DWORD bytesWrittenAt;
|
||||
|
||||
/*
|
||||
* Calculate how many bytes we can copy from this big block.
|
||||
* Calculate how many bytes we can copy to this big block.
|
||||
*/
|
||||
bytesToWrite =
|
||||
min(This->parentStorage->bigBlockSize - offsetInBlock, size);
|
||||
|
||||
TRACE("block %i\n",blockIndex);
|
||||
hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToWrite);
|
||||
|
||||
/* BlockChainStream_SetSize should have already been called to ensure we have
|
||||
* enough blocks in the chain to write into */
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERR("not enough blocks in chain to write data\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (!cachedBlock)
|
||||
{
|
||||
/* Not in cache, and we're going to write past the end of the block. */
|
||||
ulOffset.u.HighPart = 0;
|
||||
ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
|
||||
offsetInBlock;
|
||||
|
@ -6028,14 +6143,22 @@ HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
|
|||
bufferWalker,
|
||||
bytesToWrite,
|
||||
&bytesWrittenAt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cachedBlock->read && bytesToWrite != This->parentStorage->bigBlockSize)
|
||||
{
|
||||
if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
|
||||
return STG_E_READFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step to the next big block.
|
||||
*/
|
||||
if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
|
||||
&blockIndex)))
|
||||
return STG_E_DOCFILECORRUPT;
|
||||
memcpy(cachedBlock->data+offsetInBlock, bufferWalker, bytesToWrite);
|
||||
bytesWrittenAt = bytesToWrite;
|
||||
cachedBlock->read = 1;
|
||||
cachedBlock->dirty = 1;
|
||||
}
|
||||
|
||||
blockNoInSequence++;
|
||||
bufferWalker += bytesWrittenAt;
|
||||
size -= bytesWrittenAt;
|
||||
*bytesWritten += bytesWrittenAt;
|
||||
|
@ -6058,6 +6181,7 @@ static BOOL BlockChainStream_Shrink(BlockChainStream* This,
|
|||
{
|
||||
ULONG blockIndex;
|
||||
ULONG numBlocks;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Figure out how many blocks are needed to contain the new size
|
||||
|
@ -6125,6 +6249,18 @@ static BOOL BlockChainStream_Shrink(BlockChainStream* This,
|
|||
last_run->lastOffset--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the last accessed block cache.
|
||||
*/
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
if (This->cachedBlocks[i].index >= numBlocks)
|
||||
{
|
||||
This->cachedBlocks[i].index = 0xffffffff;
|
||||
This->cachedBlocks[i].dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -512,6 +512,15 @@ struct BlockChainRun
|
|||
ULONG lastOffset;
|
||||
};
|
||||
|
||||
typedef struct BlockChainBlock
|
||||
{
|
||||
ULONG index;
|
||||
ULONG sector;
|
||||
int read;
|
||||
int dirty;
|
||||
BYTE data[MAX_BIG_BLOCK_SIZE];
|
||||
} BlockChainBlock;
|
||||
|
||||
struct BlockChainStream
|
||||
{
|
||||
StorageImpl* parentStorage;
|
||||
|
@ -520,6 +529,8 @@ struct BlockChainStream
|
|||
struct BlockChainRun* indexCache;
|
||||
ULONG indexCacheLen;
|
||||
ULONG indexCacheSize;
|
||||
BlockChainBlock cachedBlocks[2];
|
||||
ULONG blockToEvict;
|
||||
ULONG tailIndex;
|
||||
ULONG numBlocks;
|
||||
};
|
||||
|
@ -553,6 +564,9 @@ BOOL BlockChainStream_SetSize(
|
|||
BlockChainStream* This,
|
||||
ULARGE_INTEGER newSize);
|
||||
|
||||
HRESULT BlockChainStream_Flush(
|
||||
BlockChainStream* This);
|
||||
|
||||
/****************************************************************************
|
||||
* SmallBlockChainStream definitions.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue