windows-nt/Source/XPSP1/NT/inetsrv/query/cindex/fresh.cxx
2020-09-26 16:20:57 +08:00

533 lines
16 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 1998.
//
// File: FRESH.CXX
//
// Contents: Fresh list
//
// Classes: CFresh
//
// History: 16-May-91 BartoszM Created.
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <enumstr.hxx>
#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<CFreshTest> 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<CFreshTest> & 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<CFreshTest> 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<ICiEnumWorkids> & 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<CFreshTest> 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;
}