Leaked source code of windows server 2003
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

/*++
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));
}
/////////////////////////////////////////////////////////////////////////////////////////