491 lines
14 KiB
C++
491 lines
14 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1991 - 1998
|
||
|
//
|
||
|
// File: dellog.cxx
|
||
|
//
|
||
|
// Contents: Deletion log for usns
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <mmstrm.hxx>
|
||
|
|
||
|
#include "cicat.hxx"
|
||
|
#include "dellog.hxx"
|
||
|
|
||
|
const LONGLONG eSigDelLog = 0x64656c746e6c6f67i64; // Signature
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CFakeVolIdMap::CFakeVolIdMap
|
||
|
//
|
||
|
// Synopsis: Constructor
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CFakeVolIdMap::CFakeVolIdMap()
|
||
|
{
|
||
|
for ( ULONG i=0; i<COUNT_SPECIAL_CHARS; i++)
|
||
|
_aVolIdSpecial[i] = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CFakeVolIdMap::VolIdToFakeVolId
|
||
|
//
|
||
|
// Synopsis: Converts a volume id to a fake volume id in the range
|
||
|
// 0..RTL_MAX_DRIVE_LETTERS-1
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
// Notes: Drive letters in the range 'a' to 'z' are mapped by subtracting
|
||
|
// 'a', which is the base volume id, i.e. they are in the range
|
||
|
// 0..25 The volume id's for the remaining drive letters are
|
||
|
// maintained in _aVolIdSpecial, and the fake volume ids for these
|
||
|
// special drives are in the range 26..RTL_MAX_DRIVE_LETTERS-1.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CFakeVolIdMap::VolIdToFakeVolId( VOLUMEID volumeId )
|
||
|
{
|
||
|
//
|
||
|
// Volume ids are obtained by the ascii value of the drive letter
|
||
|
//
|
||
|
Win4Assert( volumeId < 0xff );
|
||
|
|
||
|
if ( volumeId >= VolumeIdBase
|
||
|
&& volumeId-VolumeIdBase < COUNT_ALPHABETS )
|
||
|
{
|
||
|
return volumeId-VolumeIdBase;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Lookup in _aVolIdSpecial
|
||
|
//
|
||
|
for ( ULONG i=0; i<COUNT_SPECIAL_CHARS; i++ )
|
||
|
{
|
||
|
if ( _aVolIdSpecial[i] == volumeId )
|
||
|
return COUNT_ALPHABETS + i;
|
||
|
}
|
||
|
|
||
|
for ( i=0; i<COUNT_SPECIAL_CHARS; i++ )
|
||
|
{
|
||
|
if ( _aVolIdSpecial[i] == 0 )
|
||
|
{
|
||
|
_aVolIdSpecial[i] = volumeId;
|
||
|
return COUNT_ALPHABETS + i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Win4Assert( !"Volume id map overflow" );
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CFakeVolIdMap::FakeVolIdToVolId
|
||
|
//
|
||
|
// Synopsis: Converts a fake volume id in the range 0..RTL_MAX_DRIVE_LETTERS-1
|
||
|
// to a real volume id
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
// Notes: See VolIdToFakeVolId for mapping info.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOLUMEID CFakeVolIdMap::FakeVolIdToVolId( ULONG fakeVolId )
|
||
|
{
|
||
|
Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
|
||
|
|
||
|
if ( fakeVolId < COUNT_ALPHABETS )
|
||
|
return VolumeIdBase + fakeVolId;
|
||
|
else
|
||
|
return _aVolIdSpecial[fakeVolId-COUNT_ALPHABETS];
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::CDeletionLog
|
||
|
//
|
||
|
// Synopsis: Constructor
|
||
|
//
|
||
|
// Arguments: [fileIdMap] -- File id map
|
||
|
// [cicat] -- Ci catalog
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CDeletionLog::CDeletionLog( CFileIdMap & fileIdMap, CiCat& cicat )
|
||
|
: _fileIdMap(fileIdMap),
|
||
|
_cicat(cicat)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::FastInit
|
||
|
//
|
||
|
// Synopsis: Initialization
|
||
|
//
|
||
|
// Arguments: [pStorage] -- Ci storage
|
||
|
// [pwcsCatDir] -- Catalog dir
|
||
|
// [version] -- Version #
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
// 02-Mar-98 KitmanH Used QueryDeletionlog to obtain a new
|
||
|
// CMmStream
|
||
|
//
|
||
|
// Notes: The persistent format is <vol id><cEntries><entry 1>..<entry cEntries>
|
||
|
// for each volume id, and each entry has <fileid><wid><usn>.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CDeletionLog::FastInit( CiStorage * pStorage,
|
||
|
ULONG version )
|
||
|
{
|
||
|
|
||
|
XPtr<PMmStream> sStrm( pStorage->QueryDeletionLog() );
|
||
|
|
||
|
_xPersStream.Set( new CDynStream( sStrm.GetPointer() ) );
|
||
|
|
||
|
sStrm.Acquire();
|
||
|
|
||
|
_xPersStream->CheckVersion( *pStorage, version );
|
||
|
|
||
|
ULONG cVolumes = _xPersStream->Count();
|
||
|
_xPersStream->InitializeForRead();
|
||
|
|
||
|
for ( ULONG i=0; i<cVolumes; i++ )
|
||
|
{
|
||
|
ULONG cbRead;
|
||
|
LONGLONG llSig;
|
||
|
|
||
|
cbRead = _xPersStream->Read( &llSig, sizeof(llSig) );
|
||
|
if ( cbRead != sizeof(llSig) )
|
||
|
FatalCorruption( cbRead, sizeof(llSig) );
|
||
|
|
||
|
if ( eSigDelLog != llSig )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ERROR,
|
||
|
"CDeletionLog: Signature mismatch 0x%x:0x%x\n",
|
||
|
lltoHighPart(llSig),
|
||
|
lltoLowPart(llSig) ));
|
||
|
FatalCorruption( 0, 0 );
|
||
|
}
|
||
|
|
||
|
VOLUMEID volumeId;
|
||
|
cbRead = _xPersStream->Read( &volumeId, sizeof(VOLUMEID) );
|
||
|
if ( cbRead != sizeof(VOLUMEID) )
|
||
|
FatalCorruption( cbRead, sizeof(VOLUMEID) );
|
||
|
|
||
|
ULONG cEntries;
|
||
|
cbRead = _xPersStream->Read( &cEntries, sizeof(ULONG) );
|
||
|
if ( cbRead != sizeof(ULONG) )
|
||
|
FatalCorruption( cbRead, sizeof(ULONG) );
|
||
|
|
||
|
for ( ULONG j=0; j<cEntries;j++ )
|
||
|
{
|
||
|
FILEID fileId;
|
||
|
cbRead = _xPersStream->Read( &fileId, sizeof(FILEID) );
|
||
|
if ( cbRead != sizeof(FILEID) )
|
||
|
FatalCorruption( cbRead, sizeof(FILEID) );
|
||
|
|
||
|
WORKID wid;
|
||
|
cbRead = _xPersStream->Read( &wid, sizeof(WORKID) );
|
||
|
if ( cbRead != sizeof(WORKID) )
|
||
|
FatalCorruption( cbRead, sizeof(WORKID) );
|
||
|
|
||
|
USN usn;
|
||
|
cbRead = _xPersStream->Read( &usn, sizeof(USN) );
|
||
|
if ( cbRead != sizeof(USN) )
|
||
|
FatalCorruption( cbRead, sizeof(USN) );
|
||
|
|
||
|
MarkForDeletion( volumeId,
|
||
|
fileId,
|
||
|
wid,
|
||
|
usn );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::ReInit
|
||
|
//
|
||
|
// Synopsis: Empties the deletion log
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CDeletionLog::ReInit( ULONG version )
|
||
|
{
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
_xPersStream->SetVersion( version );
|
||
|
|
||
|
for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
|
||
|
_aDelLogEntryList[i].Clear();
|
||
|
|
||
|
Flush();
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::Flush
|
||
|
//
|
||
|
// Synopsis: Serializes the deletion log to disk
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CDeletionLog::Flush()
|
||
|
{
|
||
|
Win4Assert( !_xPersStream.IsNull() );
|
||
|
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
_xPersStream->InitializeForWrite( GetSize() );
|
||
|
LONGLONG llSig = eSigDelLog;
|
||
|
|
||
|
ULONG cVolumes = 0;
|
||
|
for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
|
||
|
{
|
||
|
if ( _aDelLogEntryList[i].Count() > 0 )
|
||
|
{
|
||
|
cVolumes++;
|
||
|
|
||
|
_xPersStream->Write( &llSig, sizeof(llSig) );
|
||
|
|
||
|
VOLUMEID volumeId = _fakeVolIdMap.FakeVolIdToVolId( i );
|
||
|
_xPersStream->Write( &volumeId, sizeof(VOLUMEID) );
|
||
|
|
||
|
ULONG cEntries = _aDelLogEntryList[i].Count();
|
||
|
_xPersStream->Write( &cEntries, sizeof(ULONG) );
|
||
|
|
||
|
#if CIDBG==1
|
||
|
ULONG cEntriesInList = 0;
|
||
|
USN usnPrev = 0;
|
||
|
#endif
|
||
|
|
||
|
for ( CDelLogEntryListIter entryListIter( _aDelLogEntryList[i] );
|
||
|
!_aDelLogEntryList[i].AtEnd(entryListIter);
|
||
|
_aDelLogEntryList[i].Advance( entryListIter) )
|
||
|
{
|
||
|
FILEID fileId = entryListIter->FileId();
|
||
|
_xPersStream->Write( &fileId, sizeof(FILEID) );
|
||
|
|
||
|
WORKID wid = entryListIter->WorkId();
|
||
|
_xPersStream->Write( &wid, sizeof(WORKID) );
|
||
|
|
||
|
USN usn = entryListIter->Usn();
|
||
|
_xPersStream->Write( &usn, sizeof(USN) );
|
||
|
|
||
|
#if CIDBG==1
|
||
|
//
|
||
|
// Check usn's are monotonically increasing
|
||
|
//
|
||
|
cEntriesInList++;
|
||
|
Win4Assert( entryListIter->Usn() >= usnPrev );
|
||
|
usnPrev = entryListIter->Usn();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if CIDBG==1
|
||
|
Win4Assert( cEntriesInList == _aDelLogEntryList[i].Count() );
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_xPersStream->SetCount( cVolumes );
|
||
|
_xPersStream->Flush();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::MarkForDeletion
|
||
|
//
|
||
|
// Synopsis: Adds a deletion entry
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CDeletionLog::MarkForDeletion( VOLUMEID volumeId,
|
||
|
FILEID fileId,
|
||
|
WORKID wid,
|
||
|
USN usn )
|
||
|
{
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
XPtr<CDelLogEntry> xEntry( new CDelLogEntry( fileId, wid, usn ) );
|
||
|
ULONG fakeVolId = _fakeVolIdMap.VolIdToFakeVolId( volumeId );
|
||
|
|
||
|
Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
|
||
|
|
||
|
if ( _aDelLogEntryList[fakeVolId].Count() == 0 )
|
||
|
{
|
||
|
//
|
||
|
// Empty list case
|
||
|
//
|
||
|
_aDelLogEntryList[fakeVolId].Queue( xEntry.Acquire() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CDelLogEntry *pEntryLast = _aDelLogEntryList[fakeVolId].GetLast();
|
||
|
if ( xEntry->Usn() > pEntryLast->Usn() )
|
||
|
{
|
||
|
//
|
||
|
// If the usn is less than the last entry's usn, then it means that it
|
||
|
// is a usn that is being replayed, and there is no need to add it
|
||
|
// to the deletion log again.
|
||
|
//
|
||
|
_aDelLogEntryList[fakeVolId].Queue( xEntry.Acquire() );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::ProcessChangesFlush
|
||
|
//
|
||
|
// Synopsis: Process the list of changes that has been flushed by
|
||
|
// framework/changelog and do the actual deletes from
|
||
|
// the file id map.
|
||
|
//
|
||
|
// Arguments: [usnFlushInfoList] -- List of changes flushed
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CDeletionLog::ProcessChangesFlush( CUsnFlushInfoList & usnFlushInfoList )
|
||
|
{
|
||
|
CLock lock( _mutex );
|
||
|
|
||
|
for ( ULONG i=0; i<usnFlushInfoList.Count(); i++ )
|
||
|
{
|
||
|
CUsnFlushInfo *pFlushInfo = usnFlushInfoList.Get(i);
|
||
|
|
||
|
ULONG fakeVolId = _fakeVolIdMap.VolIdToFakeVolId( pFlushInfo->VolumeId() );
|
||
|
|
||
|
Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
|
||
|
|
||
|
CDelLogEntryList& entryList = _aDelLogEntryList[fakeVolId];
|
||
|
#if CIDBG==1
|
||
|
USN usnPrev = 0;
|
||
|
#endif
|
||
|
|
||
|
CDelLogEntryListIter entryListIter( entryList );
|
||
|
while ( !entryList.AtEnd( entryListIter ) )
|
||
|
{
|
||
|
CDelLogEntry *pEntry = entryListIter.GetEntry();
|
||
|
entryList.Advance( entryListIter );
|
||
|
|
||
|
#if CIDBG==1
|
||
|
//
|
||
|
// Check that usn's are monotonically increasing
|
||
|
//
|
||
|
Win4Assert( pEntry->Usn() >= usnPrev );
|
||
|
usnPrev = pEntry->Usn();
|
||
|
#endif
|
||
|
|
||
|
if ( pEntry->Usn() <= pFlushInfo->UsnHighest() )
|
||
|
{
|
||
|
entryList.RemoveFromList( pEntry );
|
||
|
_fileIdMap.Delete( pEntry->FileId(), pEntry->WorkId() );
|
||
|
delete pEntry;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Since the list is in increasing usn order, we are done
|
||
|
// with this volume id.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::GetSize
|
||
|
//
|
||
|
// Synopsis: Returns the size of the serialized stream in bytes
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CDeletionLog::GetSize()
|
||
|
{
|
||
|
//
|
||
|
// Start with a slop factor
|
||
|
//
|
||
|
ULONG ulSize = 1024;
|
||
|
|
||
|
for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
|
||
|
{
|
||
|
ulSize += sizeof(VOLUMEID) // volume id field
|
||
|
+ sizeof(ULONG) // cEntries field
|
||
|
+ _aDelLogEntryList[i].Count() * sizeof(CDelLogEntry);
|
||
|
}
|
||
|
|
||
|
return ulSize;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CDeletionLog::FatalCorruption
|
||
|
//
|
||
|
// Synopsis: Handles deletion log corruption
|
||
|
//
|
||
|
// Arguments: [cbRead] -- Count of bytes read
|
||
|
// [cbToRead] -- Count of bytes to read
|
||
|
//
|
||
|
// History: 28-Jul-97 SitaramR Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CDeletionLog::FatalCorruption( ULONG cbRead, ULONG cbToRead )
|
||
|
{
|
||
|
Win4Assert( !"Corrupt deletion log" );
|
||
|
|
||
|
ciDebugOut(( DEB_ERROR,
|
||
|
"CDeletionLog: read %d bytes instead of %d\n",
|
||
|
cbRead,
|
||
|
cbToRead ));
|
||
|
|
||
|
PStorage & storage = _cicat.GetStorage();
|
||
|
storage.ReportCorruptComponent( L"Deletion log" );
|
||
|
|
||
|
THROW( CException( CI_CORRUPT_CATALOG ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|