1195 lines
34 KiB
C++
1195 lines
34 KiB
C++
//
|
|
// MODULE: TOPICSHOP.CPP
|
|
//
|
|
// PURPOSE: Provide a means of "publishing" troubleshooter topics. This is where a
|
|
// working thread goes to obtain a CTopic to use.
|
|
//
|
|
// COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com
|
|
//
|
|
// AUTHOR: Joe Mabel
|
|
//
|
|
// ORIGINAL DATE: 9-10-98
|
|
//
|
|
// NOTES:
|
|
//
|
|
// Version Date By Comments
|
|
//--------------------------------------------------------------------
|
|
// V3.0 09-10-98 JM
|
|
//
|
|
|
|
#pragma warning(disable:4786)
|
|
|
|
#include "stdafx.h"
|
|
#include <algorithm>
|
|
#include "TopicShop.h"
|
|
#include "event.h"
|
|
#include "apiwraps.h"
|
|
#include "CharConv.h"
|
|
#include "bn.h"
|
|
#include "propnames.h"
|
|
|
|
#ifdef LOCAL_TROUBLESHOOTER
|
|
#include "CHMFileReader.h"
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CTopicInCatalog
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CTopicInCatalog::CTopicInCatalog(const CTopicInfo & topicinfo) :
|
|
m_topicinfo(topicinfo),
|
|
m_bTopicInfoMayNotBeCurrent(false),
|
|
m_bInited(false),
|
|
m_countLoad(CCounterLocation::eIdTopicLoad, topicinfo.GetNetworkName()),
|
|
m_countLoadOK(CCounterLocation::eIdTopicLoadOK, topicinfo.GetNetworkName()),
|
|
m_countEvent(CCounterLocation::eIdTopicEvent, topicinfo.GetNetworkName()),
|
|
m_countHit(CCounterLocation::eIdTopicHit, topicinfo.GetNetworkName()),
|
|
m_countHitNewCookie(CCounterLocation::eIdTopicHitNewCookie, topicinfo.GetNetworkName()),
|
|
m_countHitOldCookie(CCounterLocation::eIdTopicHitOldCookie, topicinfo.GetNetworkName())
|
|
{
|
|
|
|
::InitializeCriticalSection( &m_csTopicinfo);
|
|
m_hev = ::CreateEvent(
|
|
NULL,
|
|
TRUE, // any number of (working) threads may be released on signal
|
|
FALSE, // initially non-signalled
|
|
NULL);
|
|
if (! m_hev)
|
|
{
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""),
|
|
_T(""),
|
|
EV_GTS_ERROR_EVENT );
|
|
|
|
// Simulate a bad alloc exception in this case.
|
|
// This exception will be caught by the caller if the new call has been
|
|
// properly wrapped in a try...catch() block. Only known caller is
|
|
// CTopicShop::AddTopic() which handles this properly.
|
|
throw bad_alloc();
|
|
}
|
|
|
|
m_countEvent.Increment();
|
|
}
|
|
|
|
CTopicInCatalog::~CTopicInCatalog()
|
|
{
|
|
if (m_hev)
|
|
::CloseHandle(m_hev);
|
|
::DeleteCriticalSection( &m_csTopicinfo);
|
|
}
|
|
|
|
CTopicInfo CTopicInCatalog::GetTopicInfo() const
|
|
{
|
|
|
|
::EnterCriticalSection(&m_csTopicinfo);
|
|
CTopicInfo ret(m_topicinfo);
|
|
::LeaveCriticalSection(&m_csTopicinfo);
|
|
return ret;
|
|
}
|
|
|
|
void CTopicInCatalog::SetTopicInfo(const CTopicInfo &topicinfo)
|
|
{
|
|
::EnterCriticalSection(&m_csTopicinfo);
|
|
m_topicinfo = topicinfo;
|
|
m_bTopicInfoMayNotBeCurrent = true;
|
|
::LeaveCriticalSection(&m_csTopicinfo);
|
|
}
|
|
|
|
|
|
// Just let this object know to increment the hit count
|
|
void CTopicInCatalog::CountHit(bool bNewCookie)
|
|
{
|
|
m_countHit.Increment();
|
|
if (bNewCookie)
|
|
m_countHitNewCookie.Increment();
|
|
else
|
|
m_countHitOldCookie.Increment();
|
|
}
|
|
|
|
// Obtain a CP_TOPIC as a pointer to the topic, if that topic is already built.
|
|
// As long as a CP_TOPIC remains undeleted, the associated CTopic is guaranteed to
|
|
// remain undeleted.
|
|
// Warning: this function will return with a null topic if topic is not yet built.
|
|
// Must test for null with CP_TOPIC::IsNull(). Can't test a smart pointer for null
|
|
// with ==.
|
|
CP_TOPIC & CTopicInCatalog::GetTopicNoWait(CP_TOPIC &cpTopic) const
|
|
{
|
|
cpTopic = m_cpTopic;
|
|
return cpTopic;
|
|
}
|
|
|
|
// Obtain a CP_TOPIC as a pointer to the topic.
|
|
// Wait as necessary for that topic to be built.
|
|
// Warning: this function will return with a null topic if topic cannot be built.
|
|
// As long as a CP_TOPIC remains undeleted, the associated CTopic is guaranteed to
|
|
// remain undeleted.
|
|
// Warning: this function may have to wait for TopicInCatalog.m_cpTopic to be built.
|
|
CP_TOPIC & CTopicInCatalog::GetTopic(CP_TOPIC &cpTopic) const
|
|
{
|
|
if (!m_bInited)
|
|
{
|
|
// Wait for a set period, if failure then log error msg and wait infinite.
|
|
WAIT_INFINITE( m_hev );
|
|
}
|
|
return GetTopicNoWait(cpTopic);
|
|
}
|
|
|
|
// to be called by the TopicBuilderTask thread
|
|
void CTopicInCatalog::Init(const CTopic* pTopic)
|
|
{
|
|
m_countLoad.Increment();
|
|
if(pTopic)
|
|
{
|
|
m_cpTopic = pTopic;
|
|
m_countLoadOK.Increment();
|
|
}
|
|
if(pTopic || m_cpTopic.IsNull())
|
|
m_bInited = true;
|
|
|
|
::SetEvent(m_hev);
|
|
}
|
|
|
|
// Just let this object know to increment the count of changes detected.
|
|
void CTopicInCatalog::CountChange()
|
|
{
|
|
m_countEvent.Increment();
|
|
}
|
|
|
|
CTopicInCatalog::TopicStatus CTopicInCatalog::GetTopicStatus() const
|
|
{
|
|
if (!m_bInited)
|
|
return eNotInited;
|
|
else if(m_cpTopic.IsNull())
|
|
return eFail;
|
|
else
|
|
return eOK;
|
|
}
|
|
|
|
bool CTopicInCatalog::GetTopicInfoMayNotBeCurrent() const
|
|
{
|
|
::EnterCriticalSection(&m_csTopicinfo);
|
|
bool bRet= m_bTopicInfoMayNotBeCurrent;
|
|
::LeaveCriticalSection(&m_csTopicinfo);
|
|
return bRet;
|
|
}
|
|
|
|
void CTopicInCatalog::TopicInfoIsCurrent()
|
|
{
|
|
::EnterCriticalSection(&m_csTopicinfo);
|
|
m_bTopicInfoMayNotBeCurrent = false;
|
|
::LeaveCriticalSection(&m_csTopicinfo);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CTemplateInCatalog
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CTemplateInCatalog::CTemplateInCatalog( const CString & strTemplate ) :
|
|
m_strTemplate( strTemplate ),
|
|
m_countLoad(CCounterLocation::eIdTopicLoad, strTemplate),
|
|
m_countLoadOK(CCounterLocation::eIdTopicLoadOK, strTemplate),
|
|
m_countEvent(CCounterLocation::eIdTopicEvent, strTemplate),
|
|
m_countHit(CCounterLocation::eIdTopicHit, strTemplate),
|
|
m_bInited( false )
|
|
{
|
|
m_hev = ::CreateEvent(
|
|
NULL,
|
|
TRUE, // any number of (working) threads may be released on signal
|
|
FALSE, // initially non-signalled
|
|
NULL);
|
|
if (! m_hev)
|
|
{
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""),
|
|
_T(""),
|
|
EV_GTS_ERROR_EVENT );
|
|
|
|
// Simulate a bad alloc exception in this case.
|
|
// This exception will be caught by the caller if the new call has been
|
|
// properly wrapped in a try...catch() block.
|
|
throw bad_alloc();
|
|
}
|
|
|
|
m_countEvent.Increment();
|
|
}
|
|
|
|
CTemplateInCatalog::~CTemplateInCatalog()
|
|
{
|
|
if (m_hev)
|
|
::CloseHandle(m_hev);
|
|
}
|
|
|
|
const CString & CTemplateInCatalog::GetTemplateInfo() const
|
|
{
|
|
return m_strTemplate;
|
|
}
|
|
|
|
// Just let this object know to increment the hit count
|
|
void CTemplateInCatalog::CountHit( bool bNewCookie )
|
|
{
|
|
m_countHit.Increment();
|
|
}
|
|
|
|
// Obtain a CP_TEMPLATE as a pointer to the template, if that template is already built.
|
|
// As long as a CP_TEMPLATE remains undeleted, the associated CAPGTSHTIReader is guaranteed to
|
|
// remain undeleted.
|
|
// Warning: this function will return with a null template if template is not yet built.
|
|
// Must test for null with CP_TEMPLATE::IsNull(). Can't test a smart pointer for null
|
|
// with ==.
|
|
CP_TEMPLATE & CTemplateInCatalog::GetTemplateNoWait( CP_TEMPLATE &cpTemplate ) const
|
|
{
|
|
cpTemplate= m_cpTemplate;
|
|
return cpTemplate;
|
|
}
|
|
|
|
// Obtain a CP_TEMPLATE as a pointer to the template.
|
|
// Wait as necessary for that template to be built.
|
|
// Warning: this function will return with a null template if template cannot be built.
|
|
// As long as a CP_TEMPLATE remains undeleted, the associated CAPGTSHTIReader is guaranteed to
|
|
// remain undeleted.
|
|
// Warning: this function may have to wait for TopicInCatalog.m_cpTemplate to be built.
|
|
CP_TEMPLATE & CTemplateInCatalog::GetTemplate( CP_TEMPLATE &cpTemplate ) const
|
|
{
|
|
if (!m_bInited)
|
|
{
|
|
// Wait for a set period, if failure then log error msg and wait infinite.
|
|
WAIT_INFINITE( m_hev );
|
|
}
|
|
return GetTemplateNoWait( cpTemplate );
|
|
}
|
|
|
|
// to be called by the TopicBuilderTask thread
|
|
void CTemplateInCatalog::Init( const CAPGTSHTIReader* pTemplate )
|
|
{
|
|
m_countLoad.Increment();
|
|
if (pTemplate)
|
|
{
|
|
m_cpTemplate= pTemplate;
|
|
m_countLoadOK.Increment();
|
|
}
|
|
if (pTemplate || m_cpTemplate.IsNull())
|
|
m_bInited = true;
|
|
|
|
::SetEvent(m_hev);
|
|
}
|
|
|
|
// Just let this object know to increment the count of changes detected.
|
|
void CTemplateInCatalog::CountChange()
|
|
{
|
|
m_countEvent.Increment();
|
|
}
|
|
|
|
// Just let this object know to increment the count of failures detected.
|
|
void CTemplateInCatalog::CountFailed()
|
|
{
|
|
// The load failed so increment the count of attempted loads.
|
|
m_countLoad.Increment();
|
|
}
|
|
|
|
CTemplateInCatalog::TemplateStatus CTemplateInCatalog::GetTemplateStatus() const
|
|
{
|
|
if (!m_bInited)
|
|
return eNotInited;
|
|
else if(m_cpTemplate.IsNull())
|
|
return eFail;
|
|
else
|
|
return eOK;
|
|
}
|
|
|
|
DWORD CTemplateInCatalog::CountOfFailedLoads() const
|
|
{
|
|
return( m_countLoad.GetTotal() - m_countLoadOK.GetTotal() );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// CTopicShop::CTopicBuildQueue
|
|
// This class does the bulk of its work on a separate thread.
|
|
// The thread is created in the constructor by starting static function
|
|
// CTopicShop::CTopicBuildQueue::TopicBuilderTask.
|
|
// That function, in turn does its work by calling private members of this class that
|
|
// are specific to use on the TopicBuilderTask thread.
|
|
// When this goes out of scope, its own destructor calls ShutDown to stop the thread,
|
|
// waits for the thread to shut.
|
|
// The following method is available for other threads communicating with that thread:
|
|
// CTopicShop::CTopicBuildQueue::RequestBuild
|
|
//////////////////////////////////////////////////////////////////////
|
|
CTopicShop::CTopicBuildQueue::CTopicBuildQueue( CTopicCatalog & TopicCatalog,
|
|
CTemplateCatalog & TemplateCatalog)
|
|
: m_TopicCatalog (TopicCatalog),
|
|
m_TemplateCatalog( TemplateCatalog ),
|
|
m_eCurrentlyBuilding(eUnknown),
|
|
m_bShuttingDown (false),
|
|
m_dwErr(0),
|
|
m_ThreadStatus(eBeforeInit),
|
|
m_time(0)
|
|
{
|
|
enum {eHevBuildReq, eHevShut, eThread, eOK} Progress = eHevBuildReq;
|
|
|
|
SetThreadStatus(eBeforeInit);
|
|
|
|
m_hevBuildRequested = ::CreateEvent(
|
|
NULL,
|
|
FALSE, // release one thread (the TopicBuilderTask) on signal
|
|
FALSE, // initially non-signalled
|
|
NULL);
|
|
|
|
if (m_hevBuildRequested)
|
|
{
|
|
Progress = eHevShut;
|
|
m_hevThreadIsShut = ::CreateEvent(
|
|
NULL,
|
|
FALSE, // release one thread (this one) on signal
|
|
FALSE, // initially non-signalled
|
|
NULL);
|
|
|
|
if (m_hevThreadIsShut)
|
|
{
|
|
Progress = eThread;
|
|
DWORD dwThreadID; // No need to hold onto dwThreadID in member variable.
|
|
// All Win32 functions take the handle m_hThread instead.
|
|
// The one reason you'd ever want to know this ID is for
|
|
// debugging
|
|
|
|
// Note that there is no corresponding ::CloseHandle(m_hThread).
|
|
// That is because the thread goes out of existence on the implicit
|
|
// ::ExitThread() when TopicBuilderTask returns. See documentation of
|
|
// ::CreateThread for further details JM 10/22/98
|
|
m_hThread = ::CreateThread( NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)TopicBuilderTask,
|
|
this,
|
|
0,
|
|
&dwThreadID);
|
|
|
|
if (m_hThread)
|
|
Progress = eOK;
|
|
}
|
|
}
|
|
|
|
if (Progress != eOK)
|
|
{
|
|
m_dwErr = GetLastError();
|
|
CString str;
|
|
str.Format(_T("%d"), m_dwErr);
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
(Progress == eHevBuildReq) ?_T("Can't create \"request build\" event")
|
|
: (Progress == eHevShut) ? _T("Can't create \"shut\" event")
|
|
: _T("Can't create thread"),
|
|
str,
|
|
EV_GTS_ERROR_TOPICBUILDERTHREAD );
|
|
SetThreadStatus(eFail);
|
|
|
|
if (m_hevBuildRequested)
|
|
::CloseHandle(m_hevBuildRequested);
|
|
|
|
if (m_hevThreadIsShut)
|
|
::CloseHandle(m_hevThreadIsShut);
|
|
}
|
|
}
|
|
|
|
CTopicShop::CTopicBuildQueue::~CTopicBuildQueue()
|
|
{
|
|
ShutDown();
|
|
|
|
if (m_hevBuildRequested)
|
|
::CloseHandle(m_hevBuildRequested);
|
|
|
|
if (m_hevThreadIsShut)
|
|
::CloseHandle(m_hevThreadIsShut);
|
|
}
|
|
|
|
void CTopicShop::CTopicBuildQueue::SetThreadStatus(ThreadStatus ts)
|
|
{
|
|
LOCKOBJECT();
|
|
m_ThreadStatus = ts;
|
|
time(&m_time);
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
DWORD CTopicShop::CTopicBuildQueue::GetStatus(ThreadStatus &ts, DWORD & seconds) const
|
|
{
|
|
time_t timeNow;
|
|
LOCKOBJECT();
|
|
ts = m_ThreadStatus;
|
|
time(&timeNow);
|
|
seconds = timeNow - m_time;
|
|
UNLOCKOBJECT();
|
|
return m_dwErr;
|
|
}
|
|
|
|
// report status of topics in m_TopicCatalog
|
|
// OUTPUT Total: number of topics
|
|
// OUTPUT NoInit: number of uninitialized topics (never built)
|
|
// OUTPUT Fail: number of topics we tried to build, but could never build
|
|
// INPUT parrstrFail NULL == don't care to get this output
|
|
// OUTPUT *parrstrFail: names of the topics that couldn't be built
|
|
void CTopicShop::CTopicBuildQueue::GetTopicsStatus(
|
|
DWORD &Total, DWORD &NoInit, DWORD &Fail, vector<CString>*parrstrFail) const
|
|
{
|
|
LOCKOBJECT();
|
|
Total = m_TopicCatalog.size();
|
|
NoInit = 0;
|
|
Fail = 0;
|
|
if (parrstrFail)
|
|
parrstrFail->clear();
|
|
for (CTopicCatalog::const_iterator it = m_TopicCatalog.begin(); it != m_TopicCatalog.end(); ++it)
|
|
{
|
|
CTopicInCatalog::TopicStatus status = it->second->GetTopicStatus();
|
|
switch (status)
|
|
{
|
|
case CTopicInCatalog::eNotInited:
|
|
++NoInit;
|
|
break;
|
|
case CTopicInCatalog::eFail:
|
|
++Fail;
|
|
if (parrstrFail)
|
|
{
|
|
try
|
|
{
|
|
parrstrFail->push_back(it->second->GetTopicInfo().GetNetworkName());
|
|
}
|
|
catch (exception& x)
|
|
{
|
|
CString str;
|
|
// Note STL exception in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
CCharConversion::ConvertACharToString(x.what(), str),
|
|
_T(""),
|
|
EV_GTS_STL_EXCEPTION );
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// report status of template in m_TemplateCatalog
|
|
// INPUT parrstrFail NULL == don't care to get this output
|
|
// OUTPUT *parrstrFail: names of the topics that couldn't be built
|
|
// INPUT parrcntFail NULL == don't care to get this output
|
|
// OUTPUT *parrcntFail: count of failures of the topics that couldn't be built.
|
|
// one to one correspondence with parrstrFail.
|
|
void CTopicShop::CTopicBuildQueue::GetTemplatesStatus(
|
|
vector<CString>*parrstrFail, vector<DWORD>*parrcntFail ) const
|
|
{
|
|
LOCKOBJECT();
|
|
if (parrstrFail)
|
|
parrstrFail->clear();
|
|
if (parrcntFail)
|
|
parrcntFail->clear();
|
|
|
|
for (CTemplateCatalog::const_iterator it = m_TemplateCatalog.begin(); it != m_TemplateCatalog.end(); ++it)
|
|
{
|
|
if (it->second->GetTemplateStatus() == CTemplateInCatalog::eFail)
|
|
{
|
|
if (parrstrFail)
|
|
{
|
|
// Currently we only care about failures and their related count.
|
|
try
|
|
{
|
|
parrstrFail->push_back(it->second->GetTemplateInfo());
|
|
if (parrcntFail)
|
|
parrcntFail->push_back( it->second->CountOfFailedLoads() );
|
|
}
|
|
catch (exception& x)
|
|
{
|
|
CString str;
|
|
// Note STL exception in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
CCharConversion::ConvertACharToString(x.what(), str),
|
|
_T(""),
|
|
EV_GTS_STL_EXCEPTION );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
|
|
// For use by this class and derived classes destructors.
|
|
void CTopicShop::CTopicBuildQueue::ShutDown()
|
|
{
|
|
LOCKOBJECT();
|
|
if (m_bShuttingDown)
|
|
{
|
|
// We have already shut down the topic builder thread, simply exit.
|
|
UNLOCKOBJECT();
|
|
return;
|
|
}
|
|
|
|
m_bShuttingDown = true;
|
|
if (m_hThread)
|
|
{
|
|
DWORD RetVal;
|
|
|
|
::SetEvent(m_hevBuildRequested);
|
|
UNLOCKOBJECT();
|
|
|
|
// Wait for a set period, if failure then log error msg and wait infinite.
|
|
RetVal= WAIT_INFINITE( m_hevThreadIsShut );
|
|
}
|
|
else
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// For general use (not part of TopicBuilderTask thread) code.
|
|
// Ask for a topic to be built (or rebuilt).
|
|
// INPUT strTopic - name of topic OR HTI TEMPLATE
|
|
// INPUT bPriority - If bPriority is true, move it ahead of any topics/templates
|
|
// for which this has not been called with bPriority true. At a gien priority level,
|
|
// toics always come before templates.
|
|
// INPUT eCat - indicates whether strTopic is a topic or an HTI template
|
|
// This is an asynchronous request that will eventually be fulfilled by TopicBuilderTask thread
|
|
void CTopicShop::CTopicBuildQueue::RequestBuild(const CString &strTopic, bool bPriority,
|
|
CatalogCategory eCat )
|
|
{
|
|
// Verify that this is a valid category.
|
|
if (eCat != eTopic && eCat != eTemplate)
|
|
return;
|
|
|
|
// Make a lower-case version of the topic name.
|
|
CString strTopicLC = strTopic;
|
|
strTopicLC.MakeLower();
|
|
|
|
vector<CString> & Priority = (eCat == eTopic) ?
|
|
m_PriorityBuild :
|
|
m_PriorityBuildTemplates;
|
|
vector<CString> & NonPriority = (eCat == eTopic) ?
|
|
m_NonPriorityBuild :
|
|
m_NonPriorityBuildTemplates;
|
|
|
|
LOCKOBJECT();
|
|
|
|
if ((strTopicLC != m_CurrentlyBuilding) || (eCat != m_eCurrentlyBuilding))
|
|
{
|
|
vector<CString>::iterator it = find(Priority.begin(), Priority.end(), strTopicLC);
|
|
if (it == Priority.end())
|
|
{
|
|
try
|
|
{
|
|
it = find(NonPriority.begin(), NonPriority.end(), strTopicLC);
|
|
if (bPriority)
|
|
{
|
|
if (it != NonPriority.end())
|
|
{
|
|
// it's in the non-priority list. Get it out of there.
|
|
NonPriority.erase(it);
|
|
}
|
|
// Add it to the priority list
|
|
Priority.push_back(strTopicLC);
|
|
}
|
|
else if (it == NonPriority.end())
|
|
{
|
|
// Add it to the non-priority list
|
|
NonPriority.push_back(strTopicLC);
|
|
}
|
|
// else it's already listed
|
|
}
|
|
catch (exception& x)
|
|
{
|
|
CString str;
|
|
// Note STL exception in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
CCharConversion::ConvertACharToString(x.what(), str),
|
|
_T(""),
|
|
EV_GTS_STL_EXCEPTION );
|
|
}
|
|
}
|
|
// else it's already a priority, we can't do more
|
|
}
|
|
// else it's already building, we can't do more
|
|
::SetEvent(m_hevBuildRequested);
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// For use by the TopicBuilderTask thread. Should only be called when nothing is
|
|
// currently building. Caller is responsible to build only one at a time.
|
|
// OUTPUT strTopic - name of topic OR HTI TEMPLATE
|
|
// OUTPUT eCat - indicates whether strTopic is a topic or an HTI template
|
|
// false return indicates invalid request.
|
|
// non-empty string output strTopic indicates what is currently building
|
|
// empty string output should never happen
|
|
// true return indicates valid request:
|
|
// non-empty string output strTopic indicates what to build
|
|
// empty string output strTopic indicates nothing more to build
|
|
// Note that this function has the side effect of changing the _thread_ priority.
|
|
bool CTopicShop::CTopicBuildQueue::GetNextToBuild( CString &strTopic, CatalogCategory &eCat )
|
|
{
|
|
vector<CString>::iterator it;
|
|
|
|
LOCKOBJECT();
|
|
bool bOK = m_CurrentlyBuilding.IsEmpty();
|
|
if (bOK)
|
|
{
|
|
if (!m_PriorityBuild.empty())
|
|
{
|
|
// We have priority topics to build.
|
|
it = m_PriorityBuild.begin();
|
|
m_CurrentlyBuilding = *it;
|
|
m_eCurrentlyBuilding= eTopic;
|
|
m_PriorityBuild.erase(it);
|
|
|
|
// If there are more priority builds waiting behind this, boost priority
|
|
// above normal so we get to them ASAP. Otherwise, normal priority.
|
|
::SetThreadPriority(GetCurrentThread(),
|
|
m_PriorityBuild.empty() ? THREAD_PRIORITY_NORMAL : THREAD_PRIORITY_ABOVE_NORMAL);
|
|
}
|
|
else if (!m_PriorityBuildTemplates.empty())
|
|
{
|
|
// We have priority alternate templates to build.
|
|
it = m_PriorityBuildTemplates.begin();
|
|
m_CurrentlyBuilding = *it;
|
|
m_eCurrentlyBuilding= eTemplate;
|
|
m_PriorityBuildTemplates.erase(it);
|
|
|
|
// If there are more priority builds waiting behind this, boost priority
|
|
// above normal so we get to them ASAP. Otherwise, normal priority.
|
|
::SetThreadPriority(GetCurrentThread(),
|
|
m_PriorityBuildTemplates.empty() ? THREAD_PRIORITY_NORMAL : THREAD_PRIORITY_ABOVE_NORMAL);
|
|
}
|
|
else if (!m_NonPriorityBuild.empty())
|
|
{
|
|
// We have non-priority topics to build.
|
|
it = m_NonPriorityBuild.begin();
|
|
m_CurrentlyBuilding = *it;
|
|
m_eCurrentlyBuilding= eTopic;
|
|
m_NonPriorityBuild.erase(it);
|
|
|
|
// This is initialization, no one is in a hurry for it,
|
|
// let's not burden the system unduly.
|
|
::SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_BELOW_NORMAL);
|
|
}
|
|
else if (!m_NonPriorityBuildTemplates.empty())
|
|
{
|
|
// We have non-priority alternate templates to build.
|
|
it = m_NonPriorityBuildTemplates.begin();
|
|
m_CurrentlyBuilding = *it;
|
|
m_eCurrentlyBuilding= eTemplate;
|
|
m_NonPriorityBuildTemplates.erase(it);
|
|
|
|
// This is initialization, no one is in a hurry for it,
|
|
// let's not burden the system unduly.
|
|
::SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_BELOW_NORMAL);
|
|
}
|
|
else
|
|
::SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
|
|
}
|
|
strTopic = m_CurrentlyBuilding;
|
|
eCat= m_eCurrentlyBuilding;
|
|
UNLOCKOBJECT();
|
|
return bOK;
|
|
}
|
|
|
|
// Acknowledge that we have finished building the topic previously obtained with GetNextToBuild
|
|
// This should be called before GetNextToBuild is called again.
|
|
void CTopicShop::CTopicBuildQueue::BuildComplete()
|
|
{
|
|
LOCKOBJECT();
|
|
m_CurrentlyBuilding = _T("");
|
|
m_eCurrentlyBuilding= eUnknown;
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// For use by the TopicBuilderTask thread.
|
|
// Must be called on TopicBuilderTask thread. Handles all work of building & publishing
|
|
// topics driven by the queue contents
|
|
void CTopicShop::CTopicBuildQueue::Build()
|
|
{
|
|
CString strTopic;
|
|
CatalogCategory eCat;
|
|
|
|
while (true)
|
|
{
|
|
LOCKOBJECT();
|
|
SetThreadStatus(eRun);
|
|
if (m_bShuttingDown)
|
|
{
|
|
UNLOCKOBJECT();
|
|
break;
|
|
}
|
|
GetNextToBuild( strTopic, eCat );
|
|
if (strTopic.IsEmpty())
|
|
{
|
|
::ResetEvent(m_hevBuildRequested);
|
|
UNLOCKOBJECT();
|
|
SetThreadStatus(eWait);
|
|
::WaitForSingleObject(m_hevBuildRequested, INFINITE);
|
|
continue;
|
|
}
|
|
else
|
|
UNLOCKOBJECT();
|
|
|
|
if (eCat == eTopic)
|
|
{
|
|
// at this point we have a topic name. Get access to topic info.
|
|
CTopicCatalog::const_iterator it = m_TopicCatalog.find(strTopic);
|
|
if (it == m_TopicCatalog.end())
|
|
{
|
|
// Asked to initialize a topic that doesn't have a catalog entry.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T("Asked to build"),
|
|
strTopic,
|
|
EV_GTS_UNRECOGNIZED_TOPIC );
|
|
}
|
|
else
|
|
{
|
|
CTopicInCatalog & TopicInCatalog = *(it->second);
|
|
const CTopicInfo topicinfo (TopicInCatalog.GetTopicInfo());
|
|
|
|
try
|
|
{
|
|
// must create this with new so we can manage it under a reference count regime
|
|
CTopic *ptopic = new CTopic (topicinfo.GetDscFilePath()
|
|
,topicinfo.GetHtiFilePath()
|
|
,topicinfo.GetBesFilePath()
|
|
,topicinfo.GetTscFilePath() );
|
|
if (ptopic->Read())
|
|
TopicInCatalog.Init(ptopic);
|
|
else
|
|
{
|
|
// Release memory.
|
|
delete ptopic;
|
|
TopicInCatalog.Init(NULL);
|
|
}
|
|
|
|
TopicInCatalog.TopicInfoIsCurrent();
|
|
}
|
|
catch (bad_alloc&)
|
|
{
|
|
// Note memory failure in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""), EV_GTS_CANT_ALLOC );
|
|
}
|
|
}
|
|
}
|
|
else if (eCat == eTemplate)
|
|
{
|
|
// Determine whether the passed in template is in the catalog.
|
|
CTemplateCatalog::const_iterator it = m_TemplateCatalog.find(strTopic);
|
|
if (it == m_TemplateCatalog.end())
|
|
{
|
|
// Asked to initialize a template that doesn't have a catalog entry.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T("Asked to build"),
|
|
strTopic,
|
|
EV_GTS_UNRECOGNIZED_TEMPLATE );
|
|
}
|
|
else
|
|
{
|
|
CTemplateInCatalog & TemplateInCatalog = *(it->second);
|
|
const CString & strTemplateName = TemplateInCatalog.GetTemplateInfo();
|
|
|
|
try
|
|
{
|
|
// must create this with new so we can manage it under a reference count regime
|
|
CAPGTSHTIReader *pTemplate;
|
|
|
|
pTemplate= new CAPGTSHTIReader( CPhysicalFileReader::makeReader( strTemplateName ) );
|
|
if (pTemplate->Read())
|
|
TemplateInCatalog.Init( pTemplate );
|
|
else
|
|
{
|
|
// Release memory.
|
|
delete pTemplate;
|
|
TemplateInCatalog.Init( NULL );
|
|
}
|
|
}
|
|
catch (bad_alloc&)
|
|
{
|
|
// Note memory failure in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""), EV_GTS_CANT_ALLOC );
|
|
}
|
|
}
|
|
}
|
|
BuildComplete();
|
|
}
|
|
SetThreadStatus(eExiting);
|
|
}
|
|
|
|
// For use by the TopicBuilderTask thread.
|
|
void CTopicShop::CTopicBuildQueue::AckShutDown()
|
|
{
|
|
LOCKOBJECT();
|
|
::SetEvent(m_hevThreadIsShut);
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// Main routine of a thread responsible for building and publishing CTopic objects.
|
|
// INPUT lpParams
|
|
// Always returns 0.
|
|
/* static */ UINT WINAPI CTopicShop::CTopicBuildQueue::TopicBuilderTask(LPVOID lpParams)
|
|
{
|
|
reinterpret_cast<CTopicBuildQueue*>(lpParams)->Build();
|
|
reinterpret_cast<CTopicBuildQueue*>(lpParams)->AckShutDown();
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CTopicShop::ThreadStatus
|
|
//////////////////////////////////////////////////////////////////////
|
|
/* static */ CString CTopicShop::ThreadStatusText(ThreadStatus ts)
|
|
{
|
|
switch(ts)
|
|
{
|
|
case eBeforeInit: return _T("Before Init");
|
|
case eFail: return _T("Fail");
|
|
case eWait: return _T("Wait");
|
|
case eRun: return _T("Run");
|
|
case eExiting: return _T("Exiting");
|
|
default: return _T("");
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CTopicShop
|
|
// The only functions which need to lock this class are those which modify TopicCatalog.
|
|
// TopicBuildQueue has its own protection.
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CTopicShop::CTopicShop() :
|
|
m_TopicBuildQueue( m_TopicCatalog, m_TemplateCatalog ),
|
|
m_hevShopIsOpen(NULL)
|
|
{
|
|
m_hevShopIsOpen = ::CreateEvent(
|
|
NULL,
|
|
TRUE, // any number of (working) threads may be released on signal
|
|
FALSE, // initially non-signalled
|
|
NULL);
|
|
|
|
if (! m_hevShopIsOpen)
|
|
{
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""),
|
|
_T(""),
|
|
EV_GTS_ERROR_EVENT );
|
|
|
|
// Simulate a bad alloc exception in this case.
|
|
// This constructor is only called within the ctor of CDBLoadConfiguration
|
|
// and the allocation of that object is wrapped within a try...catch() block.
|
|
throw bad_alloc();
|
|
}
|
|
}
|
|
|
|
CTopicShop::~CTopicShop()
|
|
{
|
|
// Terminate the topic builder thread prior to cleaning up the topics.
|
|
m_TopicBuildQueue.ShutDown();
|
|
|
|
if (m_hevShopIsOpen)
|
|
::CloseHandle(m_hevShopIsOpen);
|
|
|
|
// Clean up the topics.
|
|
for (CTopicCatalog::const_iterator it = m_TopicCatalog.begin(); it != m_TopicCatalog.end(); ++it)
|
|
{
|
|
delete it->second;
|
|
}
|
|
|
|
// Clean up the templates.
|
|
for (CTemplateCatalog::const_iterator itu = m_TemplateCatalog.begin(); itu != m_TemplateCatalog.end(); ++itu)
|
|
{
|
|
delete itu->second;
|
|
}
|
|
}
|
|
|
|
// Add a topic to the catalog. It must eventually be built by TopicBuilderTask thread.
|
|
// If topic is already in list identically, no effect.
|
|
void CTopicShop::AddTopic(const CTopicInfo & topicinfo)
|
|
{
|
|
// our keys into the catalog should be all lower case. This code is fine, because
|
|
// CTopicInfo::GetNetworkName() is guaranteed to return lower case.
|
|
CString strNetworkName = topicinfo.GetNetworkName();
|
|
|
|
LOCKOBJECT();
|
|
CTopicCatalog::const_iterator it = m_TopicCatalog.find(strNetworkName);
|
|
|
|
if (it == m_TopicCatalog.end())
|
|
{
|
|
try
|
|
{
|
|
m_TopicCatalog[strNetworkName] = new CTopicInCatalog(topicinfo);
|
|
}
|
|
catch (bad_alloc&)
|
|
{
|
|
// Note memory failure in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""), EV_GTS_CANT_ALLOC );
|
|
}
|
|
}
|
|
else if (! (topicinfo == it->second->GetTopicInfo()))
|
|
{
|
|
it->second->SetTopicInfo(topicinfo);
|
|
m_TopicBuildQueue.RequestBuild(strNetworkName, false, CTopicBuildQueue::eTopic);
|
|
|
|
}
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// Add a template to the catalog. It must eventually be built by TopicBuilderTask thread.
|
|
// If template is already in list, no effect.
|
|
void CTopicShop::AddTemplate( const CString & strTemplateName )
|
|
{
|
|
LOCKOBJECT();
|
|
if (m_TemplateCatalog.find( strTemplateName ) == m_TemplateCatalog.end())
|
|
{
|
|
try
|
|
{
|
|
m_TemplateCatalog[ strTemplateName ] = new CTemplateInCatalog( strTemplateName );
|
|
}
|
|
catch (bad_alloc&)
|
|
{
|
|
// Note memory failure in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""), EV_GTS_CANT_ALLOC );
|
|
}
|
|
}
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// if shop is not already open, open it.
|
|
void CTopicShop::OpenShop()
|
|
{
|
|
::SetEvent(m_hevShopIsOpen);
|
|
}
|
|
|
|
|
|
// Request that a topic be built (or rebuilt)
|
|
// Typically called in response to either the system detecting a change to the topic
|
|
// files or from an operator saying "act as if a change has been detected".
|
|
// INPUT strTopic names the topic to build.
|
|
// if pbAlreadyInCatalog is input non-null, then *pbAlreadyInCatalog returns whether
|
|
// the topic was already known to the system.
|
|
void CTopicShop::BuildTopic(const CString & strTopic, bool *pbAlreadyInCatalog /*= NULL*/)
|
|
{
|
|
if (pbAlreadyInCatalog)
|
|
*pbAlreadyInCatalog = false; // initialize
|
|
|
|
CTopicInCatalog * pTopic = GetCatalogEntryPtr(strTopic);
|
|
if (pTopic)
|
|
{
|
|
pTopic->CountChange();
|
|
if (pbAlreadyInCatalog)
|
|
*pbAlreadyInCatalog = true;
|
|
}
|
|
m_TopicBuildQueue.RequestBuild( strTopic, false, CTopicBuildQueue::eTopic );
|
|
}
|
|
|
|
// Request that a template be built (or rebuilt)
|
|
// Typically called in response to the system detecting a change to the template files.
|
|
void CTopicShop::BuildTemplate( const CString & strTemplate )
|
|
{
|
|
CTemplateInCatalog * pTemplate = GetTemplateCatalogEntryPtr( strTemplate );
|
|
if (pTemplate)
|
|
pTemplate->CountChange();
|
|
m_TopicBuildQueue.RequestBuild( strTemplate, false, CTopicBuildQueue::eTemplate );
|
|
}
|
|
|
|
|
|
CTopicInCatalog * CTopicShop::GetCatalogEntryPtr(const CString & strTopic) const
|
|
{
|
|
// Wait for a set period, if failure then log error msg and wait infinite.
|
|
WAIT_INFINITE( m_hevShopIsOpen );
|
|
CTopicCatalog::const_iterator it= m_TopicCatalog.find(strTopic);
|
|
if (it == m_TopicCatalog.end())
|
|
return NULL;
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
CTemplateInCatalog * CTopicShop::GetTemplateCatalogEntryPtr(const CString & strTemplate ) const
|
|
{
|
|
// Wait for a set period, if failure then log error msg and wait infinite.
|
|
WAIT_INFINITE( m_hevShopIsOpen );
|
|
CTemplateCatalog::const_iterator it= m_TemplateCatalog.find( strTemplate );
|
|
if (it == m_TemplateCatalog.end())
|
|
return NULL;
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
|
|
// Call this function to obtain a CP_TOPIC as a pointer to the topic (identified by
|
|
// strTopic) that you want to operate on. As long as the CP_TOPIC remains undeleted,
|
|
// the associated CTopic is guaranteed to remain undeleted.
|
|
// this function must not lock CTopicShop, because it can wait a long time.
|
|
CP_TOPIC & CTopicShop::GetTopic(const CString & strTopic, CP_TOPIC &cpTopic, bool bNewCookie)
|
|
{
|
|
CTopicInCatalog *pTopicInCatalog = GetCatalogEntryPtr(strTopic);
|
|
if (! pTopicInCatalog)
|
|
cpTopic = NULL;
|
|
else
|
|
{
|
|
pTopicInCatalog->CountHit(bNewCookie);
|
|
pTopicInCatalog->GetTopicNoWait(cpTopic);
|
|
if (cpTopic.IsNull())
|
|
{
|
|
m_TopicBuildQueue.RequestBuild( strTopic, true, CTopicBuildQueue::eTopic );
|
|
pTopicInCatalog->GetTopic(cpTopic);
|
|
}
|
|
}
|
|
|
|
return cpTopic;
|
|
}
|
|
|
|
// Call this function to obtain a CP_TEMPLATE as a pointer to the template (identified by
|
|
// strTemplate) that you want to operate on. As long as the CP_TEMPLATE remains undeleted,
|
|
// the associated CAPGTSHTIReader is guaranteed to remain undeleted.
|
|
// this function must not lock CTopicShop, because it can wait a long time.
|
|
CP_TEMPLATE & CTopicShop::GetTemplate(const CString & strTemplate, CP_TEMPLATE &cpTemplate, bool bNewCookie)
|
|
{
|
|
CTemplateInCatalog *pTemplateInCatalog = GetTemplateCatalogEntryPtr(strTemplate);
|
|
if (! pTemplateInCatalog)
|
|
cpTemplate = NULL;
|
|
else
|
|
{
|
|
pTemplateInCatalog->CountHit(bNewCookie);
|
|
pTemplateInCatalog->GetTemplateNoWait( cpTemplate );
|
|
if (cpTemplate.IsNull())
|
|
{
|
|
m_TopicBuildQueue.RequestBuild( strTemplate, true, CTopicBuildQueue::eTemplate );
|
|
pTemplateInCatalog->GetTemplate( cpTemplate );
|
|
}
|
|
}
|
|
|
|
return cpTemplate;
|
|
}
|
|
|
|
|
|
void CTopicShop::GetListOfTopicNames(vector<CString>&arrstrTopic) const
|
|
{
|
|
arrstrTopic.clear();
|
|
|
|
LOCKOBJECT();
|
|
|
|
try
|
|
{
|
|
for (CTopicCatalog::const_iterator it = m_TopicCatalog.begin(); it != m_TopicCatalog.end(); ++it)
|
|
{
|
|
arrstrTopic.push_back(it->second->GetTopicInfo().GetNetworkName());
|
|
}
|
|
}
|
|
catch (exception& x)
|
|
{
|
|
CString str;
|
|
// Note STL exception in event log.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
CCharConversion::ConvertACharToString(x.what(), str),
|
|
_T(""),
|
|
EV_GTS_STL_EXCEPTION );
|
|
}
|
|
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// Rebuild all topics from source files
|
|
void CTopicShop::RebuildAll()
|
|
{
|
|
|
|
LOCKOBJECT();
|
|
for (CTopicCatalog::const_iterator it = m_TopicCatalog.begin(); it != m_TopicCatalog.end(); ++it)
|
|
{
|
|
BuildTopic(it->second->GetTopicInfo().GetNetworkName());
|
|
}
|
|
for (CTemplateCatalog::const_iterator itu = m_TemplateCatalog.begin(); itu != m_TemplateCatalog.end(); ++itu)
|
|
{
|
|
BuildTemplate( itu->first );
|
|
}
|
|
UNLOCKOBJECT();
|
|
}
|
|
|
|
// Get status information on the topic builder thread
|
|
DWORD CTopicShop::GetThreadStatus(ThreadStatus &ts, DWORD & seconds) const
|
|
{
|
|
return m_TopicBuildQueue.GetStatus(ts, seconds);
|
|
}
|
|
|
|
// see CTopicShop::CTopicBuildQueue::GetTopicsStatus for documentation.
|
|
void CTopicShop::GetTopicsStatus(
|
|
DWORD &Total, DWORD &NoInit, DWORD &Fail, vector<CString>*parrstrFail) const
|
|
{
|
|
m_TopicBuildQueue.GetTopicsStatus(Total, NoInit, Fail, parrstrFail);
|
|
}
|
|
|
|
// see CTopicShop::CTopicBuildQueue::GetTemplatesStatus for documentation.
|
|
void CTopicShop::GetTemplatesStatus( vector<CString>*parrstrFail, vector<DWORD>*parrcntFail ) const
|
|
{
|
|
m_TopicBuildQueue.GetTemplatesStatus( parrstrFail, parrcntFail);
|
|
}
|
|
|
|
CTopicInCatalog* CTopicShop::GetCatalogEntry(const CString& strTopic) const
|
|
{
|
|
CTopicInCatalog* ret = NULL;
|
|
LOCKOBJECT();
|
|
CTopicCatalog::const_iterator it = m_TopicCatalog.find(strTopic);
|
|
if (it != m_TopicCatalog.end())
|
|
ret = it->second;
|
|
UNLOCKOBJECT();
|
|
return ret;
|
|
}
|
|
|
|
bool CTopicShop::RetTemplateInCatalogStatus( const CString& strTemplate, bool& bValid ) const
|
|
{
|
|
bool bIsPresent= false;
|
|
|
|
bValid= false;
|
|
LOCKOBJECT();
|
|
CTemplateCatalog::const_iterator it = m_TemplateCatalog.find( strTemplate );
|
|
if (it != m_TemplateCatalog.end())
|
|
{
|
|
CTemplateInCatalog* pTmp;
|
|
|
|
bIsPresent= true;
|
|
pTmp= it->second;
|
|
switch (pTmp->GetTemplateStatus())
|
|
{
|
|
case CTemplateInCatalog::eOK:
|
|
bValid= true;
|
|
break;
|
|
case CTemplateInCatalog::eFail:
|
|
// Template has failed to load so we will not try to reload it,
|
|
// but we need to increment the attempted load counter.
|
|
pTmp->CountFailed();
|
|
break;
|
|
default: ;
|
|
}
|
|
}
|
|
UNLOCKOBJECT();
|
|
return( bIsPresent );
|
|
}
|
|
|