//+--------------------------------------------------------------------------- // // 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 #pragma hdrstop #include #include #include #include //+--------------------------------------------------------------------------- //---------------------------------------------------------------------------- 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 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(); }