//+------------------------------------------------------------------ // // Copyright (C) 1991-1997 Microsoft Corporation. // // File: idxnotif.cxx // // Contents: Document notification interfaces // // Classes: CIndexNotificationTable // // History: 24-Feb-97 SitaramR Created // //------------------------------------------------------------------- #include #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 & xDocStore ) : _pCiManager( pCiManager ), _xDocStore( xDocStore.Acquire() ), _fInitialized( FALSE ), _fShutdown( FALSE ), _usnCtr( 1 ), _cRefs( 1 ) { for ( ULONG i=0; i 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 xNotifStatus( pIndexNotifStatus ); CIndexNotificationEntry *pIndexNotifEntry; BOOL fFound; { CLock lock(_mutex); fFound = LokLookup( wid, pIndexNotifEntry ); if ( fFound ) sc = CI_E_DUPLICATE_NOTIFICATION; } if ( !fFound ) { AddRef(); XInterface xNotifTable(this); CheckForUsnOverflow(); USN usn = InterlockedIncrement( &_usnCtr ); pIndexNotifEntry = new CIndexNotificationEntry( wid, CI_UPDATE_ADD, xNotifTable, xNotifStatus, _pCiManager, usn ); XInterface 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 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 xNotifTable(this); pIndexNotifEntry = new CIndexNotificationEntry( wid, CI_UPDATE_DELETE, xNotifTable, xNotifStatus, _pCiManager, usn ); XInterface xIndexNotifEntry( pIndexNotifEntry ); CHashTableEntry *pHashEntry = new CHashTableEntry( wid, pIndexNotifEntry ); XPtr 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 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 & 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 & 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 & aWidsInPersIndex ) { for ( ULONG i=0; i 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 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; iGetNextHashEntry(); CIndexNotificationEntry *pIndexNotifEntry = pEntryPrev->GetNotifEntry(); pIndexNotifEntry->Shutdown(); pIndexNotifEntry->Release(); delete pEntryPrev; } } }