[ZT]调度引擎初步分析
相关UML:
CAttempterEngine实现了两个接口:IQueueServiceSink、IAttemperEngine;
通 过前面的分析,偶们了解到,IQueueServiceSink这个接口被是用来处理CQueueService中的数据的,根据上面的UML我们可以看 到,CAttemperEngine关联了一个CQueueService(或者直接点说是:持有了一个CQueueService对象,说组合也成)。 这样的话这个CAttemperEngine暴露出来的接口就只剩下IAttemperEnging了。
//启动服务2
virtualbool __cdecl StartService();3
//停止服务4
virtualbool __cdecl StopService();5
//设置网络6
virtualbool __cdecl SetSocketEngine(IUnknownEx * pIUnknownEx);7
//注册钩子8
virtualbool __cdecl SetAttemperEngineSink(IUnknownEx * pIUnknownEx);9
//获取接口10
virtualvoid* __cdecl GetQueueService(const IID & Guid, DWORD dwQueryVer);
这个接口有两处值得单独讨论的:SetSocketEngine、GetQueueService;
SetSocketEngine,后面的分析中还会出现,我觉得这里是一个设计上的失误导致需要暴露socket引擎接口;
GetQueueService 的设计思路可能是说,每个IAttemperEngine接口背后都有一个CQueueService,从以后的分析中可以看到,这个思路是理解整个 kernel的关键。调度引擎应该是一个消息汇总(从个个引擎产生的消息)然后派发到IAttemperEngineSink。因为代码中是没有看到有关 ITimerSink ISocketSink之类的东东的,,,
整个消息是个引擎产生,然后投递到指定的CQueueService,然后汇总到这里被派发到IAttemperEngineSink出去的,,,
看看CAttemperEngine中处理数据的代码:
//队列接口2
void __cdecl CAttemperEngine::OnQueueServiceSink(WORD wIdentifier, void * pBuffer, WORD wDataSize, DWORD dwInsertTime)3
{4
//内核事件5
ASSERT(m_pIAttemperEngineSink!=NULL);6
switch (wIdentifier)7
{8
case EVENT_TIMER: //定时器事件9
{10
//效验参数11
ASSERT(wDataSize==sizeof(NTY_TimerEvent));12
if (wDataSize!=sizeof(NTY_TimerEvent)) return;13

14
//处理消息15
NTY_TimerEvent * pTimerEvent=(NTY_TimerEvent *)pBuffer;16
m_pIAttemperEngineSink->OnEventTimer(pTimerEvent->wTimerID,pTimerEvent->wBindParam);17

18
return;19
}20
case EVENT_DATABASE: //数据库事件21
{22
//效验参数23
ASSERT(wDataSize>=sizeof(NTY_DataBaseEvent));24
if (wDataSize<sizeof(NTY_DataBaseEvent)) return;25

26
//处理消息27
NTY_DataBaseEvent * pDataBaseEvent=(NTY_DataBaseEvent *)pBuffer;28
m_pIAttemperEngineSink->OnEventDataBase(pDataBaseEvent+1,wDataSize-sizeof(NTY_DataBaseEvent),pDataBaseEvent);29

30
return;31
}32
case EVENT_SOCKET_ACCEPT: //网络应答事件33
{34
//效验大小35
ASSERT(wDataSize==sizeof(NTY_SocketAcceptEvent));36
if (wDataSize!=sizeof(NTY_SocketAcceptEvent)) return;37

38
//处理消息39
NTY_SocketAcceptEvent * pSocketAcceptEvent=(NTY_SocketAcceptEvent *)pBuffer;40
m_pIAttemperEngineSink->OnEventSocketAccept(pSocketAcceptEvent);41

42
return;43
}44
case EVENT_SOCKET_READ: //网络读取事件45
{46
//效验大小47
NTY_SocketReadEvent * pSocketReadEvent=(NTY_SocketReadEvent *)pBuffer;48
ASSERT(wDataSize>=sizeof(NTY_SocketReadEvent));49
ASSERT(wDataSize==(sizeof(NTY_SocketReadEvent)+pSocketReadEvent->wDataSize));50
if (wDataSize<sizeof(NTY_SocketReadEvent)) return;51
if (wDataSize!=(sizeof(NTY_SocketReadEvent)+pSocketReadEvent->wDataSize)) return;52

53
//处理消息54
bool bSuccess=false;55
try 56
{ 57
bSuccess=m_pIAttemperEngineSink->OnEventSocketRead(pSocketReadEvent->Command,pSocketReadEvent+1,pSocketReadEvent->wDataSize,pSocketReadEvent);58
}59
catch (
) { }60
if (bSuccess==false) m_pITCPSocketEngine->CloseSocket(pSocketReadEvent->wIndex,pSocketReadEvent->wRoundID);61

62
return;63
}64
case EVENT_SOCKET_CLOSE: //网络关闭事件65
{66
//效验大小67
ASSERT(wDataSize==sizeof(NTY_SocketCloseEvent));68
if (wDataSize!=sizeof(NTY_SocketCloseEvent)) return;69

70
//处理消息71
NTY_SocketCloseEvent * pSocketCloseEvent=(NTY_SocketCloseEvent *)pBuffer;72
m_pIAttemperEngineSink->OnEventSocketClose(pSocketCloseEvent);73

74
return;75
}76
}77

78
//其他事件79
m_pIAttemperEngineSink->OnAttemperEvent(wIdentifier,pBuffer,wDataSize,dwInsertTime); 80

81
return;82
}
这个函数中一个很重要的参数:wIdentifier;
可以来追溯一下他的源头:
//数据消息2
void CQueueService::OnQueueServiceThread(const tagDataHead & DataHead, void * pBuffer, WORD wDataSize)3
{4
ASSERT(m_pIQueueServiceSink!=NULL);5
try 6
{ 7
m_pIQueueServiceSink->OnQueueServiceSink(DataHead.wIdentifier,pBuffer,DataHead.wDataSize,DataHead.dwInsertTime); 8
}9
catch (
) {}10
return;11
}可以看见他是直接保存在最底层的那个DataStroage里边的,这个在上一章分析中可以看到。(个引擎利用CQueueServiceEvent Post数据的时候就携带了类型信息)
另 外一个要注意的点是对socket事件的处理,我之前认为调度引擎组合了一个socket引擎是一个设计缺陷,应为这里的在处理socket read事件的时候如果异常了直接直接使用引擎来关闭socket而不是调用socket sink的指定接口。猜想也许是不希望客户端直接处理socket句柄吧,,,
还是用一句话描述下调度引擎:
调度引擎的工作可以这样描述消息汇总、派发。其他引擎通过CQueueServiceEvent将消息post到调度引擎上来(通过共享同一个CQueueService),然后由调度引擎集中派发出去,,,
浙公网安备 33010602011771号