|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name :
retrq.cxx
Abstract: Implements the Retry queue
Author:
Nimish Khanolkar ( NimishK ) 11-Dec-1995
Project:
CRETRY_Q sink
Functions Exported:
Revision History:
--*/
/************************************************************
* Include Headers ************************************************************/ #include "precomp.h"
//////////////////////////////////////////////////////////////////////////////
//
// Name :
// CRETRY_Q::InitializeQueue
//
// Description:
// This function initializes the class
//
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CRETRY_Q::Initialize(void) {
TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::InitializeQueue");
//Init the heaad of the queue
InitializeListHead(&m_QHead);
//Init or critical section. This protects the queue and the hash table
InitializeCriticalSection(&m_CritSec); m_fCritSecInit = TRUE; TraceFunctLeaveEx((LPARAM)this); return S_OK; } //////////////////////////////////////////////////////////////////////////////
//
// Name :
// CRETRY_Q::CreateQueue
//
// Description:
// This is the static member function that creates the Queue
//
//
////////////////////////////////////////////////////////////////////////////////
CRETRY_Q * CRETRY_Q::CreateQueue() { HRESULT hr;
CRETRY_Q * pRQueue = NULL; pRQueue = new CRETRY_Q();
if(!pRQueue) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(NULL); }
//initialize the queue
hr = pRQueue->Initialize(); if(FAILED(hr)) { delete pRQueue; pRQueue = NULL; } return pRQueue; }
/////////////////////////////////////////////////////////////////////////////////
// CRETRY_HASH_TABLE::DeInitialize
//
// Very Basic.
//
/////////////////////////////////////////////////////////////////////////////////
HRESULT CRETRY_Q::DeInitialize(void) { PLIST_ENTRY plEntry = NULL; CRETRY_HASH_ENTRY * pHashEntry = NULL;
//Release all the objects in the queue
// 10/1/98 - MikeSwa
while(!IsListEmpty(&m_QHead)) { plEntry = RemoveHeadList (&m_QHead); pHashEntry = CONTAINING_RECORD(plEntry, CRETRY_HASH_ENTRY, m_QLEntry); pHashEntry->ClearInQ();
//Execute callback on shutdown, so caller can free memory
if (pHashEntry->IsCallback()) pHashEntry->ExecCallback();
pHashEntry->DecRefCount(); }
if (m_fCritSecInit) DeleteCriticalSection(&m_CritSec);
delete this; return S_OK; }
///////////////////////////////////////////////////////////////////////
//
// Name :
// CRETRY_Q::InsertSortedIntoQueue
//
// Description:
// It takes the list entry for the new RETRY_HASH_ENTRY
// and adds it in the right order based on the Retry time
// for that entry.
// UnLocked operation. The caller has to have the lock
//
// Arguments:
//
// Returns:
//
///////////////////////////////////////////////////////////////////////
void CRETRY_Q::InsertSortedIntoQueue(PRETRY_HASH_ENTRY pHashEntry, BOOL *fTopOfQueue ) { PLIST_ENTRY pCurrentListEntry; FILETIME CurrentRetryTime; FILETIME NewRetryTime; PRETRY_HASH_ENTRY pCurrentHashEntry; TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::InsertSortedEntry");
*fTopOfQueue = FALSE; //Initialize
pCurrentListEntry = &m_QHead;
//Look at the next entry to see if we are not at the end of the queue
while(pCurrentListEntry->Flink != &m_QHead) { //Get the object pointed by the next entry
pCurrentHashEntry = CONTAINING_RECORD( pCurrentListEntry->Flink, CRETRY_HASH_ENTRY, m_QLEntry); CurrentRetryTime = pCurrentHashEntry->GetRetryTime(); NewRetryTime = pHashEntry->GetRetryTime();
//If the new entry has more delay we continue finding a place for it
if(CompareFileTime (&CurrentRetryTime, &NewRetryTime) == -1) { pCurrentListEntry = pCurrentListEntry->Flink; continue; } else { //We found the place
break; } }
//insert before the next entry
InsertHeadList(pCurrentListEntry, &pHashEntry->QueryQListEntry()); //set inQ flag
pHashEntry->SetInQ(); pHashEntry->IncRefCount(); if(m_QHead.Flink == &pHashEntry->QueryQListEntry()) *fTopOfQueue = TRUE;
TraceFunctLeaveEx((LPARAM)this); return; }
/////////////////////////////////////////////////////////////////////////////////
//
// Name :
// CRETRY_Q::CanRETRYHeadEntry
//
// We look at the entry at the top of the queue
// If it is something that we can retry right now, we remove it from the
// queue and return it to the caller
//
///////////////////////////////////////////////////////////////////////////////////
//
BOOL CRETRY_Q::CanRETRYHeadEntry(PRETRY_HASH_ENTRY* ppRHEntry, DWORD* pdwDelay) { FILETIME TimeNow; //the time now
FILETIME RetryTime; //time connection should be retried
TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::CanPopHead");
//get the current time
GetSystemTimeAsFileTime(&TimeNow);
//Lock the queue
LockQ();
_ASSERT(m_QHead.Flink);
//Look at the next entry to see if we are not at the end of the queue
if(m_QHead.Flink != &m_QHead) { //Get the object pointed by the next entry
*ppRHEntry = CONTAINING_RECORD( m_QHead.Flink, CRETRY_HASH_ENTRY, m_QLEntry); RetryTime = (*ppRHEntry)->GetRetryTime();
//If the Current time is less than the retry time
// and the time difference is greater than 1 sec then go back to waiting
//else remove the entry
if( (CompareFileTime (&TimeNow, &RetryTime) == -1) && (*pdwDelay = ((DWORD)SecFromFtSpan(TimeNow, RetryTime) * 1000))) { //We cannnot POP this entry as it is not yet release
_ASSERT(*pdwDelay > 0);
*ppRHEntry = NULL; //Unlock the queue
UnLockQ(); TraceFunctLeaveEx((LPARAM)this); return FALSE; } //end of while
else { //We can pop this entry from our retry queue
RemoveEntryList(m_QHead.Flink); (*ppRHEntry)->ClearInQ(); *pdwDelay = 0; //Unlock the queue
UnLockQ(); TraceFunctLeaveEx((LPARAM)this); return TRUE; } } else { //Unlock the queue
UnLockQ(); //There is no entry in the queue so go to sleep indefintely.
*ppRHEntry = NULL; //get the delay to sleep
*pdwDelay = INFINITE; TraceFunctLeaveEx((LPARAM)this); return FALSE; } }
////////////////////////////////////////////////////////////////////////////////
//
// CRETRY_Q::RemoveFromQueue(PLISTENTRY pEntry)
//
// This function removes an entry into the queue
//
// Arguments:
//
// none
//
/////////////////////////////////////////////////////////////////////////////////
//
BOOL CRETRY_Q::RemoveFromQueue(PRETRY_HASH_ENTRY pRHEntry) { TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::RemoveFromQueue");
_ASSERT( pRHEntry != NULL);
if(pRHEntry == NULL || &pRHEntry->QueryQListEntry() == NULL) { TraceFunctLeaveEx((LPARAM)this); return FALSE; }
// Remove
if(pRHEntry->GetInQ()) { RemoveEntryList( &pRHEntry->QueryQListEntry()); pRHEntry->ClearInQ(); TraceFunctLeaveEx((LPARAM)this); return TRUE; } else { SetLastError(ERROR_PATH_NOT_FOUND); TraceFunctLeaveEx((LPARAM)this); return FALSE; } }
////////////////////////////////////////////////////////////////////////////////
//
// CRETRY_Q::RemoveFromTop()
//
// This function removes an entry into the queue
//
// Arguments:
//
// none
//
/////////////////////////////////////////////////////////////////////////////////
//
PRETRY_HASH_ENTRY CRETRY_Q::RemoveFromTop(void) {
PLIST_ENTRY plEntry = NULL; CRETRY_HASH_ENTRY * pHashEntry = NULL;
//get the first item off the queue
if(!IsListEmpty(&m_QHead)) { plEntry = RemoveHeadList (&m_QHead); pHashEntry = CONTAINING_RECORD(plEntry, CRETRY_HASH_ENTRY, m_QLEntry); }
return pHashEntry;
}
/////////////////////////////////////////////////////////////////////////////////
// CRETRY_Q::PrintAllEntries
//
// Walks the retry queue and Prints all the domains and the times
//
/////////////////////////////////////////////////////////////////////////////////
//
void CRETRY_Q::PrintAllEntries(void) { PLIST_ENTRY HeadOfList = NULL; PLIST_ENTRY pEntry = NULL; PLIST_ENTRY pentryNext = NULL; CRETRY_HASH_ENTRY * pHashEntry = NULL; FILETIME ftTime; SYSTEMTIME stTime; char szRetryTime[20]; char szInsertedTime[20];
TraceFunctEnterEx((LPARAM)this, "CRETRY_Q::PrintAllEntries");
LockQ(); HeadOfList = &m_QHead; pEntry = m_QHead.Flink; for(; pEntry != HeadOfList; pEntry = pentryNext) { pentryNext = pEntry->Flink; pHashEntry = CONTAINING_RECORD(pEntry, CRETRY_HASH_ENTRY, m_QLEntry); ftTime = pHashEntry->GetRetryTime(); FileTimeToSystemTime(&ftTime, &stTime); sprintf(szRetryTime, "%d:%d:%d",stTime.wHour,stTime.wMinute, stTime.wSecond); ftTime = pHashEntry->GetInsertTime(); FileTimeToSystemTime(&ftTime, &stTime); sprintf(szInsertedTime, "%d:%d:%d",stTime.wHour,stTime.wMinute, stTime.wSecond);
DebugTrace((LPARAM)this,"Domain: %s RTime: %s, ITime: %s", pHashEntry->GetHashKey(),szRetryTime, szInsertedTime); } UnLockQ(); TraceFunctLeaveEx((LPARAM)this); }
//---[ CRETRY_Q::StealQueueEntries ]-------------------------------------------
//
//
// Description:
// Used to swap entries with tmp queue during config update.
// Parameters:
// pRetryQueue Queue to swap entries with.
// Returns:
// -
// History:
// 10/12/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CRETRY_Q::StealQueueEntries(CRETRY_Q *pRetryQueue) { _ASSERT(IsListEmpty(&m_QHead));
//Update our head
if (!IsListEmpty(&(pRetryQueue->m_QHead))) { m_QHead.Flink = pRetryQueue->m_QHead.Flink; m_QHead.Flink->Blink = &m_QHead; m_QHead.Blink = pRetryQueue->m_QHead.Blink; m_QHead.Blink->Flink = &m_QHead; }
//Now mark other queue as empty
InitializeListHead(&(pRetryQueue->m_QHead)); }
/////////////////////////////////////////////////////////////////////////////////////////
|