//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 1998. // // File: FRESH.CXX // // Contents: Fresh list // // Classes: CFresh // // History: 16-May-91 BartoszM Created. // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include "fresh.hxx" #include "fretest.hxx" #include "indxact.hxx" #include "merge.hxx" #include "wordlist.hxx" class CEnumWorkid; //+--------------------------------------------------------------------------- // // Member: CFresh::CFresh, public // // Synopsis: Constructor. // // History: 16-May-91 BartoszM Created. // //---------------------------------------------------------------------------- CFresh::CFresh ( PStorage& storage, CTransaction& xact, CPartList & partList ) : _storage( storage ), _persFresh( storage, partList ), _master( 0 ), _partList( partList ) { ULONG count = max( _persFresh.GetPersRecCount(), 100 ); XPtr xMaster( new CFreshTest ( count ) ); SFreshTable freshTable( xMaster.GetReference() ); _persFresh.LoadFreshTest( *freshTable ); _master = xMaster.Acquire(); } //+--------------------------------------------------------------------------- // // Member: CFresh::~CFresh, public // // Synopsis: Destructor. // // History: 16-May-91 BartoszM Created. // //---------------------------------------------------------------------------- CFresh::~CFresh () { delete _master; } //+--------------------------------------------------------------------------- // // Member: CFresh::LokInit, public // // Synopsis: Empties and re-initializes the fresh test // // History: 15-Nov-94 DwightKr Created. // //---------------------------------------------------------------------------- void CFresh::LokInit() { _persFresh.LokEmpty(); unsigned count = 100; CFreshTest* newFreshTest = new CFreshTest ( count ); LokCommitMaster( newFreshTest ); } //+--------------------------------------------------------------------------- // // Member: CFresh::LokGetFreshTest, public // // Synopsis: Creates CFreshTest object // // History: 16-May-91 BartoszM Created. // // Notes: ResMan LOCKED // FreshTest has to be released // //---------------------------------------------------------------------------- CFreshTest* CFresh::LokGetFreshTest() { ciDebugOut (( DEB_ITRACE, ">> get fresh test\n")); _master->Reference(); return _master; } //+--------------------------------------------------------------------------- // // Member: CFresh::LokReleaseFreshTest, public // // Synopsis: Dereferences CFreshTest object // // History: 16-May-91 BartoszM Created. // // Notes: ResMan LOCKED // //---------------------------------------------------------------------------- void CFresh::LokReleaseFreshTest( CFreshTest* test ) { ciDebugOut (( DEB_ITRACE, "<< release fresh test\n" )); if ( test != 0 && test->Dereference() == 0 && test != _master ) { delete test; } } //+--------------------------------------------------------------------------- // // Member: CFresh::LokCommitMaster, public // // Synopsis: Adds a new master fresh test // // History: 16-May-91 BartoszM Created. // // Notes: ResMan LOCKED // //---------------------------------------------------------------------------- void CFresh::LokCommitMaster ( CFreshTest* newMaster ) { ciDebugOut (( DEB_ITRACE, "Commit new master fresh test\n" )); Win4Assert ( newMaster != 0 ); Win4Assert ( _master != 0 ); CFreshTest* old = _master; _master = newMaster; ciDebugOut(( DEB_ITRACE, "New master (0x%x) has %u deletes\n", _master, _master->DeleteCount() )); if ( !old->InUse() ) { delete old; } } //+--------------------------------------------------------------------------- // // Member: CFresh::LokAddIndex, public // // Synopsis: Adds new mapping iid <-> documents after filtering // // Arguments: [xact] -- transaction // [iid] -- index id // [iidDeleted] -- index id for deleted objects // [docList] -- list of wids // // History: 16-May-91 BartoszM Created. // // Notes: ResMan LOCKED // //---------------------------------------------------------------------------- void CFresh::LokAddIndex ( CIndexTrans& xact, INDEXID iid, INDEXID iidDeleted, CDocList& docList, CWordList const & wordList ) { ciDebugOut (( DEB_ITRACE, "Fresh: Adding documents, iid %lx\n", iid )); CFreshTest* newMaster = new CFreshTest ( *_master ); xact.LogFresh ( newMaster ); unsigned cDocuments = docList.Count(); for ( unsigned i = 0; i < cDocuments; i++ ) { STATUS status = docList.Status(i); if ( status == SUCCESS ) { WORKID wid = docList.Wid(i); ciDebugOut (( DEB_FRESH, "Fresh wid %ld, iid %lx\n", wid, iid )); #if CIDBG==1 Win4Assert( widInvalid != wid && wordList.IsWorkIdPresent( wid ) ); #endif // CIDBG==1 newMaster->AddReplace ( wid, iid ); } else if ( status == DELETED || status == WL_NULL ) { WORKID wid = docList.Wid(i); ciDebugOut (( DEB_FRESH, "Fresh wid %ld deleted \n", wid )); newMaster->AddReplaceDelete ( wid, iidDeleted ); } else { ciDebugOut (( DEB_FRESH, "Fresh wid %ld, not changed. Status 0x%X\n", docList.Wid(i), status )); #if CIDBG==1 Win4Assert( !wordList.IsWorkIdPresent( docList.Wid(i)) ); #endif // CIDBG==1 } } newMaster->ModificationsComplete(); } //+--------------------------------------------------------------------------- // // Member: CFresh::LokDeleteDocuments, public // // Synopsis: Mark documents as deleted // // Arguments: [xact] -- transaction // [docList] -- list of wids // [iidDeleted] -- index id for deleted objects // // History: 16-May-91 BartoszM Created. // 12-Jun-97 KyleP Track unlogged deletions // // Notes: ResMan LOCKED // //---------------------------------------------------------------------------- void CFresh::LokDeleteDocuments( CIndexTrans& xact, CDocList& docList, INDEXID iidDeleted ) { ciDebugOut (( DEB_ITRACE, "Fresh: Deleting documents\n" )); CFreshTest* newMaster = new CFreshTest ( *_master ); xact.LogFresh ( newMaster ); unsigned cDocuments = docList.Count(); for ( unsigned i = 0; i < cDocuments; i++ ) { if ( docList.Status(i) == DELETED) { WORKID wid = docList.Wid(i); ciDebugOut (( DEB_FRESH, "Fresh wid %ld deleted \n", wid )); newMaster->AddReplaceDelete ( wid, iidDeleted ); } } newMaster->ModificationsComplete(); } //+--------------------------------------------------------------------------- // // Member: CFresh::LokUpdate, public // // Synopsis: Replaces old entries with the more recent entries after merge // // Arguments: [merge] -- Merge object // [xact] -- Merge transaction // [newFreshLog] -- New fresh log // [newIid] -- New index id // [cInd] -- Count of index id's to be replaced // [aIidOld] -- Array of index id's to be replaced // [xFreshTestAtMerge] -- If a new fresh test that was used at // merge time is created, store in here // // History: 16-May-91 BartoszM Created. // 01-Dec-93 DwightKr Write changes to pers. fresh log // 04-Oct-94 SrikantS Support for creating a new fresh // log after merge. // // Notes: ResMan LOCKED // //---------------------------------------------------------------------------- WORKID CFresh::LokUpdate ( CMerge& merge, CMergeTrans& xact, CPersFresh & newFreshLog, INDEXID newIid, int cInd, INDEXID aIidOld[], XPtr & xFreshTestAtMerge ) { ciDebugOut (( DEB_ITRACE, "Fresh list: updating %d entries\n", cInd )); CIdxSubstitution subst (FALSE, newIid, cInd, aIidOld); CFreshTest * newMaster = new CFreshTest( *_master, subst ); xact.LogFresh( newMaster ); WORKID widNewFreshLog; // // The new memory fresh test is created by applying the transformtion on // the master fresh test. We should apply the transformation for // persistent log on the freshtest used by the merge. If a fresh test is // created then we pass ownership to xFreshTestAtMerge, so that // LokDeleteWidsInPersistentIndex can use the newly created fresh test. // // optimization to avoid creating a new fresh test if ( _master == merge.GetFresh() ) { widNewFreshLog = LokBuildNewFreshLog( newMaster, newFreshLog, subst); newMaster->DecrementDeleteCount( _master->DeleteCount() ); } else { xFreshTestAtMerge.Set( new CFreshTest( *(merge.GetFresh()), subst ) ); widNewFreshLog = LokBuildNewFreshLog( xFreshTestAtMerge.GetPointer(), newFreshLog, subst ); newMaster->DecrementDeleteCount( xFreshTestAtMerge->DeleteCount() ); } newMaster->ModificationsComplete(); xact.LogNewFreshLog( newMaster, widNewFreshLog ); return widNewFreshLog; } //+--------------------------------------------------------------------------- // // Member: CFresh::LokRemoveIndexes, public // // Synopsis: Removes indexes from table after master merge // // Arguments: [xact] -- merge transaction // [cInd] -- count of inexes to be removed // [aIidOld] -- array of index ids of obsolete indexes // [iidOldDeleted] -- old index id for deleted objects // // History: 16-May-91 BartoszM Created. // // Notes: ResMan LOCKED // //---------------------------------------------------------------------------- WORKID CFresh::LokRemoveIndexes( CMergeTrans& xact, CPersFresh & newFreshLog, unsigned cInd, INDEXID aIidOld[], INDEXID iidOldDeleted ) { ciDebugOut (( DEB_ITRACE, "FreshList: Removing indexes\n" )); CIdxSubstitution subst (TRUE, iidOldDeleted, cInd, aIidOld); XPtr xNewMaster( new CFreshTest( *_master, subst ) ); WORKID widNewFreshLog = LokBuildNewFreshLog( xNewMaster.GetPointer(), newFreshLog, subst ); // LogNewFreshLog can't fail, so the acquire is safe to do // before the call. xNewMaster->ModificationsComplete(); xact.LogNewFreshLog( xNewMaster.Acquire(), widNewFreshLog ); return(widNewFreshLog); } //+--------------------------------------------------------------------------- // // Function: LokBuildNewFreshLog // // Synopsis: Builds a new persistent fresh log by combining the existing // fresh log and the new fresh test. // // Arguments: [newFreTest] -- Input - the new fresh test. // [newFreshLog] -- Input/Output - the new fresh log object. // [subst] -- Index substitution object // // Returns: ObjectId of the new persistent fresh log created. // // History: 03-Oct-94 srikants Created // 11-Jun-97 KyleP Track unlogged deletions // //---------------------------------------------------------------------------- WORKID CFresh::LokBuildNewFreshLog( CFreshTest * newFreTest, CPersFresh & newFreshLog, CIdxSubstitution& subst ) { SFreshTable freshTable( *newFreTest ); CFreshTableIter iter( *freshTable ); // // Create a new persistent fresh log. // WORKID widNewFreshLog = _storage.GetNewObjectIdForFreshLog(); _storage.InitRcovObj( widNewFreshLog, FALSE ); PRcovStorageObj *pPersFreshLog = _storage.QueryFreshLog( widNewFreshLog ); SRcovStorageObj PersFreshLog( pPersFreshLog ); // // Inside kernel, we are guaranteed that a new object has no data in // it. In user space, we may be using an object that was not deleted // before due to a failure. // PersFreshLog->InitHeader(_storage.GetStorageVersion()); newFreshLog.LokCompactLog( PersFreshLog, iter, subst); return(widNewFreshLog); } //+--------------------------------------------------------------------------- // // Member: CFresh::LokMakeFreshLogBackup // // Synopsis: Makes a backup of the current persistent freshlog to the // storage provided. // // Arguments: [storage] - Destination storage. // [tracker] - Progress tracker and abort indication. // // History: 3-18-97 srikants Created // //---------------------------------------------------------------------------- void CFresh::LokMakeFreshLogBackup( PStorage & storage, PSaveProgressTracker & tracker, XInterface & xEnumWorkids ) { // // Create a fresh log with the same name using the storage object // provided. // WORKID widFreshLog = _storage.GetSpecialItObjectId( itFreshLog ); ULONG cRec = 0; // // Scope for physical copy of the object. // { // // Open the source fresh log // PRcovStorageObj *pSrcFreshLog = _storage.QueryFreshLog( widFreshLog ); SRcovStorageObj xSrcFreshLog( pSrcFreshLog ); // // Create the destination fresh log // PRcovStorageObj *pDstFreshLog = storage.QueryFreshLog( widFreshLog ); SRcovStorageObj xDstFreshLog( pDstFreshLog ); // // Copy the contents of the source to the destination. // CCopyRcovObject copyData( *pDstFreshLog, *pSrcFreshLog ); NTSTATUS status = copyData.DoIt(); if ( STATUS_SUCCESS != status ) THROW( CException( status ) ); CRcovStorageHdr & hdr = pSrcFreshLog->GetHeader(); cRec = hdr.GetCount( hdr.GetPrimary() ); } // // Get the list of WORKIDs in the persistent freshlog. // CFreshTest * pFreshTest = new CFreshTest ( max(100,cRec) ); XPtr xFreTest( pFreshTest ); SFreshTable freshTable( *pFreshTest ); // // The source and destination persistent freshlogs are identical. // _persFresh.LoadFreshTest( *freshTable ); // // Copy the workids from freshhash entries to the workid enumerator. // CEnumWorkid * pEnumWorkids = new CEnumWorkid( freshTable->Count() ); xEnumWorkids.Set( pEnumWorkids ); for ( CFreshTableIter iter( *freshTable ); !iter.AtEnd(); iter.Advance() ) { pEnumWorkids->Append( iter->WorkId() ); } Win4Assert( cRec == freshTable->Count() ); ciDebugOut(( DEB_ITRACE, "%d Workids Changed \n", freshTable->Count() )); } //+--------------------------------------------------------------------------- // // Member: CFresh::LokEmpty, public // // Synopsis: Empties/deletes the fresh hash and the fresh log. // // History: 16-Aug-94 DwightKr Created // //---------------------------------------------------------------------------- void CFresh::LokEmpty() { delete _master; // Delete the fresh test _master = 0; }