Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1095 lines
29 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: keylist.cxx
//
// Contents: KeyList
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <pidxtbl.hxx>
#include <pdir.hxx>
#include <cifailte.hxx>
#include "keylist.hxx"
#include "pcomp.hxx"
#include "keyhash.hxx"
//+---------------------------------------------------------------------------
//
// Member: CKeyList::GetNextIid, public
//
// Synopsis: Returns the next valid index id for a new keylist.
//
// History: 31-Oct-93 w-PatG Created.
//
//----------------------------------------------------------------------------
INDEXID CKeyList::GetNextIid ()
{
CIndexId CurId = GetId();
if (!CurId.IsPersistent() || CurId.PersId() == MAX_PERS_ID)
return CIndexId( 1, partidKeyList );
else
return CIndexId( CurId.PersId() + 1, partidKeyList );
}
//+-------------------------------------------------------------------------
//
// Method: CKeyList::FillRecord
//
// Synopsis: Creates index record for keylist
//
// Arguments: [record] -- Record to initialize
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
void CKeyList::FillRecord (CIndexRecord& record) const
{
record._objectId = ObjectId();
record._iid = GetId();
record._type = itKeyList;
record._maxWorkId = MaxWorkId();
}
#ifdef KEYLIST_ENABLED
//+---------------------------------------------------------------------------
//
// Member: CKeyList::Size, public
//
// Synopsis: Returns number of pages in Physical Index.
//
// History: 28-Oct-93 w-PatG Created.
//
//----------------------------------------------------------------------------
unsigned CKeyList::Size() const
{
if ( _pPhysIndex )
return _pPhysIndex->PageSize();
else
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::CKeyList, public
//
// Synopsis: Default Constructor for CKeyList
//
// Effects: Creates a dummy KeyList
//
// History: 17-Dec-93 w-PatG Created.
//
// Note: The first kid/widMax in a keyList is set to 1 here, since
// kids overlap in memory with pids, and pid 0, & 1 are reserved.
//
//----------------------------------------------------------------------------
CKeyList::CKeyList()
: CIndex( CIndexId( partidKeyList, MAX_PERS_ID + 1), 1, FALSE ),
_sigKeyList(eSigKeyList),
_pstorage(0),
_obj(0),
_pPhysIndex(0),
_pPhysHash(0),
_pDir(0)
{
ciDebugOut(( DEB_KEYLIST, "Open null keylist\n" ));
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::CKeyList, public
//
// Synopsis: Constructor for CKeyList
//
// Effects: Initializes KeyList from disk
//
// Arguments: [id] -- List ID of the key list.
// [widMax] -- maximum work id
//
// History: 03-Nov-93 w-PatG Created.
// 17-Feb-94 KyleP Initial version
//
//----------------------------------------------------------------------------
CKeyList::CKeyList( PStorage & storage, WORKID objectId, INDEXID iid,
KEYID kidMax )
: CIndex( iid, kidMax, FALSE ),
_sigKeyList(eSigKeyList),
_pstorage(&storage),
_obj ( storage.QueryObject(objectId) ),
_pPhysIndex(0),
_pPhysHash(0),
_pDir(0)
{
ciDebugOut(( DEB_KEYLIST, "Open keylist 0x%x\n", iid ));
TRY
{
//
// Open the keylist index stream.
//
PMmStream * pStream = storage.QueryExistingIndexStream( _obj.GetObj(),
PStorage::eOpenForRead );
XPtr<PMmStream> sStream( pStream );
_pPhysIndex = new CPhysIndex ( storage, _obj.GetObj(), objectId,
PStorage::eOpenForRead,
sStream );
//
// Open the keylist hash stream.
//
pStream = storage.QueryExistingHashStream( _obj.GetObj(),
PStorage::eOpenForRead );
sStream.Set( pStream );
_pPhysHash = new CPhysHash ( storage, _obj.GetObj(), objectId,
PStorage::eOpenForRead,
sStream );
//
// Open the directory.
//
_pDir = storage.QueryExistingDirectory ( _obj.GetObj(), PStorage::eOpenForRead );
}
CATCH ( CException, e )
{
delete _pDir;
delete _pPhysHash;
delete _pPhysIndex;
RETHROW();
}
END_CATCH
}
//+---------------------------------------------------------------------------
//
// Member: CWKeyList::CWKeyList, public
//
// Synopsis: Create an empty writeable index
//
// Arguments: [storage] -- physical storage
//
// History: 03-Apr-91 BartoszM Created.
// 17-Feb-93 KyleP Initial version
//
//----------------------------------------------------------------------------
CWKeyList::CWKeyList ( PStorage & storage, WORKID objectId, INDEXID iid,
unsigned size, CKeyList * pOldKeyList )
: CKeyList( storage, objectId, iid, pOldKeyList->MaxWorkId(), 0 ),
_sigWKeyList(eSigWKeyList),
_pOldKeyCursor( 0),
_pKeyComp( 0 ),
_ulPage( 0xFFFFFFFF )
{
ciDebugOut(( DEB_KEYLIST, "Create keylist 0x%x\n", iid ));
_keyLast.SetCount(0);
TRY
{
//open a physindex size=1
PMmStream * pStream = storage.QueryNewIndexStream( _obj.GetObj(),
FALSE // not a master
);
XPtr<PMmStream> sStream(pStream);
_pPhysIndex = new CPhysIndex( storage, _obj.GetObj(),
objectId, size, sStream );
Win4Assert( !sStream );
pStream = storage.QueryNewHashStream( _obj.GetObj() );
sStream.Set(pStream);
_pPhysHash = new CPhysHash ( storage, _obj.GetObj(), objectId, 0,
sStream );
Win4Assert( !sStream );
ciFAILTEST( STATUS_DISK_FULL );
_pDir = storage.QueryNewDirectory ( _obj.GetObj() );
_pKeyComp = new CKeyComp( *_pPhysIndex, widInvalid, FALSE );
_pKeyComp->WriteFirstKeyFull();
_pOldKeyCursor = pOldKeyList->QueryCursor();
}
CATCH ( CException, e )
{
delete _pKeyComp;
RETHROW();
}
END_CATCH
}
//+---------------------------------------------------------------------------
//
// Function: CWKeyList - Ctor
//
// Synopsis: A writable key list constructor used when re-starting a
// paused master merge.
//
// Effects:
//
// Arguments: [storage] -- Storage object.
// [objectId] -- ObjectId of the new key list.
// [iid] -- IndexId of the new key list.
// [pOldKeyList] -- Pointer to the old key list.
// [splitKey] -- The last key that is guaranteed to be
// written to disk in the split key. If none were written,
// this will be set to "MinKey".
//
// History: 4-20-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CWKeyList::CWKeyList ( PStorage & storage, WORKID objectId, INDEXID iid,
CKeyList * pOldKeyList,
CKeyBuf & splitKey,
WORKID widMax )
: CKeyList( storage, objectId, iid, widMax, 0 ),
_sigWKeyList(eSigWKeyList),
_pOldKeyCursor( 0),
_pKeyComp( 0 ),
_ulPage( 0xFFFFFFFF )
{
ciDebugOut(( DEB_KEYLIST, "Restart keylist 0x%x\n", iid ));
Win4Assert( widMax >= pOldKeyList->MaxWorkId() );
_keyLast.SetCount(0);
TRY
{
//
// Open existing IndexStream, HashStream and Directory stream
// for write access.
//
PMmStream * pStream = storage.QueryExistingIndexStream( _obj.GetObj(),
PStorage::eOpenForWrite );
XPtr<PMmStream> sStream(pStream);
_pPhysIndex = new CPhysIndex( storage, _obj.GetObj(), objectId,
PStorage::eOpenForWrite,
sStream
);
pStream = storage.QueryExistingHashStream( _obj.GetObj(),
PStorage::eOpenForWrite );
sStream.Set( pStream );
_pPhysHash = new CPhysHash ( storage, _obj.GetObj(), objectId,
PStorage::eOpenForWrite,
sStream
);
ciFAILTEST( STATUS_DISK_FULL );
_pDir = storage.QueryExistingDirectory ( _obj.GetObj(),
PStorage::eOpenForWrite
);
//
// Restore the existing directory by reading from the beginning
// upto the split key.
//
BitOffset beginBitOff, endBitOff;
RestoreDirectory( splitKey, beginBitOff, endBitOff );
//
// Create a key compressor which can understand partially filled
// pages and position to write the next key provided.
//
_pKeyComp = new CKeyComp( *_pPhysIndex, widInvalid,
endBitOff, beginBitOff,
splitKey,
FALSE // don't use links
);
_pKeyComp->WriteFirstKeyFull();
//
// Update the used pages count in the index.
//
_pPhysIndex->SetUsedPagesCount( endBitOff.Page() + 1 );
//
// Set up the existing keylist cursor to position after the
// split key.
//
if ( splitKey.IsMinKey() )
{
_pOldKeyCursor = pOldKeyList->QueryCursor();
}
else
{
CKey Key( splitKey );
_pOldKeyCursor = (CKeyDeComp *) pOldKeyList->QueryCursor( &Key );
if ( _pOldKeyCursor )
{
CKeyBuf const * pTemp = _pOldKeyCursor->GetKey();
if ( pTemp && (pTemp->CompareStr( splitKey ) == 0) )
{
_pOldKeyCursor->GetNextKey();
}
}
_keyLast = splitKey;
}
}
CATCH ( CException, e )
{
delete _pKeyComp;
RETHROW();
}
END_CATCH
}
//+---------------------------------------------------------------------------
//
// Function: RestoreDirectory
//
// Synopsis: Restores the directory object from the keys added to the
// key list in the previous invocation of master merge.
//
// Effects:
//
// Arguments: [splitKey] -- The key that is known to be successfully
// writtent to disk.
// [beginBitOff] -- Output - beginning offset of the split
// key.
// [endBitOff] -- Output - end offset+1 (bit) of the split
// key. This is the place where the next key should be written.
//
// History: 4-20-94 srikants Created
//
// Notes: The "Pid" field in the key is used by the keylist as a
// "KeyId" and it is a monotonically increasing entity. Each
// key has a unique "KeyId" and so as part of restore, we have
// to get the last "KeyId" used thus far.
//
//----------------------------------------------------------------------------
void CWKeyList::RestoreDirectory( CKeyBuf & splitKey,
BitOffset & beginBitOff,
BitOffset & endBitOff )
{
Win4Assert( _pDir );
Win4Assert( _pPhysIndex );
beginBitOff.Init(0,0);
endBitOff.Init(0,0);
// STACKSTACK
XPtr<CKeyBuf> xKeyLast(new CKeyBuf()); // initialized to min key
//
// Remove all keys in the directory after the split key.
//
xKeyLast->FillMin();
_pDir->DeleteKeysAfter( xKeyLast.GetReference() );
//
// "MinKey" is a special case and must be dealt with by assuming
// that no key was written out.
//
if ( splitKey.IsMinKey() )
return;
CKeyDeComp decomp( *_pDir, GetId() ,
*_pPhysIndex, widInvalid,
FALSE, // Don't use links.
FALSE // Don't use directory.
);
const CKeyBuf * pKey;
#if CIDBG == 1
xKeyLast->SetPid(pidContents); // arbitrary but not pidAll
#endif
for ( pKey = decomp.GetKey() ;
0 != pKey;
pKey = decomp.GetNextKey(&beginBitOff) )
{
if ( pKey->Pid() > _widMax )
{
_widMax = pKey->Pid();
}
if ( beginBitOff.Page() != _ulPage &&
!AreEqualStr(pKey, xKeyLast.GetPointer()))
{
_ulPage = beginBitOff.Page();
_pDir->Add ( beginBitOff, *pKey );
}
if ( pKey->CompareStr(splitKey) >= 0 )
{
ciDebugOut(( DEB_ITRACE, "RestoreDirectory - SplitKey Found \n" ));
break;
}
xKeyLast.GetReference() = *pKey;
}
if ( 0 != pKey )
{
splitKey = *pKey;
}
else {
splitKey = xKeyLast.GetReference();
}
decomp.GetOffset( endBitOff );
//
// Need to skip the current key cursor until the last key
//
ciDebugOut(( DEB_ITRACE, "KeyList - Restart KeyId 0x%x\n", _widMax ));
ciDebugOut(( DEB_ITRACE, "Keylist Restart split key is '%ws'\n",
splitKey.GetStr() ));
ciDebugOut(( DEB_ITRACE, "Keylist Restart page:offset = 0x%x:0x%x\n",
endBitOff.Page(), endBitOff.Offset() ));
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::~CKeyList, public
//
// Synopsis: Destructor
//
// Effects: Release all memory used by keylist
//
// History: 31-Oct-93 w-PatG Created.
// 17-Feb-94 KyleP Initial version
//
//----------------------------------------------------------------------------
CKeyList::~CKeyList()
{
delete _pDir;
delete _pPhysHash;
delete _pPhysIndex;
}
//+-------------------------------------------------------------------------
//
// Method: CWKeyList::CWKeyList
//
// Synopsis: Dtor for writeable keylist
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
CWKeyList::~CWKeyList()
{
delete _pOldKeyCursor;
delete _pKeyComp;
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::QueryCursor, public
//
// Synopsis: Create a cursor for the KeyList
//
// Effects: Creates a cursor
//
// Returns: A pointer to a CKeyCursor.
//
// History: 31-Oct-93 w-PatG Created.
// 17-Feb-94 KyleP Initial version
//
//----------------------------------------------------------------------------
CKeyCursor * CKeyList::QueryCursor()
{
if(_pPhysIndex == 0)
{
return(0);
}
else
{
BitOffset posKey;
CKey key;
key.FillMin();
CKeyBuf keyInit;
_pDir->Seek ( key, &keyInit, posKey );
ciDebugOut (( DEB_ITRACE, "found key %.*ws at %lx:%lx\n",
keyInit.StrLen(), keyInit.GetStr(),
posKey.Page(), posKey.Offset() ));
CKeyDeComp* pCursor = new CKeyDeComp(
*_pDir, GetId(), *_pPhysIndex, posKey, keyInit, &key, _widMax, FALSE );
if ( pCursor->GetKey() == 0 )
{
delete pCursor;
pCursor = 0;
}
return pCursor;
}
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::QueryCursor, public
//
// Synopsis: Create a cursor for the KeyList
//
// Effects: Creates a cursor
//
// Arguments: [pkey] -- Key to search for
//
// Returns: A pointer to a CKeyCursor.
//
// History: 31-Oct-93 w-PatG Created.
//
//----------------------------------------------------------------------------
COccCursor * CKeyList::QueryCursor( CKey const * pkey,
BOOL isRange,
ULONG & cMaxNodes )
{
Win4Assert( cMaxNodes > 0 );
if(_pPhysIndex == 0)
return( 0 );
if (isRange)
{
CKey keyEnd;
keyEnd.FillMax (*pkey);
return QueryRangeCursor (pkey, &keyEnd, cMaxNodes );
}
cMaxNodes--;
if ( 0 == cMaxNodes )
{
ciDebugOut(( DEB_WARN, "Node limit reached in CKeyList::QueryCursor\n" ));
THROW( CException( STATUS_TOO_MANY_NODES ) );
}
BitOffset posKey;
CKeyBuf keyInit;
_pDir->Seek ( *pkey, &keyInit, posKey );
ciDebugOut (( DEB_KEYLIST, "found key %.*ws at %lx:%lx\n",
keyInit.StrLen(), keyInit.GetStr(),
posKey.Page(), posKey.Offset() ));
CKeyDeComp* pCursor = new CKeyDeComp(
*_pDir, GetId(), *_pPhysIndex, posKey, keyInit, pkey, _widMax, FALSE );
if ( pCursor->GetKey() == 0 )
{
delete pCursor;
pCursor = 0;
}
return pCursor;
}
//+-------------------------------------------------------------------------
//
// Method: CKeyList::QueryRangeCursor
//
// Synopsis: Not (yet) implemented for KeyList
//
// Arguments: [pkeyBegin] -- Beginning of range
// [pkeyEnd] -- End of range
//
// Returns: Cursor
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
COccCursor * CKeyList::QueryRangeCursor( const CKey * pkeyBegin,
const CKey * pkeyEnd,
ULONG & cMaxNodes )
{
return( 0 );
}
//+-------------------------------------------------------------------------
//
// Method: CKeyList::QuerySynCursor
//
// Synopsis: Never implemented for KeyList
//
// Arguments: [keyArr] -- Array of keys to merge
// [isRange] -- True if ???
//
// Returns: Cursor
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
COccCursor * CKeyList::QuerySynCursor( CKeyArray & keyArr,
BOOL isRange,
ULONG & cMaxNodes )
{
Win4Assert( !"CKeyList::QuerySynCursor -- Illegal call" );
return( 0 );
}
//+-------------------------------------------------------------------------
//
// Method: CKeyList::Close
//
// Synopsis: Close persistent resources
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
void CKeyList::Close()
{
if ( _pDir )
_pDir->Close();
if ( _pPhysHash )
_pPhysHash->Close();
if ( _pPhysIndex )
_pPhysIndex->Close();
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::Remove, public
//
// Synopsis: Remove index from storage
//
// History: 02-May-91 BartoszM Created.
// 16-Dec-93 w-PatG Stolen from pindex.
// 28-Jun-94 SrikantS Modified it to not throw
// exceptions.
//
//----------------------------------------------------------------------------
void CKeyList::Remove()
{
if ( _pPhysIndex )
{
Close();
_obj->Close();
if ( !_pstorage->RemoveObject( ObjectId() ) )
{
Win4Assert( !"delete of index failed" );
ciDebugOut(( DEB_ERROR, "Delete of index %08x failed: %d\n",
ObjectId(), GetLastError() ));
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::KeyToId, public
//
// Synopsis: Maps from a key to an id.
//
// Arguments: [pkey] -- pointer to the key to be mapped to ULONG
//
// Returns: key id - a ULONG
//
// History: 31-Oct-93 w-PatG Created.
// 17-Feb-94 KyleP Initial version
//
// Notes: KeyToId searches for key in index and returns the pid as
// the key id (kid).
//
//----------------------------------------------------------------------------
KEYID CKeyList::KeyToId( CKey const * pkey )
{
//
// These keys must be just a [normalized] word. No string/value id in
// front of them.
//
Win4Assert( pkey->Pid() == 0 );
KEYID kid;
if(_pPhysIndex == 0)
kid = kidInvalid;
else
{
BitOffset posKey;
CKeyBuf keyInit;
_pDir->Seek ( *pkey, &keyInit, posKey );
ciDebugOut (( DEB_KEYLIST, "found key %.*ws at %lx:%lx\n",
keyInit.StrLen(), keyInit.GetStr(),
posKey.Page(), posKey.Offset() ));
CKeyDeComp cur( *_pDir, GetId(), *_pPhysIndex, posKey, keyInit,
pkey, _widMax, FALSE );
CKeyBuf const * pkey2 = cur.GetKey();
if ( pkey2 == 0 || pkey->CompareStr( *pkey2 ) != 0 )
{
kid = kidInvalid;
}
else
{
kid = pkey2->Pid();
}
}
ciDebugOut(( DEB_KEYLIST, "Key \"%.*ws\" --> id %d\n",
pkey->Count()/sizeof(WCHAR), pkey->GetBuf(),
kid ));
return( kid );
}
//+---------------------------------------------------------------------------
//
// Member: CKeyList::IdToKey, public
//
// Synopsis: Maps an id to a key.
//
// Arguments: [ulKid] -- key id to mapped to a key
// [rkey] -- the mapped key
//
// History: 31-Oct-93 w-PatG Created.
// 17-Feb-94 KyleP Initial version
//
// Notes: IdToKey uses the key hash to locate the correct leaf page in
// the directory, then locates that leaf page and initializes
// a cursor into the index. The search then proceeds until a
// key with the matching key id is located or no more keys are
// found.
//
//----------------------------------------------------------------------------
BOOL CKeyList::IdToKey( KEYID kid, CKey & rkey )
{
if ( 0 == _pPhysHash )
return( FALSE );
if ( kid == 0 || kid > MaxKeyIdInUse() )
return( FALSE );
CRKeyHash KeyHash( *_pPhysHash, _pPhysIndex->PageSize() );
CKeyBuf keyInit;
keyInit.FillMin();
BitOffset posKey;
KeyHash.Find( kid, posKey );
CKey key;
CKeyDeComp cur( *_pDir, GetId(), *_pPhysIndex, posKey,
keyInit, &key, _widMax, FALSE );
for ( CKeyBuf const * pkey = cur.GetKey();
pkey && pkey->Pid() != kid;
pkey = cur.GetNextKey() )
continue; // Null body
if ( pkey )
rkey = *pkey;
else
{
Win4Assert( !"Can't find key!" );
return( FALSE );
}
ciDebugOut(( DEB_KEYLIST, "id %d --> Key \"%.*ws\"\n",
kid, pkey->StrLen(), pkey->GetStr() ));
return( TRUE );
}
//+-------------------------------------------------------------------------
//
// Method: CWKeyList::PutKey
//
// Synopsis: Store new key in keylist
//
// Effects: Copies all old keys <= [pKeyAdd] to keylist and then adds
// [pkeyAdd] if it does not yet exist.
//
// Arguments: [pkeyAdd] -- Key to add
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
KEYID CWKeyList::PutKey( CKeyBuf const * pkeyAdd, BitOffset & bitOff )
{
Win4Assert( _pKeyComp );
KEYID kid;
//
// Only store content keys. No value keys.
//
if ( *(pkeyAdd->GetBuf()) != STRING_KEY )
return kidInvalid;
//
// Write keys from old keylist that are <= current key.
//
if ( _pOldKeyCursor )
for ( CKeyBuf const * pkey = _pOldKeyCursor->GetKey();
pkey && pkey->CompareStr(*pkeyAdd) <= 0;
pkey = _pOldKeyCursor->GetNextKey() )
{
ciDebugOut(( DEB_KEYLIST, "Keylist: Copy Key \"%.*ws\" -- keyid = %d\n",
pkey->StrLen(), pkey->GetStr(), pkey->Pid() ));
_keyLast = *pkey;
_pKeyComp->PutKey( &_keyLast, bitOff );
if ( bitOff.Page() != _ulPage )
{
_ulPage = bitOff.Page();
_pDir->Add ( bitOff, _keyLast );
}
}
//
// Write this key?
//
if ( _keyLast.CompareStr( *pkeyAdd ) < 0 )
{
_keyLast = *pkeyAdd;
_keyLast.SetPid( GetKeyId() );
kid = _keyLast.Pid();
ciDebugOut(( DEB_KEYLIST, "Keylist: Add Key \"%.*ws\" -- keyid = %d\n",
_keyLast.StrLen(), _keyLast.GetStr(), _keyLast.Pid() ));
_pKeyComp->PutKey( &_keyLast, bitOff );
if ( bitOff.Page() != _ulPage )
{
_ulPage = bitOff.Page();
_pDir->Add ( bitOff, _keyLast );
}
}
else
{
kid = _keyLast.Pid();
}
return kid;
}
//+-------------------------------------------------------------------------
//
// Method: CWKeyList::Done
//
// Synopsis: Finish writing keylist + build hash
//
// Effects: Copy any remaining keys from old keylist and build hash
// table. Reopen for read access.
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
void CWKeyList::Done( BOOL & fAbort )
{
ciDebugOut(( DEB_KEYLIST, "KeyList::Done\n" ));
//
// Write remaining keys from old keylist;
//
BitOffset bitOff;
if ( _pOldKeyCursor )
for ( CKeyBuf const * pkey = _pOldKeyCursor->GetKey();
pkey && pkey->Count() > 0 && pkey->CompareStr( _keyLast ) > 0;
pkey = _pOldKeyCursor->GetNextKey() )
{
ciDebugOut(( DEB_KEYLIST, "Keylist: Copy Key \"%.*ws\" -- keyid = %d\n",
pkey->StrLen(), pkey->GetStr(), pkey->Pid() ));
_keyLast = *pkey;
_pKeyComp->PutKey( &_keyLast, bitOff);
if ( bitOff.Page() != _ulPage )
{
_ulPage = bitOff.Page();
_pDir->Add ( bitOff, _keyLast );
}
}
//
// Add sentinel key
//
_keyLast.FillMax();
_keyLast.SetPid(1);
_pKeyComp->PutKey( &_keyLast, bitOff );
//
// Add sentinel key to the directory.
//
_pDir->Add( bitOff, _keyLast );
//
// Close compressor, decompressor and directory
//
delete _pOldKeyCursor;
_pOldKeyCursor = 0;
delete _pKeyComp;
_pKeyComp = 0;
// STACKSTACK
XPtr<CKeyBuf> xMaxKey(new CKeyBuf());
xMaxKey->FillMax();
_pDir->LokFlushDir(xMaxKey.GetReference());
_pDir->LokBuildDir(xMaxKey.GetReference());
//
// Reopen for read access
//
_pPhysIndex->Flush();
_pPhysIndex->Reopen();
//
// Rescan to build hash table
//
BuildHash( fAbort );
_pPhysHash->Flush();
_pPhysHash->Reopen();
}
//+-------------------------------------------------------------------------
//
// Method: CWKeyList::BuildHash
//
// Synopsis: Build KeyHash
//
// History: 17-Feb-1994 KyleP Created
// 15-Aug-1994 SrikantS Modified not to use the directory
// iterator
//
//--------------------------------------------------------------------------
void CWKeyList::BuildHash( BOOL & fAbort )
{
CWKeyHash keyhash( *_pPhysHash, _pPhysIndex->PageSize(), MaxKeyIdInUse() );
#if defined(CI_KEYHASH)
CKeyDeComp * pcur = (CKeyDeComp *) QueryCursor();
if ( 0 == pcur )
{
return;
}
BitOffset hashOff; // Offset written in the hash table for kids.
BitOffset keyOff; // Offset of the current key.
hashOff.Init(0,0);
keyOff.Init(0,0);
#if CIDBG==1
unsigned cKey = 0;
#endif // CIDBG==1
for ( const CKeyBuf * pkey = pcur->GetKey(); 0 != pkey;
pkey = pcur->GetNextKey( &keyOff ) )
{
if ( fAbort )
{
fAbort = FALSE;
THROW( CException( STATUS_TOO_LATE ) );
}
//
// Check if the current key starts on a different page from
// the previous one. If so, we have to update the offset
// that is written to the hash stream.
//
if ( keyOff.Page() != hashOff.Page() )
{
Win4Assert( keyOff.Page() > hashOff.Page() );
hashOff.Init( keyOff.Page(), keyOff.Offset() );
}
keyhash.Add( pkey->Pid(), hashOff );
#if CIDBG==1
cKey++;
#endif // CIDBG==1
ciDebugOut(( DEB_KEYLIST, "Hash: index %d, key %.*ws (kid = %d)\n",
hashOff.Page(),
pkey->StrLen(),
pkey->GetStr(),
pkey->Pid() ));
}
delete pcur;
#endif // CI_KEYHASH
}
#else // !KEYLIST_ENABLED
CKeyList::CKeyList()
: CIndex( CIndexId( partidKeyList, MAX_PERS_ID + 1), 1, FALSE )
{
ciDebugOut(( DEB_KEYLIST, "Open null keylist\n" ));
}
CKeyList::CKeyList( KEYID kidMax, INDEXID iid )
: CIndex( iid, kidMax, FALSE )
{
}
#endif // !KEYLIST_ENABLED