Kaydet (Commit) e48e4891 authored tarafından Michael Meeks's avatar Michael Meeks

sot: substantially accelerate sorted cache write-out

Sort only the pages we want to write out, at the end, using a std::sort
instead of a hand-crafted linked-list mess maintained during use.
Cleanup StgPage as well, de-friend it from StgCache, clean member names.
Remove unused pCache member as well.

Change-Id: I0f53d1f85be373fce0d504b226d34ccaf575b2b3
üst fd2e3ff7
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 . * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/ */
#include <string.h> #include <string.h>
#include <osl/endian.h> #include <osl/endian.h>
#include <tools/string.hxx> #include <tools/string.hxx>
...@@ -37,34 +36,40 @@ ...@@ -37,34 +36,40 @@
// a page buffer, even if a read fails. It is up to the caller to determine // a page buffer, even if a read fails. It is up to the caller to determine
// the correctness of the I/O. // the correctness of the I/O.
StgPage::StgPage( StgCache* p, short n ) StgPage::StgPage( short nSize, sal_Int32 nPage )
: mnPage( nPage )
, mpData( new sal_uInt8[ nSize ] )
, mnSize( nSize )
, mbDirty( false )
{ {
OSL_ENSURE( n >= 512, "Unexpected page size is provided!" ); OSL_ENSURE( mnSize >= 512, "Unexpected page size is provided!" );
pCache = p; // We will write this data to a permanant file later
nData = n; // best to clear if first.
bDirty = sal_False; memset( mpData, 0, mnSize );
nPage = 0;
pData = new sal_uInt8[ nData ];
pNext2 = pLast2 = NULL;
} }
StgPage::~StgPage() StgPage::~StgPage()
{ {
delete [] pData; delete [] mpData;
} }
void StgPage::SetPage( short nOff, sal_Int32 nVal ) void StgPage::SetPage( short nOff, sal_Int32 nVal )
{ {
if( ( nOff < (short) ( nData / sizeof( sal_Int32 ) ) ) && nOff >= 0 ) if( ( nOff < (short) ( mnSize / sizeof( sal_Int32 ) ) ) && nOff >= 0 )
{ {
#ifdef OSL_BIGENDIAN #ifdef OSL_BIGENDIAN
nVal = OSL_SWAPDWORD(nVal); nVal = OSL_SWAPDWORD(nVal);
#endif #endif
((sal_Int32*) pData )[ nOff ] = nVal; ((sal_Int32*) mpData )[ nOff ] = nVal;
bDirty = sal_True; mbDirty = true;
} }
} }
bool StgPage::IsPageGreater( const StgPage *pA, const StgPage *pB )
{
return pA->mnPage < pB->mnPage;
}
//////////////////////////////// class StgCache //////////////////////////// //////////////////////////////// class StgCache ////////////////////////////
// The disk cache holds the cached sectors. The sector type differ according // The disk cache holds the cached sectors. The sector type differ according
...@@ -81,7 +86,6 @@ StgCache::StgCache() ...@@ -81,7 +86,6 @@ StgCache::StgCache()
{ {
nRef = 0; nRef = 0;
pStrm = NULL; pStrm = NULL;
pElem1 = NULL;
nPageSize = 512; nPageSize = 512;
nError = SVSTREAM_OK; nError = SVSTREAM_OK;
bMyStream = sal_False; bMyStream = sal_False;
...@@ -112,32 +116,10 @@ void StgCache::SetPhysPageSize( short n ) ...@@ -112,32 +116,10 @@ void StgCache::SetPhysPageSize( short n )
StgPage* StgCache::Create( sal_Int32 nPg ) StgPage* StgCache::Create( sal_Int32 nPg )
{ {
StgPage* pElem = new StgPage( this, nPageSize ); StgPage* pElem = new StgPage( nPageSize, nPg );
pElem->nPage = nPg;
// For data security, clear the buffer contents
memset( pElem->pData, 0, pElem->nData );
maLRUCache[pElem->nPage] = pElem; maLRUCache[pElem->GetPage()] = pElem;
// insert to Sorted
if( !pElem1 )
pElem1 = pElem->pNext2 = pElem->pLast2 = pElem;
else
{
StgPage* p = pElem1;
do
{
if( pElem->nPage < p->nPage )
break;
p = p->pNext2;
} while( p != pElem1 );
pElem->pNext2 = p;
pElem->pLast2 = p->pLast2;
pElem->pNext2->pLast2 =
pElem->pLast2->pNext2 = pElem;
if( p->nPage < pElem1->nPage )
pElem1 = pElem;
}
return pElem; return pElem;
} }
...@@ -148,12 +130,7 @@ void StgCache::Erase( StgPage* pElem ) ...@@ -148,12 +130,7 @@ void StgCache::Erase( StgPage* pElem )
OSL_ENSURE( pElem, "The pointer should not be NULL!" ); OSL_ENSURE( pElem, "The pointer should not be NULL!" );
if ( pElem ) if ( pElem )
{ {
maLRUCache.erase( pElem->nPage ); maLRUCache.erase( pElem->GetPage() );
// remove from Sorted
pElem->pNext2->pLast2 = pElem->pLast2;
pElem->pLast2->pNext2 = pElem->pNext2;
if( pElem1 == pElem )
pElem1 = ( pElem->pNext2 == pElem ) ? NULL : pElem->pNext2;
delete pElem; delete pElem;
} }
} }
...@@ -162,15 +139,6 @@ void StgCache::Erase( StgPage* pElem ) ...@@ -162,15 +139,6 @@ void StgCache::Erase( StgPage* pElem )
void StgCache::Clear() void StgCache::Clear()
{ {
StgPage *pElem = pElem1;
if( pElem ) do
{
StgPage* pDelete = pElem;
pElem = pElem->pNext2;
delete pDelete;
}
while( pElem != pElem1 );
pElem1 = NULL;
maLRUCache.clear(); maLRUCache.clear();
} }
...@@ -197,7 +165,7 @@ StgPage* StgCache::Get( sal_Int32 nPage, sal_Bool bForce ) ...@@ -197,7 +165,7 @@ StgPage* StgCache::Get( sal_Int32 nPage, sal_Bool bForce )
if( !p ) if( !p )
{ {
p = Create( nPage ); p = Create( nPage );
if( !Read( nPage, p->pData, 1 ) && bForce ) if( !Read( nPage, p->GetData(), 1 ) && bForce )
{ {
Erase( p ); Erase( p );
p = NULL; p = NULL;
...@@ -222,32 +190,39 @@ StgPage* StgCache::Copy( sal_Int32 nNew, sal_Int32 nOld ) ...@@ -222,32 +190,39 @@ StgPage* StgCache::Copy( sal_Int32 nNew, sal_Int32 nOld )
StgPage* q = Get( nOld, sal_True ); StgPage* q = Get( nOld, sal_True );
if( q ) if( q )
{ {
OSL_ENSURE( p->nData == q->nData, "Unexpected page size!" ); OSL_ENSURE( p->GetSize() == q->GetSize(), "Unexpected page size!" );
memcpy( p->pData, q->pData, p->nData ); memcpy( p->GetData(), q->GetData(), p->GetSize() );
} }
} }
p->SetDirty(); p->SetDirty( true );
return p; return p;
} }
// Flush the cache whose owner is given. NULL flushes all. // Historically this wrote pages in a sorted, ascending order;
// continue that tradition.
sal_Bool StgCache::Commit() sal_Bool StgCache::Commit()
{ {
StgPage* p = pElem1; std::vector< StgPage * > aToWrite;
if( p ) do for ( IndexToStgPage::iterator aIt = maLRUCache.begin();
aIt != maLRUCache.end(); aIt++ )
{ {
if( p->bDirty ) if ( aIt->second->IsDirty() )
{ aToWrite.push_back( aIt->second );
sal_Bool b = Write( p->nPage, p->pData, 1 ); }
if( !b )
return sal_False; std::sort( aToWrite.begin(), aToWrite.end(), StgPage::IsPageGreater );
p->bDirty = sal_False; for (std::vector< StgPage * >::iterator aWr = aToWrite.begin();
} aWr != aToWrite.end(); aWr++)
p = p->pNext2; {
} while( p != pElem1 ); StgPage *pPage = *aWr;
if ( !Write( pPage->GetPage(), pPage->GetData(), 1 ) )
return sal_False;
pPage->SetDirty( false );
}
pStrm->Flush(); pStrm->Flush();
SetError( pStrm->GetError() ); SetError( pStrm->GetError() );
return sal_True; return sal_True;
} }
......
...@@ -40,24 +40,20 @@ typedef boost::unordered_map ...@@ -40,24 +40,20 @@ typedef boost::unordered_map
> IndexToStgPage; > IndexToStgPage;
class StgCache { class StgCache {
StgPage* pCur; // top of LRU list sal_uLong nError; // error code
StgPage* pElem1; // top of ordered list sal_Int32 nPages; // size of data area in pages
sal_uLong nError; // error code sal_uInt16 nRef; // reference count
sal_Int32 nPages; // size of data area in pages
sal_uInt16 nRef; // reference count
IndexToStgPage maLRUCache; // hash of index to cached pages IndexToStgPage maLRUCache; // hash of index to cached pages
short nPageSize; // page size of the file short nPageSize; // page size of the file
UCBStorageStream* pStorageStream; // holds reference to UCB storage stream UCBStorageStream* pStorageStream; // holds reference to UCB storage stream
void Erase( StgPage* ); // delete a cache element void Erase( StgPage* ); // delete a cache element
void InsertToLRU( StgPage* ); // insert into LRU list StgPage* Create( sal_Int32 ); // create a cached page
void InsertToOrdered( StgPage* ); // insert into ordered list
StgPage* Create( sal_Int32 ); // create a cached page
protected: protected:
SvStream* pStrm; // physical stream SvStream* pStrm; // physical stream
sal_Bool bMyStream; // sal_True: delete stream in dtor sal_Bool bMyStream; // sal_True: delete stream in dtor
sal_Bool bFile; // sal_True: file stream sal_Bool bFile; // sal_True: file stream
sal_Int32 Page2Pos( sal_Int32 ); // page address --> file position sal_Int32 Page2Pos( sal_Int32 ); // page address --> file position
public: public:
StgCache(); StgCache();
~StgCache(); ~StgCache();
...@@ -89,27 +85,26 @@ public: ...@@ -89,27 +85,26 @@ public:
}; };
class StgPage { class StgPage {
friend class StgCache; const sal_Int32 mnPage; // page index
StgCache* pCache; // the cache sal_uInt8* mpData; // nSize bytes
StgPage *pNext2, *pLast2; // ordered chain short mnSize; // size of this page
sal_Int32 nPage; // page # bool mbDirty; // dirty flag
sal_uInt8* pData; // nPageSize characters
short nData; // size of this page
sal_Bool bDirty; // dirty flag
StgPage( StgCache*, short );
~StgPage();
public: public:
void SetDirty() { bDirty = sal_True; } StgPage( short nData, sal_Int32 nPage );
sal_Int32 GetPage() { return nPage; } ~StgPage();
void* GetData() { return pData; }
short GetSize() { return nData; } sal_Int32 GetPage() { return mnPage; }
void* GetData() { return mpData; }
short GetSize() { return mnSize; }
bool IsDirty() { return mbDirty; }
void SetDirty( bool bDirty ) { mbDirty = bDirty; }
// routines for accessing FAT pages // routines for accessing FAT pages
// Assume that the data is a FAT page and get/put FAT data. // Assume that the data is a FAT page and get/put FAT data.
sal_Int32 GetPage( short nOff ) sal_Int32 GetPage( short nOff )
{ {
if( ( nOff >= (short) ( nData / sizeof( sal_Int32 ) ) ) || nOff < 0 ) if( ( nOff >= (short) ( mnSize / sizeof( sal_Int32 ) ) ) || nOff < 0 )
return -1; return -1;
sal_Int32 n = ((sal_Int32*) pData )[ nOff ]; sal_Int32 n = ((sal_Int32*) mpData )[ nOff ];
#ifdef OSL_BIGENDIAN #ifdef OSL_BIGENDIAN
return OSL_SWAPDWORD(n); return OSL_SWAPDWORD(n);
#else #else
...@@ -117,6 +112,7 @@ public: ...@@ -117,6 +112,7 @@ public:
#endif #endif
} }
void SetPage( short, sal_Int32 ); // put an element void SetPage( short, sal_Int32 ); // put an element
static bool IsPageGreater( const StgPage *pA, const StgPage *pB );
}; };
#endif #endif
......
...@@ -869,7 +869,7 @@ void* StgDataStrm::GetPtr( sal_Int32 Pos, sal_Bool bForce, sal_Bool bDirty ) ...@@ -869,7 +869,7 @@ void* StgDataStrm::GetPtr( sal_Int32 Pos, sal_Bool bForce, sal_Bool bDirty )
if (pPg && nOffset < pPg->GetSize()) if (pPg && nOffset < pPg->GetSize())
{ {
if( bDirty ) if( bDirty )
pPg->SetDirty(); pPg->SetDirty( true );
return ((sal_uInt8 *)pPg->GetData()) + nOffset; return ((sal_uInt8 *)pPg->GetData()) + nOffset;
} }
} }
...@@ -964,7 +964,7 @@ sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n ) ...@@ -964,7 +964,7 @@ sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n )
{ {
// data is present, so use the cached data // data is present, so use the cached data
memcpy( pPg->GetData(), p, nBytes ); memcpy( pPg->GetData(), p, nBytes );
pPg->SetDirty(); pPg->SetDirty( true );
nRes = nBytes; nRes = nBytes;
} }
else else
...@@ -978,7 +978,7 @@ sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n ) ...@@ -978,7 +978,7 @@ sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n )
if( !pPg ) if( !pPg )
break; break;
memcpy( (sal_uInt8*)pPg->GetData() + nOffset, p, nBytes ); memcpy( (sal_uInt8*)pPg->GetData() + nOffset, p, nBytes );
pPg->SetDirty(); pPg->SetDirty( true );
nRes = nBytes; nRes = nBytes;
} }
nDone += nRes; nDone += nRes;
......
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