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.
 
 
 
 
 
 

873 lines
25 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: IDXTAB.CXX
//
// Contents: Index Manager
//
// Classes: CIndexTable
//
// History: 22-Mar-91 BartoszM Created.
// 12-Feb-92 AmyA Hacked all methods for FAT.
// 01-Jul-93 BartoszM Rewrote to use memory mapped file
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <cistore.hxx>
#include <idxtab.hxx>
#include <eventlog.hxx>
#include <imprsnat.hxx>
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
CWriteIndexFile::CWriteIndexFile ( PRcovStorageObj & rcovObj ) :
_rcovObj(rcovObj),
_xact(rcovObj),
_iter(_xact, sizeof(CIndexRecord)),
_xactPtr(0)
{
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
void CWriteIndexFile::BackUp()
{
ciAssert(_xactPtr > 0);
_xactPtr--;
_iter.Seek( _xactPtr );
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
BOOL CWriteIndexFile::ReadRecord ( CIndexRecord * pRecord )
{
ULONG ulRecCnt = _rcovObj.GetHeader().GetCount(_rcovObj.GetHeader().GetBackup());
if (_xactPtr >= ulRecCnt)
return(FALSE);
_iter.GetRec( pRecord );
_xactPtr++;
return(TRUE);
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
void CWriteIndexFile::WriteRecord ( CIndexRecord* pRecord )
{
_iter.SetRec( pRecord );
_xactPtr++;
ULONG ulRecCnt = _rcovObj.GetHeader().GetCount(_rcovObj.GetHeader().GetBackup());
if (ulRecCnt < _xactPtr)
_rcovObj.GetHeader().SetCount(_rcovObj.GetHeader().GetBackup(), _xactPtr);
}
//+---------------------------------------------------------------------------
//
// Member: CWriteIndexFile::IncrMMergeSeqNum
//
// Synopsis: Increments the master merge sequence number in the header.
//
// History: 3-21-97 srikants Created
//
//----------------------------------------------------------------------------
void CWriteIndexFile::IncrMMergeSeqNum()
{
CRcovStorageHdr & storageHdr = _rcovObj.GetHeader();
CRcovUserHdr usrHdr;
CIndexTableUsrHdr * pIdxUsrHdr = (CIndexTableUsrHdr *) &usrHdr;
storageHdr.GetUserHdr( storageHdr.GetPrimary(), usrHdr );
ciDebugOut(( DEB_ITRACE, "Current MMerge Seq Num = %d \n",
pIdxUsrHdr->GetMMergeSeqNum() ));
pIdxUsrHdr->IncrMMergeSeqNum();
ciDebugOut(( DEB_ITRACE, "New MMerge Seq Num = %d \n",
pIdxUsrHdr->GetMMergeSeqNum() ));
storageHdr.SetUserHdr( storageHdr.GetBackup(), usrHdr );
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
CReadIndexFile::CReadIndexFile ( PRcovStorageObj & rcovObj ) :
_rcovObj(rcovObj),
_xact(rcovObj),
_iter(_xact, sizeof(CIndexRecord)),
_xactPtr(0)
{
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
void CReadIndexFile::BackUp()
{
ciAssert(_xactPtr > 0);
_xactPtr--;
_iter.Seek( _xactPtr );
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
BOOL CReadIndexFile::ReadRecord ( CIndexRecord * pRecord )
{
ULONG ulRecCnt = _rcovObj.GetHeader().GetCount(_rcovObj.GetHeader().GetPrimary());
if (_xactPtr >= ulRecCnt)
return(FALSE);
_iter.GetRec( pRecord );
_xactPtr++;
return(TRUE);
}
//+---------------------------------------------------------------------------
//
// Member: CAddReplaceIndexRecord::CAddReplaceIndexRecord, public
//
// Synopsis: Rewinds the file pointer indFile, then reads in IndexRecords until
// either a record with INDEXID iid is found or EOF is reached.
//
// Notes: Whether or not a record with INDEXID iid is found can be
// determined by calling Found().
//
// History: 16-Mar-92 AmyA Created.
//
//----------------------------------------------------------------------------
CAddReplaceIndexRecord::CAddReplaceIndexRecord ( CWriteIndexFile & indFile,
INDEXID iid )
: _indFile( indFile )
{
_indFile.Rewind();
do
{
_found = _indFile.ReadRecord ( this );
} while (_found && Iid() != iid);
}
//+---------------------------------------------------------------------------
//
// Member: CAddReplaceIndexRecord::Write()
//
// Synopsis: Writes the information from CIndexRecord out to the file--
// either replacing the record that was found in the constructor
// (if there was one found) or appending to the end of the file
// indicated by _indFile.
//
// History: 28-Feb-95 DwightKr Created.
//
//----------------------------------------------------------------------------
inline void CAddReplaceIndexRecord::WriteRecord()
{
if ( Found() )
{
_indFile.BackUp();
}
_indFile.WriteRecord( this );
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::CIndexTable, public
//
// Synopsis: Constructor.
//
// History: 28-Mar-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CIndexTable::CIndexTable ( CiStorage& storage, CTransaction& xact )
: _storage(storage), _pRcovObj(0)
{
_pRcovObj = _storage.QueryIdxTableObject();
Win4Assert( 0 != _pRcovObj );
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::~CIndexTable, public
//
// Synopsis: Destructor.
//
// History: 28-May-92 BartoszM Created.
//
//----------------------------------------------------------------------------
CIndexTable::~CIndexTable ()
{
delete _pRcovObj;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTableIter::CIndexTableIter
//
// Synopsis: Constructor.
//
// History: 28-May-92 BartoszM Created.
//
//----------------------------------------------------------------------------
CIndexTabIter::CIndexTabIter ( CIndexTable& idxTable )
: _idxTable(idxTable),
_indFile( idxTable.GetIndexTableObj() )
{
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTabIter::Begin, public
//
// Synopsis: Position cursor at the beginning of table
//
// History: 28-Mar-91 BartoszM Created.
//
//----------------------------------------------------------------------------
BOOL CIndexTabIter::Begin ()
{
CNextIndexRecord rec(_indFile);
if (!rec.Found())
return FALSE;
_indFile.Rewind();
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTabIter::NextRecord, public
//
// Synopsis: Called during startup. Reads next record
//
// Arguments: [indexRecord] -- record to be filled
//
// History: 28-Mar-91 BartoszM Created.
//
//----------------------------------------------------------------------------
BOOL CIndexTabIter::NextRecord ( CIndexRecord& indexRecord )
{
CNextIndexRecord rec(_indFile);
if (!rec.Found())
return(FALSE);
if ( rec.VersionStamp() < _idxTable._storage.GetStorageVersion() )
{
Win4Assert ( !"Corrupt index table" );
PStorage & storage = GetStorage();
storage.ReportCorruptComponent ( L"IndexTable1" );
THROW( CException ( STATUS_INTERNAL_DB_CORRUPTION ));
}
else if ( rec.VersionStamp() > _idxTable._storage.GetStorageVersion() )
{
ciAssert ( !"Unknown index format: upgrade index software" );
PStorage & storage = GetStorage();
storage.ReportCorruptComponent ( L"IndexTable2" );
THROW( CException ( STATUS_INTERNAL_DB_CORRUPTION ));
}
indexRecord._objectId = rec.ObjectId();
indexRecord._iid = rec.Iid();
indexRecord._type = rec.Type();
indexRecord._maxWorkId = rec.MaxWorkId();
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTabIter::~CIndexTabIter, public
//
// Synopsis: Iteration finished
//
// History: 28-Mar-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CIndexTabIter::~CIndexTabIter()
{
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::SwapIndexes, public
//
// Synopsis: Replaces old indexes with a new one after merge
//
// Arguments: [pIndexNew] -- new index
// [cIndexOld] -- count of old indexes to be removed
// [aIidOld] -- array of old index id's
//
// Notes: ResMan LOCKED
//
// History: 02-May-91 BartoszM Created.
//
//----------------------------------------------------------------------------
void CIndexTable::SwapIndexes ( CShadowMergeSwapInfo & info )
{
CIndexRecord & record = info._recNewIndex;
ciDebugOut (( DEB_ITRACE, "IndexManager: Adding index %lx, maxWid %ld\n",
record.Iid(), record.MaxWorkId() ));
CWriteIndexFile indFile( GetIndexTableObj() );
// Mark old indexes deleted
for ( unsigned i = 0; i < info._cIndexOld; i++ )
{
CIndexId idFull = info._aIidOld[i];
if ( idFull.IsPersistent())
{
CAddReplaceIndexRecord rec(indFile, info._aIidOld[i]);
if (!rec.Found())
{
//
// We have a persistent index which was not found in the
// index list. This must be an index corruption.
//
ciDebugOut(( DEB_ERROR, "Can't find index 0x%lx\n",
info._aIidOld[i] ));
Win4Assert( !"Corrupt index table" );
_storage.ReportCorruptComponent( L"IndexTable3" );
THROW( CException ( CI_CORRUPT_DATABASE ));
}
rec.SetType(itZombie); // And one more....
rec.WriteRecord();
}
}
//
// Add record for the new index.
//
if ( widInvalid != record.ObjectId() )
AddRecord ( indFile,
record.Iid(),
record.Type(),
record.MaxWorkId(),
record.ObjectId() );
//
// Replace the old fresh test entry with the new fresh test entry.
//
DeleteObject( indFile, partidDefault, itFreshLog, info._widOldFreshLog );
AddRecord( indFile, CIndexId( 0, partidDefault ), itFreshLog,
0, info._widNewFreshLog );
indFile.Commit();
}
//+---------------------------------------------------------------------------
//
// Function: SwapIndexes
//
// Synopsis: This method marks the old indexes as "zombie" in the index
// table, deletes the MMLog, MMFreshLog and NewMasterIndex
// entries. It then adds an entry making the NewMaster the
// current master.
//
// This is done as a single TRANSACTION - either the entire
// step succeeds or the previous state is retained.
//
// Effects: All the indexes that participated in the master merge will
// be deleted from the index list and the new master will be
// made the only master index.
//
// Arguments: [partid] -- Partition Id where the master merge just
// completed.
// [cIndexOld] -- Count of the indexes in aIidOld.
// [aIidOld] -- Array of index ids to be marked zombie.
// [recNewMaster] -- CIndexRecord for the new master index.
// [widMMLog] -- WorkId of the MMLog object.
//
// History: 4-04-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CIndexTable::SwapIndexes ( CMasterMergeSwapInfo & info )
{
CIndexRecord & recNewMaster = info._recNewIndex;
CIndexRecord & recNewKeyList = info._recNewKeyList;
ciDebugOut (( DEB_ITRACE, "Master Merge Completed\n"));
CWriteIndexFile indFile( GetIndexTableObj() );
//
// Mark old indexes as "Zombie".
//
for ( unsigned i = 0; i < info._cIndexOld; i++ )
{
CIndexId idFull = info._aIidOld[i];
Win4Assert( idFull.IsPersistent() );
Win4Assert( idFull.PartId() == info._partid );
CAddReplaceIndexRecord rec(indFile, info._aIidOld[i]);
if (!rec.Found())
{
//
// We have a persistent index which was not found in the
// index list. This must be an index corruption.
//
ciDebugOut(( DEB_ERROR, "Can't find index 0x%lx\n",
info._aIidOld[i] ));
Win4Assert( !"Corrupt index table" );
_storage.ReportCorruptComponent( L"IndexTable4" );
THROW( CException ( CI_CORRUPT_DATABASE ));
}
rec.SetType(itZombie); // And one more....
rec.WriteRecord();
}
//
// Delete the MMLog entry.
//
DeleteObject( indFile, info._partid, itMMLog, info._widMMLog );
//
// Delete the itMMKeyList entry.
//
DeleteObject( indFile, partidKeyList, itMMKeyList,
recNewKeyList.ObjectId() );
//
// Delete the old itKeyList entry and add an entry for the new
// key list.
//
{
//
// DeleteRecord assumes that the record is found. When we create
// the key list for the first time, it may not be present.
//
CAddReplaceIndexRecord rec( indFile, info._iidOldKeyList );
if ( rec.Found() )
{
rec.SetIid( CIndexId(iidInvalid,partidInvalid) );
rec.WriteRecord();
}
}
AddRecord( indFile, recNewKeyList.Iid(),
recNewKeyList.Type(),
recNewKeyList.MaxWorkId(),
recNewKeyList.ObjectId()
);
//
// Delete the entry for the new master index and make it the
// current master index.
//
DeleteRecord( indFile, recNewMaster.Iid() );
AddRecord (
indFile,
recNewMaster.Iid(),
itMaster, // Note the change from itNewMaster to itMaster
recNewMaster.MaxWorkId(),
recNewMaster.ObjectId());
//
// Replace the old fresh test entry with the new fresh test entry.
//
DeleteObject( indFile, partidDefault, itFreshLog, info._widOldFreshLog );
AddRecord( indFile, CIndexId( 0, partidDefault ), itFreshLog, 0,
info._widNewFreshLog );
//
// Increment the master merge sequence number.
//
indFile.IncrMMergeSeqNum();
indFile.Commit();
}
PIndexTabIter* CIndexTable::QueryIterator()
{
return new CIndexTabIter ( *this );
}
PStorage& CIndexTable::GetStorage()
{
return(_storage);
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::RemoveIndex, public
//
// Synopsis: Removes index from table
//
// Arguments: [iid] -- index id
//
// Notes: ResMan LOCKED
//
// History: 02-May-91 BartoszM Created.
//
//----------------------------------------------------------------------------
#pragma optimize( "", off )
void CIndexTable::RemoveIndex ( INDEXID iid )
{
CImpersonateSystem impersonate;
CWriteIndexFile indFile( GetIndexTableObj() );
DeleteRecord( indFile, iid );
indFile.Commit();
}
#pragma optimize( "", on )
//+---------------------------------------------------------------------------
//
// Function: AddObject
//
// Synopsis: Appends a record for the specified object to the
// index table.
//
// Arguments: [partid] -- Id of the partition to which the object
// belongs.
// [it] -- Index type of the object.
// [wid] -- WorkId of the object.
//
// History: 2-18-94 srikants Created
//
//----------------------------------------------------------------------------
void CIndexTable::AddObject( PARTITIONID partid, IndexType it, WORKID wid )
{
CWriteIndexFile indFile( GetIndexTableObj() );
AddRecord ( indFile, CIndexId ( 0, partid ), it, 0, wid );
indFile.Commit();
}
//+---------------------------------------------------------------------------
//
// Function: AddMMergeObjects
//
// Synopsis: This method adds records for the NewMaster Index,
// and MasterMerge Log to the index table.
//
// Arguments: [partid] -- Partition id of the partition in which
// master merge is being done.
// [recNewMaster] -- The index record for the new master index.
// [widMMLog] -- WorkId of the MasterMerge Log.
// [deletedIndex] -- Index id for the current index
//
// History: 4-04-94 srikants Created
//
// Notes: The recNewMaster must be fully initialized with the correct
// indexType, WorkId and MaxWorkId.
//
//----------------------------------------------------------------------------
void CIndexTable::AddMMergeObjects( PARTITIONID partid,
CIndexRecord & recNewMaster,
WORKID widMMLog,
WORKID widMMKeyList,
INDEXID iidDelOld,
INDEXID iidDelNew )
{
CWriteIndexFile indFile( GetIndexTableObj() );
Win4Assert( recNewMaster.Type() == itNewMaster );
Win4Assert( iidDeleted1 == iidDelOld && iidDeleted2 == iidDelNew ||
iidDeleted2 == iidDelOld && iidDeleted1 == iidDelNew );
#if CIDBG == 1
CIndexId iid( recNewMaster.Iid() );
Win4Assert( iid.PartId() == partid );
#endif // CIDBG == 1
AddRecord( indFile, recNewMaster.Iid(), itNewMaster,
recNewMaster.MaxWorkId(), recNewMaster.ObjectId() );
AddRecord( indFile, CIndexId( 0, partid ), itMMLog, 0,widMMLog );
AddRecord( indFile, CIndexId( 0, partidKeyList ), itMMKeyList, 0, widMMKeyList );
DeleteRecord( indFile, iidDelOld );
AddRecord( indFile, iidDelNew, itDeleted, 0, 0 );
indFile.Commit();
}
inline BOOL IsMatched( const CIndexRecord & rec,
INDEXID iid, IndexType it, WORKID wid )
{
return rec.Type() == (ULONG) it && rec.Iid() == iid && rec.ObjectId() == wid ;
}
//+---------------------------------------------------------------------------
//
// Function: DeleteObject
//
// Synopsis: Deletes the record for the specified object by marking
// it as "iidInvalid". The record will be deleted only
// if there is an exact match with the partid, it and wid.
//
// Arguments: [partid] -- Partition Id.
// [it] -- Index type of the object.
// [wid] -- Work Id to match on.
//
// History: 2-18-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CIndexTable::DeleteObject( PARTITIONID partid, IndexType it, WORKID wid )
{
CWriteIndexFile indFile( GetIndexTableObj() );
DeleteObject( indFile, partid, it, wid );
indFile.Commit();
}
void CIndexTable::DeleteObject( CWriteIndexFile & indFile,
PARTITIONID partid, IndexType it, WORKID wid )
{
CIndexRecord rec;
BOOL found;
indFile.Rewind();
do
{
found = indFile.ReadRecord ( &rec );
}
while ( found && !IsMatched( rec, CIndexId(0, partid), it, wid) );
if ( found ) {
indFile.BackUp();
rec._iid = (INDEXID) CIndexId(iidInvalid, partidInvalid);
rec._objectId = widInvalid;
indFile.WriteRecord( &rec );
}
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::AddRecord, private
//
// Synopsis: Adds new record to table
//
// Arguments: [iid] -- index id
// [type] -- type of record
// [maxWorkId] -- max work id in the index
// [objectId] -- id of the index object
//
// Notes: ResMan LOCKED
//
// History: 02-May-91 BartoszM Created.
//
//----------------------------------------------------------------------------
void CIndexTable::AddRecord( CWriteIndexFile & indFile,
INDEXID iid,
ULONG type,
WORKID maxWorkId,
WORKID objectId )
{
ciDebugOut (( DEB_ITRACE, "Indexes: AddRecord %lx, %ld %s\n",
iid, maxWorkId, (type == itMaster)? "master": "not-master" ));
CAddReplaceIndexRecord rec(indFile, CIndexId(iidInvalid,partidInvalid) );
rec.SetIid(iid);
rec.SetType(type);
rec.SetWid(maxWorkId);
rec.SetObjectId ( objectId );
rec.WriteRecord();
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::AddIndex, public
//
// Synopsis: Adds new index to table
//
// Arguments: [iid] -- index id
// [type] -- type of record
// [maxWorkId] -- max work id in the index
// [objectId] -- id of the index object
//
// Notes: ResMan LOCKED
//
// History: 14-Jul-94 DwightKr Created.
//
//----------------------------------------------------------------------------
void CIndexTable::AddIndex( INDEXID iid,
IndexType type,
WORKID maxWorkId,
WORKID objectId )
{
CWriteIndexFile indFile( GetIndexTableObj() );
AddRecord( indFile, iid, type, maxWorkId, objectId );
indFile.Commit();
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::LokEmpty, public
//
// Synopsis: Deleted everything from the index table
//
// Notes: ResMan LOCKED
//
// History: 16-Aug-94 DwightKr Created
//
//----------------------------------------------------------------------------
void CIndexTable::LokEmpty()
{
PRcovStorageObj & rcovObj = GetIndexTableObj();
CRcovStrmWriteTrans xact( rcovObj );
rcovObj.GetHeader().SetCount( rcovObj.GetHeader().GetBackup(), 0 );
xact.Empty();
xact.Seek(0);
xact.Commit();
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::LokMakeBackupCopy
//
// Synopsis: Makes a backup copy of the index table.
//
// Arguments: [storage] - Storage to use for creation of the
// destination index table.
// [fFullSave] - Set to TRUE if a full save is being performed.
// [progressTracker] - Progress tracker.
//
// History: 3-18-97 srikants Created
//
//----------------------------------------------------------------------------
void CIndexTable::LokMakeBackupCopy( PStorage & storage,
BOOL fFullSave,
PSaveProgressTracker & progressTracker )
{
//
// Create a new index table object using the storage provided.
//
PRcovStorageObj * pDstObj = storage.QueryIdxTableObject();
XPtr<PRcovStorageObj> xDstObj( pDstObj );
PRcovStorageObj & srcObj = GetIndexTableObj();
//
// Copy the contents of source to destination.
//
CCopyRcovObject copier( *pDstObj, srcObj );
NTSTATUS status = copier.DoIt();
if ( STATUS_SUCCESS != status )
{
THROW(CException(status) );
}
//
// Set the Full/Partial Save bit appropriately.
//
CRcovStrmAppendTrans xact( *pDstObj );
CRcovStorageHdr & storageHdr = pDstObj->GetHeader();
CRcovUserHdr usrHdr;
CIndexTableUsrHdr * pIdxUsrHdr = (CIndexTableUsrHdr *) &usrHdr;
storageHdr.GetUserHdr( storageHdr.GetBackup(), usrHdr );
if ( fFullSave )
pIdxUsrHdr->SetFullSave();
else pIdxUsrHdr->ClearFullSave();
storageHdr.SetUserHdr( storageHdr.GetBackup(), usrHdr );
xact.Commit();
}
//+---------------------------------------------------------------------------
//
// Member: CIndexTable::GetUserHdrInfo
//
// Synopsis: Retrieves the information in the user header.
//
// Arguments: [mMergeSeqNum] - Master Merge sequence number.
// [fFullSave] - Set to TRUE if a full save was performed.
//
// History: 3-21-97 srikants Created
//
//----------------------------------------------------------------------------
void CIndexTable::GetUserHdrInfo( unsigned & mMergeSeqNum, BOOL & fFullSave )
{
PRcovStorageObj & obj = GetIndexTableObj();
CRcovUserHdr usrHdr;
CIndexTableUsrHdr * pIdxUsrHdr = (CIndexTableUsrHdr *) &usrHdr;
CRcovStorageHdr & storageHdr = obj.GetHeader();
storageHdr.GetUserHdr( storageHdr.GetPrimary(), usrHdr );
ciDebugOut(( DEB_ERROR, "Current MMerge Seq Num = %d \n",
pIdxUsrHdr->GetMMergeSeqNum() ));
mMergeSeqNum = pIdxUsrHdr->GetMMergeSeqNum();
fFullSave = pIdxUsrHdr->IsFullSave();
}