windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/infocomm/atq/abw.hxx
2020-09-26 16:20:57 +08:00

472 lines
12 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name :
abw.hxx
Abstract:
Declares constants, types and functions for bandwidth throttling.
Author:
Bilal Alam ( t-bilala ) 13-March-1997
Environment:
User Mode -- Win32
Project:
Internet Services Asynchronous Thread Queue Library
Revision History:
--*/
typedef struct _BANDWIDTH_LEVELS {
DWORD dwSpecifiedLevel;
DWORD dwLowThreshold; // uses 0.90 * bwSpecifiedLevel
DWORD dwHighThreshold; // uses 1.10 * bwSpecifiedLevel
} BANDWIDTH_LEVELS;
# define ATQ_LOW_BAND_THRESHOLD(bw) (bw.dwLowThreshold)
# define ATQ_HIGH_BAND_THRESHOLD(bw) (bw.dwHighThreshold)
# define CIRCULAR_INCREMENT( sm_pB, sm_rgB, size) \
(sm_pB) = ((((sm_pB) + 1) < (sm_rgB)+(size)) ? (sm_pB)+1 : (sm_rgB))
typedef enum {
ZoneLevelLow = 0, // if MeasuredBw < Bandwidth specified
ZoneLevelMedium, // if MeasuredBw approxEquals Bandwidth specified
ZoneLevelHigh, // if MeasuredBw > Bandwidth specified
ZoneLevelMax // just a boundary element
} ZoneLevel;
/*++
The following array specifies the status of operations for different
operations in different zones of the measured bandwidth.
We split the range of bandwidth into three zones as specified in
the type ZoneLevel. Depending upon the zone of operation, differet
operations are enabled/disabled. Priority is given to minimize the amount
of CPU work that needs to be redone when an operation is to be rejected.
We block operations on which considerable amount of CPU is spent earlier.
--*/
static OPERATION_STATUS sm_rgStatus[ZoneLevelMax][AtqIoMaxOp] = {
// For ZoneLevelLow: Allow All operations
{ StatusRejectOperation,
StatusAllowOperation,
StatusAllowOperation,
StatusAllowOperation,
StatusAllowOperation,
StatusAllowOperation,
},
// For ZoneLevelMedium:
{ StatusRejectOperation,
StatusBlockOperation, // Block Read
StatusAllowOperation,
StatusAllowOperation,
StatusAllowOperation,
StatusAllowOperation
},
// For ZoneLevelHigh
{ StatusRejectOperation,
StatusRejectOperation, // Reject Read
StatusAllowOperation, // Allow Writes
StatusBlockOperation, // Block TransmitFile
StatusBlockOperation, // Block TransmitFileAndRecv
StatusAllowOperation // Allow SendAndRecv
}
};
#define ATQ_BW_INFO_SIGNATURE ( (DWORD) 'BQTA')
#define ATQ_BW_INFO_SIGNATURE_FREE ( (DWORD) 'BQTX')
#define ATQ_BW_INFO_MAX_DESC 32
/*++
class BANDWIDTH_INFO
This class encapsulates all the statistics and state used in the
implementation of bandwidth throttling.
--*/
class BANDWIDTH_INFO
{
private:
DWORD _Signature;
LONG _cReference;
BOOL _fIsFreed;
BOOL _fPersistent;
// statistics
DWORD _cCurrentBlockedRequests;
DWORD _cTotalBlockedRequests;
DWORD _cTotalAllowedRequests;
DWORD _cTotalRejectedRequests;
DWORD _dwMeasuredBw;
// bandwidth status members
BANDWIDTH_LEVELS _bandwidth;
LARGE_INTEGER _rgBytesXfered[ ATQ_HISTOGRAM_SIZE ];
LARGE_INTEGER * _pBytesXferCur;
LARGE_INTEGER _cbXfered;
OPERATION_STATUS * _pStatus;
BOOL _fEnabled;
// list of blocked context manipulation
CRITICAL_SECTION _csPrivateLock;
LIST_ENTRY _BlockedListHead;
DWORD _cMaxBlockedList;
// user friendly description of this descriptor. Useful for debugging
#if DBG
CHAR _achDescription[ ATQ_BW_INFO_MAX_DESC ];
#endif
// private members shared by all BANDWIDTH_INFO objects
static CRITICAL_SECTION sm_csSharedLock;
static LIST_ENTRY sm_BornListHead;
static LIST_ENTRY sm_ActiveListHead;
static DWORD sm_cBornList;
static DWORD sm_cActiveList;
static ALLOC_CACHE_HANDLER * sm_pachBWInfos;
static BOOL sm_fGlobalEnabled;
static BOOL sm_fGlobalActive;
static DWORD sm_cNonInfinite;
// private member functions
VOID Initialize( IN BOOL fPersistent );
VOID Terminate( VOID );
BOOL UnblockRequest( IN OUT PATQ_CONT pAtqContext );
BOOL UpdateBandwidth( VOID );
VOID Lock( VOID )
{
EnterCriticalSection( &_csPrivateLock );
}
VOID Unlock( VOID )
{
LeaveCriticalSection( &_csPrivateLock );
}
static VOID SharedLock( VOID )
{
EnterCriticalSection( &sm_csSharedLock );
}
static VOID SharedUnlock( VOID )
{
LeaveCriticalSection( &sm_csSharedLock );
}
VOID RemoveFromActiveList( VOID )
// Assume caller has acquired shared lock!
{
sm_cActiveList--;
if ( !sm_cActiveList )
{
sm_fGlobalActive = FALSE;
}
#ifndef _NO_TRACING_
CHKINFO(( DBG_CONTEXT,
"Removed %p (%s) from active bandwidth info list (list size = %d)\n",
this,
_achDescription,
sm_cActiveList ));
#else
ATQ_PRINTF(( DBG_CONTEXT,
"Removed %p (%s) from active bandwidth info list (list size = %d)\n",
this,
_achDescription,
sm_cActiveList ));
#endif
RemoveEntryList( &_ActiveListEntry );
_fMemberOfActiveList = FALSE;
_ActiveListEntry.Flink = NULL;
}
VOID RemoveFromBornList( VOID )
{
SharedLock();
sm_cBornList--;
#ifndef _NO_TRACING_
CHKINFO(( DBG_CONTEXT,
"Removed %p (%s) from born bandwidth info list (list size = %d)\n",
this,
_achDescription,
sm_cBornList ));
#else
ATQ_PRINTF(( DBG_CONTEXT,
"Removed %p (%s) from born bandwidth info list (list size = %d)\n",
this,
_achDescription,
sm_cBornList ));
#endif
RemoveEntryList( &_BornListEntry );
_BornListEntry.Flink = NULL;
// Now remove from the active list
if ( _fMemberOfActiveList )
{
RemoveFromActiveList();
}
SharedUnlock();
}
public:
LIST_ENTRY _BornListEntry;
LIST_ENTRY _ActiveListEntry;
BOOL _fMemberOfActiveList;
static DWORD sm_cSamplesForTimeout;
// public member functions
VOID Reference( VOID )
{
InterlockedIncrement( &_cReference );
}
VOID Dereference( VOID )
{
if ( !_fPersistent && !InterlockedDecrement( &_cReference ) )
{
delete this;
}
}
OPERATION_STATUS QueryStatus( ATQ_OPERATION operation ) const
{
return _pStatus[ operation ];
}
BOOL IsFreed( VOID )
{
return _fIsFreed;
}
VOID IncTotalBlockedRequests( VOID )
{
INC_ATQ_COUNTER( _cTotalBlockedRequests );
}
DWORD QueryTotalBlockedRequests( VOID ) const
{
return _cTotalBlockedRequests;
}
VOID IncTotalAllowedRequests( VOID )
{
INC_ATQ_COUNTER( _cTotalAllowedRequests );
}
DWORD QueryTotalAllowedRequests( VOID ) const
{
return _cTotalAllowedRequests;
}
VOID IncTotalRejectedRequests( VOID )
{
INC_ATQ_COUNTER( _cTotalRejectedRequests );
}
DWORD QueryTotalRejectedRequests( VOID ) const
{
return _cTotalRejectedRequests;
}
VOID IncCurrentBlockedRequests( VOID )
{
INC_ATQ_COUNTER( _cCurrentBlockedRequests );
}
DWORD QueryCurrentBlockedRequests( VOID ) const
{
return _cCurrentBlockedRequests;
}
VOID DecCurrentBlockedRequests( VOID )
{
DEC_ATQ_COUNTER( _cCurrentBlockedRequests );
}
DWORD QueryMeasuredBw( VOID ) const
{
return _dwMeasuredBw;
}
BOOL Enabled( VOID ) const
{
return _fEnabled;
}
DWORD QuerySignature( VOID ) const
{
return _Signature;
}
DWORD QueryMaxBlockedSize( VOID ) const
{
return _cMaxBlockedList;
}
VOID SetMaxBlockedSize( DWORD Size )
{
_cMaxBlockedList = Size;
}
VOID AddToActiveList( VOID )
{
if ( _fEnabled && !_fMemberOfActiveList )
{
SharedLock();
if ( _fEnabled && !_fMemberOfActiveList )
{
sm_cActiveList++;
#ifndef _NO_TRACING_
CHKINFO(( DBG_CONTEXT,
"Added %p (%s) to active bandwidth info list (list size = %d)\n",
this,
_achDescription,
sm_cActiveList ));
#else
ATQ_PRINTF(( DBG_CONTEXT,
"Added %p (%s) to active bandwidth info list (list size = %d)\n",
this,
_achDescription,
sm_cActiveList ));
#endif
InsertTailList( &sm_ActiveListHead, &_ActiveListEntry );
_fMemberOfActiveList = TRUE;
sm_fGlobalActive = TRUE;
}
SharedUnlock();
}
}
VOID AddToBornList( VOID )
{
SharedLock();
sm_cBornList++;
InsertTailList( &sm_BornListHead, &_BornListEntry );
SharedUnlock();
}
BOOL UpdateBytesXfered( IN PATQ_CONT pAtqContext,
IN DWORD cbIo )
{
if ( _fEnabled )
{
Lock();
_pBytesXferCur->QuadPart = _pBytesXferCur->QuadPart + cbIo;
Unlock();
}
return TRUE;
}
CHAR * QueryDescription( VOID ) const
{
// :(
#if DBG
return (CHAR*) _achDescription;
#else
return NULL;
#endif
}
VOID SetDescription( CHAR * pszDescription )
{
#if DBG
Lock();
strncpy( _achDescription,
pszDescription ? pszDescription : "Unknown",
sizeof( _achDescription ) );
Unlock();
#endif
}
BANDWIDTH_INFO( IN BOOL fPersistent )
{
Initialize( fPersistent );
}
~BANDWIDTH_INFO( VOID )
{
Terminate();
}
BOOL PrepareToFree( VOID );
BOOL RemoveFromBlockedList( IN PATQ_CONT patqContext );
BOOL BlockRequest( IN OUT PATQ_CONT patqContext );
DWORD SetBandwidthLevel( IN DWORD Data );
BOOL CheckAndUnblockRequests( VOID );
DWORD SetMaxBlockedListSize( IN DWORD Data );
DWORD QueryBandwidthLevel( VOID );
BOOL ClearStatistics( VOID );
BOOL GetStatistics( OUT ATQ_STATISTICS * patqStats );
static BOOL GlobalActive( VOID )
{
return sm_fGlobalActive;
}
static BOOL GlobalEnabled( VOID )
{
return sm_fGlobalEnabled;
}
static BOOL AbwInitialize( VOID );
static BOOL AbwTerminate( VOID );
static BOOL UpdateAllBandwidths( VOID );
void * operator new( size_t s )
{
ATQ_ASSERT( s == sizeof( BANDWIDTH_INFO ));
// allocate from allocation cache.
ATQ_ASSERT( sm_pachBWInfos != NULL );
return (sm_pachBWInfos->Alloc());
}
void operator delete( void * pBandwidthInfo )
{
ATQ_ASSERT( pBandwidthInfo != NULL );
// free to the allocation pool
ATQ_ASSERT( NULL != sm_pachBWInfos );
ATQ_REQUIRE( sm_pachBWInfos->Free( pBandwidthInfo ) );
return;
}
};
typedef BANDWIDTH_INFO * PBANDWIDTH_INFO;