You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
413 lines
10 KiB
413 lines
10 KiB
/*++
|
|
|
|
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));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|