/*++ Copyright (c) 1995-1996 Microsoft Corporation Module Name : svmap.cpp Abstract: Provides name/id mapping for server variables. Used to allow server variable values to be cached by out of process applications. Author: Taylor Weiss ( TaylorW ) 19-Apr-1999 Environment: Project: w3svc.dll private\inet\iis\svcs\w3\server wam.dll private\inet\iis\svcs\wam\object Functions Exported: Revision History: --*/ #include #include #include // Define a table of name, len pairs for each cachable server variable #define DEFINE_SV( token ) { #token, sizeof(#token) - 1 }, SV_CACHE_MAP::SV_NAME SV_CACHE_MAP::sm_rgNames[] = { ALL_SERVER_VARIABLES() }; #undef DEFINE_SV BOOL SV_CACHE_MAP::Initialize( VOID ) /*++ Routine Description: Fills our hash table with name, id pairs. --*/ { BOOL fInitialized = TRUE; DWORD dwHashValue; for( int i = 0; i < SV_COUNT; ++i ) { dwHashValue = HashString( FindName(i) ); DBG_ASSERT( dwHashValue < TABLE_SIZE ); // It really isn't bad if we collide, it just means that // this particular server variable will not be cachable DBG_REQUIRE( m_rgHashTable[dwHashValue].InsertValue( i ) ); } return fInitialized; } BOOL SV_CACHE_MAP::FindOrdinal( IN LPCSTR pszName, IN INT cchName, OUT DWORD * pdwOrdinal ) const /*++ Routine Description: Lookup the server variable specified by name and return it's ordinal if found. NOTE - We should provide method that doesn't require the length! Return Value FALSE == Not found TRUE == Found - pdwOrdinal contains the server variable id. --*/ { BOOL fFoundIt = FALSE; DBG_ASSERT( pdwOrdinal ); DWORD dwHashValue = HashString(pszName); const HASH_TABLE_ENTRY &hte = m_rgHashTable[dwHashValue]; if( !hte.IsSlotEmpty(0) ) { // Hashed to a non empty entry if( hte.IsSlotEmpty(1) ) { // It's the only one. *pdwOrdinal = hte.GetSlotValue(0); fFoundIt = StringMatches( pszName, cchName, *pdwOrdinal ); } else { // Collision, need to compare strings with all // the non empty slots or until we get a hit DBG_ASSERT( !hte.IsSlotEmpty(0) ); DBG_ASSERT( !hte.IsSlotEmpty(1) ); if( StringMatches(pszName, cchName, hte.GetSlotValue(0)) ) { *pdwOrdinal = hte.GetSlotValue(0); fFoundIt = TRUE; } else if( StringMatches(pszName, cchName, hte.GetSlotValue(1)) ) { *pdwOrdinal = hte.GetSlotValue(1); fFoundIt = TRUE; } else if( !hte.IsSlotEmpty(2) && StringMatches( pszName, cchName, hte.GetSlotValue(2) ) ) { *pdwOrdinal = hte.GetSlotValue(2); fFoundIt = TRUE; } else if( !hte.IsSlotEmpty(3) && StringMatches( pszName, cchName, hte.GetSlotValue(3) ) ) { *pdwOrdinal = hte.GetSlotValue(3); fFoundIt = TRUE; } } } return fFoundIt; } VOID SV_CACHE_MAP::PrintToBuffer( IN CHAR * pchBuffer, IN OUT LPDWORD pcch ) const /*++ Routine Description: Dump the hash table to pchBuffer. Note: We really aren't checking pcch as an in parameter. If the buffer is too small we will overwrite it. --*/ { DWORD cb = 0; DBG_ASSERT( NULL != pchBuffer); cb += wsprintfA( pchBuffer + cb, "SV_CACHE_MAP(%p): sizeof(SV_CACHE_MAP)=%08x\n", this, sizeof(SV_CACHE_MAP) ); DBG_ASSERT( cb < *pcch ); // Gather some stats on the hash table DWORD dwEmptyEntries = 0; DWORD dwFilledEntries = 0; DWORD dwCollisions = 0; for( int i = 0; i < TABLE_SIZE; ++i ) { if( m_rgHashTable[i].IsSlotEmpty(0) ) { ++dwEmptyEntries; } else { ++dwFilledEntries; if( !m_rgHashTable[i].IsSlotEmpty(1) ) { ++dwCollisions; } if( !m_rgHashTable[i].IsSlotEmpty(2) ) { ++dwCollisions; } if( !m_rgHashTable[i].IsSlotEmpty(3) ) { ++dwCollisions; } } } cb += wsprintfA( pchBuffer + cb, "Table Size = %d; Hashed Items = %d; Empty Entries = %d; " "Filled Entries = %d; Collisions = %d;\n", TABLE_SIZE, SV_COUNT, dwEmptyEntries, dwFilledEntries, dwCollisions ); DBG_ASSERT( cb < *pcch ); for( int j = 0; j < TABLE_SIZE; ++j ) { if( !m_rgHashTable[j].IsSlotEmpty(0) ) { cb += wsprintfA( pchBuffer + cb, "%03d", j ); DBG_ASSERT( cb < *pcch ); int k = 0; while( k < HASH_TABLE_ENTRY::MAX_ITEMS && !m_rgHashTable[j].IsSlotEmpty(k) ) { cb += wsprintfA( pchBuffer + cb, " - %d (%s)", m_rgHashTable[j].GetSlotValue(k), sm_rgNames[m_rgHashTable[j].GetSlotValue(k)] ); DBG_ASSERT( cb < *pcch ); k++; } cb += wsprintfA( pchBuffer + cb, "\n" ); DBG_ASSERT( cb < *pcch ); } } *pcch = cb; return; } VOID SV_CACHE_MAP::Print( VOID ) const /*++ Routine Description: --*/ { // DANGER - This buffer size is much larger then necessary, but // changes to the PrintToBuffer or the underlying size of the // SV_CACHE_MAP may make this buffer insufficient. CHAR pchBuffer[ 10000 ]; DWORD cb = sizeof( pchBuffer ); PrintToBuffer( pchBuffer, &cb ); DBG_ASSERT( cb < sizeof(pchBuffer) ); DBGDUMP(( DBG_CONTEXT, pchBuffer )); } VOID SV_CACHE_LIST::GetBufferItems ( IN OUT BUFFER_ITEM * pBufferItems, IN OUT DWORD * pdwBufferItemCount ) /*++ Routine Description: Initialize pBufferItems with the server variable ids that should be cached. --*/ { DBG_ASSERT( pdwBufferItemCount && *pdwBufferItemCount >= SVID_COUNT ); DWORD dwCount = 0; for( DWORD svid = 0; svid < SVID_COUNT; ++svid ) { if( m_rgItems[svid].fCached ) { if( dwCount < *pdwBufferItemCount ) { pBufferItems[dwCount].svid = svid; pBufferItems[dwCount].dwOffset = 0; } ++dwCount; } } *pdwBufferItemCount = dwCount; }