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

811 lines
23 KiB
C++

//+------------------------------------------------------------------
//
// Copyright (C) 1991-1997 Microsoft Corporation.
//
// File: idxnotif.cxx
//
// Contents: Document notification interfaces
//
// Classes: CIndexNotificationTable
//
// History: 24-Feb-97 SitaramR Created
//
//-------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "idxnotif.hxx"
#include "idxentry.hxx"
#include "notifdoc.hxx"
#include "cimanger.hxx"
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::CIndexNotificationTable
//
// Synopsis: Constructor
//
// History: 24-Feb-97 SitaramR Created
//
//----------------------------------------------------------------------------
CIndexNotificationTable::CIndexNotificationTable( CCiManager * pCiManager,
XInterface<ICiCDocStore> & xDocStore )
: _pCiManager( pCiManager ),
_xDocStore( xDocStore.Acquire() ),
_fInitialized( FALSE ),
_fShutdown( FALSE ),
_usnCtr( 1 ),
_cRefs( 1 )
{
for ( ULONG i=0; i<NOTIF_HASH_TABLE_SIZE; i++)
_aHashTable[i] = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::~CIndexNotificationTable
//
// Synopsis: Destructor
//
// History: 24-Feb-97 SitaramR Created
//
//----------------------------------------------------------------------------
CIndexNotificationTable::~CIndexNotificationTable()
{
Shutdown();
}
//+-------------------------------------------------------------------------
//
// Method: CIndexNotificationTable::AddRef
//
// Synopsis: Increments refcount
//
// History: 24-Feb-1997 SitaramR Created
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CIndexNotificationTable::AddRef()
{
return InterlockedIncrement( (long *) &_cRefs );
}
//+-------------------------------------------------------------------------
//
// Method: CIndexNotificationTable::Release
//
// Synopsis: Decrement refcount. Delete if necessary.
//
// History: 24-Feb-1997 SitaramR Created
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CIndexNotificationTable::Release()
{
Win4Assert( _cRefs > 0 );
ULONG uTmp = InterlockedDecrement( (long *) &_cRefs );
if ( 0 == uTmp )
delete this;
return uTmp;
}
//+-------------------------------------------------------------------------
//
// Method: CIndexNotificationTable::QueryInterface
//
// Synopsis: Rebind to other interface
//
// Arguments: [riid] -- IID of new interface
// [ppvObject] -- New interface * returned here
//
// Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
//
// History: 24-Feb-1997 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CIndexNotificationTable::QueryInterface( REFIID riid,
void ** ppvObject)
{
Win4Assert( 0 != ppvObject );
if ( riid == IID_ICiIndexNotification )
*ppvObject = (void *)(ICiIndexNotification *) this;
else if ( riid == IID_ICiCFilterClient )
*ppvObject = (void *)(ICiCFilterClient *) this;
else if ( riid == IID_ICiCAdviseStatus )
return _xDocStore->QueryInterface( riid, ppvObject );
else if ( riid == IID_ICiCLangRes )
return _xDocStore->QueryInterface( riid, ppvObject );
else if ( riid == IID_IUnknown )
*ppvObject = (void *)(IUnknown *)(ICiIndexNotification *) this;
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Method: CIndexNotificationTable::AddNotification
//
// Synopsis: New document notification
//
// Arguments: [wid] -- Workid of document
// [pIndexNotifStatus] -- Status of notifcation returned here
// [ppIndexNotifEntry] -- Buffer to document properties
//
// History: 24-Feb-1997 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CIndexNotificationTable::AddNotification(
WORKID wid,
ICiCIndexNotificationStatus *pIndexNotifStatus,
ICiIndexNotificationEntry **ppIndexNotifEntry )
{
Win4Assert( wid != widInvalid );
Win4Assert( pIndexNotifStatus != 0 );
if ( _fShutdown )
return CI_E_SHUTDOWN;
SCODE sc = S_OK;
TRY
{
pIndexNotifStatus->AddRef();
XInterface<ICiCIndexNotificationStatus> xNotifStatus( pIndexNotifStatus );
CIndexNotificationEntry *pIndexNotifEntry;
BOOL fFound;
{
CLock lock(_mutex);
fFound = LokLookup( wid, pIndexNotifEntry );
if ( fFound )
sc = CI_E_DUPLICATE_NOTIFICATION;
}
if ( !fFound )
{
AddRef();
XInterface<CIndexNotificationTable> xNotifTable(this);
CheckForUsnOverflow();
USN usn = InterlockedIncrement( &_usnCtr );
pIndexNotifEntry = new CIndexNotificationEntry( wid,
CI_UPDATE_ADD,
xNotifTable,
xNotifStatus,
_pCiManager,
usn );
XInterface<CIndexNotificationEntry> xIndexNotifEntry( pIndexNotifEntry );
CHashTableEntry *pHashEntry = new CHashTableEntry( wid, pIndexNotifEntry );
{
CLock lock(_mutex);
LokNoFailAdd( pHashEntry );
if ( _fShutdown )
pIndexNotifEntry->Shutdown();
}
xIndexNotifEntry.Acquire(); // Passed ownership to hash table
sc = pIndexNotifEntry->QueryInterface( IID_ICiIndexNotificationEntry,
(void **)ppIndexNotifEntry );
//
// No release on pIndexNotifEntry because both the hash table the client
// own pIndexNotifEntry
//
Win4Assert( SUCCEEDED( sc ) );
}
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
ciDebugOut(( DEB_ERROR,
"CIndexNotificationTable::AddNotification - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
}
//+-------------------------------------------------------------------------
//
// Method: CIndexNotificationTable::ModifyNotification
//
// Synopsis: Change document notification
//
// Arguments: [wid] -- Workid of document
// [pIndexNotifStatus] -- Status of notifcation returned here
// [ppIndexNotifEntry] -- Buffer to document properties
//
// History: 24-Feb-1997 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CIndexNotificationTable::ModifyNotification(
WORKID wid,
ICiCIndexNotificationStatus *pIndexNotifStatus,
ICiIndexNotificationEntry **ppIndexNotifEntry )
{
//
// There is no difference between an add and a modify in the CI engine
//
SCODE sc = AddNotification( wid, pIndexNotifStatus, ppIndexNotifEntry );
return sc;
}
//+-------------------------------------------------------------------------
//
// Method: CIndexNotificationTable::DeleteNotification
//
// Synopsis: Delete document notification
//
// Arguments: [wid] -- Workid of document
// [pIndexNotifStatus] -- Status of notifcation returned here
//
// History: 24-Feb-1997 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CIndexNotificationTable::DeleteNotification(
WORKID wid,
ICiCIndexNotificationStatus *pIndexNotifStatus )
{
Win4Assert( wid != widInvalid );
Win4Assert( pIndexNotifStatus != 0 );
if ( _fShutdown )
return CI_E_SHUTDOWN;
SCODE sc = S_OK;
TRY
{
pIndexNotifStatus->AddRef();
XInterface<ICiCIndexNotificationStatus> xNotifStatus( pIndexNotifStatus );
CIndexNotificationEntry *pIndexNotifEntry;
BOOL fFound;
{
CLock lock(_mutex);
fFound = LokLookup( wid, pIndexNotifEntry );
if ( fFound )
sc = CI_E_DUPLICATE_NOTIFICATION;
}
if ( !fFound )
{
CheckForUsnOverflow();
USN usn = InterlockedIncrement( &_usnCtr );
AddRef();
XInterface<CIndexNotificationTable> xNotifTable(this);
pIndexNotifEntry = new CIndexNotificationEntry( wid,
CI_UPDATE_DELETE,
xNotifTable,
xNotifStatus,
_pCiManager,
usn );
XInterface<CIndexNotificationEntry> xIndexNotifEntry( pIndexNotifEntry );
CHashTableEntry *pHashEntry = new CHashTableEntry( wid, pIndexNotifEntry );
XPtr<CHashTableEntry> xHashEntry( pHashEntry );
CDocumentUpdateInfo info( wid, CI_VOLID_USN_NOT_ENABLED, usn, TRUE );
sc = _pCiManager->UpdDocumentNoThrow( &info );
if ( FAILED( sc ) )
{
SCODE scode = pIndexNotifStatus->Abort();
//
// We don't have retry logic coded in case of failure,
// hence check that it succeeded
//
Win4Assert( SUCCEEDED( scode ) );
}
else
{
CLock lock(_mutex);
LokNoFailAdd( pHashEntry );
if ( _fShutdown )
pIndexNotifEntry->Shutdown();
xIndexNotifEntry.Acquire(); // Passed ownership to hash table
xHashEntry.Acquire();
}
}
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
ciDebugOut(( DEB_ERROR,
"CIndexNotificationTable::DeleteNotification - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
}
//+-------------------------------------------------------------------------
//
// Method: CIndexNotificationTable::GetConfigInfo
//
// Synopsis: Return configuration info
//
// Arguments: [pConfigInfo] - output data structure
//
// History: 24-Feb-1997 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CIndexNotificationTable::GetConfigInfo(
CI_CLIENT_FILTER_CONFIG_INFO *pConfigInfo )
{
//
// Security generation must be specified as part of configuration
// information to the push model.
//
pConfigInfo->fSupportsOpLocks = FALSE;
pConfigInfo->fSupportsSecurity = FALSE;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::Init
//
// Synopsis: Initialize storage filtering
//
// Arguments: [pbData] - input data, ignored
// [cbData] - length of data, ignored
// [pICiAdminParams] - interface for retrieving configuration
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CIndexNotificationTable::Init( const BYTE * pbData,
ULONG cbData,
ICiAdminParams *pICiAdminParams )
{
_fInitialized = TRUE;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::GetOpenedDoc
//
// Synopsis: Return a new OpenedDoc instance
//
// Arguments: [ppICiCOpenedDoc] - Interface pointer returned here
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CIndexNotificationTable::GetOpenedDoc( ICiCOpenedDoc ** ppICiCOpenedDoc )
{
if ( !_fInitialized )
{
ppICiCOpenedDoc = 0;
return CI_E_NOT_INITIALIZED;
}
SCODE sc = S_OK;
TRY
{
AddRef();
XInterface<CIndexNotificationTable> xNotifTable( this );
CINOpenedDoc *pOpenedDoc = new CINOpenedDoc( xNotifTable );
sc = pOpenedDoc->QueryInterface( IID_ICiCOpenedDoc, (void **)ppICiCOpenedDoc );
pOpenedDoc->Release(); // QI does an AddRef
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
ciDebugOut(( DEB_ERROR,
"CIndexNotificationTable::GetOpenedDoc - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::Hash
//
// Synopsis: Implements the hash function
//
// Arguments: [wid] - Workid to hash
//
// History: 24-Feb-1997 SitaramR Created
//
// Returns: Position of chained list in hash table
//
//----------------------------------------------------------------------------
ULONG CIndexNotificationTable::Hash( WORKID wid )
{
return wid % NOTIF_HASH_TABLE_SIZE;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::LokLookup
//
// Synopsis: Return the mapping corresponding to given wid
//
// Arguments: [wid] -- Workid to hash
// [pIndexNotifEntry] -- Index entry returned here
//
// History: 24-Feb-1997 SitaramR Created
//
// Returns: True if a mapping was found in the hash table
//
//----------------------------------------------------------------------------
BOOL CIndexNotificationTable::LokLookup( WORKID wid,
CIndexNotificationEntry * &pIndexNotifEntry )
{
unsigned uHashValue = Hash( wid );
Win4Assert( uHashValue < NOTIF_HASH_TABLE_SIZE );
for ( CHashTableEntry *pHashEntry = _aHashTable[uHashValue];
pHashEntry != 0;
pHashEntry = pHashEntry->GetNextHashEntry() )
{
if ( pHashEntry->GetWorkId() == wid )
{
pIndexNotifEntry = pHashEntry->GetNotifEntry();
return TRUE;
}
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::LokNoFailAdd
//
// Synopsis: Add a wid->pIndexEntry mapping
//
// Arguments: [pHashEntry] -- Hash entry
//
// History: 24-Feb-1997 SitaramR Created
//
// Notes: LokNoFailAdd should not fail due to memory allocations
//
//----------------------------------------------------------------------------
void CIndexNotificationTable::LokNoFailAdd( CHashTableEntry *pHashEntry )
{
#if DBG == 1
//
// Check for duplicate entries
//
CIndexNotificationEntry *pExistingData;
BOOL fFound = LokLookup( pHashEntry->GetWorkId(), pExistingData );
Win4Assert( !fFound );
#endif
unsigned uHashValue = Hash( pHashEntry->GetWorkId() );
pHashEntry->SetNextHashEntry( _aHashTable[uHashValue] );
_aHashTable[uHashValue] = pHashEntry;
ciDebugOut(( DEB_ITRACE, "Adding Workid %d at %d hash entry\n",
pHashEntry->GetWorkId(),
uHashValue ));
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::LokRemove
//
// Synopsis: Return the mapping corresponding to given wid
//
// Arguments: [wid] -- Workid to hash
// [xIndexNotifEntry] -- Index entry returned here
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
void CIndexNotificationTable::LokRemove( WORKID wid,
XInterface<CIndexNotificationEntry> & xIndexNotifEntry )
{
unsigned uHashValue = Hash( wid );
Win4Assert( uHashValue < NOTIF_HASH_TABLE_SIZE );
CHashTableEntry *pHashEntry = _aHashTable[uHashValue];
if ( pHashEntry == 0 )
{
Win4Assert( !"Wid not found in hash table" );
return;
}
if ( pHashEntry->GetWorkId() == wid )
{
//
// Wid is the first entry in chain
//
_aHashTable[uHashValue] = pHashEntry->GetNextHashEntry();
xIndexNotifEntry.Set( pHashEntry->GetNotifEntry() );
ciDebugOut(( DEB_ITRACE, "Removing Workid %d:%d at %d hash entry\n",
pHashEntry->GetWorkId(), wid,
uHashValue ));
delete pHashEntry;
return;
}
CHashTableEntry *pHashEntryPrev = pHashEntry;
pHashEntry = pHashEntry->GetNextHashEntry();
while ( pHashEntry != 0 )
{
if ( pHashEntry->GetWorkId() == wid )
{
pHashEntryPrev->SetNextHashEntry( pHashEntry->GetNextHashEntry() );
xIndexNotifEntry.Set( pHashEntry->GetNotifEntry() );
ciDebugOut(( DEB_ITRACE, "Removing Workid %d:%d at %d hash entry\n",
pHashEntry->GetWorkId(), wid,
uHashValue ));
delete pHashEntry;
return;
}
pHashEntryPrev = pHashEntry;
pHashEntry = pHashEntry->GetNextHashEntry();
}
Win4Assert( !"Wid not found in hash table" );
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::Remove
//
// Synopsis: Return the mapping corresponding to given wid
//
// Arguments: [wid] -- Workid to hash
// [xIndexNotifEntry] -- Index entry returned here
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
void CIndexNotificationTable::Remove( WORKID wid,
XInterface<CIndexNotificationEntry> & xIndexNotifEntry )
{
CLock lock(_mutex);
LokRemove( wid, xIndexNotifEntry );
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::Lookup
//
// Synopsis: Lookup the mapping corresponding to given wid
//
// Arguments: [wid] -- Workid to hash
// [pIndexNotifEntry] -- Index entry returned here
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
BOOL CIndexNotificationTable::Lookup( WORKID wid,
CIndexNotificationEntry * &pIndexNotifEntry )
{
CLock lock(_mutex);
return LokLookup( wid, pIndexNotifEntry );
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::CommitWids
//
// Synopsis: Commits the notification status transactions on the given list
// of wids
//
// Arguments: [aWidsInPersIndex] -- Array of wids to be committed
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
void CIndexNotificationTable::CommitWids( CDynArrayInPlace<WORKID> & aWidsInPersIndex )
{
for ( ULONG i=0; i<aWidsInPersIndex.Count(); i++)
{
WORKID wid = aWidsInPersIndex.Get( i );
XInterface<CIndexNotificationEntry> xIndexNotifEntry;
{
CLock lock(_mutex);
LokRemove( wid, xIndexNotifEntry );
}
Win4Assert( !xIndexNotifEntry.IsNull() );
xIndexNotifEntry->Commit(); // Commit client transaction
//
// xIndexNotifEntry is released when it goes out of scope
//
}
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::AbortWid
//
// Synopsis: Commits the notification status transactions on the given list
// of wids
//
// Arguments: [cWidsInPersIndex] -- Count of wids in array
// [aWidsInPersIndex] -- Array of wids to be committed
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
void CIndexNotificationTable::AbortWid( WORKID wid, USN usn )
{
XInterface<CIndexNotificationEntry> xIndexNotifEntry;
{
CLock lock(_mutex);
LokRemove( wid, xIndexNotifEntry );
}
Win4Assert( !xIndexNotifEntry.IsNull() );
Win4Assert( xIndexNotifEntry->Usn() == usn );
xIndexNotifEntry->Abort(); // Abort client transaction
//
// xIndexNotifEntry is released when it goes out of scope
//
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::CheckForUsnOverflow
//
// Synopsis: Handles overflows of usn by resetting the counter to 1
//
// History: 24-Feb-1997 SitaramR Created
//
//----------------------------------------------------------------------------
void CIndexNotificationTable::CheckForUsnOverflow()
{
if ( _usnCtr == LONG_MAX )
{
//
// Overflow should be rare, if ever
//
Win4Assert( !"Usn counter overflow, resetting" );
InterlockedExchange( &_usnCtr, 1 );
}
}
//+---------------------------------------------------------------------------
//
// Member: CIndexNotificationTable::Shutdown
//
// Synopsis: Shutdown processing
//
// History: 24-Feb-97 SitaramR Created
//
//----------------------------------------------------------------------------
void CIndexNotificationTable::Shutdown()
{
//
// Shutdown all entries in hash table
//
CLock lock( _mutex );
_fShutdown = TRUE;
for ( ULONG i=0; i<NOTIF_HASH_TABLE_SIZE; i++ )
{
CHashTableEntry *pEntry = _aHashTable[i];
_aHashTable[i] = 0;
while ( pEntry != 0 )
{
CHashTableEntry *pEntryPrev = pEntry;
pEntry = pEntry->GetNextHashEntry();
CIndexNotificationEntry *pIndexNotifEntry = pEntryPrev->GetNotifEntry();
pIndexNotifEntry->Shutdown();
pIndexNotifEntry->Release();
delete pEntryPrev;
}
}
}