windows-nt/Source/XPSP1/NT/inetsrv/query/cindex/pcomp.cxx
2020-09-26 16:20:57 +08:00

2321 lines
62 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: PComp.cxx
//
// Contents: Persistent index compressor, decompressor
//
// Classes: CCoder, CKeyComp, CPersComp
//
// History: 05-Jul-91 KyleP Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#pragma optimize( "t", on )
#include "pcomp.hxx"
#include "bitstm.hxx"
const unsigned short NoKey = 0xffff;
const unsigned OccCountBits = 3; // Bits to initially store for
// an occurrence count.
const unsigned cPidBits = 4;
//+---------------------------------------------------------------------------
//
// Member: CCoder::CCoder, public
//
// Synopsis: Creates a coder
//
// Arguments: [widMax] -- The maximum workid in this index
//
// History: 05-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CCoder::CCoder ( WORKID widMax)
:_widMaximum(widMax),
_wid(0),
_occ(0)
{
_key.SetCount(0);
}
//+---------------------------------------------------------------------------
//
// Member: CCoder::CCoder, public
//
// Synopsis: Creates a coder
//
// Arguments: [widMax] -- The maximum workid in this index
// [keyInit] -- initial key
//
// History: 26-Aug-92 BartoszM Created.
//
//----------------------------------------------------------------------------
CCoder::CCoder ( WORKID widMax, const CKeyBuf& keyInit)
:_widMaximum(widMax),
_wid(0),
_occ(0),
_key(keyInit)
{
}
//+---------------------------------------------------------------------------
//
// Member: CCoder::CCoder, public
//
// Synopsis: Copy Constructor
//
// Arguments: [coder] -- The original CCoder that is being copied.
//
// History: 15-Jan-92 AmyA Created.
//
//----------------------------------------------------------------------------
CCoder::CCoder ( CCoder &coder)
:_key(coder._key),
_widMaximum(coder._widMaximum),
_wid(coder._wid),
_occ(coder._occ),
_cbitAverageWid(coder._cbitAverageWid)
{
}
//+---------------------------------------------------------------------------
//
// Member: CCoder::~CCoder, public
//
// History: 05-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CCoder::~CCoder ( )
{
}
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::CKeyComp, public
//
// Synopsis: Creates a new (empty) key compressor.
//
// Arguments: [phIndex] -- physical index
//
// [widMax] -- The maximum workid which may be stored via
// PutWorkId.
//
// History: 13-Nov-93 w-PatG Created.
//
//----------------------------------------------------------------------------
CKeyComp::CKeyComp( CPhysIndex& phIndex,
WORKID widMax,
BOOL fUseLinks )
: CCoder( widMax ),
_sigKeyComp(eSigKeyComp),
_phIndex(phIndex),
_bitStream ( phIndex ),
_fUseLinks( fUseLinks ),
_bitStreamLink(phIndex),
_fWriteFirstKeyFull(FALSE)
{
_bitOffCurKey.Init(0,0);
_bitOffLastKey.Init(0,0);
}
//+---------------------------------------------------------------------------
//
// Function: CKeyComp
//
// Synopsis: Constructor used for creating a key compressor during a
// restarted master merge. It has the ability to open an
// existing index stream, seek to the specified point after
// which new keys are to be added and zero-fill fromt the
// starting point to the end of the page. Subsequent pages
// are automatically zero-filled when they are loaded.
//
// Arguments: [phIndex] -- The physindex to which new keys are
// going to be added
// [widMax] -- Maximum wid in the index.
// [bitoffRestart] -- BitOffset indicating where the new
// keys will be added.
// [bitoffSplitKey] -- BitOffset of the last key written
// successfully to the disk completely. It is assumed that
// there will be no need to even fix up the forward links.
// [splitKey] -- The key which was written last.
// [fUseLinks] -- Flag indicating if forward links should
// be used or not.
//
// History: 4-10-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CKeyComp::CKeyComp( CPhysIndex& phIndex,
WORKID widMax,
const BitOffset & bitoffRestart,
const BitOffset & bitoffSplitKey,
const CKeyBuf & splitKey,
BOOL fUseLinks )
: CCoder( widMax ),
_sigKeyComp(eSigKeyComp),
_phIndex(phIndex),
_bitStream ( phIndex, bitoffRestart, FALSE ),
_fUseLinks( fUseLinks ),
_bitStreamLink(phIndex),
_fWriteFirstKeyFull(FALSE)
{
//
// Zero fill everything after the current position to the end of the
// page.
//
ZeroToEndOfPage();
// Write the signature
InitSignature();
_bitOffCurKey.Init(0,0);
_bitOffLastKey.Init(0,0);
//
// Position to the place from where new keys must be written.
//
#if CIDBG == 1
BitOffset bitOffCurr;
GetOffset(bitOffCurr);
Win4Assert( bitoffRestart.Page() == bitOffCurr.Page() &&
bitoffRestart.Offset() == bitOffCurr.Offset() );
// _bitStream.Seek(bitoffRestart);
#endif // CIDBG
//
// If we are restarting and the split key is not the "MinKey"
// then we must remember the split key as the "previous key".
// If the split key is "MinKey", then we are starting from
// beginning.
//
_key = splitKey;
if ( _fUseLinks ) {
//
// Initialize the forward link tracker.
//
_bitStreamLink.Seek(bitoffSplitKey);
}
}
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::~CKeyComp, public
//
// Synopsis: Destroy a compressor/buffer pair.
//
// Effects: The main effect of destroying a compressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 05-Jul-91 KyleP Created.
// 13-Nov-93 w-PatG Converted from CPersComp to CKeyComp
//
// Notes: Previous compressor is deleted in PutKey
//
//----------------------------------------------------------------------------
CKeyComp::~CKeyComp()
{
ciDebugOut (( DEB_PCOMP,"CKeyComp::~CKeyComp() -- Last Key = %.*ws\n",
_key.StrLen(), _key.GetStr() ));
}
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::PutKey, public
//
// Synopsis: Starts recording data for a new key.
//
// Arguments: [key] -- The new key.
//
// [bitOff] -- (out) actual bit offset of the key in the index
//
// History: 05-Jul-91 KyleP Created.
// 22-Nov-93 w-PatG Converted from CPersComp.
//
// Notes: The structure for each key is:
// Prefix/Suffix size
// Suffix
// Property ID (Actually the key id)
//
//----------------------------------------------------------------------------
void CKeyComp::PutKey(const CKeyBuf * pkey,
BitOffset & bitOffCurKey)
{
//Debug message broken into two pieces due to use of static buffer
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
"\"%.*ws\"", pkey->StrLen(), pkey->GetStr() ));
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
" after \"%.*ws\"", _key.StrLen(), _key.GetStr() ));
Win4Assert(pkey->Count() != 0 );
Win4Assert((_key.Count() == 0) || Compare(&_key, pkey) < 0);
Win4Assert(pkey->Pid() != pidAll);
Win4Assert(pkey->Pid() != pidInvalid);
// record the offset now.
// for use by the directory
_bitStream.GetOffset ( _bitOffCurKey );
bitOffCurKey = _bitOffCurKey;
if ( _fUseLinks )
{
// Get offset of previous key (the link stream is there)
_bitStreamLink.GetOffset (_bitOffLastKey);
// store the link data
ULONG DeltaValue = bitOffCurKey.Delta(_bitOffLastKey);
ciDebugOut (( 0x02000000, "@@@@ Delta : %lu @@@@\n", DeltaValue ));
// check whether the size of whole persistent index exceed the maximum limit
if ( DeltaValue >= LINK_MAX_VALUE ) {
ciDebugOut (( 0x01000000 | DEB_PCOMP | DEB_NOCOMPNAME,
"\n@@@@ Key : \"%.*ws\" Exceed the MAX SIZE : %lu\n",
_key.StrLen(), _key.GetStr(), DeltaValue ));
DeltaValue = 0;
}
_bitStreamLink.OverwriteBits( DeltaValue, LINK_MAX_BITS );
// reposition the link stream
_bitStreamLink.Seek ( bitOffCurKey );
// save space for the link
_bitStream.PutBits ( 0, LINK_MAX_BITS );
}
//
// If we need to write the FIRST key on each page in its entirety,
// and we have crossed a page boundary, then set the prefix to 0,
// which forces the key to be written in its entirety.
//
unsigned cPrefix = 0;
if ( _fWriteFirstKeyFull &&
( _bitOffCurKey.Page() != _bitOffLastKey.Page()) )
{
//
// If we're not using links, then we haven't been tracking the
// bit offset of the last key. Do it here.
//
if ( !_fUseLinks )
{
_bitOffLastKey = _bitOffCurKey;
}
}
else
{
unsigned mincb = __min(_key.Count(), pkey->Count());
for (cPrefix = 0; cPrefix < mincb; cPrefix++)
if ((_key.GetBuf())[cPrefix] != (pkey->GetBuf())[cPrefix])
break;
}
unsigned cSuffix = pkey->Count() - cPrefix;
PutPSSize ( cPrefix, cSuffix );
//
// Store the suffix.
//
_bitStream.PutBytes( pkey->GetBuf() + cPrefix, cSuffix);
PutPid ( pkey->Pid() );
//
// Copy the piece of key that changed.
//
memcpy(_key.GetWritableBuf() + cPrefix, pkey->GetBuf() + cPrefix, cSuffix);
_key.SetCount( pkey->Count() );
_key.SetPid ( pkey->Pid() );
}
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::IBitCompress, private
//
// Synopsis: Compress and store a number.
//
// Arguments: [ul] -- Number to store.
//
// [cbitAverage] -- Minimum number of bits to store.
//
// Algorithm: First, store the bottom cbitAverage bits.
// while there are more bits to store
// store a 1 bit indicating more to follow
// store the next n bits, where n = 2, 3, 4, ...
// store a 0 bit indicating end of sequence
//
// History: 08-Jul-91 KyleP Created.
// 06-Dec-93 w-PatG Moved from CPersComp.
//
//----------------------------------------------------------------------------
void CKeyComp::IBitCompress(ULONG ul, unsigned cbitAverage, unsigned bitSize)
{
//
// Figure out the size of the 'hole' after the last bits are
// written out and add 0 bits at the high end so that the
// last putbits really stores exactly the remaining bits.
// (Right pad the number)
//
int cbitToStore;
int cbitPadding = (int)(bitSize - cbitAverage);
for (cbitToStore = 2; cbitPadding > 0; cbitToStore++)
cbitPadding -= cbitToStore;
Win4Assert(cbitPadding >= -cbitToStore);
cbitPadding = -cbitPadding;
bitSize += cbitPadding;
//
// Store the bits a dword at a time for efficiency. They are kept
// in ultmp until they are stored. cbitTmp is the count of valid bits
// in ulTmp. ibitValid is the highest unstored bit.
//
int ibitValid;
ULONG ulTmp;
unsigned cbitTmp;
ibitValid = bitSize;
Win4Assert( (ibitValid - cbitAverage) < ULONG_BITS );
ulTmp = ul >> (ibitValid - cbitAverage);
cbitTmp = cbitAverage;
ibitValid -= cbitAverage;
bitSize -= cbitAverage;
//
// Now store the cbitAverage bits and the
// remaining bits, 2, 3, 4, ... at a time
//
for (cbitToStore = 2; ibitValid > 0; cbitToStore++)
{
//
// If there isn't enough space left in the DWord, then
// write it out and start a new one.
//
if (cbitTmp + cbitToStore + 1 > ULONG_BITS)
{
_bitStream.PutBits(ulTmp, cbitTmp);
ulTmp = 0;
cbitTmp = 0;
}
//
// Store a continuation bit
//
ulTmp = (ulTmp << 1) | 1;
cbitTmp++;
//
// Store the next top 2, 3, ... bits
//
Win4Assert( cbitToStore < ULONG_BITS );
Win4Assert( (ibitValid - cbitToStore) < ULONG_BITS );
ulTmp = (ulTmp << cbitToStore) |
(ul >> (ibitValid - cbitToStore)) &
~(0xffffffffL << cbitToStore);
ibitValid -= cbitToStore;
cbitTmp += cbitToStore;
Win4Assert(ibitValid >= 0); // Loop should terminate w/
// ibitValid == 0
}
//
// Write out the final termination bit (0).
//
if (cbitTmp == ULONG_BITS)
{
_bitStream.PutBits(ulTmp, cbitTmp);
ulTmp = 0;
cbitTmp = 0;
}
ulTmp <<= 1;
_bitStream.PutBits(ulTmp, cbitTmp + 1);
}
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::PutPSSize, private
//
// Synopsis: Writes key prefix and suffix sizes
//
// Arguments: [cPrefix] -- size of prefix
// [cSuffix] -- size of suffix
//
// History: 06-Nov-91 BartoszM Created.
// 22-Nov-93 w-PatG Moved from CPersComp to CKeyComp
//
// Notes:
// Store the prefix/suffix size followed by the suffix. If both
// the prefix and suffix fit in 4 bits each then store each as
// 4 bits, else store a 0 byte followed by a 8 bits each for
// prefix and suffix.
//
//----------------------------------------------------------------------------
inline void CKeyComp::PutPSSize ( unsigned cPrefix, unsigned cSuffix )
{
Win4Assert ( cPrefix + cSuffix != 0 );
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
"\n(%d:%d) ", cPrefix, cSuffix ));
if ((cPrefix <= 0xF) && (cSuffix <= 0xF))
{
_bitStream.PutBits((cPrefix << 4) | cSuffix, 8);
}
else
{
Win4Assert((cPrefix < 256) && (cSuffix < 256));
Win4Assert(cPrefix + cSuffix <= MAXKEYSIZE );
_bitStream.PutBits((cPrefix << 8) | cSuffix, 8 + 16);
}
}
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::PutPid, private
//
// Synopsis: Writes Property ID
//
// Arguments: [pid] -- property id
//
// History: 06-Nov-91 BartoszM Created.
// 22-Nov-93 w-PatG Moved from CPersComp to CKeyComp
//
//----------------------------------------------------------------------------
inline void CKeyComp::PutPid ( PROPID pid )
{
//
// Just store a 0 bit if contents, else
// a 1 followed by ULONG propid.
//
if ( pid == pidContents)
{
_bitStream.PutBits(0, 1);
}
else
{
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
" =PID %d= ", pid ));
_bitStream.PutBits(1, 1);
BitCompress ( pid, cPidBits );
}
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::CKeyDeComp, public
//
// Synopsis: Creates a new persistent decompressor
// at the beginning of an index
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 30-Nov-93 w-PatG Converted from CPersDeComp
// 10-Apr-94 SrikantS Adapted to not use the directory
// because it may not exist during a
// restarted master merge.
//
// Notes: Some of the arguments passed in may later be deemed to be
// unnecessary. Some may be converted to different purposes at a
// later date.
//----------------------------------------------------------------------------
CKeyDeComp::CKeyDeComp( PDirectory& pDir,
INDEXID iid,
CPhysIndex& phIndex,
WORKID widMax,
BOOL fUseLinks,
BOOL fUseDir )
: CCoder ( widMax ),
CKeyCursor (iid, widMax),
_sigKeyDeComp(eSigKeyDeComp),
_bitStream ( phIndex ),
_fUseLinks( fUseLinks ),
_pDir( pDir ),
_fUseDir( fUseDir ),
_fAtSentinel( FALSE ),
_physIndex ( phIndex )
#if (CIDBG == 1)
,_fLastKeyFromDir( FALSE )
#endif
{
LoadKey();
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::CKeyDeComp, public
//
// Synopsis: Creates a new persistent decompressor.
// positioned at a specified key
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [keyPos] -- bit offset to key stored in directory
// [keyInit] -- initial key
// [pKey] -- actual key to search for
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 30-Nov-93 w-PatG Converted from CPersDeComp
//
//----------------------------------------------------------------------------
CKeyDeComp::CKeyDeComp( PDirectory& pDir,
INDEXID iid,
CPhysIndex& phIndex,
BitOffset& keyPos,
const CKeyBuf& keyInit,
const CKey* pKey,
WORKID widMax,
BOOL fUseLinks,
BOOL fUseDir )
: CCoder ( widMax, keyInit ),
CKeyCursor (iid, widMax),
_sigKeyDeComp(eSigKeyDeComp),
_bitStream( phIndex, keyPos ),
_fUseLinks( fUseLinks ),
_pDir( pDir ),
_fUseDir( fUseDir ),
_fAtSentinel( FALSE ),
_physIndex ( phIndex )
#if (CIDBG == 1)
,_fLastKeyFromDir( FALSE )
#endif
{
Win4Assert(pKey);
LoadKey();
SeekKey( pKey);
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::CKeyDeComp, public
//
// Synopsis: Copy Constructor
//
// Effects: Copies most of the values in decomp. Calls copy constructor
// for CCoder.
//
// Arguments: [decomp] -- Original CKeyDeComp to be copied.
//
// History: 08-Jan-92 AmyA Created.
// 07-Dec-93 w-PatG Stole from CPersDeComp.
//
//----------------------------------------------------------------------------
CKeyDeComp::CKeyDeComp(CKeyDeComp & decomp)
: CCoder (decomp),
CKeyCursor(decomp),
_sigKeyDeComp(eSigKeyDeComp),
_bitStream(decomp._bitStream),
_fUseLinks( decomp._fUseLinks ),
_bitOffNextKey(decomp._bitOffNextKey),
_pDir( decomp._pDir ),
_fUseDir( decomp._fUseDir ),
_fAtSentinel( decomp._fAtSentinel ),
_physIndex(decomp._physIndex)
#if (CIDBG == 1)
,_fLastKeyFromDir( decomp._fLastKeyFromDir )
#endif
{
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::~CKeyDeComp, public
//
// Synopsis: Destroy a decompressor/buffer pair.
//
// Effects: The main effect of destroying a decompressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 30-Nov-93 w-PatG Created.
//
//----------------------------------------------------------------------------
CKeyDeComp::~CKeyDeComp()
{}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::GetKey, public
//
// Synopsis: Retrieves the current key.
//
// Returns: A pointer to the current key. If at the end of page or
// end of index, returns null.
//
// History: 15-Jul-91 KyleP Created.
// 30-Nov-93 w-PatG Moved from CPersDeComp.
//
//----------------------------------------------------------------------------
const CKeyBuf * CKeyDeComp::GetKey( BitOffset * pBitOff )
{
if ( IsAtSentinel() )
return(0);
if ( pBitOff )
GetOffset( *pBitOff );
return(&_key);
}
const CKeyBuf * CKeyDeComp::GetKey()
{
if ( IsAtSentinel() )
return(0);
return(&_key);
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::GetNextKey, public
//
// Synopsis: Retrieve the next key from the content index.
//
// Arguments: [pBitOff] -- optional, will have the offset of the beginning
// of the key.
//
// Returns: A pointer to the key, or 0 if end of page/index reached.
//
// History: 15-Jul-91 KyleP Created.
// 30-Nov-93 w-PatG Converted from CPersDeComp.
// 10-Apr-94 SrikantS Added pBitOff as an optional param.
//
//----------------------------------------------------------------------------
const CKeyBuf * CKeyDeComp::GetNextKey( BitOffset * pBitOff )
{
if ( _fUseLinks )
{
if ( !_bitOffNextKey.Valid() )
{
Win4Assert( _fUseDir );
_pDir.SeekNext( _key, 0, _bitOffNextKey );
Win4Assert( _bitOffNextKey.Valid() );
ciDebugOut (( 0x01000000 | DEB_PCOMP | DEB_NOCOMPNAME, "*** Result : Page %lu OffSet %lu\n",
_bitOffNextKey.Page(), _bitOffNextKey.Offset() ));
#if (CIDBG == 1)
_fLastKeyFromDir = TRUE;
#endif // CIDBG == 1
}
_bitStream.Seek ( _bitOffNextKey );
}
if ( pBitOff )
{
_bitStream.GetOffset( *pBitOff );
}
LoadKey();
const CKeyBuf * pkey = GetKey();
return(pkey);
}
const CKeyBuf * CKeyDeComp::GetNextKey()
{
return GetNextKey( 0 );
}
void CKeyDeComp::GetOffset( BitOffset & bitOff )
{
_bitStream.GetOffset( bitOff );
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::SeekKey, private
//
// Synopsis: Seek in the decompressor
//
// Arguments: [pkey] -- Key to search for.
//
// [op] -- Seek equality operation (EQ, GE, etc.)
//
// Returns: A pointer to the key to cursor is actually on. This may
// be = or > [pkey].
//
// History: 26-Apr-91 KyleP Created.
// 25-Aug-92 BartoszM Moved to CPersDecomp
// 30-Nov-93 w-PatG Moved to CKeyDeComp
//
//----------------------------------------------------------------------------
const CKeyBuf * CKeyDeComp::SeekKey(const CKey * pKeySearch)
{
//
// Find the key >= the specified key.
//
const CKeyBuf* pKeyFound = GetKey();
while (pKeyFound != 0)
{
//----------------------------------------------------
// Notice: Make sure that pidAll is smaller
// than any other legal PID. If the search key
// has pidAll we want to be positioned at the beginning
// of the range.
//----------------------------------------------------
Win4Assert ( pidAll == 0 );
// skip keys less than the search key
if ( pKeySearch->Compare(*pKeyFound) > 0)
{
pKeyFound = GetNextKey();
}
else
break;
}
return(pKeyFound);
}
void CPersDeComp::RatioFinished (ULONG& denom, ULONG& num)
{
denom = _cWid;
Win4Assert ( _cWid >= _cWidLeft );
num = _cWid - _cWidLeft;
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::BitUnCompress, private
//
// Synopsis: Uncompress a number
//
// Arguments: [cbitAverage] -- Minimum number of bits to store.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
__forceinline ULONG CKeyDeComp::BitUnCompress( unsigned cbitAverage)
{
//
// Get the initial count plus a stop bit.
//
Win4Assert( cbitAverage < ULONG_BITS );
ULONG ul = _bitStream.GetBits(cbitAverage + 1);
//
// Simple case: The number fits in the original cbitAverage bits
// (e.g. the stop bit is 0).
// No additional processing necessary.
//
// Complex: Retrieve additional components.
//
if ((ul & 1) == 0)
return(ul >> 1);
return IBitUnCompress ( cbitAverage, ul );
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::IBitUnCompress, private
//
// Synopsis: Uncompress a number
//
// Arguments: [cbitAverage] -- Minimum number of bits to store.
//
// History: 15-Jul-91 KyleP Created.
// 06-Dec-93 w-PatG Moved from CPersDeComp.
//
//----------------------------------------------------------------------------
ULONG CKeyDeComp::IBitUnCompress( unsigned cbitAverage, ULONG ul)
{
Win4Assert ( ul & 1 );
int BitsToGetPlus1 = 3;
do
{
//
// Kill the stop bit.
//
ul >>= 1;
//
// Get the next component and its stop bit.
//
ULONG ulPartial = _bitStream.GetBits(BitsToGetPlus1);
Win4Assert( BitsToGetPlus1 < ULONG_BITS );
ul = (ul << BitsToGetPlus1) | ulPartial;
BitsToGetPlus1++;
}
while (ul & 1);
ul >>= 1;
return(ul);
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::LoadKey, private
//
// Synopsis: Loads data for the next key.
//
// Effects: Reads a key from the current position in _bitStream and
// sets per key state.
//
// Signals: ???
//
// History: 12-Jul-91 KyleP Created.
// 06-Dec-93 w-PatG Modified from CPersDeComp.
//
//----------------------------------------------------------------------------
void CKeyDeComp::LoadKey()
{
ULONG TmpValue;
if ( _fUseLinks )
{
_bitStream.GetOffset ( _bitOffNextKey );
TmpValue = _bitStream.GetBits ( LINK_MAX_BITS );
}
//
// Retrieve the prefix/suffix. Assume they are stored in 4 bits each
// first.
//
unsigned cPrefix, cSuffix;
LoadPSSize ( cPrefix, cSuffix );
//
// Load the key itself.
//
#if CIDBG == 1
if ( _fLastKeyFromDir )
{
//
// We know what the key should be. Compute prefix and
// suffix. Make sure they match.
//
unsigned mincb = __min( _key.Count(), _pDir.GetLastKey().Count() );
for (unsigned cOldPrefix = 0; cOldPrefix < mincb; cOldPrefix++)
{
if ( (_key.GetBuf())[cOldPrefix] !=
(_pDir.GetLastKey().GetBuf())[cOldPrefix] )
break;
}
unsigned cOldSuffix = _pDir.GetLastKey().Count() - cOldPrefix;
if ( (0 != cPrefix) && (cPrefix != cOldPrefix || cSuffix != cOldSuffix) )
{
ciDebugOut(( DEB_ERROR, "Corrupt index or directory!\n" ));
ciDebugOut(( DEB_ERROR, "From index: cPrefix = %d, cSuffix = %d\n",
cPrefix, cSuffix ));
ciDebugOut(( DEB_ERROR, "From directory: cPrefix = %d, cSuffix = %d\n",
cOldPrefix, cOldSuffix ));
Win4Assert( !"Corrupt index or directory" );
}
_fLastKeyFromDir = FALSE;
}
#endif // CIDBG == 1
if ( 0 == ( cPrefix + cSuffix ) )
{
//
// Disabled asserts prior to widespread Query rollout in NT 5, so
// that the general NT user is not bothered by this asserts.
//
//Win4Assert ( "Data corruption" && cPrefix + cSuffix != 0 );
PStorage & storage = _physIndex.GetStorage();
storage.ReportCorruptComponent( L"KeyDecompressor1" );
THROW( CException( CI_CORRUPT_DATABASE) );
}
if ( cPrefix > _key.Count() )
{
//
// Disabled asserts prior to widespread Query rollout in NT 5, so
// that the general NT user is not bothered by this asserts.
//
//Win4Assert ( "Data corruption" && cPrefix <= _key.Count() );
PStorage & storage = _physIndex.GetStorage();
storage.ReportCorruptComponent( L"KeyDecompressor2" );
THROW( CException( CI_CORRUPT_DATABASE) );
}
_bitStream.GetBytes(_key.GetWritableBuf() + cPrefix, cSuffix);
_key.SetCount( cPrefix + cSuffix );
if ( _key.IsMaxKey() )
{
ciDebugOut (( DEB_ITRACE, "\n<<Sentinel key>>\n" ));
_fAtSentinel = TRUE;
return;
}
#if CIDBG == 1
//
// This it to test the directory-index interaction when things go wrong. Don't delete
// this code before talking with Dwight/SrikantS/KyleP.
//
#if 0
{
iidDebug = 0x10002; // Looking for this index
WCHAR wcsDebugKey[] = L"TRUE"; // Looking for this key
unsigned lenDebug = min( wcslen( wcsDebugKey ), _key.StrLen() );
//
// If the key we are looking for is found in the desired index, break and
// step through the code to see what is going on.
//
if ( iidDebug == _iid && 0 == _wcsnicmp( _key.GetStr(), wcsDebugKey , lenDebug ) )
{
Win4Assert( !"Only during baby-sitting mode" );
}
}
#endif // 1
#endif // CIDBG==1
//
// Load the property ID.
//
//
// Store a 0 bit if contents, else
// a 1 followed by ULONG propid.
//
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
"\"%.*ws\" ", _key.StrLen(),_key.GetStr()));
LoadPid();
// continue to set _bitOffNextKey
if ( _fUseLinks )
{
if ( TmpValue == 0 )
{
// the size of the current index must exceed the
// max. limit. Use CI Directory to search the next key
// position
ciDebugOut (( 0x01000000, "\n*** Key : \"%.*ws\"\n",_key.StrLen(), _key.GetStr() ));
ciDebugOut (( 0x01000000 | DEB_PCOMP | DEB_NOCOMPNAME, "\n\t*** Start search next key's offset\n" ));
_bitOffNextKey.SetInvalid();
}
else
{
_bitOffNextKey += TmpValue;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "\n\t$$$ Next key : Page %lu OffSet %lu\n",
_bitOffNextKey.Page(), _bitOffNextKey.Offset() ));
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::LoadPSSize, private
//
// Synopsis: Load key prefix and suffix sizes
//
// Arguments: [cPrefix] -- (return) prefix size
// [cSuffix] -- (return) suffix size
//
// History: 05-Nov-91 BartoszM Created.
// 30-Nov-93 w-PatG Moved from CPersDeComp.
//
//----------------------------------------------------------------------------
inline void CKeyDeComp::LoadPSSize ( unsigned& cPrefix, unsigned& cSuffix )
{
ULONG ul = _bitStream.GetBits(8);
if (ul != 0) // 4 bits for prefix and suffix
{
cPrefix = (unsigned)ul >> 4;
cSuffix = (unsigned)ul & 0xF;
}
else // 8 bits for prefix and suffix
{
ul = _bitStream.GetBits(16);
cPrefix = (unsigned)ul >> 8;
cSuffix = (unsigned)ul & 0xFF;
}
Win4Assert(cPrefix + cSuffix <= MAXKEYSIZE );
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
"\n(%d:%d) ", cPrefix, cSuffix));
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::LoadPid, private
//
// Synopsis: Load property id
//
// History: 05-Nov-91 BartoszM Created.
// 06-Dec-93 w-PatG Moved from CPersDeComp.
//
// Notes: The Property id is used for different purposes in CKeyDeComp
// and CPersDeComp. In CKeyDeComp, a PROPID is actually a key id.
//
//----------------------------------------------------------------------------
__forceinline void CKeyDeComp::LoadPid ()
{
ULONG ul = _bitStream.GetBits(1);
if (ul == 0)
{
_key.SetPid(pidContents);
}
else
{
ul = BitUnCompress ( cPidBits );
_key.SetPid (ul);
}
#if CIDBG == 1
if (ul != 0)
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME," =PID %d= ", ul ));
#endif
}
//
// Unused, but required for inheritance.
//
OCCURRENCE CKeyDeComp::Occurrence()
{
Win4Assert( !"CKeyDeComp::Occurrence() -- invalid call" );
return( 0 );
}
OCCURRENCE CKeyDeComp::NextOccurrence()
{
Win4Assert( !"CKeyDeComp::NextOccurrence() -- invalid call" );
return( 0 );
}
ULONG CKeyDeComp::OccurrenceCount()
{
Win4Assert( !"CKeyDeComp::OccurrenceCount() -- invalid call" );
return( 0 );
}
OCCURRENCE CKeyDeComp::MaxOccurrence()
{
Win4Assert( !"CKeyDeComp::MaxOccurrence() -- invalid call" );
return( 1 );
}
WORKID CKeyDeComp::WorkId()
{
Win4Assert( !"CKeyDeComp::WorkId() -- invalid call" );
return( 0 );
}
WORKID CKeyDeComp::NextWorkId()
{
Win4Assert( !"CKeyDeComp::NextWorkId() -- invalid call" );
return( 0 );
}
ULONG CKeyDeComp::HitCount()
{
Win4Assert( !"CKeyDeComp::HitCount() -- invalid call" );
return(0);
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::CPersComp, public
//
// Synopsis: Creates a new (empty) persistent compressor.
//
// Arguments: [phIndex] -- physical index
//
// [widMax] -- The maximum workid which may be stored via
// PutWorkId.
//
// History: 05-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
CPersComp::CPersComp(
CPhysIndex& phIndex,
WORKID widMax)
: CKeyComp( phIndex, widMax ),
_sigPersComp(eSigPersComp),
_cWidProposed(0),
_cWidActual(0),
_bitStreamPatch ( phIndex )
{
#if CIDBG == 1
_cOccLeft = 0;
#endif // CIDBG == 1
}
//+---------------------------------------------------------------------------
//
// Function: CPersComp::CPersComp
//
// Synopsis: Constructor for the persistent compressor capable of dealing
// with a partially constructed index stream during a restarted
// master merge.
//
// Arguments: [phIndex] -- The physical index being constructed
// during a restarted master merge.
// [widMax] -- Maximum wid for the index.
// [bitOffRestart] -- Offset where to restart adding new
// keys.
// [bitOffSplitKey] -- Beginning offset of the last key added.
// If no keys added, set to 0,0.
// [splitKey] -- The key last successfully written to
// disk (split key). If there is no key, set it to "MinKey".
//
// History: 4-10-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CPersComp::CPersComp(
CPhysIndex& phIndex,
WORKID widMax,
const BitOffset & bitOffRestart,
const BitOffset & bitOffSplitKey,
const CKeyBuf & splitKey)
: CKeyComp( phIndex, widMax, bitOffRestart, bitOffSplitKey, splitKey),
_sigPersComp(eSigPersComp),
_cWidProposed(0),
_cWidActual(0),
_bitStreamPatch ( phIndex )
{
#if CIDBG == 1
_cOccLeft = 0;
#endif // CIDBG == 1
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::~CPersComp, public
//
// Synopsis: Destroy a compressor/buffer pair.
//
// Effects: The main effect of destroying a compressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 05-Jul-91 KyleP Created.
//
// Notes: Previous compressor is deleted in PutKey
//
//----------------------------------------------------------------------------
CPersComp::~CPersComp()
{
ciDebugOut (( DEB_PCOMP,"CPersComp::~CPersComp() -- Last Key = %.*ws\n",
_key.StrLen(), _key.GetStr() ));
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PatchWidCount, private
//
// Synopsis: Overwrites wid count
//
// History: 06-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
inline void CPersComp::PatchWidCount ()
{
if (_cWidProposed <= 15)
{
_bitStreamPatch.OverwriteBits(_cWidActual, 4);
}
else if (_cWidProposed <= 255)
{
_bitStreamPatch.OverwriteBits(_cWidActual, 12); // 4 0's + 8 bit number
}
else
{
_bitStreamPatch.OverwriteBits(0, 12); // 12 0's
_bitStreamPatch.OverwriteBits(_cWidActual, ULONG_BITS); // ULONG_BITS bit number
}
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutWidCount, private
//
// Synopsis: Writes work id count
//
// Arguments: [cWorkId] -- Count of wid's
//
// History: 06-Nov-91 BartoszM Created.
//
// Notes: Store the workid count. First, store the WID count used for
// compression. We will store a 4 bit count. If the count is
// greater than 15 then a 4-bit 0 will be stored followed by an 8 bit
// count. If the count is greater than 255 then a 12-bit 0 will be
// stored followed by a ULONG_BITS bit count.
//
//----------------------------------------------------------------------------
inline void CPersComp::PutWidCount ( ULONG cWorkId )
{
Win4Assert(cWorkId > 0);
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
"[%d]", cWorkId ));
BitOffset off;
// Position the patch stream at current offset
_bitStream.GetOffset(off);
_bitStreamPatch.Seek(off);
if (cWorkId <= 15)
{
_bitStream.PutBits(cWorkId, 4);
}
else if (cWorkId <= 255)
{
_bitStream.PutBits(cWorkId, 12); // 4 0's + 8 bit number
}
else
{
_bitStream.PutBits(0, 12); // 12 0's
_bitStream.PutBits(cWorkId, ULONG_BITS); // ULONG_BITS bit number
}
//
// Store a single bit indicating whether the count is accurrate.
// Regardless of whether it is accurrate, it is used for encoding.
//
_bitStream.PutBits(1, 1);
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::SkipWidCount, private
//
// Synopsis: Skips wid count
//
// History: 06-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
inline void CPersComp::SkipWidCount ()
{
unsigned posDelta;
if (_cWidProposed <= 15)
posDelta = 4;
else if (_cWidProposed <= 255)
posDelta = 12;
else
posDelta = 12 + ULONG_BITS;
_bitStreamPatch.SkipBits(posDelta);
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutKey, public
//
// Synopsis: Starts recording data for a new key.
//
// Arguments: [key] -- The new key.
//
// [cWorkId] -- Count of work ids to follow.
//
// [bitOff] -- (out) actual bit offset of the key in the index
//
// History: 05-Jul-91 KyleP Created.
//
// Notes: The structure for each key is:
// Prefix/Suffix size
// Suffix
// Property ID
// Work ID count
//
//----------------------------------------------------------------------------
void CPersComp::PutKey(const CKeyBuf * pkey,
ULONG cWorkId,
BitOffset & bitOffCurKey)
{
Win4Assert(_cOccLeft == 0);
Win4Assert(cWorkId > 0);
#if 0
if ( ( _cWidActual == 0 ) && ( _cWidProposed != 0 ) )
{
BackSpace();
}
else
{
#endif // 0
//
// Set the WorkId count accuracy bit for the previous key (if any).
// Then reset the workid counter.
//
SetCWIDAccuracy();
#if 0
}
#endif // 0
CKeyComp::PutKey(pkey, bitOffCurKey);
//
// Assume that a cursor just counted a few too many workids.
// If the final workid count is > _widMaximum that is very bad.
//
if ( cWorkId > _widMaximum )
cWorkId = _widMaximum;
PutWidCount ( cWorkId );
//
// Set up per/workid state
//
SetAverageBits ( cWorkId );
_wid = 0;
_cWidProposed = cWorkId;
_cWidActual = 0;
#if CIDBG == 1
_cOccLeft = 0;
#endif
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutWorkId, public
//
// Synopsis: Store a new WorkId.
//
// Arguments: [wid] -- WorkId
// [maxOcc] -- Max occurrence of wid
// [cOccurrence] -- Count of occurrences to follow
//
// Requires: [wid] must be larger than the last WorkId stored in
// the current key.
//
// Modifies: The input is added to the new index.
//
// History: 08-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
void CPersComp::PutWorkId(WORKID wid, OCCURRENCE maxOcc, ULONG cOccurrence)
{
Win4Assert(wid != widInvalid);
Win4Assert(wid > 0);
Win4Assert( wid > _wid );
Win4Assert( _cbitAverageWid > 0 );
Win4Assert(wid <= _widMaximum);
Win4Assert(_cOccLeft == 0);
Win4Assert( cOccurrence > 0 );
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,"<%d>", wid ));
//
// Store the workid delta.
//
BitCompress(wid - _wid, _cbitAverageWid);
//
// Store the max occurrence
//
PutMaxOccurrence( maxOcc );
//
// And store the occurrence count.
//
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,"(%d)", cOccurrence ));
BitCompress(cOccurrence, OccCountBits);
//
// Update state
//
_wid = wid;
_occ = 0;
_cWidActual++;
#if CIDBG == 1
_cOccLeft = cOccurrence;
#endif
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutMaxOccurrence
//
// Synopsis: Writes the max occurrence using the same compression
// scheme as that for writing widCount
//
// Arguments: [maxOcc] -- Max occurrence to write
//
// History: 20-Jun-96 SitaramR Created
//
//----------------------------------------------------------------------------
void CPersComp::PutMaxOccurrence( OCCURRENCE maxOcc )
{
Win4Assert( maxOcc > 0 );
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "[%d]", maxOcc ));
if ( maxOcc <= 15 )
{
_bitStream.PutBits( maxOcc, 4 );
}
else if ( maxOcc <= 255 )
{
_bitStream.PutBits( maxOcc, 12 ); // 4 0's + 8 bit number
}
else
{
_bitStream.PutBits( 0, 12 ); // 12 0's
_bitStream.PutBits( maxOcc, ULONG_BITS ); // ULONG_BITS bit number
}
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::SetCWIDAccuracy, private
//
// Effects: Determines if the originally specified number of WorkIds
// was accurate, and sets the 'accuracy' bit in the key
// accordingly.
//
// Modifies: The most recent 'accuracy' bit may be changed. This may
// be in a previous compressor or the current compressor.
//
// History: 18-Jul-91 KyleP Created.
//
// Notes: The only time additional space is needed is when we have
// an inaccurate count which cannot be fixed up.
//
//----------------------------------------------------------------------------
void CPersComp::SetCWIDAccuracy()
{
Win4Assert(_cWidActual <= _widMaximum);
//
// If the count was accurrate, then do nothing except delete the
// previous compressor (if any). If the count is inaccurate, then
// set the 'accuracy' bit.
//
if (_cWidActual != _cWidProposed)
{
//
// Decide if the count can be fixed up without having to shift
// any previously written data. This can generally be accomplished
// if the real count is either smaller than the proposed count or
// not too much larger *and* _cbitAverageWid remains the same.
//
Win4Assert ( _cWidActual <= _widMaximum );
if ( _cWidActual != 0 &&
_cbitAverageWid == AverageWidBits(_cWidActual) )
{
// ciDebugOut (( DEB_PCOMP, "fixed.\n"));
Win4Assert(_cWidActual < _cWidProposed);
PatchWidCount ();
}
else
{
//
// If we can't fix the count, then just set the 'count invalid' bit.
// And append a workid delta of 0.
//
// ciDebugOut (( DEB_PCOMP, "not fixed.\n"));
//
// Read forward over the count.
//
SkipWidCount ();
//
// And set the count invalid bit
//
#if CIDBG == 1
if (_bitStreamPatch.PeekBit() != 1)
{
Dump();
Win4Assert ( _bitStreamPatch.PeekBit() == 1 );
}
#endif // CIDBG == 1
_bitStreamPatch.OverwriteBits(0, 1);
//
// Store the sentinel workid delta.
//
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME," end "));
BitCompress(0, _cbitAverageWid);
}
_cWidActual = 0;
_cWidProposed = 0;
}
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::CPersDeComp, public
//
// Synopsis: Creates a new persistent decompressor
// at the beginning of an index
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
// [fUseDir] -- Flag indicating if the directory should be
// used or not for decompressing. Normally set to FALSE but
// during an in-progress master merge, we may not have a
// directory constructed yet.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 10-Apr=94 SrikantS Added fUseDir for restarted master
// merge.
//
//----------------------------------------------------------------------------
CPersDeComp::CPersDeComp(
PDirectory& pDir,
INDEXID iid,
CPhysIndex& phIndex,
WORKID widMax,
BOOL fUseLinks,
BOOL fUseDir )
: CKeyDeComp( pDir, iid, phIndex, widMax, fUseLinks, fUseDir ),
_sigPersDeComp(eSigPersDeComp)
{
FinishKeyLoad();
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::CPersDeComp, public
//
// Synopsis: Creates a new persistent decompressor.
// positioned at a specified key
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [keyPos] -- bit offset to key stored in directory
// [keyInit] -- initial key
// [pKey] -- actual key to search for
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
// [fUseDir] -- Flag indicating if the directory should be
// used or not for decompressing. Normally set to FALSE but
// during an in-progress master merge, we may not have a
// directory constructed yet.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 10-Apr=94 SrikantS Added fUseDir for restarted master
// merge.
//
//----------------------------------------------------------------------------
CPersDeComp::CPersDeComp(
PDirectory& pDir,
INDEXID iid,
CPhysIndex& phIndex,
BitOffset& keyPos,
const CKeyBuf& keyInit,
const CKey* pKey,
WORKID widMax,
BOOL fUseLinks,
BOOL fUseDir )
: CKeyDeComp( pDir, iid, phIndex, keyPos, keyInit, pKey, widMax,
fUseLinks, fUseDir ),
_sigPersDeComp(eSigPersDeComp),
_maxOcc(OCC_INVALID)
{
FinishKeyLoad();
CKeyCursor::_pid = _key.Pid();
UpdateWeight();
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::CPersDeComp, public
//
// Synopsis: Copy Constructor
//
// Effects: Copies most of the values in decomp. Calls copy constructor
// for CCoder.
//
// Arguments: [decomp] -- Original CPersDeComp to be copied.
//
// History: 08-Jan-92 AmyA Created.
//
//----------------------------------------------------------------------------
CPersDeComp::CPersDeComp(CPersDeComp & decomp)
:
CKeyDeComp (decomp),
_sigPersDeComp(eSigPersDeComp),
_cWid(decomp._cWid),
_cOcc(decomp._cOcc),
_fcwidAccurate(decomp._fcwidAccurate),
_cWidLeft(decomp._cWidLeft),
_cOccLeft(decomp._cOccLeft),
_maxOcc(OCC_INVALID)
{
UpdateWeight();
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::~CPersDeComp, public
//
// Synopsis: Destroy a decompressor/buffer pair.
//
// Effects: The main effect of destroying a decompressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 22-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
CPersDeComp::~CPersDeComp()
{}
const CKeyBuf * CPersDeComp::GetNextKey()
{
return GetNextKey(0);
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::GetNextKey, public
//
// Synopsis: Retrieve the next key from the content index.
//
// Returns: A pointer to the key, or 0 if end of page/index reached.
//
// History: 15-Jul-91 KyleP Created.
// 10-Apr-94 SrikantS Added pBitOff and the ability to
// decompress without using the dir.
//
//----------------------------------------------------------------------------
const CKeyBuf * CPersDeComp::GetNextKey( BitOffset *pBitOff )
{
//
// If we are not using links or
// we are not using the directory and the offset of next key
// is invalid, we must skip over the wid/occurrence data and
// find out the offset of the next key.
//
if ( !_fUseLinks || (!_fUseDir && !_bitOffNextKey.Valid()) )
{
//
// Just iterate through any remaining data for this key.
//
while (_wid != widInvalid)
{
while ( 0 != _cOccLeft )
{
BitUnCompress( OccDeltaBits );
_cOccLeft--;
}
LoadWorkId();
}
if ( _fUseLinks )
{
//
// We should fill the bitoffset for the next key as
// the current position in the bitstream.
//
Win4Assert( !_fUseDir );
_bitStream.GetOffset( _bitOffNextKey );
}
}
const CKeyBuf * pkey = CKeyDeComp::GetNextKey( pBitOff );
if ( pkey )
{
FinishKeyLoad();
CKeyCursor::_pid = pkey->Pid();
UpdateWeight();
}
return pkey;
} //GetNextKey
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::WorkId, public
//
// Synopsis: Retrieves the current Work ID
//
// Returns: The current WorkId or, if there is none or if at the end
// of the compressor then returns widInvalid.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
WORKID CPersDeComp::WorkId()
{
return(_wid);
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::NextWorkId, public
//
// Synopsis: Retrieve the next workid from the content index.
//
// Returns: A pointer to the workid, or widInvalid if end of
// page/index reached.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
WORKID CPersDeComp::NextWorkId()
{
//
// Just iterate through any remaining data for this WorkId.
//
while ( 0 != _cOccLeft )
{
BitUnCompress( OccDeltaBits );
_cOccLeft--;
}
// _occ may be invalid and really should be OCC_INVALID, but it doesn't matter
LoadWorkId();
return _wid;
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::WorkIdCount, public
//
// Returns: The total count of workids for the current key.
//
// History: 15-Jul-91 KyleP Created.
//
// Notes: Unlike the Get* calls, it is illegal to get a workid count
// if there is no valid key.
//
//----------------------------------------------------------------------------
ULONG CPersDeComp::WorkIdCount()
{
Win4Assert( _key.Count() > 0 );
return(_cWid);
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::Occurrence, public
//
// Synopsis: Retrieves the current occurrence
//
// Returns: The current occurrence or, if there is none or if at the end
// of the compressor then returns OCC_INVALID.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
OCCURRENCE CPersDeComp::Occurrence()
{
return(_occ);
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::NextOccurrence, public
//
// Synopsis: Retrieve the next occurrence from the content index.
//
// Returns: A pointer to the occurrence, or OCC_INVALID if end of
// page/index reached.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
OCCURRENCE CPersDeComp::NextOccurrence()
{
LoadOccurrence();
return _occ;
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::OccurrenceCount, public
//
// Returns: The total count of occurrences for the current workid.
//
// History: 15-Jul-91 KyleP Created.
//
// Notes: Unlike the Get* calls, it is illegal to get an occ count
// if there is no valid workid.
//
//----------------------------------------------------------------------------
ULONG CPersDeComp::OccurrenceCount()
{
Win4Assert(_wid != widInvalid);
return(_cOcc);
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadWidCount, private
//
// Synopsis: Loads wid count
//
// History: 05-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
inline void CPersDeComp::LoadWidCount ()
{
//
// Get the WorkId count. Initially assume it is 4 bits, then 8,
// then ULONG_BITS.
//
ULONG ul = _bitStream.GetBits(4);
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "{0x%x}", ul ));
if (ul == 0)
{
ul = _bitStream.GetBits(8);
if (ul == 0)
{
ul = _bitStream.GetBits(ULONG_BITS);
Win4Assert(ul != 0);
}
}
_cWid = _cWidLeft = ul;
//
// Get the bit signifying that the workid count is accurate.
//
ul = _bitStream.GetBits(1);
_fcwidAccurate = ul ? TRUE : FALSE;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,
"[%s%d]", _fcwidAccurate?"":"!", _cWid ));
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadKey, private
//
// Synopsis: Loads data for the next key.
//
// Effects: Reads a key from the current position in _bitStream and
// sets per key state.
//
// Signals: ???
//
// History: 12-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
void CPersDeComp::LoadKey()
{
CKeyDeComp::LoadKey();
FinishKeyLoad();
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::FinishKeyLoad, private
//
// Synopsis: Loads wid count and first wid. Finishes LoadKey call of
// CKeyDeComp
//
// History: 07-Dec-93 w-PatG Created.
//
//----------------------------------------------------------------------------
void CPersDeComp::FinishKeyLoad()
{
//Parent class has loaded in a key and id. Finish the job by loading in
//a wid count and first wid.
if ( IsAtSentinel() )
{
_wid = widInvalid;
_occ = OCC_INVALID;
_maxOcc = OCC_INVALID;
return;
}
LoadWidCount ();
_wid = 0;
#if CIDBG == 1
if ( _cWid > _widMaximum )
ciDebugOut (( DEB_ERROR, "_cWid = %ld, _widMaximum = %ld\n",
_cWid, _widMaximum ));
#endif
Win4Assert ( _cWid <= _widMaximum );
SetAverageBits( _cWid );
LoadWorkId();
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadOccurrence, private
//
// Synopsis: Load an occurrence from the bit buffer.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
__forceinline void CPersDeComp::LoadOccurrence()
{
if (_cOccLeft == 0)
{
_occ = OCC_INVALID;
return;
}
ULONG occDelta = BitUnCompress(OccDeltaBits);
Win4Assert( occDelta > 0 );
_occ += occDelta;
_cOccLeft--;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "%d ", _occ ));
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadFirstOccurrence, private
//
// Synopsis: Load an occurrence from the bit buffer.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
__forceinline void CPersDeComp::LoadFirstOccurrence()
{
Win4Assert( 0 != _cOccLeft );
_occ = BitUnCompress(OccDeltaBits);
Win4Assert( _occ > 0 );
_cOccLeft--;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "%d ", _occ ));
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadMaxOccurrence
//
// Synopsis: Load max occurrence from the bit buffer.
//
// History: 20-Jun-96 SitaramR Created
//
//----------------------------------------------------------------------------
__forceinline void CPersDeComp::LoadMaxOccurrence()
{
//
// Initially assume it is 4 bits, then 8, then ULONG_BITS
//
_maxOcc = _bitStream.GetBits(4);
if ( _maxOcc == 0 )
{
_maxOcc = _bitStream.GetBits(8);
if ( _maxOcc == 0 )
{
_maxOcc = _bitStream.GetBits(ULONG_BITS);
Win4Assert( _maxOcc != 0 );
}
}
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "{0x%x}", _maxOcc ));
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadWorkId, private
//
// Synopsis: Loads data for a WorkId.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
void CPersDeComp::LoadWorkId()
{
if (_cWidLeft == 0)
{
Win4Assert(_fcwidAccurate);
_wid = widInvalid;
return;
}
ULONG widDelta = BitUnCompress( _cbitAverageWid);
if (widDelta == 0)
{
#if CIDBG == 1
if (_fcwidAccurate)
Dump();
#endif
Win4Assert(!_fcwidAccurate);
_wid = widInvalid;
return;
}
LoadMaxOccurrence();
ULONG occCount = BitUnCompress( OccCountBits);
_wid += widDelta;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "<%d>", _wid ));
Win4Assert(_wid <= _widMaximum);
_cOcc = _cOccLeft = occCount;
_cWidLeft--;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "(%d)", _cOcc ));
LoadFirstOccurrence();
}
#if DEVL == 1
void CCoder::Dump()
{
#if CIDBG == 1
ciDebugOut((DEB_ITRACE,
"CCoder:\n"
"\t_widMaximum %d\n"
"\tKey \"%.*ws\"\n"
"\t_wid %d"
"\t_occ %d\n"
"\t_cbitAverageWid %d\n",
_widMaximum, _key.StrLen(), _key.GetStr(), _wid, _occ, _cbitAverageWid ));
#endif // CIDBG == 1
}
void CKeyComp::Dump()
{
}
void CKeyDeComp::Dump()
{
}
void CPersDeComp::Dump()
{
#if CIDBG == 1
CCoder::Dump();
ciDebugOut((DEB_ITRACE,
"CPersDeComp:\n"
"\t_cWid %d\n"
"\t_cOcc %d\n"
"\t_fcwidAccurate %d"
"\t_cWidLeft %d\n"
"\t_cOccLeft %d\n",
_cWid, _cOcc, _fcwidAccurate, _cWidLeft, _cOccLeft ));
_bitStream.Dump();
#endif // CIDBG == 1
}
void CPersComp::Dump()
{
#if CIDBG == 1
CCoder::Dump();
ciDebugOut((DEB_ITRACE,
"CPersComp:\n"
"\t_cWidActual %d\n"
"\t_cWidProposed %d\n"
"\t_cOccLeft %d\n",
_cWidActual, _cWidProposed, _cOccLeft ));
ciDebugOut((DEB_ITRACE, "BitStream\n" ));
_bitStream.Dump();
ciDebugOut((DEB_ITRACE, "BitStreamPatch\n" ));
_bitStreamPatch.Dump();
#endif // CIDBG == 1
}
#endif // DEVL == 1