/*++ Copyright (c) 1999 Microsoft Corporation Module Name : cachemanager.cxx Abstract: Manages a list of all the caches and handles invalidation of them Author: Bilal Alam (balam) 11-Nov-2000 Environment: Win32 - User Mode Project: ULW3.DLL --*/ #include "precomp.hxx" #define DIR_CHANGE_FILTER (FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS) CACHE_MANAGER * g_pCacheManager; CACHE_MANAGER::CACHE_MANAGER() { _pDirMonitor = NULL; ZeroMemory( &_Caches, sizeof( _Caches ) ); } CACHE_MANAGER::~CACHE_MANAGER() { } HRESULT CACHE_MANAGER::Initialize( IMSAdminBase * pAdminBase ) /*++ Routine Description: Initialize cache manager Arguments: pAdminBase - Admin base object pointer Return Value: HRESULT --*/ { // // Initialize dir monitor // DBG_ASSERT( _pDirMonitor == NULL ); _pDirMonitor = new CDirMonitor; if ( _pDirMonitor == NULL ) { return HRESULT_FROM_WIN32( GetLastError() ); } // // Keep a pointer to the admin base object // _pAdminBase = pAdminBase; _pAdminBase->AddRef(); return NO_ERROR; } VOID CACHE_MANAGER::Terminate( VOID ) /*++ Routine Description: Cleanup the cache manager Arguments: None Return Value: HRESULT --*/ { if ( _pAdminBase != NULL ) { _pAdminBase->Release(); _pAdminBase = NULL; } if ( _pDirMonitor != NULL ) { _pDirMonitor->Cleanup(); delete _pDirMonitor; _pDirMonitor = NULL; } } HRESULT CACHE_MANAGER::AddNewCache( OBJECT_CACHE * pObjectCache ) /*++ Routine Description: Add new cache to be managed Arguments: pObjectCache - Object cache to add Return Value: HRESULT --*/ { DWORD dwInsertPos; if ( pObjectCache == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // First the first non-NULL entry // for ( dwInsertPos = 0; _Caches[ dwInsertPos ] != NULL; dwInsertPos++ ) { } // // Add the new cache // _Caches[ dwInsertPos ] = pObjectCache; return NO_ERROR; } HRESULT CACHE_MANAGER::RemoveCache( OBJECT_CACHE * pObjectCache ) /*++ Routine Description: Cache to remove from list of managed caches Arguments: pObjectCache - Object cache to remove Return Value: HRESULT --*/ { DWORD dwPos; BOOL fFound = FALSE; if ( pObjectCache == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // First find the cache to remove // for ( dwPos = 0; _Caches[ dwPos ] != NULL; dwPos++ ) { if ( _Caches[ dwPos ] == pObjectCache ) { memmove( _Caches + dwPos, _Caches + dwPos + 1, ( MAX_CACHE_COUNT - dwPos - 1 ) * sizeof( OBJECT_CACHE*) ); fFound = TRUE; break; } } if ( !fFound ) { return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ); } return NO_ERROR; } VOID CACHE_MANAGER::FlushAllCaches( VOID ) /*++ Routine Description: Flush all caches Arguments: None Return Value: None --*/ { DWORD dwPos; for ( dwPos = 0; _Caches[ dwPos ] != NULL; dwPos++ ) { // // Clear the cache // _Caches[ dwPos ]->Clear(); // // Wait for scavengers to go away // _Caches[ dwPos ]->UnregisterScavenger(); } } HRESULT CACHE_MANAGER::HandleDirMonitorInvalidation( WCHAR * pszFilePath, BOOL fFlushAll ) /*++ Routine Description: Invalidate any caches which are interested in dir monitor invalidation Arguments: pszFilePath - File name changed fFlushAll - Should we flush all items prefixed with pszFilePath? Return Value: HRESULT --*/ { DWORD dwPos; OBJECT_CACHE * pCache; if ( pszFilePath == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Iterate thru all the caches which support dirmon invalidation // for ( dwPos = 0; _Caches[ dwPos ] != NULL; dwPos++ ) { pCache = _Caches[ dwPos ]; // // If this cache doesn't support dirmon at all, continue // if ( !pCache->QuerySupportsDirmonSpecific() && !pCache->QuerySupportsDirmonFlush() ) { continue; } // // If this is a specific invalidation, check whether the cache // supports it. If it doesn't, but does support flush, the do a // flush instead // if ( !fFlushAll ) { if ( pCache->QuerySupportsDirmonSpecific() ) { pCache->DoDirmonInvalidationSpecific( pszFilePath ); } else { pCache->DoDirmonInvalidationFlush( pszFilePath ); } } else { pCache->DoDirmonInvalidationFlush( pszFilePath ); } } return NO_ERROR; } HRESULT CACHE_MANAGER::HandleMetadataInvalidation( WCHAR * pszMetaPath ) /*++ Routine Description: Invalidate any caches which are interested in metadata invalidation Arguments: pszMetaPath - Metabase path which changed Return Value: HRESULT --*/ { DWORD dwPos; OBJECT_CACHE * pCache; if ( pszMetaPath == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // Iterate thru all the caches which support metadata invalidation // for ( dwPos = 0; _Caches[ dwPos ] != NULL; dwPos++ ) { pCache = _Caches[ dwPos ]; if ( pCache->QuerySupportsMetadataFlush() ) { pCache->DoMetadataInvalidationFlush( pszMetaPath ); } } return NO_ERROR; } HRESULT CACHE_MANAGER::MonitorDirectory( DIRMON_CONFIG * pDirmonConfig, CDirMonitorEntry ** ppDME ) /*++ Routine Description: Monitor given directory Arguments: pDirmonConfig - Name of directory and token to impersonate with ppDME - Set to monitor entry on success Return Value: HRESULT --*/ { CacheDirMonitorEntry * pDME = NULL; HRESULT hr = NO_ERROR; BOOL fRet; BOOL fImpersonated = FALSE; if ( ppDME == NULL || pDirmonConfig == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // First check if we are already monitoring this directory // pDME = (CacheDirMonitorEntry*) _pDirMonitor->FindEntry( pDirmonConfig->pszDirPath ); if ( pDME == NULL ) { // // It is not. We'll have to start monitoring // pDME = new CacheDirMonitorEntry; if ( pDME == NULL ) { return HRESULT_FROM_WIN32( GetLastError() ); } pDME->AddRef(); if ( pDirmonConfig->hToken != NULL ) { fRet = SetThreadToken( NULL, pDirmonConfig->hToken ); if ( !fRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); pDME->Release(); return hr; } fImpersonated = TRUE; } fRet = _pDirMonitor->Monitor( pDME, pDirmonConfig->pszDirPath, TRUE, DIR_CHANGE_FILTER ); if ( fImpersonated ) { RevertToSelf(); fImpersonated = FALSE; } if ( !fRet ) { // // Note: It is OK if we can't monitor the directory. The error // will trickle up and the caller will not cache the entry // hr = HRESULT_FROM_WIN32( GetLastError() ); pDME->Release(); pDME = NULL; return hr; } } DBG_ASSERT( pDME != NULL ); *ppDME = (CDirMonitorEntry*) pDME; return NO_ERROR; }