2026-09-09 01:19:31 +03:00 | | | //+------------------------------------------------------------------+
|
2026-09-10 16:43:28 +03:00 | | | //| EventJournal.mqh |
|
2026-09-16 15:37:55 +03:00 | | | //| Copyright 2026, MetaQuotes Ltd. |
|
2026-09-10 16:43:28 +03:00 | | | //| www.mql5.com |
|
2026-09-09 01:19:31 +03:00 | | | //+------------------------------------------------------------------+
|
| | | #ifndef REQUEST_LATENCY_LAB_EVENT_JOURNAL_MQH
|
| | | #define REQUEST_LATENCY_LAB_EVENT_JOURNAL_MQH
|
| | |
|
| | | #include "..\..\Include\RequestLatencyLab\Models.mqh"
|
| | |
|
| | | class CEventJournal
|
| | | {
|
| | | private:
|
2026-09-12 22:14:24 +03:00 | | | LabEvent m_events[];
|
| | | int m_capacity;
|
| | | int m_count;
|
| | | ulong m_next_sequence; // event_sequence - порядок регистрации
|
| | | ulong m_records_lost; // записи, не поместившиеся в буфер
|
| | | ulong m_high_watermark; // максимум занятости буфера
|
| | | string m_session_id;
|
2026-09-09 01:19:31 +03:00 | | |
|
| | | public:
|
2026-09-16 15:37:55 +03:00 | | | CEventJournal(void);
|
| | | bool Init(const int capacity, const string session_id);
|
2026-09-12 22:14:24 +03:00 | | | void Clear(void)
|
2026-09-09 01:19:31 +03:00 | | | {
|
2026-09-12 22:14:24 +03:00 | | | m_count = 0;
|
2026-09-09 01:19:31 +03:00 | | | }
|
2026-09-12 22:14:24 +03:00 | | | int Count() const { return(m_count); }
|
| | | int Capacity() const { return(m_capacity); }
|
| | | ulong NextSequence() const { return(m_next_sequence); }
|
| | | ulong LostCount() const { return(m_records_lost); }
|
| | | ulong HighWatermark() const { return(m_high_watermark); }
|
2026-09-09 01:19:31 +03:00 | | | //--- регистрация события; возвращает event_sequence
|
2026-09-16 15:37:55 +03:00 | | | bool Add(const LabEvent &event, ulong &event_sequence);
|
2026-09-09 01:19:31 +03:00 | | | //--- удобная регистрация типизированной записи
|
2026-09-12 22:14:24 +03:00 | | | bool AddTyped(const ENUM_LAB_RECORD_KIND kind, const ulong local_time_us,
|
| | | const ulong origin_sequence, const string payload_json,
|
2026-09-16 15:37:55 +03:00 | | | const string quality_code);
|
2026-09-10 16:43:28 +03:00 | | | //--- фиксация времени выхода обработчика по event_sequence (п.11 аудита)
|
2026-09-16 15:37:55 +03:00 | | | bool SetExitTime(const ulong event_sequence, const ulong exit_us);
|
| | | bool GetByIndex(const int i, LabEvent &out) const;
|
2026-09-09 01:19:31 +03:00 | | | //--- освобождение места для последующих событий после контрольного
|
| | | //--- сохранения (без молчаливой потери: потерянные уже учтены)
|
2026-09-16 15:37:55 +03:00 | | | void DropPersisted(const int persisted_count, ulong &dropped);
|
| | | };
|
| | | //+------------------------------------------------------------------+
|
| | | //| Внешние определения методов. |
|
| | | //+------------------------------------------------------------------+
|
| | | CEventJournal::CEventJournal(void)
|
| | | {
|
| | | m_capacity = 0;
|
| | | m_count = 0;
|
| | | m_next_sequence = 1;
|
| | | m_records_lost = 0;
|
| | | m_high_watermark = 0;
|
| | | m_session_id = "";
|
| | | }
|
| | | bool CEventJournal::Init(const int capacity, const string session_id)
|
| | | {
|
| | | m_capacity = capacity;
|
| | | m_session_id = session_id;
|
| | | m_count = 0;
|
| | | m_next_sequence = 1;
|
| | | m_records_lost = 0;
|
| | | m_high_watermark = 0;
|
| | | if(ArrayResize(m_events, m_capacity) != m_capacity)
|
| | | return(false);
|
| | | return(true);
|
| | | }
|
| | | bool CEventJournal::Add(const LabEvent &event, ulong &event_sequence)
|
| | | {
|
| | | if(m_capacity <= 0 || m_count >= m_capacity)
|
2026-09-09 01:19:31 +03:00 | | | {
|
2026-09-16 15:37:55 +03:00 | | | m_records_lost++;
|
| | | return(false);
|
| | | }
|
| | | m_count++;
|
| | | m_events[m_count - 1] = event;
|
| | | m_events[m_count - 1].session_id = m_session_id;
|
| | | m_events[m_count - 1].event_sequence = m_next_sequence;
|
| | | event_sequence = m_next_sequence;
|
| | | m_next_sequence++;
|
| | | if((ulong)m_count > m_high_watermark)
|
| | | m_high_watermark = (ulong)m_count;
|
| | | return(true);
|
| | | }
|
| | | bool CEventJournal::AddTyped(const ENUM_LAB_RECORD_KIND kind, const ulong local_time_us,
|
| | | const ulong origin_sequence, const string payload_json,
|
| | | const string quality_code)
|
| | | {
|
| | | LabEvent e;
|
| | | e.Zero();
|
| | | e.kind = kind;
|
| | | e.local_time_us = local_time_us;
|
| | | e.origin_sequence = origin_sequence;
|
| | | e.payload_json = payload_json;
|
| | | e.quality_code = quality_code;
|
| | | ulong seq = 0;
|
| | | return(Add(e, seq));
|
| | | }
|
| | | bool CEventJournal::SetExitTime(const ulong event_sequence, const ulong exit_us)
|
| | | {
|
| | | for(int i = 0; i < m_count; i++)
|
| | | if(m_events[i].event_sequence == event_sequence)
|
2026-09-09 01:19:31 +03:00 | | | {
|
2026-09-16 15:37:55 +03:00 | | | m_events[i].handler_exit_us = exit_us;
|
| | | return(true);
|
2026-09-09 01:19:31 +03:00 | | | }
|
2026-09-16 15:37:55 +03:00 | | | return(false);
|
| | | }
|
| | | bool CEventJournal::GetByIndex(const int i, LabEvent &out) const
|
| | | {
|
| | | if(i < 0 || i >= m_count)
|
| | | return(false);
|
| | | out = m_events[i];
|
| | | return(true);
|
| | | }
|
| | | void CEventJournal::DropPersisted(const int persisted_count, ulong &dropped)
|
| | | {
|
| | | dropped = 0;
|
| | | if(persisted_count <= 0)
|
| | | return;
|
| | | if(persisted_count >= m_count)
|
| | | {
|
| | | dropped = m_count;
|
| | | m_count = 0;
|
| | | return;
|
2026-09-09 01:19:31 +03:00 | | | }
|
2026-09-16 15:37:55 +03:00 | | | dropped = persisted_count;
|
| | | for(int i = persisted_count; i < m_count; i++)
|
| | | m_events[i - persisted_count] = m_events[i];
|
| | | m_count -= persisted_count;
|
| | | }
|
2026-09-09 01:19:31 +03:00 | | |
|
2026-09-12 22:14:24 +03:00 | | | #endif // REQUEST_LATENCY_LAB_EVENT_JOURNAL_MQH
|
| | | //+------------------------------------------------------------------+
|