windows-nt/Source/XPSP1/NT/inetsrv/query/h/rcstrmit.hxx
2020-09-26 16:20:57 +08:00

672 lines
19 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: RCSTRMIT.HXX
//
// Contents: Persistent Recoverable Stream Iterators for fixed
// size records.
//
// Classes: CRcovStrmReadIter
// CRcovStrmWriteIter
// CRcovStrmAppendIter
//
// History: 25-Jan-94 SrikantS Created.
//
//----------------------------------------------------------------------------
#pragma once
#include <rcstxact.hxx>
//+---------------------------------------------------------------------------
//
// Class: CRcovStrmIter
//
// Purpose: Iterator for the recoverable stream class assuming fixed
// size records are stored in the stream.
//
// History: 1-25-94 srikants Created
//
//----------------------------------------------------------------------------
class CRcovStrmIter
{
public:
inline CRcovStrmIter( CRcovStrmTrans & trans , USHORT cbRec );
inline BOOL GetRec( void *pvRec, ULONG iRec );
inline void GetRec( void *pvRec );
inline ULONG GetVariableRecSize();
inline void GetVariableRecData( void * pvRec, ULONG cbRec );
BOOL AtEnd() const { return _trans.AtEnd(); }
inline void Advance();
inline void Seek( ULONG iRec );
ULONG UserDataSize( ULONG cRec ) { return cRec * (_cbRec + _CHECKSUM_SIZE); }
ULONG UserRecordCount( ULONG cbUserData ) { return cbUserData / (_cbRec + _CHECKSUM_SIZE); }
static unsigned SizeofChecksum() { return _CHECKSUM_SIZE; }
protected:
enum { _CHECKSUM_SIZE = sizeof(ULONG) };
inline ULONG CheckSum( void const * pvRec ) const;
inline ULONG CheckSum( void const * pvRec, unsigned cbRec ) const;
CRcovStrmTrans & _trans; // Transaction context
const USHORT _cbRec; // Size of user record, sans checksum
};
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmIter::CRcovStrmIter, public
//
// Synopsis: Constructor. Just squirrels away member variables.
//
// Arguments: [trans] -- Transaction context to iterate
// [cbRec] -- Size of 'records' to be written.
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline CRcovStrmIter::CRcovStrmIter( CRcovStrmTrans & trans , USHORT cbRec )
: _trans( trans ),
_cbRec(cbRec)
{
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmIter::Advance, public
//
// Synopsis: Moves to next record
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline void CRcovStrmIter::Advance()
{
Win4Assert( !AtEnd() );
_trans.Advance( _cbRec + _CHECKSUM_SIZE );
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmIter::Seek, public
//
// Synopsis: Moves to specified record
//
// Arguments: [iRec] -- Record to position to.
//
// History: 27-May-1998 KyleP Created
//
//----------------------------------------------------------------------------
inline void CRcovStrmIter::Seek( ULONG iRec )
{
_trans.Seek( iRec * (_cbRec + _CHECKSUM_SIZE) );
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmIter::CheckSum, protected
//
// Synopsis: Computes checksum for record
//
// Arguments: [pvRec] -- Record to examine
//
// Returns: Checksum
//
// History: 27-May-1998 KyleP Created
//
// Notes: Checksum is never 0. This is to avoid a common failed write
// scenario where zeros are written (or nothing is ever written)
// to a persistent data structure.
//
//----------------------------------------------------------------------------
inline ULONG CRcovStrmIter::CheckSum( void const * pvRec ) const
{
return CheckSum( pvRec, _cbRec );
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmIter::CheckSum, protected
//
// Synopsis: Computes checksum for variable size records
//
// Arguments: [pvRec] -- Record to examine
// [cbRec] -- Size of record
//
// Returns: Checksum
//
// History: 1-Jun-1998 VikasMan Created
//
// Notes: Checksum is never 0. This is to avoid a common failed write
// scenario where zeros are written (or nothing is ever written)
// to a persistent data structure.
//
//----------------------------------------------------------------------------
inline ULONG CRcovStrmIter::CheckSum( void const * pvRec, unsigned cbRec ) const
{
BYTE * pb = (BYTE *)pvRec;
ULONG ulCheckSum = 0;
//
// First, the DWORD granular portion
//
unsigned cbEnd = cbRec - _CHECKSUM_SIZE;
for ( unsigned i = 0; i <= cbEnd; i += _CHECKSUM_SIZE )
{
ulCheckSum += *(ULONG UNALIGNED *)pb;
pb += _CHECKSUM_SIZE;
}
//
// Then whatever is left.
//
ULONG ul = 0;
for ( ; i < cbRec; i++ )
{
ul = (ul << 8) + *pb;
pb++;
}
ulCheckSum += ul;
//
// Make sure the checksum is never zero. Just to avoid an obvious case
// of error where a whole section has been zero-ed (including checksum).
//
if ( 0 == ulCheckSum )
ulCheckSum = 1;
return ulCheckSum;
}
//+---------------------------------------------------------------------------
//
// Function: CRcovStrmIter::GetRec, public
//
// Synopsis: Gets the specified record.
//
// Effects: Positions the current pointer after the current read.
//
// Arguments: [pvRec] -- Buffer to read the contents into.
// [iRec] -- Number of the record, starting at 0.
//
// Returns: TRUE if a record was successfully read. FALSE if iRec
// is beyond the end of stream.
//
// History: 2-10-94 srikants Created
//
//----------------------------------------------------------------------------
inline BOOL CRcovStrmIter::GetRec( void * pvRec , ULONG iRec )
{
if ( !_trans.Seek(iRec * (_cbRec + _CHECKSUM_SIZE) ) || AtEnd() ) {
return FALSE;
}
ULONG cbRead = _trans.Read( pvRec, _cbRec );
Win4Assert( cbRead == _cbRec );
ULONG ulCheckSum;
if ( _CHECKSUM_SIZE != _trans.Read( &ulCheckSum, sizeof(ulCheckSum) ) )
{
ciDebugOut(( DEB_ERROR, "Error reading checksum for record %u (cbRec = %u).\n",
iRec, _cbRec ));
Win4Assert( !"Bad checksum" );
THROW( CException(CI_CORRUPT_CATALOG) );
}
if ( ulCheckSum != CheckSum( pvRec ) )
{
ciDebugOut(( DEB_ERROR,
"Incorrect checksum 0x%x (should be 0x%x) for record %u (cbRec = %u). pvRec = 0x%x\n",
CheckSum( pvRec ), ulCheckSum, iRec, _cbRec, pvRec ));
Win4Assert( !"Bad checksum" );
THROW( CException(CI_CORRUPT_CATALOG) );
}
return cbRead == _cbRec;
}
//+---------------------------------------------------------------------------
//
// Function: CRcovStrmIter::GetRec, public
//
// Synopsis: Gets the current record.
//
// Effects: Positions the current pointer after the current read.
//
// Arguments: [pvRec] -- Buffer to read the contents into.
//
// History: 27-May-1998 KyleP Created
//
//----------------------------------------------------------------------------
inline void CRcovStrmIter::GetRec( void *pvRec )
{
GetVariableRecData( pvRec, _cbRec );
}
//+---------------------------------------------------------------------------
//
// Function: CRcovStrmIter::GetVariableRecSize, public
//
// Synopsis: Gets the size of the current variable record.
//
// Effects: Positions the current pointer after the current read.
//
// Arguments:
//
// Returns: The size in bytes of the records
//
// History: 1-Jun-1998 VikasMan Created
//
//----------------------------------------------------------------------------
inline ULONG CRcovStrmIter::GetVariableRecSize()
{
Win4Assert( !AtEnd() );
ULONG cbRec;
ULONG cbRead;
// Read Size
cbRead = _trans.Read( &cbRec, sizeof( cbRec ) );
Win4Assert( sizeof( cbRec ) == cbRead );
Win4Assert( cbRec );
return cbRec;
}
//+---------------------------------------------------------------------------
//
// Function: CRcovStrmIter::GetVariableRecData, public
//
// Synopsis: Gets the current variable record.
//
// Effects: Positions the current pointer after the current read.
//
// Arguments: [pvRec] -- Pointer to buffer to read the contents into.
// [cbRec] -- Size in bytes of pvRec
//
//
// History: 1-Jun-1998 VikasMan Created
//
//----------------------------------------------------------------------------
inline void CRcovStrmIter::GetVariableRecData( void * pvRec, ULONG cbRec )
{
Win4Assert( !AtEnd() );
ULONG cbRead = _trans.Read( pvRec, cbRec );
Win4Assert( cbRead == cbRec );
ULONG ulCheckSum;
if ( _CHECKSUM_SIZE != _trans.Read( &ulCheckSum, sizeof(ulCheckSum) ) )
{
ciDebugOut(( DEB_ERROR, "Error reading checksum.\n" ));
Win4Assert( !"Bad checksum" );
THROW( CException(CI_CORRUPT_CATALOG) );
}
if ( ulCheckSum != CheckSum( pvRec, cbRec ) )
{
ciDebugOut(( DEB_ERROR,
"Incorrect checksum 0x%x (should be 0x%x). pvRec = 0x%x\n",
CheckSum( pvRec ), ulCheckSum, pvRec ));
Win4Assert( !"Bad checksum" );
THROW( CException(CI_CORRUPT_CATALOG) );
}
}
#if 0 // untested unsused new function
//+---------------------------------------------------------------------------
//
// Function: CRcovStrmIter::GetVariableRec, public
//
// Synopsis: Gets the current variable record. In the process would also
// allocate memory for it
//
// Effects: Positions the current pointer after the current read.
//
// Arguments: [ppvRec] -- Pointer to buffer to read the contents into.
//
// Returns: The size in bytes of *ppvRec
//
// History: 1-Jun-1998 VikasMan Created
//
//----------------------------------------------------------------------------
inline ULONG CRcovStrmIter::GetVariableRec( void ** ppvRec )
{
Win4Assert( !AtEnd() );
*ppvRec = NULL;
ULONG cbRec;
// Read Size
cbRec = GetVariableRecSize();
// Now allocate and read data
*ppvRec = (void*) new BYTE[cbRec];
XPtrST<BYTE> xRec((BYTE*)*ppvRec);
GetVariableRecData( *ppvRec, cbRec );
xRec.Acquire();
return cbRec;
}
#endif
//+---------------------------------------------------------------------------
//
// Class: CRcovStrmReadIter
//
// Purpose: Read-only version of recoverable stream iterator.
//
// History: 1-25-94 srikants Created
//
//----------------------------------------------------------------------------
class CRcovStrmReadIter : public CRcovStrmIter
{
public:
inline CRcovStrmReadIter( CRcovStrmReadTrans &readTrans, USHORT cbRec );
};
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmReadIter::CRcovStrmReadIter, public
//
// Synopsis: Constructor. Just squirrels away member variables.
//
// Arguments: [trans] -- Transaction context to iterate
// [cbRec] -- Size of 'records' to be written.
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline CRcovStrmReadIter::CRcovStrmReadIter( CRcovStrmReadTrans & readTrans , USHORT cbRec )
: CRcovStrmIter( readTrans, cbRec )
{
_trans.Seek(0);
}
//+---------------------------------------------------------------------------
//
// Class: CRcovStrmAppendIter
//
// Purpose: Iterator to append fixed size records to the recoverable
// streams. This is just an optimized case of a write iterator.
//
// History: 2-10-94 srikants Created
//
//----------------------------------------------------------------------------
class CRcovStrmAppendIter : public CRcovStrmIter
{
public:
inline CRcovStrmAppendIter( CRcovStrmAppendTrans &appendTrans, USHORT cbRec );
inline void AppendRec( const void *pvRec );
inline void AppendVariableRec( const void *pvRec, ULONG cbRec );
private:
CRcovStrmAppendTrans & _appendTrans;
};
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmAppendIter::CRcovStrmAppendIter, public
//
// Synopsis: Constructor. Just squirrels away member variables.
//
// Arguments: [trans] -- Transaction context to iterate
// [cbRec] -- Size of 'records' to be written.
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline CRcovStrmAppendIter::CRcovStrmAppendIter( CRcovStrmAppendTrans & trans, USHORT cbRec )
: CRcovStrmIter( trans, cbRec ),
_appendTrans( trans )
{
_appendTrans.Seek( ENDOFSTRM );
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmAppendIter::AppendRec, public
//
// Synopsis: Appends record to end of stream.
//
// Arguments: [pvRec] -- Record to append.
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline void CRcovStrmAppendIter::AppendRec( const void *pvRec )
{
_appendTrans.Append( pvRec, _cbRec );
ULONG ulCheckSum = CheckSum( pvRec );
_appendTrans.Append( &ulCheckSum, sizeof(ulCheckSum), FALSE );
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmAppendIter::AppendVariableRec, public
//
// Synopsis: Appends variable size record to end of stream
//
// Arguments: [pvRec] -- Record to append.
// [cbRec] -- Count in bytes of pvRec
//
// Returns: void
//
// History: 01-Jun-1998 VikasMan Created
//
//----------------------------------------------------------------------------
inline void CRcovStrmAppendIter::AppendVariableRec( const void *pvRec,
ULONG cbRec )
{
ULONG ulCheckSum;
Win4Assert( cbRec != 0 && pvRec != 0 );
// first write the size
_appendTrans.Append( &cbRec, sizeof( cbRec ), FALSE );
// next write the data
_appendTrans.Append( pvRec, cbRec );
ulCheckSum = CheckSum( pvRec, cbRec );
_appendTrans.Append( &ulCheckSum, sizeof(ulCheckSum), FALSE );
}
//+---------------------------------------------------------------------------
//
// Class: CRcovStrmWriteIter
//
// Purpose: Iterator for writing fixed size anywhere in the
// recoverable stream.
//
// History: 2-10-94 srikants Created
//
//----------------------------------------------------------------------------
class CRcovStrmWriteIter : public CRcovStrmIter
{
public:
inline CRcovStrmWriteIter( CRcovStrmWriteTrans & writeTrans, USHORT cbRec );
inline BOOL SetRec( const void *pvBuf, ULONG iRec );
inline void SetRec( const void *pvBuf );
inline void AppendRec( const void *pvBuf );
#if 0 // untested unused new function
inline void SetVariableRec( const void *pvRec,
ULONG cbRec,
BOOL fAppend = FALSE );
#endif
private:
CRcovStrmWriteTrans & _writeTrans;
};
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmWriteIter::CRcovStrmWriteIter, public
//
// Synopsis: Constructor. Just squirrels away member variables.
//
// Arguments: [trans] -- Transaction context to iterate
// [cbRec] -- Size of 'records' to be written.
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline CRcovStrmWriteIter::CRcovStrmWriteIter( CRcovStrmWriteTrans & writeTrans, USHORT cbRec )
: CRcovStrmIter( writeTrans, cbRec ),
_writeTrans(writeTrans)
{
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmWriteIter::SetRec, public
//
// Synopsis: Writes specified record to stream.
//
// Arguments: [pvRec] -- Record data
// [iRec] -- Location at which write should occur
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline BOOL CRcovStrmWriteIter::SetRec( const void * pvRec, ULONG iRec )
{
if (! _writeTrans.Seek( (_cbRec + _CHECKSUM_SIZE) * iRec ) || AtEnd() )
{
return FALSE;
}
SetRec( pvRec );
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmWriteIter::SetRec, public
//
// Synopsis: Writes specified record to current location in stream.
//
// Arguments: [pvRec] -- Record data
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline void CRcovStrmWriteIter::SetRec( const void * pvRec )
{
_writeTrans.Write( pvRec, _cbRec );
ULONG ulCheckSum = CheckSum( pvRec );
_writeTrans.Write( &ulCheckSum, sizeof(ulCheckSum) );
}
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmWriteIter::AppendRec, public
//
// Synopsis: Appends record to end of stream.
//
// Arguments: [pvRec] -- Record to append.
//
// History: 27-May-1998 KyleP Added header
//
//----------------------------------------------------------------------------
inline void CRcovStrmWriteIter::AppendRec( const void *pvRec )
{
_writeTrans.Append( pvRec, _cbRec );
ULONG ulCheckSum = CheckSum( pvRec );
_writeTrans.Write( &ulCheckSum, sizeof(ulCheckSum) );
}
#if 0 // untested unused new function
//+---------------------------------------------------------------------------
//
// Method: CRcovStrmWriteIter::SetVariableRec, public
//
// Synopsis: Writes/Appends variable size record to end of stream
//
// Arguments: [pvRec] -- Record to append.
// [cbRec] -- Count in bytes of pvRec
// [fAppend] -- If TRUE, then record is appended
//
// Returns: void
//
// History: 01-Jun-1998 VikasMan Created
//
//----------------------------------------------------------------------------
inline void CRcovStrmWriteIter::SetVariableRec( const void *pvRec,
ULONG cbRec,
BOOL fAppend /* = FALSE */ )
{
ULONG ulCheckSum;
Win4Assert( cbRec != 0 && pvRec != 0 );
// first write the size
if ( fAppend )
_writeTrans.Append( &cbRec, sizeof( cbRec ) );
else
_writeTrans.Write( &cbRec, sizeof( cbRec ) );
// next write the data
_writeTrans.Write( pvRec, cbRec );
ulCheckSum = CheckSum( pvRec, cbRec );
_writeTrans.Write( &ulCheckSum, sizeof(ulCheckSum) );
}
#endif