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.
|
|
//-----------------------------------------------------------------------------
//
//
// File: failmsgq.cpp
//
// Description:
// Implementation of CFailedMsgQueue class.
//
// Author: Mike Swafford (MikeSwa)
//
// History:
// 1/18/99 - MikeSwa Created
//
// Copyright (C) 1999 Microsoft Corporation
//
//-----------------------------------------------------------------------------
#include "aqprecmp.h"
#include "failmsgq.h"
#include "aqutil.h"
#include <mailmsgi_i.c>
//---[ IMailMsgAQueueListEntry ]----------------------------------------------
//
//
// Description:
// Helper function that gets list entry for message.
// Parameters:
// IN pIMailMsgPropertes Msg to get list entry for
// Returns:
// Pointer to list entry
// History:
// 1/19/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
AQueueFailedListEntry *pfliGetListEntryForMsg( IMailMsgProperties *pIMailMsgProperties) { HRESULT hr = S_OK; AQueueFailedListEntry *pfli = NULL; IMailMsgAQueueListEntry *pIMailMsgAQueueListEntry = NULL;
_ASSERT(pIMailMsgProperties);
hr = pIMailMsgProperties->QueryInterface(IID_IMailMsgAQueueListEntry, (void **) &pIMailMsgAQueueListEntry);
//This are spec'd to never fail
_ASSERT(SUCCEEDED(hr)); _ASSERT(pIMailMsgAQueueListEntry);
if (pIMailMsgAQueueListEntry) { hr = pIMailMsgAQueueListEntry->GetListEntry((void **) &pfli); _ASSERT(SUCCEEDED(hr)); _ASSERT(pfli); pIMailMsgAQueueListEntry->Release();
pfli->m_pIMailMsgProperties = pIMailMsgProperties; pIMailMsgProperties->AddRef(); }
return pfli; }
//---[ ValidateListEntry ]-----------------------------------------------------
//
//
// Description:
// Debug code to do some validation on the list entry pulled off the list
// Parameters:
// IN pfli list entry struct pulled off of
// Returns:
//
// History:
// 1/19/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
#ifndef DEBUG
#define AQValidateListEntry(x)
#else //is DEBUG
void AQValidateListEntry(AQueueFailedListEntry *pfli) { HRESULT hr = S_OK; AQueueFailedListEntry *pfliNew = NULL; IMailMsgAQueueListEntry *pIMailMsgAQueueListEntry = NULL;
_ASSERT(pfli); _ASSERT(pfli->m_pIMailMsgProperties);
hr = pfli->m_pIMailMsgProperties->QueryInterface(IID_IMailMsgAQueueListEntry, (void **) &pIMailMsgAQueueListEntry);
//This are spec'd to never fail
_ASSERT(SUCCEEDED(hr)); _ASSERT(pIMailMsgAQueueListEntry); hr = pIMailMsgAQueueListEntry->GetListEntry((void **) &pfliNew); _ASSERT(SUCCEEDED(hr)); _ASSERT(pfliNew);
//The list entry returned should be the same one pass into this function
_ASSERT(pfli == pfliNew); pIMailMsgAQueueListEntry->Release(); } #endif //DEBUG
//---[ CFailedMsgQueue::CFailedMsgQueue ]--------------------------------------
//
//
// Description:
// Constuctor for CFailedMsgQueue
// Parameters:
// -
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CFailedMsgQueue::CFailedMsgQueue() { m_dwSignature = FAILEDMSGQUEUE_SIG; m_cMsgs = 0; m_paqinst = NULL; m_dwFlags = 0;
InitializeListHead(&m_liHead);
}
//---[ CFailedMsgQueue::~CFailedMsgQueue ]-------------------------------------
//
//
// Description:
// Default destructor for CFailedMsgQueue
// Parameters:
// -
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CFailedMsgQueue::~CFailedMsgQueue() { Deinitialize(); }
//---[ CFailedMsgQueue::Initialize ]-------------------------------------------
//
//
// Description:
// Initialization routine for CFailedMsgQueue
// Parameters:
// IN paqinst Ptr to the server instance object
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CFailedMsgQueue::Initialize(CAQSvrInst *paqinst) { _ASSERT(paqinst); m_paqinst = paqinst;
if (m_paqinst) m_paqinst->AddRef(); }
//---[ CFailedMsgQueue::Deinitialize ]-----------------------------------------
//
//
// Description:
// Deinitialization code for CFailedMsgQueue. Release server instance
// object.
// Parameters:
// -
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CFailedMsgQueue::Deinitialize() { CAQSvrInst *paqinst = NULL; AQueueFailedListEntry *pfli = NULL;
m_slPrivateData.ExclusiveLock(); paqinst = m_paqinst; m_paqinst = NULL;
//Loop through list & release messages
while (!IsListEmpty(&m_liHead)) { pfli = (AQueueFailedListEntry *) m_liHead.Flink;
_ASSERT(&m_liHead != ((PLIST_ENTRY) pfli));
_ASSERT(pfli->m_pIMailMsgProperties);
if (paqinst) paqinst->ServerStopHintFunction();
RemoveEntryList((PLIST_ENTRY)pfli);
pfli->m_pIMailMsgProperties->Release(); } m_slPrivateData.ExclusiveUnlock();
if (paqinst) paqinst->Release(); }
//---[ CFailedMsgQueue::HandleFailedMailMsg ]----------------------------------
//
//
// Description:
// Puts a failed mailmsg in the queue of mailmsgs to retry
// Parameters:
// IN pIMailMsgProperties MailMsgProperties to try
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CFailedMsgQueue::HandleFailedMailMsg(IMailMsgProperties *pIMailMsgProperties) { AQueueFailedListEntry *pfli = NULL;
if (!pIMailMsgProperties) { m_slPrivateData.ShareLock(); if (m_paqinst) m_paqinst->DecPendingFailed(); m_slPrivateData.ShareUnlock();
return; }
pfli = pfliGetListEntryForMsg(pIMailMsgProperties);
//If above fails... there is nothing we can do
_ASSERT(pfli); if (!pfli) return;
m_slPrivateData.ExclusiveLock();
if (!m_paqinst) { _ASSERT(pfli->m_pIMailMsgProperties); pfli->m_pIMailMsgProperties->Release(); pfli->m_pIMailMsgProperties = NULL; } else { InsertTailList(&m_liHead, &(pfli->m_li)); InterlockedIncrement((PLONG) &m_cMsgs); }
m_slPrivateData.ExclusiveUnlock();
//Make sure we have a retry pending
StartProcessingIfNecessary(); }
//---[ CFailedMsgQueue::InternalStartProcessingIfNecessary ]-------------------
//
//
// Description:
// Called at various times (ie SubmitMessage) to kick off the processing
// of Failed Msgs.
// Parameters:
// -
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CFailedMsgQueue::InternalStartProcessingIfNecessary() { CAQSvrInst *paqinst = NULL; HRESULT hr = S_OK; BOOL fCallbackRequestFailed = FALSE;
//See if there is work to be done and no one else doing it or scheduled to
if (!(FMQ_CALLBACK_REQUESTED & m_dwFlags) && m_cMsgs) { //Try to set the call back bit.... if this thread gets it... arrange for
//a callback.
if (!(FMQ_CALLBACK_REQUESTED & dwInterlockedSetBits(&m_dwFlags, FMQ_CALLBACK_REQUESTED))) { //Get Virtual server object in a thread safe manner
m_slPrivateData.ShareLock(); paqinst = m_paqinst; if (paqinst) paqinst->AddRef(); m_slPrivateData.ShareUnlock();
//Only worry about trying if we have a virtual server object.
if (paqinst) { //Retry in 5 minutes
hr = paqinst->SetCallbackTime( CFailedMsgQueue::ProcessEntriesCallback, this, 5); if (FAILED(hr)) fCallbackRequestFailed = TRUE; } else { fCallbackRequestFailed = TRUE; }
} }
//We failed to request a callback... unset the flag, so another thread
//can try
if (fCallbackRequestFailed) dwInterlockedUnsetBits(&m_dwFlags, FMQ_CALLBACK_REQUESTED);
if (paqinst) paqinst->Release(); }
//---[ CFailedMsgQueue::ProcessEntries ]---------------------------------------
//
//
// Description:
// Walks queues of failed IMailMsgs and proccesses them for retry
// Parameters:
// -
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CFailedMsgQueue::ProcessEntries() { DWORD cMsgsToProcess = m_cMsgs; //Only walk list once.
HRESULT hr = S_OK; AQueueFailedListEntry *pfli = NULL; CAQSvrInst *paqinst = NULL;
//There should only be 1 thread processing entries, and we should have
//set the bit
_ASSERT(FMQ_CALLBACK_REQUESTED & m_dwFlags);
m_slPrivateData.ExclusiveLock();
paqinst = m_paqinst; if (paqinst) { paqinst->AddRef();
while (!IsListEmpty(&m_liHead) && cMsgsToProcess-- && m_paqinst) { pfli = (AQueueFailedListEntry *) m_liHead.Flink;
_ASSERT(&m_liHead != ((PLIST_ENTRY) pfli));
RemoveEntryList((PLIST_ENTRY)pfli);
m_slPrivateData.ExclusiveUnlock();
//Verify that pli we have now is the same as what the interface
//returns
AQValidateListEntry(pfli);
paqinst->DecPendingFailed(); InterlockedDecrement((PLONG) &m_cMsgs); hr = paqinst->HrInternalSubmitMessage(pfli->m_pIMailMsgProperties); if (FAILED(hr) && (AQUEUE_E_SHUTDOWN != hr) && paqinst->fShouldRetryMessage(pfli->m_pIMailMsgProperties)) { HandleFailedMailMsg(pfli->m_pIMailMsgProperties); }
pfli->m_pIMailMsgProperties->Release();
//Should be lock when we hit top of loop
m_slPrivateData.ExclusiveLock(); }
paqinst->Release(); paqinst = NULL; }
m_slPrivateData.ExclusiveUnlock();
}
//---[ CFailedMsgQueue::ProcessEntries ]---------------------------------------
//
//
// Description:
// Static function that is used as a retry callback for ProcessEntries.
// Parameters:
// IN pvContext This ptr of CFailedMsgQueue object
// Returns:
// -
// History:
// 1/18/99 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CFailedMsgQueue::ProcessEntriesCallback(PVOID pvContext) { CFailedMsgQueue *pfmq = (CFailedMsgQueue *) pvContext;
_ASSERT(pfmq); _ASSERT(FAILEDMSGQUEUE_SIG == pfmq->m_dwSignature);
if (pfmq && (FAILEDMSGQUEUE_SIG == pfmq->m_dwSignature)) { pfmq->ProcessEntries(); _ASSERT(FMQ_CALLBACK_REQUESTED & (pfmq->m_dwFlags)); dwInterlockedUnsetBits(&(pfmq->m_dwFlags), FMQ_CALLBACK_REQUESTED); pfmq->StartProcessingIfNecessary(); }
}
|