//****************************************************************************** // // QSINK.H // // Copyright (C) 1996-1999 Microsoft Corporation // //****************************************************************************** #ifndef __QSINK_H__ #define __QSINK_H__ #include #include #include #include #include #include #include #include #include #include "eventrep.h" #include "evsink.h" #include "delivrec.h" /*************************************************************************** CQueueingEventSink ****************************************************************************/ class CQueueingEventSink : public CEventSink { protected: CUniquePointerQueue m_qpEvents; CCritSec m_cs; CCritSec m_sl; BOOL m_bDelivering; DWORD m_dwTotalSize; DWORD m_dwMaxSize; CEssNamespace* m_pNamespace; // // the logical name of this queueing sink. Queueing sinks can be // as fined grained ( e.g one per logical consumer instance ) or // they can be more coarse grained (e.g one per consumer provider) // LPWSTR m_wszName; // // aquired when performing and testing persistent queue initialization. // CCritSec m_csQueue; // // if recovery fails, then it stores its failure here. When new // deliveries come in we use this to tell us if we should reinitiate // recovery. // HRESULT m_hrRecovery; // // Used to synchronize with recovery. // HANDLE m_hRecoveryComplete; BOOL m_bRecovering; // // These buffers are used to marshal guaranteed deliveries. This // happens in SaveDeliveryRecord(). All calls to SaveDeliveryRecord() // are serialized, so we can keep re-using the buffers. // CBuffer m_MsgData; CBuffer m_MsgAuxData; // // Is used for removing messages after delivery. // CWbemPtr m_pRcvr; CWbemPtr m_pXactRcvr; // TODO : XACT // // Is used for saving deliveries before they are put into the // transient queue. // CWbemPtr m_pSend; CWbemPtr m_pXactSend; // TODO : XACT // // saves the record in the specified queue. called before the // delivery record is put on the transient queue. after a // guaranteed type record is actually delivered to the // consumer, then it will be removed from the queue. This happens // in delivery record's PostDeliveryAction. // HRESULT SaveDeliveryRecord( IWmiMessageSendReceive* pSend, CDeliveryRecord* pRecord ); // // Handles the creation of the appropriate persistent record type // based on QoS ( right now just guaranteed ). Saves records before // returning. // HRESULT GetPersistentRecord( ULONG cEvents, IWbemEvent** apEvents, DWORD dwQoS, CEventContext* pContext, CDeliveryRecord** ppRecord ); // // Handles creation of the appropriate record type based on the // QoS specified. If the QoS is a guaranteed type, then // it will call GetPersistentRecord(). // HRESULT GetDeliveryRecord( ULONG cEvents, IWbemEvent** apEvents, DWORD dwQoS, CEventContext* pContext, IWbemCallSecurity* pCallSec, CDeliveryRecord** ppRecord ); // // Called if GetPersistentRecord() returns an error. If the problem // can be corrected ( e.g. msmq service can be restarted ), then // recovery will be initiated. a return code of S_OK indicates to // the caller that they should retry their GetPersistentRecord() request. // HRESULT HandlePersistentQueueError( HRESULT hr, DWORD dwQos ); HRESULT InternalRecover( LPCWSTR wszQueueName, DWORD dwQoS ); HRESULT OpenReceiver( LPCWSTR wszQueueName, DWORD dwQoS, IWmiMessageSendReceive* pRecv, IWmiMessageQueueReceiver** pRcvr ); HRESULT OpenSender( LPCWSTR wszQueueName, DWORD dwQoS, IWmiMessageSendReceive** ppSend ); ~CQueueingEventSink(); public: CQueueingEventSink( CEssNamespace* pNamespace ); HRESULT SetName( LPCWSTR wszName ); void SetMaxQueueSize(DWORD dwMaxSize) {m_dwMaxSize = dwMaxSize;} // TODO : a lot of these parameters should go inside the context. STDMETHODIMP SecureIndicate( long lNumEvents, IWbemEvent** apEvents, BOOL bMaintainSecurity, BOOL bSlowDown, DWORD dwQoS, CEventContext* pContext ); HRESULT Indicate( long lNumEvents, IWbemEvent** apEvents, CEventContext* pContext ) { return SecureIndicate( lNumEvents, apEvents, TRUE, FALSE, WMIMSG_FLAG_QOS_EXPRESS, pContext); } HRESULT DeliverAll(); virtual HRESULT ActuallyDeliver(long lNumEvents, IWbemEvent** apEvents, BOOL bSecure, CEventContext* pContext) = 0; virtual HRESULT ReportQueueOverflow(IWbemEvent* pEvent, DWORD dwQueueSize) {return S_OK;} virtual HRESULT ReportQosFailure(IWbemEvent* pEvent, HRESULT hresError ) {return S_OK;} static HRESULT QueueNameToSinkName( LPCWSTR wszQueueName, WString& rwsSinkName, WString& rwsNamespace, DWORD& rdwQoS ); static HRESULT SinkNameToQueueName( LPCWSTR wszSinkName, LPCWSTR wszNamespace, DWORD dwQoS, WString& rwsQueueName ); // // called by guaranteed delivery record when it needs to remove a // delivery from the guaranteed queue. // HRESULT GuaranteedPostDeliverAction( IWmiMessageQueueReceiver* pRcvr ); // // Opens the specified queue and initiates the delivery of persisted // records. Called on startup by the ess object on a background thread. // Also called when encountering errors with saving or removing // delivery records from the persistent queues. // HRESULT Recover( LPCWSTR wszQueueName, DWORD dwQoS ); // // this method is called when a queueing sink is removed because all of // the consumers associated with it have been removed. // HRESULT CleanupPersistentQueues(); protected: DWORD GetMaxDeliverySize(); BOOL DoesRecordFitBatch( CDeliveryRecord* pRecord, IWbemCallSecurity* pBatchSecurity, LUID luidBatch ); HRESULT DeliverSome( ); void ClearAll(); HRESULT DeliverEvents( IWbemCallSecurity* pBatchSecurity, long lNumEvents, IWbemEvent** apEvents); BOOL AddRecord( ACQUIRE CDeliveryRecord* pRecord, BOOL bSlowDown, DWORD* pdwSleep, BOOL* pbFirst); void WaitABit(); }; #endif // __QSINK_H__