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
30 KiB
1095 lines
30 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
|
|
|