WindowsXP/Source/XPSP1/NT/inetsrv/query/cindex/pindex.cxx
2024-08-03 16:30:48 +02:00

995 lines
29 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 1998.
//
// File: PINDEX.CXX
//
// Contents: Persistent Index
//
// Classes: CPersIndex, CMergeSourceCursor
//
// History: 03-Apr-91 BartoszM Created stub.
// 20-Apr-94 DwightKr Moved CMergeSourceCursor here
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <pdir.hxx>
#include <pstore.hxx>
#include <pidxtbl.hxx>
#include <rwex.hxx>
#include "pindex.hxx"
#include "pcomp.hxx"
#include "mcursor.hxx"
#include "fresh.hxx"
#include "physidx.hxx"
#include "pcomp.hxx"
#include "fretest.hxx"
#include "indsnap.hxx"
#include "keylist.hxx"
#include "partn.hxx"
unsigned const FOUR_MEGABYTES = 0x400000;
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::Size, public
//
// Synopsis: Returns size in pages
//
// History: 22-May-92 BartoszM Created.
//
//----------------------------------------------------------------------------
unsigned CPersIndex::Size() const
{
return _xPhysIndex->PageSize();
}
void CPersIndex::FillRecord ( CIndexRecord& record )
{
record._objectId = ObjectId();
record._iid = GetId();
record._type = IsMaster()? itMaster: itShadow;
record._maxWorkId = MaxWorkId();
}
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::CPersIndex, public
//
// Synopsis: Create an empty index
//
// Arguments: [id] -- index id
// [storage] -- physical storage
//
// History: 3-Apr-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CPersIndex::CPersIndex(
PStorage & storage,
WORKID objectId,
INDEXID iid,
unsigned c4KPages,
CDiskIndex::EDiskIndexType idxType ) :
CDiskIndex( iid, idxType ),
_sigPersIndex( eSigPersIndex ),
_storage( storage ),
_obj( storage.QueryObject( objectId ) ),
_fAbortMerge( FALSE )
{
XPtr<PMmStream> sStream( storage.QueryNewIndexStream( _obj.GetObj(),
CDiskIndex::eMaster == idxType ) );;
_xPhysIndex.Set( new CPhysIndex( storage,
_obj.GetObj(),
objectId,
c4KPages,
sStream ) );
_xPhysIndex->SetPageGrowth( FOUR_MEGABYTES / CI_PAGE_SIZE );
Win4Assert( 0 == sStream.GetPointer() );
_xDir.Set( _storage.QueryNewDirectory( _obj.GetObj() ) );
}
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::CPersIndex, public
//
// Synopsis: Restore an index from storage
//
// Arguments: [id] -- index id
// [storage] -- physical storage
// [widMax] -- max work id
// [isMaster] -- Set to TRUE if this is a master index.
// [fWritable] -- Set to TRUE if various streams should be
// opened for Write access.
// [fReadDir] -- should the directory be opened for r or r/w
//
// History: 3-Apr-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CPersIndex::CPersIndex(
PStorage & storage,
WORKID objectId,
INDEXID iid,
WORKID widMax,
CDiskIndex::EDiskIndexType idxType,
PStorage::EOpenMode mode,
BOOL fReadDir ) :
CDiskIndex( iid, idxType, widMax ),
_sigPersIndex( eSigPersIndex ),
_storage( storage ),
_obj( storage.QueryObject( objectId ) ),
_fAbortMerge( FALSE )
{
Win4Assert( PStorage::eOpenForWrite == mode ||
PStorage::eOpenForRead == mode );
PStorage::EOpenMode modeIndex = mode;
//
// Open master indexes writable so we can shrink them from the front
//
if ( CDiskIndex::eMaster == idxType )
modeIndex = PStorage::eOpenForWrite;
PMmStream * pStream = storage.QueryExistingIndexStream( _obj.GetObj(),
modeIndex );
XPtr<PMmStream> sStream( pStream );
_xPhysIndex.Set( new CPhysIndex( storage,
_obj.GetObj(),
objectId,
modeIndex,
sStream ) );
Win4Assert( 0 == sStream.GetPointer() );
Win4Assert( fReadDir );
if ( fReadDir )
_xDir.Set( _storage.QueryExistingDirectory( _obj.GetObj(), mode ) );
else
_xDir.Set( _storage.QueryNewDirectory( _obj.GetObj() ) );
}
//+---------------------------------------------------------------------------
//
// Member: CMergeSourceCursor::CMergeSourceCursor
//
// Synopsis: Constructor
//
// History: 29-Aug-92 BartoszM Created
//
//----------------------------------------------------------------------------
CMergeSourceCursor::CMergeSourceCursor ( CIndexSnapshot& indSnap,
const CKeyBuf * pKey )
{
if (0 != pKey)
{
CKey SplitKey(*pKey);
_pCurSrc = indSnap.QueryMergeCursor ( &SplitKey );
}
else
{
_pCurSrc = indSnap.QueryMergeCursor ();
}
}
//+---------------------------------------------------------------------------
//
// Member: CMergeSourceCursor::~CMergeSourceCursor
//
// Synopsis: Destructor
//
// History: 29-Aug-92 BartoszM Created
//
//----------------------------------------------------------------------------
CMergeSourceCursor::~CMergeSourceCursor ()
{
delete _pCurSrc;
}
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::Merge, public
//
// Synopsis: Merge index(es) into an empty pesistent index.
//
// Effects: Fills the persistent index with data from the input
// indexes.
// [fresh] is deleted.
//
// Arguments: [indSnap] -- array of indexes to be merged
// [pNewKeyList] -- Keylist to merge (master merge only)
// [mergeProgress] -- % merge complete
//
// Requires: The index is initially empty.
//
// Notes: Every compressor is transacted.
//
// History: 15-May-91 KyleP Use new PutOccurrence() method.
// 16-Apr-91 KyleP Created.
// 17-Feb-93 KyleP Merge keylist
// 25-Oct-95 DwightKr Add merge complete measurement
//
//----------------------------------------------------------------------------
void CPersIndex::Merge( CIndexSnapshot& indSnap,
const CPartition & partn,
CCiFrmPerfCounter & mergeProgress,
BOOL fGetRW )
{
// Calculate max of all input widMaxs
#if CIDBG == 1
unsigned cKey = 0;
#endif
WORKID widMax = indSnap.MaxWorkId();
ciDebugOut (( DEB_ITRACE, "Max work id %ld\n", widMax ));
SetMaxWorkId ( widMax );
CFreshTest* pFreshTest = indSnap.GetFresh();
CKeyBuf keyLast;
CMergeSourceCursor pCurSrc( indSnap );
if ( !pCurSrc.IsEmpty() )
{
//
// Read-ahead on the source indexes results in better merge
// performance, but slower queries. Temporarily switch modes.
//
CSetReadAhead readAhead( _storage );
CPersComp compr( _xPhysIndex.GetReference(), _widMax );
ciDebugOut (( DEB_ITRACE, "widMax passed to compressor: %ld\n",
_widMax ));
const CKeyBuf * pKey;
ULONG page = ULONG(-1);
BitOffset bitOff;
#if CIDBG == 1
keyLast.SetPid(pidContents); // arbitrary but not pidAll
#endif
#if CIDBG == 1
WCHAR FirstLetter = '@';
#endif
mergeProgress.Update( 0 );
ciDebugOut (( DEB_ITRACE,"Merging. Merge on letter: "));
for (pKey = pCurSrc->GetKey();
pKey != NULL; pKey = pCurSrc->GetNextKey())
{
#if CIDBG == 1
cKey++;
if ( *(pKey->GetStr()) != FirstLetter )
{
FirstLetter = *(pKey->GetStr());
if ( FirstLetter < L'~' )
ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "%c",
FirstLetter ));
else
ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "<%04x>",
FirstLetter ));
}
#endif
//
// Don't store empty keys
//
WORKID wid = pCurSrc->WorkId();
if ( wid == widInvalid )
continue;
//
// Add the key to the new index.
//
// This would later lead to a divide by 0
Win4Assert( 0 != pCurSrc->WorkIdCount() );
compr.PutKey(pKey, pCurSrc->WorkIdCount(), bitOff);
for ( ;
wid != widInvalid;
wid = pCurSrc->NextWorkId())
{
// fresh test
CFreshTest::IndexSource indexSrc =
pFreshTest->IsCorrectIndex (pCurSrc->IndexId(), wid);
//
// There should always be an entry for a workid in the fresh
// test whose data is contained in a wordlist/shadow-index.
//
Win4Assert( CFreshTest::Master != indexSrc );
if ( CFreshTest::Invalid != indexSrc )
{
compr.PutWorkId(wid, pCurSrc->MaxOccurrence(), pCurSrc->OccurrenceCount());
for (OCCURRENCE occ = pCurSrc->Occurrence();
occ != OCC_INVALID;
occ = pCurSrc->NextOccurrence())
{
compr.PutOccurrence(occ);
}
}
}
//
// If this key didn't have any wids then we can delete it from
// the new index. Otherwise, track it as a possible splitkey
// and update the index as necessary.
//
if ( bitOff.Page() != page )
{
page = bitOff.Page();
_xDir->Add ( bitOff, *pKey );
}
else
{
Win4Assert( page == _xDir->GetBitOffsetLastAdded().Page() );
}
keyLast = *pKey;
//
// There's no point in special abort code. We have to handle
// exceptions anyway.
//
if ( _fAbortMerge || partn.IsCleaningUp() )
{
ciDebugOut(( DEB_ITRACE, "Aborting Merge\n" ));
THROW( CException( STATUS_UNSUCCESSFUL ) );
}
mergeProgress.Update( _xPhysIndex->PagesInUse() * 100 / _xPhysIndex->PageSize() );
}
ciDebugOut(( DEB_ITRACE | DEB_PENDING, "%d keys in index\n", cKey ));
// add sentinel key
keyLast.FillMax();
keyLast.SetPid( pidContents );
compr.PutKey( &keyLast, 1, bitOff );
//
// If the MaxKey is the first key on a page, it must be added
// to the directory.
//
if ( bitOff.Page() != page )
{
page = bitOff.Page();
_xDir->Add ( bitOff, keyLast );
}
else
{
Win4Assert( page == _xDir->GetBitOffsetLastAdded().Page() );
}
mergeProgress.Update( 100 );
compr.FreeStream();
} // compr goes out of scope
else
{
ciDebugOut (( DEB_ITRACE, "No merge cursor created\n" ));
CPersComp compr( _xPhysIndex.GetReference(), _widMax );
keyLast.FillMax();
keyLast.SetPid(pidContents);
BitOffset bitOff;
compr.PutKey( &keyLast, 1, bitOff );
compr.FreeStream();
}
//
// Compressor MUST NOT be in scope here.
//
keyLast.FillMax();
_xDir->LokFlushDir( keyLast );
_xDir->LokBuildDir( keyLast );
// after compr is dead
_xPhysIndex->Flush();
_xPhysIndex->Reopen( FALSE );
} //Merge
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::QueryCursor, public
//
// Synopsis: Return a cursor for the whole persistent index.
//
// Returns: A new cursor.
//
// History: 24-Apr-91 KyleP Created.
//
//----------------------------------------------------------------------------
CKeyCursor * CPersIndex::QueryCursor()
{
CKey key;
key.FillMin();
return QueryKeyCursor( &key );
}
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::QueryKeyCursor, public
//
// Synopsis: Return a key cursor for the shadow index when restarting a
// master merge
//
// Returns: A new cursor.
//
// History: 12-Apr-94 DwightKr Created.
//
//----------------------------------------------------------------------------
CKeyCursor * CPersIndex::QueryKeyCursor(const CKey * pKey)
{
BitOffset posKey;
CKeyBuf keyInit;
_xDir->Seek( *pKey, &keyInit, posKey );
ciDebugOut(( DEB_ITRACE, "found key %.*ws at %lx:%lx\n",
keyInit.StrLen(), keyInit.GetStr(),
posKey.Page(), posKey.Offset() ));
XPtr<CPersDeComp> xCursor( new CPersDeComp( _xDir.GetReference(),
GetId(),
_xPhysIndex.GetReference(),
posKey,
keyInit,
pKey,
_widMax ) );
if ( 0 == xCursor->GetKey() )
xCursor.Free();
return xCursor.Acquire();
} //QueryKeyCursor
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::QueryCursor, public
//
// Synopsis: Return a cursor for the persistent index.
//
// Arguments: [pKey] -- Key to initially seek for.
// [isRange] -- TRUE for range query
// [cMaxNodes] -- Max number of nodes to create. Decremented
// on return.
//
// Returns: A new cursor.
//
// History: 24-Apr-91 KyleP Created.
//
//----------------------------------------------------------------------------
COccCursor * CPersIndex::QueryCursor( const CKey * pKey,
BOOL isRange,
ULONG & cMaxNodes )
{
Win4Assert( cMaxNodes > 0 );
if (isRange)
{
CKey keyEnd;
keyEnd.FillMax (*pKey);
return QueryRangeCursor (pKey, &keyEnd, cMaxNodes);
}
if (pKey->Pid() == pidAll)
return QueryRangeCursor ( pKey, pKey, cMaxNodes );
cMaxNodes--;
if ( 0 == cMaxNodes )
{
ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::QueryCursor.\n" ));
THROW( CException( STATUS_TOO_MANY_NODES ) );
}
BitOffset posKey;
CKeyBuf keyInit;
_xDir->Seek( *pKey, &keyInit, posKey );
ciDebugOut(( DEB_ITRACE, "found key %.*ws at %lx:%lx\n",
keyInit.StrLen(), keyInit.GetStr(),
posKey.Page(), posKey.Offset() ));
XPtr<CPersDeComp> xCursor( new CPersDeComp( _xDir.GetReference(),
GetId(),
_xPhysIndex.GetReference(),
posKey,
keyInit,
pKey,
_widMax ) );
if ( xCursor->GetKey() == 0 || !pKey->MatchPid( *xCursor->GetKey())
|| pKey->CompareStr(*xCursor->GetKey()) != 0 )
{
xCursor.Free();
}
return xCursor.Acquire();
} //QueryCursor
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::QueryRangeCursor, public
//
// Synopsis: Return a range cursor for the persistent index.
//
// Arguments: [pKey] -- Key at beginning of the range.
// [pKeyEnd] -- Key at the end of the range.
// [cMaxNodes] -- Max number of nodes to create. Decremented
// on return.
//
// Returns: A new cursor.
//
// History: 11-Dec-91 AmyA Created.
// 31-Jan-92 AmyA Moved code to CreateRange().
//
//----------------------------------------------------------------------------
COccCursor * CPersIndex::QueryRangeCursor( const CKey * pKey,
const CKey * pKeyEnd,
ULONG & cMaxNodes )
{
Win4Assert( cMaxNodes > 0 );
COccCurStack curStk;
CreateRange(curStk, pKey, pKeyEnd, cMaxNodes );
return curStk.QuerySynCursor( MaxWorkId() );
}
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::QuerySynCursor, public
//
// Synopsis: Return a synonym cursor for the persistent index.
//
// Arguments: [keyStk] -- Stack of keys to be searched for.
// [isRange] -- Whether or not this is a range search.
// [cMaxNodes] -- Max number of nodes to create. Decremented
// on return.
//
// Returns: A new cursor.
//
// History: 31-Jan-92 AmyA Created.
//
//----------------------------------------------------------------------------
COccCursor * CPersIndex::QuerySynCursor( CKeyArray & keyArr,
BOOL isRange,
ULONG & cMaxNodes )
{
COccCurStack curStk;
int keyCount = keyArr.Count();
for (int i = 0; i < keyCount; i++)
{
Win4Assert( cMaxNodes > 0 );
CKey& key = keyArr.Get(i);
if (isRange)
{
CKey keyEnd;
keyEnd.FillMax(key);
CreateRange(curStk, &key, &keyEnd, cMaxNodes );
}
else if ( key.Pid() == pidAll )
{
CreateRange ( curStk, &key, &key, cMaxNodes );
}
else
{
XPtr<COccCursor> xCursor( QueryCursor( &key, FALSE, cMaxNodes ) );
if ( !xCursor.IsNull() )
{
curStk.Push( xCursor.GetPointer() );
xCursor.Acquire();
}
}
}
return(curStk.QuerySynCursor( MaxWorkId()));
}
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::CreateRange, private
//
// Synopsis: Adds all cursors with keys between pKey and pKeyEnd to curStk.
//
// Arguments: [curStk] -- CKeyCurStack to add cursors to.
// [pKey] -- Key at beginning of range.
// [pKeyEnd] -- End of key range.
// [cMaxNodes] -- Max number of nodes to create. Decremented
// on return.
//
// History: 31-Jan-92 AmyA Created.
//
//----------------------------------------------------------------------------
void CPersIndex::CreateRange( COccCurStack & curStk,
const CKey * pKeyStart,
const CKey * pKeyEnd,
ULONG & cMaxNodes )
{
Win4Assert( cMaxNodes > 0 );
cMaxNodes--;
if ( 0 == cMaxNodes )
{
ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::CreateRange.\n" ));
THROW( CException( STATUS_TOO_MANY_NODES ) );
}
BitOffset posKey;
CKeyBuf keyInit;
_xDir->Seek( *pKeyStart, &keyInit, posKey );
ciDebugOut (( DEB_ITRACE, "CreateRange %.*ws-%.*ws. Dir seek %.*ws, pid %d\n",
pKeyStart->StrLen(), pKeyStart->GetStr(),
pKeyEnd->StrLen(), pKeyEnd->GetStr(),
keyInit.StrLen(), keyInit.GetStr(),
keyInit.Pid() ));
CPersDeComp* pCursor = new CPersDeComp( _xDir.GetReference(),
GetId(),
_xPhysIndex.GetReference(),
posKey,
keyInit,
pKeyStart,
_widMax);
XPtr<CPersDeComp> xCursor( pCursor );
const CKeyBuf * pKeyCurrent = pCursor->GetKey();
if ( 0 == pKeyCurrent )
return;
PROPID pid = pKeyStart->Pid();
curStk.Push(pCursor);
xCursor.Acquire();
ciDebugOut(( DEB_ITRACE, "First key %.*ws, pid %d\n",
pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pKeyCurrent->Pid() ));
do
{
if (pid != pidAll) // exact pid match
{
// skip wrong pids
while (pid != pKeyCurrent->Pid())
{
#if CIDBG == 1 //------------------------------------------
if (pKeyCurrent)
{
ciDebugOut(( DEB_ITRACE, " skip: %.*ws, pid %d, wid %d\n",
pKeyCurrent->StrLen(),
pKeyCurrent->GetStr(),
pKeyCurrent->Pid(),
pCursor->WorkId() ));
}
else
ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
#endif //--------------------------------------------------
pKeyCurrent = pCursor->GetNextKey();
if (pKeyCurrent == 0
|| pKeyEnd->CompareStr(*pKeyCurrent) < 0 )
break;
}
// either pid matches or we have overshot
// i.e. different pids and current string > end
}
if (pKeyCurrent == 0 || !pKeyEnd->MatchPid (*pKeyCurrent)
|| pKeyEnd->CompareStr (*pKeyCurrent) < 0 )
{
break; // <--- LOOP EXIT
}
cMaxNodes--;
if ( 0 == cMaxNodes )
{
ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::CreateRange.\n" ));
THROW( CException( STATUS_TOO_MANY_NODES ) );
}
// Clone the previous cursor...
pCursor = new CPersDeComp(*pCursor);
xCursor.Set( pCursor );
// Add it to avoid memory leaks if GetNextKey fails
curStk.Push(pCursor); // may be wrong pid
xCursor.Acquire();
// increment the added cursor
pKeyCurrent = pCursor->GetNextKey();
#if CIDBG == 1
if (pKeyCurrent)
{
ciDebugOut(( DEB_ITRACE, " %.*ws, wid %d\n",
pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pCursor->WorkId() ));
}
else
ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
#endif
} while ( pKeyCurrent );
// Since we have one more cursor in curStk than we wanted...
curStk.DeleteTop();
}
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::Remove, public
//
// Synopsis: Remove index from storage
//
// History: 02-May-91 BartoszM Created.
//
//----------------------------------------------------------------------------
void CPersIndex::Remove()
{
_xPhysIndex->Close();
_xDir->Close();
_obj->Close();
if ( !_storage.RemoveObject( ObjectId() ) )
{
DWORD dwError = GetLastError();
ciDebugOut(( DEB_ERROR, "Delete of index %08x failed: %d\n",
ObjectId(), dwError ));
}
}
#ifdef KEYLIST_ENABLED
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::AcquireRelevantWords, public
//
// Synopsis: Return relevant word key ids computed at the most recent
// master merge. The caller must delete the object returned.
//
// Returns: CRWStore *
//
// History: 25-Apr-94 v-dlee Created
//
//----------------------------------------------------------------------------
CRWStore * CPersIndex::AcquireRelevantWords()
{
CRWStore *p = _pRWStore;
ciDebugOut (( DEB_ITRACE,"CPersIndex::acquire _pRWStore: %lx\n",_pRWStore));
_pRWStore = 0;
return p;
} //AcquireRelevantWords
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::ComputeRelevantWords, public
//
// Synopsis: Compute and return relevant word key ids
//
// Arguments: [cRows] -- # of wids in pwid array
// [cRW] -- max # of rw keys per wid
// [pwid] -- an array of wids in increasing order whose
// rw key ids are to be returned
// [pKeyList] -- keylist to use in translation of keys to ids
//
// Returns: CRWStore *
//
// History: 25-Apr-94 v-dlee Created
//
//----------------------------------------------------------------------------
CRWStore * CPersIndex::ComputeRelevantWords(ULONG cRows,ULONG cRW,
WORKID *pwid,CKeyList *pKeyList)
{
ciDebugOut((DEB_ITRACE,"ComputeRelevantWords top\n"));
//
// Get the resources needed to do the computation
//
CRelevantWord RelWord(pwid,cRows,cRW);
CPersIndexCursor indCur(this);
CKeyListCursor keylCur(pKeyList);
//
// Walk through the index and find occurances of keys in the wids
//
const CKeyBuf * pKey, * pklKey;
for (pKey = indCur->GetKey(), pklKey = keylCur->GetKey();
pKey != 0; pKey = indCur->GetNextKey())
{
if (pKey->Pid() == pidContents &&
((CKeyBuf * const) pKey)->IsPossibleRW())
{
ULONG cWids = 0;
for (WORKID wid = indCur->WorkId(); wid != widInvalid;
wid = indCur->NextWorkId())
{
cWids++;
if (RelWord.isTrackedWid(wid))
RelWord.Add(wid,indCur->OccurrenceCount());
}
//
// Walk the keylist until we match it up with where the
// index cursor is.
//
while (pklKey->CompareStr(*pKey) != 0)
pklKey = keylCur->GetNextKey();
RelWord.DoneWithKey(pklKey->Pid(),MaxWorkId(),cWids);
}
}
return RelWord.AcquireStore();
} //ComputeRelevantWords
#endif // KEYLIST_ENABLED
//+---------------------------------------------------------------------------
//
// Member: CPersIndex::MakeBackupCopy
//
// Synopsis: Makes a copy of the index and directory using the storage
// provided.
//
// Arguments: [storage] - Storage
//
// History: 3-17-97 srikants Created
//
//----------------------------------------------------------------------------
void CPersIndex::MakeBackupCopy( PStorage & storage,
WORKID wid,
PSaveProgressTracker & tracker )
{
//
// Create an index in the destination storage.
//
CPersIndex * pDstIndex = new CPersIndex( storage,
wid,
GetId(),
_xPhysIndex->PageSize(),
IsMaster() ? eMaster : eShadow );
XPtr<CPersIndex> xDstIndex( pDstIndex );
//
// Make a backup copy of the stream.
//
_xPhysIndex->MakeBackupCopy( pDstIndex->_xPhysIndex.GetReference(),
tracker );
// Make a backup copy of the directory.
//
_xDir->MakeBackupCopy( storage, tracker );
}
#if CIDBG == 1
//+---------------------------------------------------------------------------
//
// Member: CDiskIndex::VerifyContents, public
//
// Synopsis: Walks through an index and thus verifies each key
//
// History: 28-Oct-94 DwightKr Created
//
//----------------------------------------------------------------------------
void CDiskIndex::VerifyContents()
{
//
// Turn this on when we think we are missing keys.
//
#if 0
CKeyCursor *pCursor = QueryCursor();
if ( pCursor )
{
TRY
{
ciDebugOut((DEB_ITRACE, "Verifying contents of new index\n"));
WCHAR FirstLetter = '@';
for ( const CKeyBuf * pKey = pCursor->GetKey();
pKey != NULL; pKey = pCursor->GetNextKey())
{
if ( *(pKey->GetStr()) != FirstLetter )
{
FirstLetter = *(pKey->GetStr());
if ( FirstLetter < L'~' )
ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "%c",
FirstLetter ));
else
ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "<%04x>",
FirstLetter ));
}
}
ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "\n" ));
}
CATCH (CException, e)
{
ciDebugOut(( DEB_ERROR, "Error 0x%x while verifying contents of new index\n", e.GetErrorCode() ));
}
END_CATCH
delete pCursor;
}
#endif // 0
}
#endif