533 lines
16 KiB
C++
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;
|
|
}
|
|
|