//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2000. // // File: keylist.cxx // // Contents: KeyList // // History: 17-Feb-1994 KyleP Created // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #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 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 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 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 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 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