Commit 89646084 authored by Vincent Povirk's avatar Vincent Povirk Committed by Alexandre Julliard

ole32: Cache data and block locations in BigBlockStream objects.

parent 101de22a
...@@ -2857,7 +2857,10 @@ end: ...@@ -2857,7 +2857,10 @@ end:
*result = NULL; *result = NULL;
} }
else else
{
StorageImpl_Flush((StorageBaseImpl*)This);
*result = This; *result = This;
}
return hr; return hr;
} }
...@@ -2896,8 +2899,26 @@ static void StorageImpl_Destroy(StorageBaseImpl* iface) ...@@ -2896,8 +2899,26 @@ static void StorageImpl_Destroy(StorageBaseImpl* iface)
static HRESULT StorageImpl_Flush(StorageBaseImpl* iface) static HRESULT StorageImpl_Flush(StorageBaseImpl* iface)
{ {
StorageImpl *This = (StorageImpl*) iface; StorageImpl *This = (StorageImpl*) iface;
int i;
HRESULT hr;
TRACE("(%p)\n", This);
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]);
return ILockBytes_Flush(This->lockBytes); if (SUCCEEDED(hr))
hr = ILockBytes_Flush(This->lockBytes);
return hr;
} }
/****************************************************************************** /******************************************************************************
...@@ -5820,6 +5841,53 @@ ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset) ...@@ -5820,6 +5841,53 @@ ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset)
return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset; 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( BlockChainStream* BlockChainStream_Construct(
StorageImpl* parentStorage, StorageImpl* parentStorage,
ULONG* headOfStreamPlaceHolder, ULONG* headOfStreamPlaceHolder,
...@@ -5835,6 +5903,11 @@ BlockChainStream* BlockChainStream_Construct( ...@@ -5835,6 +5903,11 @@ BlockChainStream* BlockChainStream_Construct(
newStream->indexCache = NULL; newStream->indexCache = NULL;
newStream->indexCacheLen = 0; newStream->indexCacheLen = 0;
newStream->indexCacheSize = 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))) if (FAILED(BlockChainStream_UpdateIndexCache(newStream)))
{ {
...@@ -5846,10 +5919,30 @@ BlockChainStream* BlockChainStream_Construct( ...@@ -5846,10 +5919,30 @@ BlockChainStream* BlockChainStream_Construct(
return newStream; 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) void BlockChainStream_Destroy(BlockChainStream* This)
{ {
if (This) if (This)
{
BlockChainStream_Flush(This);
HeapFree(GetProcessHeap(), 0, This->indexCache); HeapFree(GetProcessHeap(), 0, This->indexCache);
}
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} }
...@@ -5915,6 +6008,8 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This, ...@@ -5915,6 +6008,8 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
ULONG blockIndex; ULONG blockIndex;
BYTE* bufferWalker; BYTE* bufferWalker;
ULARGE_INTEGER stream_size; ULARGE_INTEGER stream_size;
HRESULT hr;
BlockChainBlock *cachedBlock;
TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead); TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
...@@ -5936,32 +6031,50 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This, ...@@ -5936,32 +6031,50 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
*/ */
bufferWalker = buffer; bufferWalker = buffer;
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) while (size > 0)
{ {
ULARGE_INTEGER ulOffset; ULARGE_INTEGER ulOffset;
DWORD bytesReadAt; DWORD bytesReadAt;
/* /*
* Calculate how many bytes we can copy from this big block. * Calculate how many bytes we can copy from this big block.
*/ */
bytesToReadInBuffer = bytesToReadInBuffer =
min(This->parentStorage->bigBlockSize - offsetInBlock, size); min(This->parentStorage->bigBlockSize - offsetInBlock, size);
TRACE("block %i\n",blockIndex); hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToReadInBuffer);
ulOffset.u.HighPart = 0;
ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
offsetInBlock;
StorageImpl_ReadAt(This->parentStorage, if (FAILED(hr))
ulOffset, return hr;
bufferWalker,
bytesToReadInBuffer, if (!cachedBlock)
&bytesReadAt); {
/* /* Not in cache, and we're going to read past the end of the block. */
* Step to the next big block. ulOffset.u.HighPart = 0;
*/ ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) offsetInBlock;
return STG_E_DOCFILECORRUPT;
StorageImpl_ReadAt(This->parentStorage,
ulOffset,
bufferWalker,
bytesToReadInBuffer,
&bytesReadAt);
}
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; bufferWalker += bytesReadAt;
size -= bytesReadAt; size -= bytesReadAt;
*bytesRead += bytesReadAt; *bytesRead += bytesReadAt;
...@@ -5991,51 +6104,61 @@ HRESULT BlockChainStream_WriteAt(BlockChainStream* This, ...@@ -5991,51 +6104,61 @@ HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
ULONG bytesToWrite; ULONG bytesToWrite;
ULONG blockIndex; ULONG blockIndex;
const BYTE* bufferWalker; const BYTE* bufferWalker;
HRESULT hr;
/* BlockChainBlock *cachedBlock;
* 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;
}
*bytesWritten = 0; *bytesWritten = 0;
bufferWalker = buffer; bufferWalker = buffer;
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) while (size > 0)
{ {
ULARGE_INTEGER ulOffset; ULARGE_INTEGER ulOffset;
DWORD bytesWrittenAt; 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 = bytesToWrite =
min(This->parentStorage->bigBlockSize - offsetInBlock, size); min(This->parentStorage->bigBlockSize - offsetInBlock, size);
TRACE("block %i\n",blockIndex); hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToWrite);
ulOffset.u.HighPart = 0;
ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
offsetInBlock;
StorageImpl_WriteAt(This->parentStorage, /* BlockChainStream_SetSize should have already been called to ensure we have
ulOffset, * enough blocks in the chain to write into */
bufferWalker, if (FAILED(hr))
bytesToWrite, {
&bytesWrittenAt); ERR("not enough blocks in chain to write data\n");
return hr;
}
/* if (!cachedBlock)
* Step to the next big block. {
*/ /* Not in cache, and we're going to write past the end of the block. */
if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, ulOffset.u.HighPart = 0;
&blockIndex))) ulOffset.u.LowPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
return STG_E_DOCFILECORRUPT; offsetInBlock;
StorageImpl_WriteAt(This->parentStorage,
ulOffset,
bufferWalker,
bytesToWrite,
&bytesWrittenAt);
}
else
{
if (!cachedBlock->read && bytesToWrite != This->parentStorage->bigBlockSize)
{
if (!StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data))
return STG_E_READFAULT;
}
memcpy(cachedBlock->data+offsetInBlock, bufferWalker, bytesToWrite);
bytesWrittenAt = bytesToWrite;
cachedBlock->read = 1;
cachedBlock->dirty = 1;
}
blockNoInSequence++;
bufferWalker += bytesWrittenAt; bufferWalker += bytesWrittenAt;
size -= bytesWrittenAt; size -= bytesWrittenAt;
*bytesWritten += bytesWrittenAt; *bytesWritten += bytesWrittenAt;
...@@ -6058,6 +6181,7 @@ static BOOL BlockChainStream_Shrink(BlockChainStream* This, ...@@ -6058,6 +6181,7 @@ static BOOL BlockChainStream_Shrink(BlockChainStream* This,
{ {
ULONG blockIndex; ULONG blockIndex;
ULONG numBlocks; ULONG numBlocks;
int i;
/* /*
* Figure out how many blocks are needed to contain the new size * Figure out how many blocks are needed to contain the new size
...@@ -6125,6 +6249,18 @@ static BOOL BlockChainStream_Shrink(BlockChainStream* This, ...@@ -6125,6 +6249,18 @@ static BOOL BlockChainStream_Shrink(BlockChainStream* This,
last_run->lastOffset--; 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; return TRUE;
} }
......
...@@ -512,6 +512,15 @@ struct BlockChainRun ...@@ -512,6 +512,15 @@ struct BlockChainRun
ULONG lastOffset; ULONG lastOffset;
}; };
typedef struct BlockChainBlock
{
ULONG index;
ULONG sector;
int read;
int dirty;
BYTE data[MAX_BIG_BLOCK_SIZE];
} BlockChainBlock;
struct BlockChainStream struct BlockChainStream
{ {
StorageImpl* parentStorage; StorageImpl* parentStorage;
...@@ -520,6 +529,8 @@ struct BlockChainStream ...@@ -520,6 +529,8 @@ struct BlockChainStream
struct BlockChainRun* indexCache; struct BlockChainRun* indexCache;
ULONG indexCacheLen; ULONG indexCacheLen;
ULONG indexCacheSize; ULONG indexCacheSize;
BlockChainBlock cachedBlocks[2];
ULONG blockToEvict;
ULONG tailIndex; ULONG tailIndex;
ULONG numBlocks; ULONG numBlocks;
}; };
...@@ -553,6 +564,9 @@ BOOL BlockChainStream_SetSize( ...@@ -553,6 +564,9 @@ BOOL BlockChainStream_SetSize(
BlockChainStream* This, BlockChainStream* This,
ULARGE_INTEGER newSize); ULARGE_INTEGER newSize);
HRESULT BlockChainStream_Flush(
BlockChainStream* This);
/**************************************************************************** /****************************************************************************
* SmallBlockChainStream definitions. * SmallBlockChainStream definitions.
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment