|
|
//+------------------------------------------------------------------
//
// 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; } } }
|